home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / apps / text_ed / elv16b2 / st / fmt.c < prev    next >
C/C++ Source or Header  |  1992-05-12  |  5KB  |  268 lines

  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. }
  268.