📄 efaxlib.c
字号:
/* efaxlib.c - utility routines for efax Copyright 1995 Ed Casas*/#include <ctype.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdarg.h> #include <time.h>#include "efaxlib.h"#define MAXTSTAMP 80 /* maximum length of a time stamp */#ifndef SEEK_SET#define SEEK_SET 0#endifchar *verb = "ewin" ; char *argv0 = "" ;int optind = 1 ;char *optarg ;extern t4tab wtab [ ( 64 + 27 + 13 ) + 1 ] ; /* T.4 coding tables */extern t4tab btab [ ( 64 + 27 + 13 ) + 1 ] ;char *iformatstr[] = { "0text", "1pbm", "2fax", 0 } ;char *oformatstr[] = { "1pbm" , "2fax", "3pcl", "4ps", "5pgm", 0 } ; /* Print time stamp. */void tstamp ( int dotime ){ static time_t last = 0, now ; char *fmt = 0, tbuf [ MAXTSTAMP ] ; now = time ( 0 ) ; if ( dotime || ( now - last > 0 ) ) fmt = " (%M:%S)" ; if ( now - last > 600 ) fmt = " %c" ; if ( fmt ) { strftime ( tbuf, MAXTSTAMP, fmt, localtime( &now ) ) ; fputs ( tbuf , LOGF ) ; last = now ; }}/* For systems without strerror(3) */char *strerror( int i ) { extern int sys_nerr; extern char *sys_errlist[]; return ( i >= 0 && i < sys_nerr ) ? sys_errlist[i] : "Unknown Error" ;}/* Return string corresponding to character c. */char *cname ( u_char c ) {#define CNAMEFMT "<0x%02x>"#define CNAMELEN 6+1 static char *cname [ 256 ] = { /* character names */ "<NUL>","<SOH>","<STX>","<ETX>", "<EOT>","<ENQ>","<ACK>","<BEL>", "<BS>", "<HT>", "<LF>", "<VT>", "<FF>", "<CR>", "<SO>", "<SI>", "<DLE>","<XON>","<DC2>","<XOFF>","<DC4>","<NAK>","<SYN>","<ETB>", "<CAN>","<EM>", "<SUB>","<ESC>", "<FS>", "<GS>", "<RS>", "<US>" } ; static char names[ (127-32)*2 + 129*(CNAMELEN) ], *p=names ; static int i=0 ; if ( ! i ) for ( i=32 ; i<256 ; i++ ) { sprintf ( cname [ i ] = p , i<127 ? "%c" : CNAMEFMT , i ) ; p += strlen ( p ) + 1 ; } return cname [ c ] ;} /* Print a message with a variable number of printf()-type arguments if the first character appears in the global verb[ose] string. Other leading characters and digits do additional actions: + allows the message to be continued on the same line, '-' buffers the message instead of printing it, E, and W expand into strings, S prints the error message for the most recent system error, 0-4 set the return value, a space is skipped and ends prefix. Returns 0 if no prefix digit. */int msg ( const char *fmt, ... ) { int err=0, dolf=1, flush=1, dotime=0 ; char *ps="", *pe="", *pw="" ; const char *p ; static int atcol1=1 ; va_list ap ; va_start ( ap, fmt ) ; for ( p=fmt ; *p ; p++ ) { switch ( *p ) { case ' ': p++ ; goto print ; case 'A': break ; /* program args */ case 'C': break ; /* commands/responses */ case 'M': break ; /* modem dialogue */ case 'N': break ; /* negotiation */ case 'E': pw = "Error: " ; break ; case 'H': break ; /* HDLC frame data */ case 'I': break ; /* information */ case '+': dolf = 0 ; break ; case '-': flush = 0 ; break ; case 'R': break ; /* reception errors */ case 'S': ps = strerror ( errno ) ; break ; case 'T': dotime = 1 ; break ; case 'W': pw = "Warning: " ; break ; case '0': case '1': case '2': case '3': case '4': case '5': err = *p - '0' ; break ; default: goto print ; } } print: if ( strchr ( verb , tolower ( *fmt ) ) ) { if ( atcol1 ) fprintf ( LOGF , "%s: %s%s" , argv0 , pe , pw ) ; vfprintf( LOGF, p , ap ) ; fputs ( ps , LOGF ) ; atcol1 = dolf ; if ( atcol1 ) { tstamp ( dotime ) ; fputs ( "\n" , LOGF ) ; } if ( flush ) fflush ( LOGF ) ; } va_end ( ap ) ; return err ;}/* Simple (one option per argument) version of getopt(3). */int nextopt( int argc, char **argv, char *args ){ char *a, *p ; if ( optind >= argc || *(a = argv[optind]) != '-' ) return -1 ; optind++ ; if ( ! *(a+1) || ( ( p = strchr ( args , *(a+1) ) ) == 0 ) ) return msg ( "Eunknown option (%s)" , a ) , '?' ; if ( *(p+1) != ':' ) optarg = 0 ; else if ( *(a+2) ) optarg = a+2 ; else if ( optind >= argc ) return msg ( "Eno argument for (%s)", a ) , '?' ; else optarg = argv [ optind++ ] ; return *(a+1) ;}/* Initialize state of encoder for variable-length code words. */void newENCODER ( ENCODER *e ){ e->x = 0 ; e->shift = -8 ;}/* Store a code word `code' of length `bits' (<=24) in buffer pointed to by `buf'. Bits that don't fit in complete bytes are saved between calls. To flush the remaining bits call the function with code=0 and bits=0. Returns pointer to next free element in output buffer. Calling function must ensure at least bits/8 bytes are available in buffer. */u_char *putcode ( ENCODER *e, short code, short bits , u_char *buf ){ e->x = ( e->x << bits ) | code ; e->shift += bits ? bits : -e->shift ; while ( e->shift >= 0 ) { *buf++ = e->x >> e->shift ; e->shift -= 8 ; } return buf ;}/* Convert run lengths to 1-D T.4-codes. First run is white. Silently truncates run lengths that are too long. After using this function EOLs may need to be added and/or the putcode() buffer flushed. Returns pointer to next free element in output buffer. */u_char *runtocode ( ENCODER *e, short *runs, int nr, u_char *codes ){ u_char col = 0, *maxcodes = codes + MAXCODES ; t4tab *ctab = wtab, *p ; short rlen ; long x ; short shift ;#define PUTCODE(p) { x = ( x << p->bits ) | p->code ; shift += p->bits ; \ while ( shift >= 0 ) { *codes++ = x >> shift ; shift -= 8 ; } } x = e->x ; shift = e->shift ; while ( nr-- > 0 ) { rlen = *runs++ ; if ( rlen > 63 ) { /* make-up code */ if ( rlen > MAXRUNLEN ) rlen = MAXRUNLEN ; p = ctab + 63 + ( rlen >> 6 ) ; if ( codes < maxcodes ) PUTCODE(p) ; } p = ctab + ( rlen & 0x3f ) ; /* terminating code */ if ( codes < maxcodes ) PUTCODE(p) ; ctab = ( col ^= 1 ) ? btab : wtab ; } e->x = x ; e->shift = shift ; return codes ;}/* Pad/truncate run-length coded scan line 'runs' of 'nr' runs by 'pad' pixels (truncate if negative). Returns the new number of runs. */int xpad ( short *runs, int nr, int pad ){ if ( pad < 0 ) { /* truncate */ while ( pad < 0 ) pad += ( nr <= 0 ? -pad : runs [ --nr ] ) ; runs [ nr++ ] = pad ; } else { /* pad with white */ if ( nr & 1 ) runs [ nr - 1 ] += pad ; else runs [ nr++ ] = pad ; } return nr ;}/* Shift a run-length coded scan line right by s pixels (left if negative). If necessary, zero-length runs are created to avoid copying. Returns the pixel width change (+/-). */int xshift ( short *runs, int nr, int s ){ int i=0, n=0 ; if ( s < 0 ) { for ( i = 0 ; s < 0 && i < nr ; i++ ) { s += runs [ i ] ; n -= runs [ i ] ; runs [ i ] = 0 ; } i-- ; } if ( i < nr ) { runs [ i ] += s ; n += s ; } return n ;}/* Scale nr run lengths in buffer pointed to by p to scale image horizontally. The scaling factor is xs/256. Returns new line width in pixels. */int xscale ( short *p , int nr, int xs ){ int inlen=0, outlen=0 ; for ( ; nr-- > 0 ; p++ ) { inlen += *p ; *p = ( ( inlen * xs + 128 ) >> 8 ) - outlen ; outlen += *p ; } return outlen ;}/* Zero-terminated lists of run lengths for each byte. */u_char byteruns [ 1408 + 1 ] = "8071061106205120511105210530413041210411110411204220421104310440" "3140313103121103122031112031111103112103113032303221032111032120" "3320331103410350215021410213110213202121202121110212210212302111" "3021112102111111021111202112202112110211310211402240223102221102" "2220221120221111022121022130233023210231110231202420241102510260" "1160115101141101142011312011311101132101133011213011212101121111" "0112112011222011221101123101124011114011113101111211011112201111" "1120111111110111112101111130111230111221011121110111212011132011" "1311011141011150125012410123110123201221201221110122210122301211" "3012112101211111012111201212201212110121310121401340133101321101" "3220131120131111013121013130143014210141110141201520151101610170" "1701610151101520141201411101421014301313013121013111101311201322" "0132110133101340121401213101212110121220121112012111110121121012" "1130122301222101221110122120123201231101241012501115011141011131" "1011132011121201112111011122101112301111130111112101111111101111" "1120111122011112110111131011114011240112310112211011222011211201" "1211110112121011213011330113210113111011312011420114110115101160" "2602510241102420231202311102321023302213022121022111102211202222" "0222110223102240211402113102112110211220211112021111110211121021" "1130212302122102121110212120213202131102141021503503410331103320" "3212032111032210323031130311210311111031112031220312110313103140" "4404310421104220411204111104121041305305210511105120620611071080" ;/* Convert byte-aligned bit-mapped n-byte scan line into array of run lengths. Run length array must have *more* than 8*n elements. First run is white. Returns number of runs coded. */int bittorun ( u_char *bits, int n, short *runs ){ static u_char init=0, *rltab [ 256 ] ; register u_char *p, c, lastc = 0x00 ; short *runs0 = runs ; if ( ! init ) { /* initialize pointer and run tables */ int i = 0 ; for ( rltab[ 0 ] = p = byteruns ; *p ; p++ ) if ( ! ( *p -= '0' ) && i < 255 ) rltab [ ++i ] = p+1 ; init = 1 ; } *runs = 0 ; for ( ; n > 0 ; n-- ) { p = rltab [ c = *bits++ ] ; if ( ( lastc & 0x01 ) ? ! ( c & 0x80 ) : ( c & 0x80 ) ) *(++runs) = *p++ ; /* new run */ else *runs += *p++ ; /* continue run */ while ( *p ) *(++runs) = *p++ ; lastc = c ; } return runs - runs0 + 1 ;}/* Bitwise-OR two run-length coded scan lines. The run length vectors a and b are OR-ed into c. If c is null, the result is placed in a. The new image width is stored in pels if it is not null. Returns the number of runs in the result. */int runor ( short *a, int na, short *b, int nb, short *c, int *pels ){ register short la, lb ; int ia, ib, ic, np=0 ; short tmp [ MAXRUNS ] ; if ( ! c ) c = tmp ; la = a [ ia = 0 ] ; lb = b [ ib = 0 ] ; c [ ic = 0 ] = 0 ; while ( 1 ) { if ( la <= lb ) { /* select shorter sub-run */ if ( ( ( ia | ib ) ^ ic ) & 1 ) /* OR of subruns same colour as c? */ c [ ++ic ] = la ; /* no, new output run */ else c [ ic ] += la ; /* yes, add it */ lb -= la ; /* align subruns */ if ( ++ia >= na ) break ; /* done */ la = a [ ia ] ; /* get new subrun */ } else { /* same for line b ... */ if ( ( ( ia | ib ) ^ ic ) & 1 ) c [ ++ic ] = lb ; else c [ ic ] += lb ; la -= lb ; if ( ++ib >= nb ) break ; lb = b [ ib ] ; } } if ( ia < na ) while ( 1 ) { if ( ( ia ^ ic ) & 1 ) c [ ++ic ] = la ; else c [ ic ] += la ; if ( ++ia >= na ) break ; la = a [ ia ] ; } else while ( 1 ) { if ( ( ib ^ ic ) & 1 ) c [ ++ic ] = lb ; else c [ ic ] += lb ; if ( ++ib >= nb ) break ; lb = b [ ib ] ; } if ( c == tmp ) for ( ia=0 ; ia <= ic ; ia++ ) np += a[ia] = c[ia] ; if ( pels ) *pels = np ; return ic + 1 ;} /* Check a raw PBM file header and get bitmap dimensions. Leaves stream positioned on first data byte. Returns 0 or closes file and returns 2 on errors. */int openpbm ( FILE *f, int *w, int *h ){ int err = 0 ; if ( f && fscanf ( f , "P4 %d %d%*c", w, h ) != 2 ) { err = msg ("E2can't read (raw) PBM header" ) ; fclose ( f ) ; *w = *h = 0 ; } return err ;}/* Read a PBM font and fill in font structure. If the file name is null or there are errors, it initializes the font to the built-in font. Returns 0 if OK, 2 on errors. */int readfont ( char *fname, pbmfont *font ){ int err=0, i, j, n=0 ; if ( fname ) { FILE *f ; if ( ( f = fopen ( fname , "rb" ) ) == 0 ) err = msg ("ES2can't open font file %s:\n", fname ) ; if ( ! err && openpbm ( f, & font->w, & font->h ) != 0 ) err = msg ( "E2bad font file (%s) header", fname ) ; if ( ! err && ( n = fread ( font->buf, 1, MAXFONTBUF, f ) ) != font->w * font->h / 8 ) err = msg ( "E2error reading font data" ) ; if ( ! err && ( font->w / 256 > MAXFONTW || font->h > MAXFONTH ) ) { err = msg ( "E2font size (%dx%d) too large", font->w, font->h ) ; } if ( err ) { if ( f ) fclose ( f ) ; font->w = font->h = 0 ; } else { font->w /= 256 ; /* convert PBM width to character width */ for ( i=0 ; i<256 ; i++ ) font->offset[i] = i*font->w ; msg ("Iread %dx%d font %s (%d bytes)", font->w, font->h, fname, n ) ; } } if ( err || ! fname ) { /* use built-in font */ font->w = STDFONTW ; font->h = STDFONTH ; for ( i=j=0 ; j<STDFONTBUF ; i++ ) /* expand bit map */ if ( stdfont [ i ] == 0 ) for ( n = stdfont [ ++i ] ; n > 0 ; n-- ) font->buf [ j++ ] = 0 ; else font->buf [ j++ ] = stdfont [ i ] ; if ( i != 1980 ) err = msg ( "E2can't happen(readfont)" ) ; for ( i=0 ; i<256 ; i++ ) font->offset[i] = i*font->w ; } return err ;}/* Append nb bits from in[from] to bit-mapped scan line buffer where `from' is a bit (not byte) index. Bits in bytes are ordered from MS to LS bit. Initialize before each scan line by calling with nb=0 and in pointing to output buffer. Flush
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -