home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume4 / fill / fill.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-02-03  |  8.1 KB  |  294 lines

  1. /* fill.c - Simple text formatter - 1.7 */
  2.  
  3. /*
  4. ** fill is a simple text formatter meant to be used from within
  5. ** your editor to provide the same functionality as the ^B command
  6. ** in WordStar.  This presumes your editor can pipe an object through
  7. ** a filter.  In vi, you would do something like "!}fill" to word wrap
  8. ** a paragraph.  Of course, you may, in the spirit of Unix, find other
  9. ** uses for it.  For example, fill has the side-effect of de-tabifying
  10. ** lines passed to it.
  11. **    Usage: fill [-c | -j] [-l n] [-o n]
  12. **        -c    center the lines
  13. **        -j    justify the right margin
  14. **        -r n    set right margin to "n", defaults to 72
  15. **        -l n    set left margin to "n", defaults to 1
  16. */
  17.  
  18. /*
  19. ** Author:
  20. **   Chad R. Larson            This program is placed in the
  21. **   DCF, Inc.                Public Domain.  You may do with
  22. **   14623 North 49th Place        it as you please.
  23. **   Scottsdale, AZ 85254
  24. */
  25.  
  26. /*
  27. ** Programming note:  functions from the string library were used
  28. ** wherever logical, under the assumption that they are more optimized
  29. ** (or assemblerized) than whatever I built would be.  On my C library
  30. ** this is true, your milage may vary.  Buffer pointers were generally
  31. ** avoided for readability (this doesn't have to blaze, after all).
  32. */
  33.  
  34. /* maximum length of a line (for centering only) */
  35. #define LINE_MAX    512
  36.  
  37. /* maximum length of a word */
  38. #define WORD_MAX    128
  39.  
  40. /* the default right margin */
  41. #define DEF_MARGIN    72
  42.  
  43. #include <stdio.h>
  44. #include <string.h>
  45. #include <memory.h>
  46.  
  47. /* forward references */
  48. void    j_line();    /* justify a line */
  49. void    exit();
  50. char    *malloc();
  51.  
  52.  
  53. /* main program */
  54. void main(argc, argv)
  55. int    argc;
  56. char    *argv[];
  57. {
  58.     int        c;            /* a generic character */
  59.     int        center = 0;        /* center text flag */
  60.     int        justify = 0;        /* justify right margin flag */
  61.     int        w_length;        /* length of current word */
  62.     int        l_length = 0;        /* length of current line */
  63.     int        l_margin = 1;        /* left margin */
  64.     int        r_margin = DEF_MARGIN;    /* right margin */
  65.     int        wrap_point;        /* max chars allowed on a line */
  66.     char    *margin;        /* points to left margin string */
  67.     char    *out_line;        /* points to the output line */
  68.     char    word[WORD_MAX];        /* the current word */
  69.     char    *bp;            /* a buffer pointer for centering */
  70.     extern char    *optarg;        /* option argument pointer
  71.  
  72.     /* parse the command line */
  73.     while ((c = getopt(argc, argv, "cjr:l:")) != EOF)
  74.     switch (c) {
  75.     case 'c':
  76.         center++;
  77.         break;
  78.     case 'j':
  79.         justify++;
  80.         break;
  81.     case 'r':
  82.         r_margin = atoi(optarg);
  83.         break;
  84.     case 'l':
  85.         l_margin = atoi(optarg);
  86.         break;
  87.     case '?':
  88.         (void)fprintf(stderr,
  89.           "Usage: %s [-c | -j] [-l n] [-o n]\n", argv[0]);
  90.         exit(-1);
  91.     }
  92.  
  93.     /* validate command line inputs */
  94.     if ( justify && center ) {
  95.     (void)fputs("Center and Justify are mutually exclusive.\n", stderr);
  96.     exit(1);
  97.     }
  98.     if (l_margin >= r_margin || l_margin < 1) {
  99.     (void)fputs("Illogical margin setting.\n", stderr);
  100.     exit(2);
  101.     }
  102.  
  103.     /* Center the text if requested.  Will exit without filling. */
  104.     if (center) {
  105.     if ( (out_line = malloc(LINE_MAX)) == NULL ) {
  106.         (void)fputs("Unable to allocate centering buffer.\n", stderr);
  107.         exit(3);
  108.     }
  109.     while ( fgets(out_line, LINE_MAX, stdin) != NULL ) {
  110.         bp = out_line;
  111.         while (*bp == ' ' || *bp == '\t')    /* strip leading spaces */
  112.         bp++;
  113.         l_length = strlen(bp);
  114.         l_length--;            /* back over new-line */
  115.         while (bp[l_length - 1] == ' ' || bp[l_length - 1] == '\t')
  116.         l_length--;            /* strip trailing space */
  117.         bp[l_length] = '\0';
  118.         center = (r_margin - l_length) / 2;
  119.         while (center--)
  120.         (void)putc(' ', stdout);
  121.         (void)puts(bp);
  122.     }
  123.     exit(0);
  124.     }
  125.  
  126.     /* create the left margin string */
  127.     if ( (margin = malloc( (unsigned)l_margin) ) == NULL ) {
  128.     (void)fputs("Unable to allocate space for margin.\n", stderr);
  129.     exit(4);
  130.     }
  131.     (void)memset(margin, ' ', l_margin - 1);
  132.     margin[l_margin - 1] = '\0';
  133.  
  134.     /* create the output line buffer */
  135.     wrap_point = r_margin - l_margin + 1;
  136.     if ((out_line = malloc( (unsigned)wrap_point + 3) ) == NULL) {
  137.     (void)fputs("Unable to allocate space for line buffer.\n", stderr);
  138.     exit(5);
  139.     }
  140.  
  141.     /* move words from the input to the output */
  142.     while ( (w_length = get_word(word) ) != 0 ) {
  143.     if ( (l_length + w_length) > wrap_point ) {    /* line wrap? */
  144.         while (out_line[l_length - 1] == ' ')   /* trailing space strip */
  145.         l_length--;
  146.         out_line[l_length] = '\0';
  147.         if (justify)            /* justify the line? */
  148.         j_line(out_line, wrap_point);
  149.         (void)fputs(margin, stdout);    /* set any offset */
  150.         (void)puts(out_line);        /* put the line to stdout */
  151.         *out_line = '\0';            /* reset the output line */
  152.         l_length = 0;
  153.     }
  154.     (void)strcat(out_line, word);
  155.     (void)strcat(out_line, " ");
  156.     l_length = l_length + w_length + 1;
  157.     if ( (c = word[w_length - 1]) == '.' || c == '?' || c == '!' ) {
  158.         (void)strcat(out_line, " ");    /* end-of-sentence handling */
  159.         l_length++;
  160.     }
  161.     }
  162.  
  163.     /* clean up and exit */
  164.     if (l_length) {        /* residual to flush */
  165.     while (out_line[l_length - 1] == ' ')
  166.         l_length--;
  167.     out_line[l_length] = '\0';
  168.     (void)fputs(margin, stdout);
  169.     (void)puts(out_line);
  170.     }
  171.     exit(0);
  172. }
  173.  
  174. /*
  175. ** get_word - a routine to return the next word from the standard input.
  176. ** Copies the next word from the input stream to the location pointed to
  177. ** by its argument.  The word will be null terminated.  A word is any
  178. ** string of characters delimited by whitespace.  Returns the length
  179. ** of the word.
  180. */
  181.  
  182. int get_word(Word)
  183. char    *Word;
  184. {
  185.     register int    c;    /* generic character */
  186.     register int    i;    /* a counter */
  187.  
  188.     /* first strip any leading whitespace */
  189.     while ((c = getchar()) == ' ' || c == '\n' || c == '\t' || c == '\f') ;
  190.     if (c == EOF) {
  191.     *Word = '\0';
  192.     return 0;
  193.     } else
  194.     (void)ungetc(c, stdin);
  195.  
  196.     /* copy the word */
  197.     i = 0;
  198.     while ((c = getchar()) != ' ' && c != '\n'
  199.       && c != '\t' && c != '\f' && c != EOF) {
  200.     *Word++ = c;
  201.     if (++i >= WORD_MAX) {
  202.         (void)fputs("Encountered word too large.\n", stderr);
  203.         exit(6);
  204.     }
  205.     }
  206.     *Word = '\0';
  207.     return i;
  208. }
  209.  
  210. /*
  211. ** Routine to justify a line.
  212. */
  213. void j_line(buffer, margin)
  214. char    *buffer;
  215. int    margin;
  216. {
  217.     static unsigned    direction = 0;    /* which end to we fill from? */
  218.     static char        *work = NULL;    /* working storage */
  219.     int            insert;        /* count of places to insert */
  220.     int            spaces;        /* count of spaces to insert */
  221.     int            multi;        /* spaces to insert each chance */
  222.     int            extra;        /* count of extra spaces needed */
  223.     int            count;        /* loop counter */
  224.     int            loop;        /* loop counter */
  225.     char        *Ibp;        /* Input buffer pointer */
  226.     char        *Obp;        /* Output buffer pointer */
  227.  
  228.     /*
  229.     ** Allocate a working storage large enough to hold the line.  We
  230.     ** only do this once (and only if we are justifing).
  231.     */
  232.     if (work == NULL)
  233.     if ((work = malloc( (unsigned)margin + 1 )) == NULL) {
  234.         (void)fputs("Unable to allocate work buffer.\n", stderr);
  235.         exit(7);
  236.     }
  237.  
  238.     /* how many spaces do we have to insert? */
  239.     loop = strlen(buffer);
  240.     spaces = margin - loop;
  241.     if (spaces == 0)
  242.     return;
  243.  
  244.     /* find how many opportunities there are for space stuffing */
  245.     Ibp = buffer;
  246.     insert = 0;
  247.     while (loop--) {
  248.     if ( (*Ibp++ == ' ') && (*Ibp != ' ') )
  249.         insert++;
  250.     }
  251.     if (insert == 0)
  252.     return;
  253.  
  254.     /* how many spaces do we have to stuff per chance? */
  255.     extra = spaces % insert;        /* extra spaces needed */
  256.     multi = spaces / insert;        /* spaces per slot to insert */
  257.  
  258.     /* copy the buffer contents, inserting spaces */
  259.     direction = ~direction;        /* flip end to fill from */
  260.     (void)strcpy(work, buffer);        /* make a working copy */
  261.     if (direction) {
  262.     Ibp = work;
  263.     Obp = buffer;
  264.     loop = strlen(buffer) + 1;
  265.     while (loop--) {
  266.         *Obp++ = *Ibp++;        /* move a character */
  267.         if ((*(Ibp - 1) == ' ') && (*(Ibp - 2) != ' ')) {
  268.         if (extra) {
  269.             extra--;
  270.             *Obp++ = ' ';
  271.         }
  272.         for (count = multi; count; count--)
  273.             *Obp++ = ' ';
  274.         }
  275.     }
  276.     } else {
  277.     loop = strlen(buffer);
  278.     Ibp = work + loop;
  279.     Obp = buffer + loop + spaces;
  280.     *(Obp + 1) = '\0';
  281.     while (loop--) {
  282.         *Obp-- = *Ibp--;
  283.         if ((*(Ibp + 1) == ' ') && (*(Ibp + 2) != ' ')) {
  284.         if (extra) {
  285.             extra--;
  286.             *Obp-- = ' ';
  287.         }
  288.         for (count = multi; count; count--)
  289.             *Obp-- = ' ';
  290.         }
  291.     }
  292.     }
  293. }
  294.