home *** CD-ROM | disk | FTP | other *** search
Wrap
/*------------------------------------------------------------+ | reformat.c -- 5/16/1992 public domain | | by Alex Matulich, Unicorn Research Corporation | | Reformat a text file with different line lenghts. Original| | hard carriage returns are deleted and new ones added in, | | depending on specified line width. Original hard returns | | will be kept in the file if: | | (1) They are followed by whitespace, | | (2) They are preceded by a newlines, or | | (3) They are on a shorter line than the specified | | width, and re-wrapping is not specified. | | For this program to work, the EOL code in the text must be | | with the OS being run. Use StripCR or AddCR as necessary. | +------------------------------------------------------------*/ #include <stdio.h> #include <stdlib.h> #include <ctype.h> #define OUTBUFSIZ 24000 unsigned long outbufsiz = OUTBUFSIZ; unsigned short replace, bufptr = 0, lineptr = 0; signed char *buf = NULL; FILE *infile, *outfile; long inpos = 0L, outpos = 0L; /* file position trackers */ int writebuf(void); void main(int argc, char *argv[]) { short j, err = 0, linelength = 72, tabwidth = 8, reformshort = 0, cntinu = 0, plast, ptr = 1, pnext; /* pointers to characters in lookahead buffer */ signed char lk[3]; /* lookahead buffer */ if (argc < 2 || argc > 5) err = 3; if (!err) { short i = 0; while (!err && ++i < argc) /* process any commandline switches */ if (*argv[i] == '-') { if (argv[i][1] == 'l' || argv[i][1] == 'L') { /* line length */ linelength = atoi(&argv[i][2]); if (linelength < 32) err = 3; if (linelength >= OUTBUFSIZ) outbufsiz = linelength; } else if (argv[i][1] == 't' || argv[i][1] == 'T') { /* tab width */ if ((tabwidth = atoi(&argv[i][2])) > 30) err = 3; } else if (argv[i][1] == 'r' || argv[i][1] == 'R') reformshort = 1; else err = 3; if (!err) { --argc; for (j = i--; j < argc; j++) argv[j] = argv[j+1]; } } if (argc != 3 && argc != 2) err = 3; } if (err) { fputs("REFORMAT by Unicorn Research Corporation\nReformat a text file with new line lengths.\n\nUsage: Reformat [-r] [-lN] [-tM] infile [outfile]\n\n", stdout); fputs("-r = re-wrap lines shorter than N (default is to leave them alone)\n N = the new line length (minimum 32, default 72)\n M = the tab width (maximum 30, assumed 8)\n\n", stdout); fputs("If outfile is omitted, then infile will be replaced.\nThe end-of-line code in the text file must be compatible with your\noperating system -- use StripCR / AddCR as necessary.\n", stdout); return; } if ((infile = fopen( argv[1], (replace = (argc == 2)) ? "r+" : "r" )) == NULL) { fputs("Could not open input file.\n", stdout); return; } if (replace) outfile = infile; else if ((outfile = fopen( argv[2], "w" )) == NULL) { fputs("Could not open output file.\n", stdout); fclose(infile); return; } if ((buf = (signed char *)malloc(outbufsiz)) == NULL) { fputs("Not enough memory!\n", stdout); goto cleanup; } for (inpos = 0; inpos < 3; inpos++) /* read first three characters */ if ((lk[inpos] = fgetc(infile)) == EOF) { err = 2; goto clean2; } buf[bufptr++] = lk[0]; /* record first char in output buffer */ if (!isspace(lk[0])) ++lineptr; else if (lk[0] == '\t') lineptr += tabwidth; /* the cntinu flag is confusing. If 1, that means the current OUTPUT line * has wrapped while reading the current INPUT line. */ do { /* process the file */ plast = (ptr + 2) % 3; /* index of next character */ pnext = (ptr + 1) % 3; /* index of previous character */ if (cntinu && !lineptr && isspace(lk[ptr]) && lk[ptr] != '\n') { ptr = pnext; continue; } if (lk[ptr] != '\n' /* if not newline */ || (lk[ptr] == '\n' && /* or if newline and */ (isspace(lk[pnext]) || lk[plast] == '\n'))){ /* whitespace, then */ if (lk[ptr] == '\t') /* first ajust for */ lineptr = ((lineptr+tabwidth)/tabwidth)*tabwidth; else if (lk[ptr] == '\n') lineptr=cntinu=0; /* new character or */ else ++lineptr; if (lineptr >= linelength) { /* a possible tab, */ if (isspace(lk[ptr])) { /* check if line */ if (lk[ptr] != '\n') { lk[ptr] = '\n'; /* length exceeded */ cntinu = 1; lineptr = 0; } else cntinu = 0; } else { /* w/nonwhite space */ for (j = bufptr-1; j > 0; j--) /* (in which case */ if (isspace(buf[j])) break; /* go back & insert */ if (j) buf[j] = '\n'; /* a newline), */ cntinu = 1; lineptr = bufptr - 1 - j; /* and after reset */ } /* of lineptr we */ } /* will put the char */ buf[bufptr++] = lk[ptr]; /* into the buffer. */ if (replace) inpos = ftell(infile); if (bufptr == outbufsiz) if (err = writebuf()) break; } else { /* otherwise substitute a space for the newline */ if ((!reformshort && !cntinu) || lineptr+1 >= linelength) { buf[bufptr++] = '\n'; lineptr = 0; } else { buf[bufptr++] = ' '; ++lineptr; } cntinu = 0; if (replace) inpos = ftell(infile); if (bufptr == outbufsiz) if (err = writebuf()) break; } ptr = pnext; } while ((lk[plast] = fgetc(infile)) != EOF); buf[bufptr++] = lk[pnext]; /* grab the last character */ while (!err && bufptr) { inpos = outpos + bufptr; /* reset to allow remaining writes */ err = writebuf(); } clean2: if (err == 1) fputs("Error writing output file.\n", stdout); else if (err == 2) fputs("Error reading input file.\n", stdout); else if (replace) { fseek(outfile, outpos, 0); fputc('\x1A', outfile); fputs(argv[1], stdout); fputs(" is now reformatted.\nDelete any text after the ctrl-Z.\n", stdout); } else { fputs("Reformatted file ", stdout); fputs(argv[2], stdout); fputs(" successfully created.\n", stdout); } cleanup: free(buf); fclose(infile); if (!replace) fclose(outfile); } /* Write the buffer to the output file, when full or when done. * Stop writing when end of buffer is hit, or, if we are in replace mode, * when current input pointer is hit. */ int writebuf() { unsigned short i = 0, j = 0, k = 0, buflimit; if (replace) { if ((buflimit = inpos - outpos) <= 0) return -100; /* For the next buffer fill, we may need to back up a bit and * insert a newline. So, we dump out just half the buffer. */ if (bufptr >= outbufsiz) buflimit = (buflimit >> 1) + 1; if (fseek(outfile, outpos, 0)) return 1; } else buflimit = bufptr; /* this loop is used either in replace or create mode, so we'll avoid using ftell() -- we will just assume that all EOLs are 2 characters */ while (i < buflimit) { if (fputc(buf[k++], outfile) == EOF) return 1; if (buf[i++] == '\n') if (++i >= buflimit) break; /* safety if we have 2-char EOLs */ } /* k is the number of characters written */ if (replace) { outpos = ftell(outfile); if (fseek(infile, inpos, 0)) return 2; } /* shift remaining contents of buffer to the beginning of it */ i = k; while (i < bufptr) buf[j++] = buf[i++]; bufptr -= k; return 0; }