|
|
1.1 ! root 1: /* fmt.c */ ! 2: ! 3: /* usage: fmt [-width] [files]... ! 4: * ! 5: * Fmt rearrages text in order to make each line have roughly the ! 6: * same width. Indentation and word spacing is preserved. ! 7: * ! 8: * The default width is 72 characters, but you can override that via -width. ! 9: * If no files are given on the command line, then it reads stdin. ! 10: */ ! 11: ! 12: #include <stdio.h> ! 13: #include <ctype.h> ! 14: ! 15: #ifndef TRUE ! 16: # define TRUE 1 ! 17: # define FALSE 0 ! 18: #endif ! 19: ! 20: ! 21: ! 22: int width = 72; /* the desired line width */ ! 23: int isblank; /* is the current output line blank? */ ! 24: int indent; /* width of the indentation */ ! 25: char ind[512]; /* indentation text */ ! 26: char word[1024]; /* word buffer */ ! 27: ! 28: /* This function displays a usage message and quits */ ! 29: void usage() ! 30: { ! 31: fprintf(stderr, "usage: fmt [-width] [files]...\n"); ! 32: exit(2); ! 33: } ! 34: ! 35: ! 36: ! 37: /* This function outputs a single word. It takes care of spacing and the ! 38: * newlines within a paragraph. ! 39: */ ! 40: void putword() ! 41: { ! 42: int i; /* index into word[], or whatever */ ! 43: int ww; /* width of the word */ ! 44: int sw; /* width of spacing after word */ ! 45: static int psw; /* space width of previous word */ ! 46: static int tab; /* the width of text already written */ ! 47: ! 48: ! 49: /* separate the word and its spacing */ ! 50: for (ww = 0; word[ww] && !isspace(word[ww]); ww++) ! 51: { ! 52: } ! 53: sw = strlen(word) - ww; ! 54: word[ww] = '\0'; ! 55: ! 56: /* if no spacing (that is, the word was at the end of the line) then ! 57: * assume 1 space unless the last char of the word was punctuation ! 58: */ ! 59: if (sw == 0) ! 60: { ! 61: sw = 1; ! 62: if (word[ww - 1] == '.' || word[ww - 1] == '?' || word[ww - 1] == '!') ! 63: sw = 2; ! 64: } ! 65: ! 66: /* if this is the first word on the line... */ ! 67: if (isblank) ! 68: { ! 69: /* output the indentation first */ ! 70: fputs(ind, stdout); ! 71: tab = indent; ! 72: } ! 73: else /* text has already been written to this output line */ ! 74: { ! 75: /* will the word fit on this line? */ ! 76: if (psw + ww + tab <= width) ! 77: { ! 78: /* yes - so write the previous word's spacing */ ! 79: for (i = 0; i < psw; i++) ! 80: { ! 81: putchar(' '); ! 82: } ! 83: tab += psw; ! 84: } ! 85: else ! 86: { ! 87: /* no, so write a newline and the indentation */ ! 88: putchar('\n'); ! 89: fputs(ind, stdout); ! 90: tab = indent; ! 91: } ! 92: } ! 93: ! 94: /* write the word itself */ ! 95: fputs(word, stdout); ! 96: tab += ww; ! 97: ! 98: /* remember this word's spacing */ ! 99: psw = sw; ! 100: ! 101: /* this output line isn't blank anymore. */ ! 102: isblank = FALSE; ! 103: } ! 104: ! 105: ! 106: ! 107: /* This function reformats text. */ ! 108: void fmt(in) ! 109: FILE *in; /* the input stream */ ! 110: { ! 111: int ch; /* character from input stream */ ! 112: int prevch; /* the previous character in the loop */ ! 113: int i; /* index into ind[] or word[] */ ! 114: int inword; /* boolean: are we between indent & newline? */ ! 115: ! 116: ! 117: /* for each character in the stream... */ ! 118: for (indent = -1, isblank = TRUE, inword = FALSE, i = 0, prevch = '\n'; ! 119: (ch = getc(in)) != EOF; ! 120: prevch = ch) ! 121: { ! 122: /* is this the end of a line? */ ! 123: if (ch == '\n') ! 124: { ! 125: /* if end of last word in the input line */ ! 126: if (inword) ! 127: { ! 128: /* if it really is a word */ ! 129: if (i > 0) ! 130: { ! 131: /* output it */ ! 132: word[i] = '\0'; ! 133: putword(); ! 134: } ! 135: } ! 136: else /* blank line in input */ ! 137: { ! 138: /* finish the previous paragraph */ ! 139: if (!isblank) ! 140: { ! 141: putchar('\n'); ! 142: isblank = TRUE; ! 143: } ! 144: ! 145: /* output a blank line */ ! 146: putchar('\n'); ! 147: } ! 148: ! 149: /* continue with next input line... */ ! 150: indent = -1; ! 151: i = 0; ! 152: inword = FALSE; ! 153: continue; ! 154: } ! 155: ! 156: /* if we're expecting indentation now... */ ! 157: if (indent < 0) ! 158: { ! 159: /* if this is part of the indentation... */ ! 160: if (isspace(ch)) ! 161: { ! 162: /* remember it */ ! 163: ind[i++] = ch; ! 164: } ! 165: else /* end of indentation */ ! 166: { ! 167: /* mark the end of the indentation string */ ! 168: ind[i] = '\0'; ! 169: ! 170: /* calculate the width of the indentation */ ! 171: for (i = indent = 0; ind[i]; i++) ! 172: { ! 173: if (ind[i] == '\t') ! 174: indent = (indent | 7) + 1; ! 175: else ! 176: indent++; ! 177: } ! 178: ! 179: /* reset the word index */ ! 180: i = 0; ! 181: ! 182: /* reprocess that last character */ ! 183: ungetc(ch, in); ! 184: } ! 185: ! 186: /* continue in the for-loop */ ! 187: continue; ! 188: } ! 189: ! 190: /* if we get here, we're either in a word or in the space ! 191: * after a word. ! 192: */ ! 193: inword = TRUE; ! 194: ! 195: /* is this the start of a new word? */ ! 196: if (!isspace(ch) && isspace(prevch)) ! 197: { ! 198: /* yes! output the previous word */ ! 199: word[i] = '\0'; ! 200: putword(); ! 201: ! 202: /* reset `i' to the start of the word[] buffer */ ! 203: i = 0; ! 204: } ! 205: word[i++] = ch; ! 206: } ! 207: ! 208: /* if necessary, write a final newline */ ! 209: if (!isblank) ! 210: { ! 211: putchar('\n'); ! 212: isblank = TRUE; ! 213: } ! 214: } ! 215: ! 216: ! 217: ! 218: ! 219: ! 220: int main(argc, argv) ! 221: int argc; ! 222: char **argv; ! 223: { ! 224: FILE *in; /* an input stream */ ! 225: int error; /* if non-zero, then an error occurred */ ! 226: int i; ! 227: ! 228: ! 229: /* handle the -width flag, if given */ ! 230: if (argc > 1 && argv[1][0] == '-') ! 231: { ! 232: width = atoi(argv[1] + 1); ! 233: if (width <= 0) ! 234: { ! 235: usage(); ! 236: } ! 237: argc--; ! 238: argv++; ! 239: } ! 240: ! 241: /* if no filenames given, then process stdin */ ! 242: if (argc == 1) ! 243: { ! 244: fmt(stdin); ! 245: } ! 246: else /* one or more filenames given */ ! 247: { ! 248: for (error = 0, i = 1; i < argc; i++) ! 249: { ! 250: in = fopen(argv[i], "r"); ! 251: if (!in) ! 252: { ! 253: perror(argv[i]); ! 254: error = 3; ! 255: } ! 256: else ! 257: { ! 258: fmt(in); ! 259: fclose(in); ! 260: } ! 261: } ! 262: } ! 263: ! 264: /* exit, possibly indicating an error */ ! 265: exit(error); ! 266: /*NOTREACHED*/ ! 267: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.