v04i091: simple formatting filter for text editors

chad at anasaz.UUCP chad at anasaz.UUCP
Sun Sep 25 11:29:37 AEST 1988


Posting-number: Volume 4, Issue 91
Submitted-by: "A. Nonymous" <chad at anasaz.UUCP>
Archive-name: fill

This is another simple filter to make it easier to enter and revise
text from within vi or some other editor.  It provides centering,
filling and justification on selectable margins.

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  fill.c fill.1 Makefile test_file
# Wrapped by chad at dcfinc on Sat Sep 24 01:29:59 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'fill.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'fill.c'\"
else
echo shar: Extracting \"'fill.c'\" \(8314 characters\)
sed "s/^X//" >'fill.c' <<'END_OF_FILE'
X/* fill.c - Simple text formatter - 1.7 */
X
X/*
X** fill is a simple text formatter meant to be used from within
X** your editor to provide the same functionality as the ^B command
X** in WordStar.  This presumes your editor can pipe an object through
X** a filter.  In vi, you would do something like "!}fill" to word wrap
X** a paragraph.  Of course, you may, in the spirit of Unix, find other
X** uses for it.  For example, fill has the side-effect of de-tabifying
X** lines passed to it.
X**	Usage: fill [-c | -j] [-l n] [-o n]
X**		-c	center the lines
X**		-j	justify the right margin
X**		-r n	set right margin to "n", defaults to 72
X**		-l n	set left margin to "n", defaults to 1
X*/
X
X/*
X** Author:
X**   Chad R. Larson			This program is placed in the
X**   DCF, Inc.				Public Domain.  You may do with
X**   14623 North 49th Place		it as you please.
X**   Scottsdale, AZ 85254
X*/
X
X/*
X** Programming note:  functions from the string library were used
X** wherever logical, under the assumption that they are more optimized
X** (or assemblerized) than whatever I built would be.  On my C library
X** this is true, your milage may vary.  Buffer pointers were generally
X** avoided for readability (this doesn't have to blaze, after all).
X*/
X
X/* maximum length of a line (for centering only) */
X#define LINE_MAX	512
X
X/* maximum length of a word */
X#define WORD_MAX	128
X
X/* the default right margin */
X#define DEF_MARGIN	72
X
X#include <stdio.h>
X#include <string.h>
X#include <memory.h>
X
X/* forward references */
Xvoid	j_line();	/* justify a line */
Xvoid	exit();
Xchar	*malloc();
X
X
X/* main program */
Xvoid main(argc, argv)
Xint	argc;
Xchar	*argv[];
X{
X    int		c;			/* a generic character */
X    int		center = 0;		/* center text flag */
X    int		justify = 0;		/* justify right margin flag */
X    int		w_length;		/* length of current word */
X    int		l_length = 0;		/* length of current line */
X    int		l_margin = 1;		/* left margin */
X    int		r_margin = DEF_MARGIN;	/* right margin */
X    int		wrap_point;		/* max chars allowed on a line */
X    char	*margin;		/* points to left margin string */
X    char	*out_line;		/* points to the output line */
X    char	word[WORD_MAX];		/* the current word */
X    char	*bp;			/* a buffer pointer for centering */
X    extern char	*optarg;		/* option argument pointer
X
X    /* parse the command line */
X    while ((c = getopt(argc, argv, "cjr:l:")) != EOF)
X	switch (c) {
X	case 'c':
X		center++;
X	    break;
X	case 'j':
X		justify++;
X	    break;
X	case 'r':
X	    r_margin = atoi(optarg);
X	    break;
X	case 'l':
X	    l_margin = atoi(optarg);
X	    break;
X	case '?':
X	    (void)fprintf(stderr,
X	      "Usage: %s [-c | -j] [-l n] [-o n]\n", argv[0]);
X	    exit(-1);
X	}
X
X    /* validate command line inputs */
X    if ( justify && center ) {
X	(void)fputs("Center and Justify are mutually exclusive.\n", stderr);
X	exit(1);
X    }
X    if (l_margin >= r_margin || l_margin < 1) {
X	(void)fputs("Illogical margin setting.\n", stderr);
X	exit(2);
X    }
X
X    /* Center the text if requested.  Will exit without filling. */
X    if (center) {
X	if ( (out_line = malloc(LINE_MAX)) == NULL ) {
X	    (void)fputs("Unable to allocate centering buffer.\n", stderr);
X	    exit(3);
X	}
X	while ( fgets(out_line, LINE_MAX, stdin) != NULL ) {
X	    bp = out_line;
X	    while (*bp == ' ' || *bp == '\t')	/* strip leading spaces */
X		bp++;
X	    l_length = strlen(bp);
X	    l_length--;			/* back over new-line */
X	    while (bp[l_length - 1] == ' ' || bp[l_length - 1] == '\t')
X		l_length--;			/* strip trailing space */
X	    bp[l_length] = '\0';
X	    center = (r_margin - l_length) / 2;
X	    while (center--)
X		(void)putc(' ', stdout);
X	    (void)puts(bp);
X	}
X	exit(0);
X    }
X
X    /* create the left margin string */
X    if ( (margin = malloc( (unsigned)l_margin) ) == NULL ) {
X	(void)fputs("Unable to allocate space for margin.\n", stderr);
X	exit(4);
X    }
X    (void)memset(margin, ' ', l_margin - 1);
X    margin[l_margin - 1] = '\0';
X
X    /* create the output line buffer */
X    wrap_point = r_margin - l_margin + 1;
X    if ((out_line = malloc( (unsigned)wrap_point + 3) ) == NULL) {
X	(void)fputs("Unable to allocate space for line buffer.\n", stderr);
X	exit(5);
X    }
X
X    /* move words from the input to the output */
X    while ( (w_length = get_word(word) ) != 0 ) {
X	if ( (l_length + w_length) > wrap_point ) {	/* line wrap? */
X	    while (out_line[l_length - 1] == ' ')   /* trailing space strip */
X		l_length--;
X	    out_line[l_length] = '\0';
X	    if (justify)			/* justify the line? */
X		j_line(out_line, wrap_point);
X	    (void)fputs(margin, stdout);	/* set any offset */
X	    (void)puts(out_line);		/* put the line to stdout */
X	    *out_line = '\0';			/* reset the output line */
X	    l_length = 0;
X	}
X	(void)strcat(out_line, word);
X	(void)strcat(out_line, " ");
X	l_length = l_length + w_length + 1;
X	if ( (c = word[w_length - 1]) == '.' || c == '?' || c == '!' ) {
X	    (void)strcat(out_line, " ");	/* end-of-sentence handling */
X	    l_length++;
X	}
X    }
X
X    /* clean up and exit */
X    if (l_length) {		/* residual to flush */
X	while (out_line[l_length - 1] == ' ')
X	    l_length--;
X	out_line[l_length] = '\0';
X	(void)fputs(margin, stdout);
X	(void)puts(out_line);
X    }
X    exit(0);
X}
X
X/*
X** get_word - a routine to return the next word from the standard input.
X** Copies the next word from the input stream to the location pointed to
X** by its argument.  The word will be null terminated.  A word is any
X** string of characters delimited by whitespace.  Returns the length
X** of the word.
X*/
X
Xint get_word(Word)
Xchar	*Word;
X{
X    register int	c;	/* generic character */
X    register int	i;	/* a counter */
X
X    /* first strip any leading whitespace */
X    while ((c = getchar()) == ' ' || c == '\n' || c == '\t' || c == '\f') ;
X    if (c == EOF) {
X	*Word = '\0';
X	return 0;
X    } else
X	(void)ungetc(c, stdin);
X
X    /* copy the word */
X    i = 0;
X    while ((c = getchar()) != ' ' && c != '\n'
X      && c != '\t' && c != '\f' && c != EOF) {
X	*Word++ = c;
X	if (++i >= WORD_MAX) {
X	    (void)fputs("Encountered word too large.\n", stderr);
X	    exit(6);
X	}
X    }
X    *Word = '\0';
X    return i;
X}
X
X/*
X** Routine to justify a line.
X*/
Xvoid j_line(buffer, margin)
Xchar	*buffer;
Xint	margin;
X{
X    static unsigned	direction = 0;	/* which end to we fill from? */
X    static char		*work = NULL;	/* working storage */
X    int			insert;		/* count of places to insert */
X    int			spaces;		/* count of spaces to insert */
X    int			multi;		/* spaces to insert each chance */
X    int			extra;		/* count of extra spaces needed */
X    int			count;		/* loop counter */
X    int			loop;		/* loop counter */
X    char		*Ibp;		/* Input buffer pointer */
X    char		*Obp;		/* Output buffer pointer */
X
X    /*
X    ** Allocate a working storage large enough to hold the line.  We
X    ** only do this once (and only if we are justifing).
X    */
X    if (work == NULL)
X	if ((work = malloc( (unsigned)margin + 1 )) == NULL) {
X	    (void)fputs("Unable to allocate work buffer.\n", stderr);
X	    exit(7);
X	}
X
X    /* how many spaces do we have to insert? */
X    loop = strlen(buffer);
X    spaces = margin - loop;
X    if (spaces == 0)
X	return;
X
X    /* find how many opportunities there are for space stuffing */
X    Ibp = buffer;
X    insert = 0;
X    while (loop--) {
X	if ( (*Ibp++ == ' ') && (*Ibp != ' ') )
X	    insert++;
X    }
X    if (insert == 0)
X	return;
X
X    /* how many spaces do we have to stuff per chance? */
X    extra = spaces % insert;		/* extra spaces needed */
X    multi = spaces / insert;		/* spaces per slot to insert */
X
X    /* copy the buffer contents, inserting spaces */
X    direction = ~direction;		/* flip end to fill from */
X    (void)strcpy(work, buffer);		/* make a working copy */
X    if (direction) {
X	Ibp = work;
X	Obp = buffer;
X	loop = strlen(buffer) + 1;
X	while (loop--) {
X	    *Obp++ = *Ibp++;		/* move a character */
X	    if ((*(Ibp - 1) == ' ') && (*(Ibp - 2) != ' ')) {
X		if (extra) {
X		    extra--;
X		    *Obp++ = ' ';
X		}
X		for (count = multi; count; count--)
X		    *Obp++ = ' ';
X	    }
X	}
X    } else {
X	loop = strlen(buffer);
X	Ibp = work + loop;
X	Obp = buffer + loop + spaces;
X	*(Obp + 1) = '\0';
X	while (loop--) {
X	    *Obp-- = *Ibp--;
X	    if ((*(Ibp + 1) == ' ') && (*(Ibp + 2) != ' ')) {
X		if (extra) {
X		    extra--;
X		    *Obp-- = ' ';
X		}
X		for (count = multi; count; count--)
X		    *Obp-- = ' ';
X	    }
X	}
X    }
X}
END_OF_FILE
if test 8314 -ne `wc -c <'fill.c'`; then
    echo shar: \"'fill.c'\" unpacked with wrong size!
fi
# end of 'fill.c'
fi
if test -f 'fill.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'fill.1'\"
else
echo shar: Extracting \"'fill.1'\" \(1177 characters\)
sed "s/^X//" >'fill.1' <<'END_OF_FILE'
X.TH FILL 1 local
X.SH NAME
Xfill - a simple text formatter
X.SH SYNOPSIS
Xfill [-c | -j] [-r n] [-l n]
X.SH DESCRIPTION
X.I Fill
Xis a simple text formatter meant to be used from within
Xyour editor to provide the same functionality as the ^B command
Xin WordStar.  This presumes your editor can pipe an object through
Xa filter.  In vi, you would do something like "!}fill" to word wrap
Xa paragraph.  Of course, you may, in the spirit of Unix, find other
Xuses for it.  For example,
X.I fill
Xhas the side-effect of de-tabifying
Xlines passed to it.
X.PP
XThe following options pertain:
X.nf
X	-c	center the lines
X	-j	justify the right margin
X	-r n	set right margin to "n", defaults to 72
X	-l n	set left margin to "n", defaults to 1
X.fi
X.SH CAVEATS
XThis ability is built in to emacs (but then, what isn't).  It is
Xrumored a similar program exists in the Berkely world.
X.SH FEATURES
X.I Fill
Xhas no pracical limit on line lengths (except when centering).
X.SH BUGS
XThe justification algorithm is a little crude.
X.br
X.I Fill
Xmakes no attempt to preserve existing indentations or blank
Xlines (this could be construed as a feature).
X.SH AUTHOR
XChad R. Larson
X.SH "SEE ALSO"
Xpr(1), nroff(1), troff(1)
END_OF_FILE
if test 1177 -ne `wc -c <'fill.1'`; then
    echo shar: \"'fill.1'\" unpacked with wrong size!
fi
# end of 'fill.1'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(243 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#
X# Makefile for fill, a simple text formatter
X#
X#	Last changed 9/23/88
X#
X
XBINDIR = /usr/local/bin
X
Xfill:	fill.c
X	$(CC) $(CFLAGS) -o fill fill.c
X
Xinstall:	fill
X	strip fill
X	-ln fill $(BINDIR)
X	touch install
X
XLint:	fill.c
X	lint -p fill.c >Lint
END_OF_FILE
if test 243 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'test_file' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'test_file'\"
else
echo shar: Extracting \"'test_file'\" \(852 characters\)
sed "s/^X//" >'test_file' <<'END_OF_FILE'
XThis is just a silly file of words to see if fill wraps them properly.
XThis is just a silly file of words to see if fill wraps them properly.
XThis is just a silly file of words to see if fill wraps them properly.
XThis is just a silly file of words to see if fill wraps them properly.
XThis is just a silly file of words to see if fill wraps them properly.
XThis is just a silly file of words to see if fill wraps them properly.
XThis is just a silly file of words to see if fill wraps them properly.
XThis is just a silly file of words to see if fill wraps them properly.
XThis is just a silly file of words to see if fill wraps them properly.
XThis is just a silly file of words to see if fill wraps them properly.
XThis is just a silly file of words to see if fill wraps them properly.
XThis is just a silly file of words to see if fill wraps them properly.
END_OF_FILE
if test 852 -ne `wc -c <'test_file'`; then
    echo shar: \"'test_file'\" unpacked with wrong size!
fi
# end of 'test_file'
fi
echo shar: End of shell archive.
exit 0
---------------
"I read the news today, oh boy!"  --John Lennon
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
| DCF, Inc.               | UUCP: ...ncar!noao!nud!anasaz!dcfinc!chad   |
| 14623 North 49th Place  | Ma Bell: (602) 953-1392                     |
| Scottsdale, AZ 85254    | Loran: N-33deg37min20sec W-111deg58min26sec |
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|         Disclaimer: These ARE the opinions of my employer!            |
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=



More information about the Comp.sources.misc mailing list