/* fwid.c -- fix width of a file */ /* Syntax: fwid maxwidth [-t] [filename] */ /* Write standard output. If no filename is given, read standard input. Use width = 0 to remove "hard" linefeeds. Otherwise, width is the max. width of any line, not counting esc. seqs. and control chars. Supported esc. seqs. are those of the form ...m The "-t" switch prevents line merging, i.e., preserves all linefeeds in the original. */ #include #include #define MAX(a,b) ((a)>(b)?(a):(b)) #define MIN(a,b) ((a)<(b)?(a):(b)) #define OBUFSIZE 255 #define TABSIZE 3 #define MAXWIDTH 255L #define BSCH 0x08 /* backspace */ #define FFCH 0x0c /* formfeed */ #define ESCH 0x1b /* escape */ #define PRAL 0x21 /* visible ascii low end */ #define CSEL 0x40 /* control seq. end low */ #define CSEH 0x7f /* control seq. end high */ #define PRAH 0x7f /* visible ascii high end */ #define CSCH 0x9b /* control seq. intro. */ #define PREL 0xa0 /* visible extended low end */ #define PREH 0xff /* visible extended high end */ /****** Function declarations ******/ extern long atol(); void syntax(), passch(); /********************** Global variables ***********************/ char obuf[OBUFSIZE+1]; /* holding buffer for stdout */ char *abuf; /* abuf = &obuf[1] */ int obuflen; /* length of obuf */ long width; /* arg. spec for max width */ long wide; /* visible column of current char. */ long pwide; /* wide value just before last word */ /*******************************************************************/ main(argc,argv) int argc; char *argv[]; { register int chx; register FILE *instream; FILE *filearg = (FILE *)NULL; int argn; int consec = 0; /* count of consecutive linefeeds */ int escflag = 0, csiflag = 0, flushflag = 0, tflag = 0; int jj = 0; long brokenword = 0L; long twide = 0L; width = 0L; wide = 0L; pwide = 0L; instream = stdin; abuf = &obuf[1]; /* Most of the time obuf[0] will be '\n' */ obuflen = 0; argn = argc - 1; if((argc ==2)&&((!strcmp(argv[1],"?"))|| (!strcmp(argv[1],"h"))||(!strcmp(argv[1], "-h")))) { syntax(argv[0]); exit(0); } if((argc < 2)||(argc > 4)) { syntax(argv[0]); exit(5); } for(jj=0; jj < strlen(argv[1]); jj ++) { if( !isdigit( (int)(argv[1][jj]) ) ) { strcpy(obuf, " The first argument must be a non-negative integer.\n"); fputs(obuf, stderr); exit(5); } } width = atol(argv[1]); if(width < 0) { strcpy(obuf, " The first argument must be non-negative.\n"); fputs(obuf, stderr); exit(11); } if(argc >= 3) { if(strcmp(argv[2], "-t")==0) { tflag = 1; } else if(argn == 3) { syntax(argv[0]); exit(5); } if(argn >= 2+tflag) { filearg = fopen(argv[2+tflag], "r"); if (filearg == (FILE *)NULL) { strcpy(obuf, " Cannot open the file \""); strcat(obuf, argv[2+tflag]); strcat(obuf, "\"\n"); fputs(obuf, stderr); exit(5); } instream = filearg; } } obuf[0] = '\n'; obuflen = 1; obuf[1] = '\0'; while (( chx = getc(instream)) != EOF) { /* Skip over null characters in input */ if (chx == '\0') continue; /* First, is it mandatory to put out a linefeed? */ if (chx == '\n') /* current character is a linefeed */ { consec ++; if(flushflag) { flushflag = 0; wide = 0L; pwide = 0L; passch(chx); consec --; } } else /* current character is not a linefeed */ { if (consec > 0) /* deal with accumulated linefeeds */ { if (consec == 1) { if ((chx==' ')||(chx=='\t')||(chx==FFCH)) /* new paragraph */ { passch('\n'); /* pass the previous linefeed */ wide = 0L; pwide = 0L; } else /* the previous \n should become ' ' unless "-t". */ { if(!tflag) { passch(' '); wide ++; pwide = wide; } else /* tflag is set; preserve linefeeds */ { passch('\n'); /* pass the previous linefeed */ wide = 0L; pwide = 0L; } } } else /* pass through the sequence of '\n' */ { for (; consec > 0; consec--) passch('\n'); wide = 0L; pwide = 0L; } consec = 0; } /* end of case: consec > 0 (chx not LF) */ if(flushflag) { flushflag = 0; if((chx == ' ')||(chx == '\t')) { passch('\n'); wide = 0L; pwide = 0L; continue; } else if(chx == FFCH) { passch(chx); wide = 0L; pwide = 0L; continue; } else { if(pwide) /* Flush buffer beginning with a linefeed */ { passch('\0'); wide = wide - pwide; pwide = 0L; } else /* Case: word longer than width */ { brokenword ++; passch('\n'); wide = 0L; } } } /* end of case: flushflag (chx not LF) */ passch(chx); } /* end of case: current character not a linefeed */ /* deal with escape sequences */ if( ( (escflag == 1)&&(chx == '[') ) || (chx == CSCH) ) { escflag = 0; csiflag = 1; continue; } if( (csiflag == 1) && (chx >= CSEL) && (chx <= CSEH) ) { csiflag = 0; continue; } escflag = 0; if( (chx == ESCH) && (csiflag == 0) ) { escflag = 1; continue; } if(csiflag) continue; /* Computation of "wide" */ if( (chx == ' ') || (chx == '\n') || (chx == '\t') || (chx == FFCH) ) { if(chx == ' ') wide ++; if(chx == '\t') wide = wide + (long)TABSIZE; pwide = wide; } else /* chx is not a word-ending character */ { if(chx == BSCH) { wide --; pwide = MIN(pwide, wide); } if( ( (PRAL <= chx)&&(chx <= PRAH) ) || ( (PREL <= chx)&&(chx <= PREH) ) ) /* visible != ' ' */ { wide ++; } } /* Is a linefeed now forced by width? */ if (width > 0) { if(wide == width) { flushflag = 1; /* Before flushing buffer, look at next chx */ } if(wide > width) { if(pwide) /* Flush buffer beginning with a linefeed */ { passch('\0'); wide = wide - pwide; pwide = 0L; } else /* Case: word longer than width */ { brokenword ++; passch('\n'); wide = 0L; } } } } /* end of "while" loop on chx */ if (consec > 0) for (; consec > 0; consec--) passch('\n'); if(filearg) fclose(filearg); if(brokenword) fprintf(stderr, "%s %ld: %ld words broken\n", argv[0], width, brokenword); exit(0); } void syntax(xstr) char *xstr; { strcpy(obuf, " Usage: "); strcat(obuf, xstr); strcat(obuf, " maxwidth [-t] [filename]\n"); strcat(obuf, " Use maxwidth = 0 to remove all \"hard\" linefeeds.\n"); strcat(obuf, " Use \"-t\" to prevent line merging.\n"); fputs(obuf, stderr); return; } /* passch -- pass a character through for output */ void passch(chx) register int chx; { if(obuflen>=OBUFSIZE) /* emergency buffer flush */ { fputs(abuf, stdout); obuflen = 1; obuf[1] = '\0'; } if( (chx=='\n') || (chx==FFCH) ) { /***************************************************************************/ /* if( (obuflen>=2) && (obuf[obuflen-1]==' ') && (obuf[obuflen-2]!=' ') )*/ /* { */ /*/* obuf[--obuflen] = '\0'; */ /* Remove lone blank at end of line */ /* } */ /***************************************************************************/ obuf[obuflen] = (char)chx; obuf[++obuflen] = '\0'; fputs(abuf, stdout); obuflen = 1; obuf[1] = '\0'; return; } if( (chx==' ') || (chx=='\t') ) { fputs(abuf, stdout); obuf[1] = (char)chx; obuflen = 2; obuf[2] = '\0'; return; } if(chx=='\0') /* Flush signal; nulls from instream are not passed. */ { if((obuflen >=2)&&(obuf[1]==' ')&&(obuf[2]!=' ')) { obuf[1] = '\n'; fputs(abuf, stdout); } else { fputs(obuf, stdout); } obuflen = 1; obuf[1] = '\0'; return; } else { obuf[obuflen] = (char)chx; obuf[++obuflen] = '\0'; return; } return; }