home *** CD-ROM | disk | FTP | other *** search
- /* fill.c - Simple text formatter - 1.7 */
-
- /*
- ** fill is a simple text formatter meant to be used from within
- ** your editor to provide the same functionality as the ^B command
- ** in WordStar. This presumes your editor can pipe an object through
- ** a filter. In vi, you would do something like "!}fill" to word wrap
- ** a paragraph. Of course, you may, in the spirit of Unix, find other
- ** uses for it. For example, fill has the side-effect of de-tabifying
- ** lines passed to it.
- ** Usage: fill [-c | -j] [-l n] [-o n]
- ** -c center the lines
- ** -j justify the right margin
- ** -r n set right margin to "n", defaults to 72
- ** -l n set left margin to "n", defaults to 1
- */
-
- /*
- ** Author:
- ** Chad R. Larson This program is placed in the
- ** DCF, Inc. Public Domain. You may do with
- ** 14623 North 49th Place it as you please.
- ** Scottsdale, AZ 85254
- */
-
- /*
- ** Programming note: functions from the string library were used
- ** wherever logical, under the assumption that they are more optimized
- ** (or assemblerized) than whatever I built would be. On my C library
- ** this is true, your milage may vary. Buffer pointers were generally
- ** avoided for readability (this doesn't have to blaze, after all).
- */
-
- /* maximum length of a line (for centering only) */
- #define LINE_MAX 512
-
- /* maximum length of a word */
- #define WORD_MAX 128
-
- /* the default right margin */
- #define DEF_MARGIN 72
-
- #include <stdio.h>
- #include <string.h>
- #include <memory.h>
-
- /* forward references */
- void j_line(); /* justify a line */
- void exit();
- char *malloc();
-
-
- /* main program */
- void main(argc, argv)
- int argc;
- char *argv[];
- {
- int c; /* a generic character */
- int center = 0; /* center text flag */
- int justify = 0; /* justify right margin flag */
- int w_length; /* length of current word */
- int l_length = 0; /* length of current line */
- int l_margin = 1; /* left margin */
- int r_margin = DEF_MARGIN; /* right margin */
- int wrap_point; /* max chars allowed on a line */
- char *margin; /* points to left margin string */
- char *out_line; /* points to the output line */
- char word[WORD_MAX]; /* the current word */
- char *bp; /* a buffer pointer for centering */
- extern char *optarg; /* option argument pointer
-
- /* parse the command line */
- while ((c = getopt(argc, argv, "cjr:l:")) != EOF)
- switch (c) {
- case 'c':
- center++;
- break;
- case 'j':
- justify++;
- break;
- case 'r':
- r_margin = atoi(optarg);
- break;
- case 'l':
- l_margin = atoi(optarg);
- break;
- case '?':
- (void)fprintf(stderr,
- "Usage: %s [-c | -j] [-l n] [-o n]\n", argv[0]);
- exit(-1);
- }
-
- /* validate command line inputs */
- if ( justify && center ) {
- (void)fputs("Center and Justify are mutually exclusive.\n", stderr);
- exit(1);
- }
- if (l_margin >= r_margin || l_margin < 1) {
- (void)fputs("Illogical margin setting.\n", stderr);
- exit(2);
- }
-
- /* Center the text if requested. Will exit without filling. */
- if (center) {
- if ( (out_line = malloc(LINE_MAX)) == NULL ) {
- (void)fputs("Unable to allocate centering buffer.\n", stderr);
- exit(3);
- }
- while ( fgets(out_line, LINE_MAX, stdin) != NULL ) {
- bp = out_line;
- while (*bp == ' ' || *bp == '\t') /* strip leading spaces */
- bp++;
- l_length = strlen(bp);
- l_length--; /* back over new-line */
- while (bp[l_length - 1] == ' ' || bp[l_length - 1] == '\t')
- l_length--; /* strip trailing space */
- bp[l_length] = '\0';
- center = (r_margin - l_length) / 2;
- while (center--)
- (void)putc(' ', stdout);
- (void)puts(bp);
- }
- exit(0);
- }
-
- /* create the left margin string */
- if ( (margin = malloc( (unsigned)l_margin) ) == NULL ) {
- (void)fputs("Unable to allocate space for margin.\n", stderr);
- exit(4);
- }
- (void)memset(margin, ' ', l_margin - 1);
- margin[l_margin - 1] = '\0';
-
- /* create the output line buffer */
- wrap_point = r_margin - l_margin + 1;
- if ((out_line = malloc( (unsigned)wrap_point + 3) ) == NULL) {
- (void)fputs("Unable to allocate space for line buffer.\n", stderr);
- exit(5);
- }
-
- /* move words from the input to the output */
- while ( (w_length = get_word(word) ) != 0 ) {
- if ( (l_length + w_length) > wrap_point ) { /* line wrap? */
- while (out_line[l_length - 1] == ' ') /* trailing space strip */
- l_length--;
- out_line[l_length] = '\0';
- if (justify) /* justify the line? */
- j_line(out_line, wrap_point);
- (void)fputs(margin, stdout); /* set any offset */
- (void)puts(out_line); /* put the line to stdout */
- *out_line = '\0'; /* reset the output line */
- l_length = 0;
- }
- (void)strcat(out_line, word);
- (void)strcat(out_line, " ");
- l_length = l_length + w_length + 1;
- if ( (c = word[w_length - 1]) == '.' || c == '?' || c == '!' ) {
- (void)strcat(out_line, " "); /* end-of-sentence handling */
- l_length++;
- }
- }
-
- /* clean up and exit */
- if (l_length) { /* residual to flush */
- while (out_line[l_length - 1] == ' ')
- l_length--;
- out_line[l_length] = '\0';
- (void)fputs(margin, stdout);
- (void)puts(out_line);
- }
- exit(0);
- }
-
- /*
- ** get_word - a routine to return the next word from the standard input.
- ** Copies the next word from the input stream to the location pointed to
- ** by its argument. The word will be null terminated. A word is any
- ** string of characters delimited by whitespace. Returns the length
- ** of the word.
- */
-
- int get_word(Word)
- char *Word;
- {
- register int c; /* generic character */
- register int i; /* a counter */
-
- /* first strip any leading whitespace */
- while ((c = getchar()) == ' ' || c == '\n' || c == '\t' || c == '\f') ;
- if (c == EOF) {
- *Word = '\0';
- return 0;
- } else
- (void)ungetc(c, stdin);
-
- /* copy the word */
- i = 0;
- while ((c = getchar()) != ' ' && c != '\n'
- && c != '\t' && c != '\f' && c != EOF) {
- *Word++ = c;
- if (++i >= WORD_MAX) {
- (void)fputs("Encountered word too large.\n", stderr);
- exit(6);
- }
- }
- *Word = '\0';
- return i;
- }
-
- /*
- ** Routine to justify a line.
- */
- void j_line(buffer, margin)
- char *buffer;
- int margin;
- {
- static unsigned direction = 0; /* which end to we fill from? */
- static char *work = NULL; /* working storage */
- int insert; /* count of places to insert */
- int spaces; /* count of spaces to insert */
- int multi; /* spaces to insert each chance */
- int extra; /* count of extra spaces needed */
- int count; /* loop counter */
- int loop; /* loop counter */
- char *Ibp; /* Input buffer pointer */
- char *Obp; /* Output buffer pointer */
-
- /*
- ** Allocate a working storage large enough to hold the line. We
- ** only do this once (and only if we are justifing).
- */
- if (work == NULL)
- if ((work = malloc( (unsigned)margin + 1 )) == NULL) {
- (void)fputs("Unable to allocate work buffer.\n", stderr);
- exit(7);
- }
-
- /* how many spaces do we have to insert? */
- loop = strlen(buffer);
- spaces = margin - loop;
- if (spaces == 0)
- return;
-
- /* find how many opportunities there are for space stuffing */
- Ibp = buffer;
- insert = 0;
- while (loop--) {
- if ( (*Ibp++ == ' ') && (*Ibp != ' ') )
- insert++;
- }
- if (insert == 0)
- return;
-
- /* how many spaces do we have to stuff per chance? */
- extra = spaces % insert; /* extra spaces needed */
- multi = spaces / insert; /* spaces per slot to insert */
-
- /* copy the buffer contents, inserting spaces */
- direction = ~direction; /* flip end to fill from */
- (void)strcpy(work, buffer); /* make a working copy */
- if (direction) {
- Ibp = work;
- Obp = buffer;
- loop = strlen(buffer) + 1;
- while (loop--) {
- *Obp++ = *Ibp++; /* move a character */
- if ((*(Ibp - 1) == ' ') && (*(Ibp - 2) != ' ')) {
- if (extra) {
- extra--;
- *Obp++ = ' ';
- }
- for (count = multi; count; count--)
- *Obp++ = ' ';
- }
- }
- } else {
- loop = strlen(buffer);
- Ibp = work + loop;
- Obp = buffer + loop + spaces;
- *(Obp + 1) = '\0';
- while (loop--) {
- *Obp-- = *Ibp--;
- if ((*(Ibp + 1) == ' ') && (*(Ibp + 2) != ' ')) {
- if (extra) {
- extra--;
- *Obp-- = ' ';
- }
- for (count = multi; count; count--)
- *Obp-- = ' ';
- }
- }
- }
- }
-