ff: fast test formatter (part 2 of 2)

sources-request at panda.UUCP sources-request at panda.UUCP
Fri Nov 29 02:35:38 AEST 1985


Mod.sources:  Volume 3, Issue 52
Submitted by: decvax!wanginst!perlman

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	ff.c
# This archive created: Wed Nov 13 19:28:01 1985
# By:	Gary Perlman (Wang Institute, Tyngsboro, MA 01879 USA)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'ff.c'" '(29326 characters)'
if test -f 'ff.c'
then
	echo shar: "will not over-write existing file 'ff.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'ff.c'
	X/*COPYRIGHT (c) 1985 Wang Institute, Tyngsboro, MA 01879 USA */
	X/*DISCLAIMER:	No guarantees of performance are made. */
	X/*MODULE	ff: "fast formatter" "Sun 01 Sep 1985" */
	X/*PGMR  	ff: "Gary Perlman" "Wang Institute, Tyngsboro, MA 01879 USA" */
	X/*VER   	$Header: ff.c,v 1.3 85/09/01 21:23:38 perlman Exp $ */
	X/*COMP  	ff: see makefile */
	X
	X/*MANUAL.TH FF 1 "August 10, 1985" "Wang Institute" "UNIX User's Manual"
	X.\" $Compile: iroff -man.new %f
	X.SH NAME
	Xff \- fast text formatter
	X.SH USAGE
	X.B ff
	X[options] [-] [files]
	X.SH DESCRIPTION
	X.I ff
	Xis a simple text formatter for flexible uniform formatting of
	Xinput files.
	XProgram options are used to control formatting.
	XThis is in contrast to text formatters like
	X.I nroff (1)
	Xthat require special format requests to be part of their input files.
	XBesides avoiding cryptic format requests in text,
	X.I ff
	Xis considerably faster than traditional formatters like
	X.I nroff (1)
	Xand even simple formatters like
	X.I fmt (1).
	X.PP
	XThe most complicated concept with
	X.I ff
	Xis that of a line break.
	XA line break causes an interruption in the filling
	X(evening out of the text lines).
	XLine breaks occur when special characters are seen at the beginnings
	Xof lines, or when all lines are broken.
	XBy default, any non-alphanumeric character will cause a break,
	Xbut this can be controlled with the
	X.B -B
	Xoption.
	XA blank line always causes a break.
	X*/
	X
	X
	X#include <stdio.h>
	X#include <ctype.h>
	X#include <strings.h>
	X
	Xtypedef	int 	Status;
	X#define	SUCCESS   ((Status) 0)
	X#define	FAILURE   ((Status) 1)
	Xtypedef	int 	Boole;
	X#define	TRUE      ((Boole) 1)
	X#define	FALSE     ((Boole) 0)
	X
	X#define	TAB       '\t'
	X#define	EOL       '\n'
	X#define	FF        '\f'
	X#define	EOS       '\0'
	X#define	SP        ' '
	X#define	MAXLEN    128                  /* max length of lines */
	X#define	MAXLINES  200                  /* max # lines on pages */
	X
	X/* Alphabetical listing of this file's functions */
	Xvoid	beginline ();  /* process text at the beginning of lines */
	Xvoid	beginpage ();  /* handle pagination at page breaks */
	XStatus	dobreak ();    /* handle broken lines, if appropriate */
	Xvoid	dofill ();     /* do the text filling */
	Xchar	*dotab ();     /* return expanded tabs in line */
	Xvoid	endpage ();    /* handle pagination at page ends */
	Xchar	*expand ();    /* expand strings in three part titles */
	XStatus	ff ();         /* main formatting routine */
	Xint 	initial ();    /* set options and check consistency */
	Xchar	*itoa ();      /* convert integer to ascii format, with padding */
	Xvoid	dojustify ();  /* even out (justify) the right margin of filled lines */
	Xchar	*preprocess ();/* handle blank trimming and titling */
	Xvoid	println ();    /* print a line, watching for page boundaries */
	Xvoid	repeat ();     /* repeatedly print a character */
	XStatus	setint ();     /* check type & convert a string to an integer */
	Xchar	*threepart (); /* build three part titles */
	Xvoid	usage ();      /* print usage summary */
	X
	X/* GLOBALS */
	Xchar	*Argv0;              /* will be name of program */
	Xint 	Curpos;              /* current position on output line */
	Xchar	*Filename;           /* current input file name */
	XBoole	Filling;             /* is text being filled right now */
	Xchar	Justbuf[MAXLEN];     /* buffer for justified text */
	Xint 	Justpos;             /* current position in justification buffer */
	Xint 	Outline;             /* output line number */
	Xint 	Pageline;            /* line number on current output page */
	Xint 	Pagenum;             /* current page number */
	X
	X/* Default values of options */
	X#define	MAXTAB     20                  /* max # of tab stops */
	X#define	FOOTSIZE    5                  /* default footer size */
	X#define	HEADSIZE    5                  /* default header size */
	X#define	NUMWIDTH    4                  /* default width of line numbers */
	X#define	PAGESIZE   66                  /* default length of page */
	X#define	WIDTH      72                  /* default width of page */
	X#define	PAGENUM   '%'                  /* expands to page number in titles */
	X#define	FILENAME  '*'                  /* expands to file name in title */
	X#define	HEADER	  "|File: *||Page: %|" /* default page header */
	X
	X/*MANUAL.SH OPTIONS
	XThere are many, many options to allow control of
	Xindentation, line width, line spacing, filling,
	Xpagination with headers and footers,
	Xline numbering, right justification,
	Xand perhaps some other things.
	XThey have extensive type and range checking
	Xthat produces diagnostic error messages,
	Xso warnings of obviously wrong options will not be discussed here.
	XIn general, options that imply the use of others
	Xwork the way they should; if the page size is set,
	Xthen pagination is automatically assumed.
	XSome combinations of options give impressive, even artistic, effects.
	XMaking a small text file and playing with it is the easiest
	Xway to learn how the options interact.
	X.de OP
	X.TP
	X.B -\\$1 \\$2
	X..
	X*/
	X
	X	Boole	Breaklines = FALSE; /*MANUAL.OP b
	XBreak all lines of text.
	XThat is, don't even-out lines by filling.
	XBy default, text lines are filled.
	X*/
	X
	X	char	*Breakchars = NULL; /*MANUAL.OP B breakchars
	XChange the set of characters that cause line breaks at the start of lines to
	X.I breakchars.
	XBy default, any characters but letters and numbers cause a break.
	XA good choice for break characters might be "*-+" and TABS
	Xthat might be used for lists.
	X*/
	X
	X	Boole	Center = FALSE; /*MANUAL.OP c
	XCenter all lines of text.
	XThis option stops all filling of text.
	X*/
	X
	X	Boole	Delspace = FALSE; /*MANUAL.OP d
	XDelete white space at the beginning and end of lines.
	XThis option is useful to help un-format text to be re-formatted.
	X*/
	X
	X	Boole	Delline = FALSE; /*MANUAL.OP D
	XDelete empty input lines.
	XAn input line is empty if it has no characters,
	Xnot even invisible character like tabs or spaces.
	XThis option can be combined with the option to remove white space
	Xto delete visibly blank lines.
	X*/
	X
	X	char	*Footer = NULL; /*MANUAL.OP f footer
	XSet the page footer to the string
	X.I footer.
	XThis can be any string,
	Xbut if the first character is not a letter or a digit,
	Xbut a punctuation character like /,
	Xthen that character separates the left,
	Xcenter, and right fields of a title.
	XFor example, the title
	X.ce
	X"/ff: fast formatter//1985/"
	Xwould have "ff: fast formatter" as a left justified field
	Xand 1985 as a right justified field on each page.
	XNote that there is no middle field in this example,
	Xbut there could have been, between the two consecutive /'s.
	XThere are two special characters, % and *,
	Xthat respectively are variables for the page number
	Xand the input file name.
	XThe default page footer is blank.
	X*/
	X
	X	int 	Footsize = FOOTSIZE; /*MANUAL.OP F footersize
	XSet the number of blank lines at the bottom of the page.
	XThe footer, if any, is placed in the middle of the space,
	Xwhich by default, is five lines.
	XIf
	X.I footersize
	Xis 0, no footer will be printed.
	X*/
	X
	X	char	*Header = HEADER; /*MANUAL.OP h header
	XSet the page header.
	XSee the description of three-part titles for the
	X.B -f footer
	Xoption.
	XThe default page header is
	X.ce
	X"|File: *||Page: %|".
	X*/
	X
	X	int 	Headsize = HEADSIZE; /*MANUAL.OP H headersize
	XSee the description of the footer size.
	X*/
	X
	X	int 	Indent = 0; /*MANUAL.OP i indent
	XSet the indentation of the text to
	X.I indent
	Xspaces.
	XNote that this effectively reduces the usable width of the page.
	X*/
	X
	X	int 	Tindent = 0; /*MANUAL.OP I tempindent
	XSet the temporary indent.
	XThis causes filled text found immediately after a break to
	Xbe indented for one line.
	XIt is useful for indenting the first lines of paragraphs.
	XIf
	X.I tempindent
	Xis negative,
	Xthe the temporary indent will be relative to the current
	X.I indent
	Xvalue.
	XIf the
	X.I tempindent
	Xvalue is more negative than the
	X.I indent
	Xvalue is positive,
	X.I ff
	Xwill automatically increase
	X.I indent.
	X*/
	X
	X	Boole	Justify = FALSE; /*MANUAL.OP j
	XJustify the text.
	XThat is, even the right margin by inserting spaces in the line.
	XOnly filled text can be justified.
	X*/
	X
	X	Boole	Numlines = FALSE; /*MANUAL.OP n
	XNumber all output lines produced by the input text.
	XLines from multiple line spacing or pagination will not
	Xbe numbered.
	X*/
	X
	X	int 	Numwidth = NUMWIDTH; /*MANUAL.OP N numberwidth
	XSet the width of the line numbers.
	XThe default is to take up 4 spaces.
	XNote that this effectively reduces the usable part of the page.
	X*/
	X
	X	Boole	Paginate = FALSE; /*MANUAL.OP p
	XPaginate the output.
	XSee the options for page header and footer control.
	X*/
	X
	X	int 	Pagesize = PAGESIZE; /*MANUAL.OP P pagesize
	XSet the number of lines in a page to
	X.I pagesize.
	XBy default, the standard 66 line page is assumed.
	X*/
	X
	X	int 	Spacing = 1; /*MANUAL.OP s spacing
	XSet the line spacing.
	XBy default, text is single spaced (\fIspacing\fR equals 1).
	X*/
	X
	X	int 	Tab[MAXTAB];
	X	int 	Ntabs = 0; /*MANUAL.OP t tab
	XSet individual absolute and relative tab stops.
	XThese values tell the formatter
	Xwhere to put the text (from an unfilled line)
	Xthat follows a tab character.
	XEach tab stop is supplied with its own
	X.B -t
	Xoption; there is no way to bundle them.
	X.I tab
	Xvalues can be integers without a plus sign.
	XThese are \fIabsolute\fR tab settings;
	Xthe tabs go to that position.
	XThe values must increase monotonically.
	XIf a
	X.I tab
	Xvalue is preceded by a plus sign,
	Xthen it is interpreted \fIrelative\fR to the previous tab setting.
	XFor example, a tab setting of 40 followed by one of +20
	Xwill set the second tab stop to 60.
	X*/
	X
	X	int 	Alltabs = 0; /*MANUAL.OP T tabs
	XSet tab stops to every
	X.I tabs
	Xspaces.
	XIt is useful to get equally spaced tabs.
	XThis option cannot be used with the other tab setting option.
	X*/
	X
	X	Boole	Uppercase = FALSE; /*MANUAL.OP u
	XPrint All Input Text As Initial Upper-Case Titles,
	XLike This Sentence.
	XThis option goes well with the one for centering lines.
	X*/
	X
	X	/*MANUAL.OP U
	XPrint a usage summary of all the options and stop.
	X*/
	X
	X	int 	Width = WIDTH; /*MANUAL.OP w width
	XSet the page width.
	XBy default, the page width is 72 characters.
	XNote that the usable line length is sometimes less
	Xthan the page width.
	XIf line numbering or indentation is requested,
	Xthese subtract from the line length.
	X*/
	X
	X/*MANUAL.SH EXAMPLES
	XSome of these examples can make shell scripts or aliases.
	X.nf
	X.ta .5i
	X.sp
	XCentered Titles: title
	X	ff -dcu $*
	XDouble Spaced Unfilled Paginated indented (for editing): draft
	X	ff -s 2 -b -p -f "`date`" -i 8 $*
	XProgram Listing: cpr
	X	H="@        Dir: `pwd`@@File: *@"
	X	F="@        $NAME@`date`@Page %@"
	X	ff -b -N 8 -H 3 -h "$H" -F 3 -f "$F" -T 4 -w 79 -i 2 $*
	XReformat Paragraphed Text: nr
	X	ff -jd -I 5 -i 10 -w 65 -B "TAB SP'*.@" $*
	X.fi
	X*/
	X/*MANUAL.SH DIAGNOSTICS
	XSome options are incompatible with others.
	XFor example, centered text cannot be right-justified.
	X.I ff
	Xwill not allow inconsistent combinations of options.
	X*/
	X/*MANUAL.SH "SEE ALSO"
	Xfmt(1), nroff(1), scribe(1w)
	X*/
	X/*MANUAL.SH AUTHOR
	XGary Perlman (with help from many students)
	X*/
	X/*MANUAL.SH STATUS
	XPretty well tested.
	X*/
	X
	X/* Macro Functions */
	X/*MACRO isendsent: is the character one that ends a sentence? */
	X#define	isendsent(c) ((c) == '.' || (c) == '?' || (c) == '!')
	X
	X/*MACRO justchar: add char to a buffer that will later be flushed */
	X#define	justchar(c) (Justbuf[Justpos++] = (c))
	X
	X/*MACRO fillchar: save to justify if necessary, else output */
	X#define fillchar(c) \
	X	{ \
	X	if (Justify == TRUE) justchar (c); \
	X	else putc (c, stdout); \
	X	}
	X
	X/*FUNCTION main: loop through files in classic UNIX filter style */
	Xmain (argc, argv)
	Xint 	argc;     /* argument count */
	Xchar	**argv;   /* argument vector */
	X	{
	X	Status 	ff ();      /* ff (file, ioptr) will filter files */
	X	Status	status;     /* return status of filter () */
	X	int 	firstfile;  /* first file name index returned by initial */
	X
	X	firstfile = initial (argc, argv);
	X	status = filter (argc, argv, firstfile, ff);
	X	exit (status);
	X	}
	X
	X/*FUNCTION setint: check type, convert string, and set integer option */
	XStatus
	Xsetint (flag, value, var, min, max)
	Xint 	flag;    /* the single character option name */
	Xchar	*value;  /* the candidate value, in string format */
	Xint 	*var;    /* ptr to variable to stuff in answer */
	Xint 	min;     /* minimum allowed value */
	Xint 	max;     /* maximum allowed value */
	X	{
	X	int 	tmpvar;
	X	if (number (value) == 1) /* number returns 1 for integers, 2 for reals */
	X		{
	X		tmpvar = atoi (value);
	X		if (tmpvar >= min && tmpvar <= max)
	X			{
	X			*var = tmpvar;
	X			return (SUCCESS);
	X			}
	X		fprintf (stderr, "%s: -%c option value must be between %d and %d\n",
	X			Argv0, flag, min, max);
	X		return (FAILURE);
	X		}
	X	fprintf (stderr, "%s: -%c option requires an integer value\n", Argv0, flag);
	X	return (FAILURE);
	X	}
	X
	X/*FUNCTION usage: print help menu */
	Xvoid
	Xusage (ioptr)
	XFILE	*ioptr;
	X	{
	X	fprintf (ioptr, "%s: fast text formatter options:\n", Argv0);
	X	fprintf (ioptr, "-b  	break all lines of text--do no filling\n");
	X	fprintf (ioptr, "-B s	line break characters\n");
	X	fprintf (ioptr, "-c  	center all text lines\n");
	X	fprintf (ioptr, "-d  	delete blank space around input lines\n");
	X	fprintf (ioptr, "-D  	delete blank input lines\n");
	X	fprintf (ioptr, "-f s	page footer three-part title\n");
	X	fprintf (ioptr, "-F i	page footer size (%d lines)\n", Footsize);
	X	fprintf (ioptr, "-h s	page header three-part title (%s)\n", Header);
	X	fprintf (ioptr, "-H i	page header size (%d lines)\n", Headsize);
	X	fprintf (ioptr, "-i i	text indentation (%d spaces)\n", Indent);
	X	fprintf (ioptr, "-I i	indent after line breaks (%d spaces)\n", Tindent);
	X	fprintf (ioptr, "-j  	justify the right margin of the text\n");
	X	fprintf (ioptr, "-n  	number output text lines\n");
	X	fprintf (ioptr, "-N i	width of line numbers (%d spaces)\n", Numwidth);
	X	fprintf (ioptr, "-p  	paginate output\n");
	X	fprintf (ioptr, "-P i	page size (%d lines)\n", Pagesize);
	X	fprintf (ioptr, "-s i	line spacing (%d line)\n", Spacing);
	X	fprintf (ioptr, "-t i	absolute or relative tab stop\n");
	X	fprintf (ioptr, "-T i	uniform tab stops\n");
	X	fprintf (ioptr, "-u  	show text with upper-case initial letters\n");
	X	fprintf (ioptr, "-U  	print long usage synopsis for this command\n");
	X	fprintf (ioptr, "-w i	page line width (%d spaces)\n", Width);
	X	}
	X
	X/*FUNCTION initial: set options */
	Xint
	Xinitial (argc, argv) char **argv;
	X	{
	X	extern	char	*optarg;   /* string value to option set by getopt */
	X	extern	int 	optind;    /* will be index of first command operand */
	X	int 	errcount = 0;        /* count of number of errors */
	X	int 	flag;              /* options flag names read in here */
	X	char	*optstring =       /* Boolean flags and integer options with : */
	X		"bcdDjnpuUB:f:F:h:H:i:I:N:P:s:t:T:w:";
	X
	X	Argv0 = argv[0];
	X	while ((flag = getopt (argc, argv, optstring)) != EOF)
	X		switch (flag)
	X		{
	X		default:
	X			errcount++;
	X			break;
	X
	X		case 'b':
	X			Breaklines = TRUE;
	X			break;
	X
	X		case 'B':
	X			Breakchars = optarg;
	X			break;
	X
	X		case 'c':
	X			Center = TRUE;
	X			Breaklines = TRUE;
	X			break;
	X
	X		case 'd':
	X			Delspace = TRUE;
	X			break;
	X
	X		case 'D':
	X			Delline = TRUE;
	X			break;
	X
	X		case 'f':
	X			Footer = optarg;
	X			Paginate = TRUE;
	X			break;
	X
	X		case 'F':
	X			if (setint (flag, optarg, &Footsize, 0, MAXLINES) == FAILURE)
	X				errcount++;
	X			Paginate = TRUE;
	X			break;
	X
	X		case 'h':
	X			Header = optarg;
	X			Paginate = TRUE;
	X			break;
	X
	X		case 'H':
	X			if (setint (flag, optarg, &Headsize, 0, MAXLINES) == FAILURE)
	X				errcount++;
	X			Paginate = TRUE;
	X			break;
	X
	X		case 'i':
	X			if (setint (flag, optarg, &Indent, 0, MAXLEN) == FAILURE)
	X				errcount++;
	X			break;
	X
	X		case 'I':
	X			if (setint (flag, optarg, &Tindent, -MAXLEN, MAXLEN) == FAILURE)
	X				errcount++;
	X			break;
	X
	X		case 'j':
	X			Justify = TRUE;
	X			break;
	X
	X		case 'N':
	X			if (setint (flag, optarg, &Numwidth, 1, MAXLEN) == FAILURE)
	X				errcount++;
	X			/* FALLTHROUGH */
	X
	X		case 'n':
	X			Numlines = TRUE;
	X			break;
	X
	X		case 'P':
	X			if (setint (flag, optarg, &Pagesize, 1, MAXLINES) == FAILURE)
	X				errcount++;
	X			/* FALLTHROUGH */
	X
	X		case 'p':
	X			Paginate = TRUE;
	X			break;
	X
	X		case 's':
	X			if (setint (flag, optarg, &Spacing, 1, MAXLINES) == FAILURE)
	X				errcount++;
	X			break;
	X
	X		case 't':
	X			if (Ntabs >= MAXTAB)
	X				{
	X				fprintf (stderr, "%s: at most %d -%c options allowed\n",
	X					Argv0, MAXTAB, flag);
	X				errcount++;
	X				}
	X			else if (setint (flag, optarg, &Tab[Ntabs], 0, MAXLEN) == FAILURE)
	X				errcount++;
	X			else if (Ntabs > 0)
	X				{
	X				if (*optarg == '+')
	X					Tab[Ntabs] += Tab[Ntabs-1];
	X				else if (Tab[Ntabs] <= Tab[Ntabs-1])
	X					{
	X					fprintf (stderr, "%s: -%c values must increase\n",
	X						Argv0, flag);
	X					errcount++;
	X					}
	X				}
	X			if (Tab[Ntabs] >= MAXLEN)
	X				{
	X				fprintf (stderr, "%s: -%c values must be < %d\n",
	X					Argv0, flag, MAXLEN);
	X				errcount++;
	X				}
	X			Ntabs++;
	X			break;
	X
	X		case 'T':
	X			if (setint (flag, optarg, &Alltabs, 1, MAXLEN) == FAILURE)
	X				errcount++;
	X			break;
	X
	X		case 'u':
	X			Uppercase = TRUE;
	X			break;
	X
	X		case 'U':
	X			usage (stdout);
	X			exit (0);
	X
	X		case 'w':
	X			if (setint (flag, optarg, &Width, 1, MAXLEN) == FAILURE)
	X				errcount++;
	X			break;
	X		}
	X
	X	/* Now check validity of option settings */
	X	if (Tindent < 0 && Indent < (-Tindent))
	X		Indent = (-Tindent);
	X	if (Ntabs > 0 && Alltabs > 0)
	X		{
	X		fprintf (stderr, "%s: can't set individual and all tabs\n", Argv0);
	X		errcount++;
	X		}
	X	if (Center == TRUE && Justify == TRUE)
	X		{
	X		fprintf (stderr, "%s: centering and justifying incompatible\n", Argv0);
	X		errcount++;
	X		}
	X	else if (Breaklines == TRUE && Justify == TRUE)
	X		{
	X		fprintf (stderr, "%s: breaking and justifying incompatible\n", Argv0);
	X		errcount++;
	X		}
	X	if (Ntabs > 0 && Center == TRUE)
	X		{
	X		fprintf (stderr,"%s: centering and setting tabs incompatible\n", Argv0);
	X		errcount++;
	X		}
	X	if ((Ntabs > 0 || Alltabs > 0) && (Justify == TRUE))
	X		{
	X		fprintf (stderr, "%s: tabstops and justifying incompatible\n", Argv0);
	X		errcount++;
	X		}
	X
	X	/* Print an error message and exit or return index to first file name */
	X	if (errcount > 0)
	X		{
	X		fprintf (stderr, "Usage: %s [options] [-] [files]\n", Argv0);
	X		exit (FAILURE);
	X		}
	X	return (optind);
	X	}
	X
	X/*FUNCTION repeat: repeat a character some number of times */
	Xvoid
	Xrepeat (c, n)
	Xint 	c;     /* character to print */
	Xint 	n;     /* number of times to print c */
	X	{
	X	while (n-- > 0)
	X		putc (c, stdout);
	X	}
	X
	X/*FUNCTION dotab: expand tabs to spaces to tab stops, returns static buffer */
	X/*ALGORITHM
	X	if all tabs are set to the same value (Alltabs > 0)
	X		then advance on a tab to the next tab stop
	X	else if there are individual tabs set (Ntabs > tabno)
	X		then advance (possibly retreat!) to next set tab
	X	else just treat the tab like a space character
	X*/
	Xchar *
	Xdotab (line)
	Xregister	char	*line;
	X	{
	X	static	char outline[MAXLEN];   /* new line will be built here */
	X	register char *lptr;            /* pointer to current position in outline */
	X	register char *nextptr;         /* position of next tab stop */
	X	int 	tabno = 0;              /* how many tabs have been processed */
	X
	X	for (lptr = outline; *line != EOS && *line != EOL; line++)
	X		{
	X		if (*line == TAB)
	X			{
	X			if (Alltabs > 0)
	X				nextptr = lptr + Alltabs - ((lptr - outline) % Alltabs);
	X			else if (Ntabs > tabno) /* move to next set tab */
	X				nextptr = outline + Tab[tabno++];
	X			else
	X				nextptr = lptr + 1;
	X			if (lptr < nextptr)
	X				do	{
	X					*lptr++ = SP;
	X				} while (lptr < nextptr);
	X			else lptr = nextptr;
	X			}
	X		else
	X			*lptr++ = *line;
	X
	X		/* check for line overflow */
	X		if (lptr >= (outline + MAXLEN))
	X			return (NULL);
	X		}
	X
	X	/* end the expanded tab string and return */
	X	*lptr = EOS;
	X	return (outline);
	X	}
	X
	X/*FUNCTION dojustify: even the right margin for all lines */
	X/*ALGORITHM
	X		directly output any indenting spaces (this is not expanded)
	X		trim trailing spaces (don't want to pad at end)
	X		count number of spaces inside line (where extra spaces will be inserted)
	X		distribute the extra spaces needed among the spaces there
	X	Note: if we are not filling (e.g., last line of output before a break)
	X		then we do not justfy the right margin.
	X*/
	Xvoid
	Xdojustify ()
	X	{
	X	register char *line;       /* will point to first non-space char on line */
	X	int 	width;             /* width of line to pad - #'s and indent */
	X	register char *lptr;       /* zips through the line */
	X	int     pad;               /* will need to pad with this many spaces */
	X	int     spaces = 0;        /* will be number of embedded spaces in line */
	X	register int i;            /* used inside inner loop */
	X	int 	n = 0;
	X
	X	if (Justpos == 0)          /* nothing to justify, so bail out */
	X		return;
	X
	X	/* strip spaces from end of line and end with EOS */
	X	for (lptr = Justbuf+Justpos; lptr>Justbuf && isspace(lptr[-1]); lptr--);
	X	*lptr = EOS;
	X
	X	width = Width - (Numlines == TRUE ? Numwidth : 0);
	X	pad = width - (lptr - Justbuf);
	X
	X	for (line = Justbuf; *line == SP; line++)
	X		putc (*line, stdout);
	X
	X	if (Filling == TRUE && pad > 0) /* might not fill last line of output */
	X		for (lptr = line; *lptr != EOS; lptr++)
	X			if (*lptr == SP)
	X				spaces++;
	X
	X	if (spaces > 0) /* we have places to insert spaces */
	X		{
	X		for (lptr = line; *lptr != EOS; lptr++)
	X			{
	X			if (*lptr == SP)
	X				for (i = 0; i < pad; i++)
	X					if (++n == spaces)
	X						{
	X						putc (SP, stdout);
	X						n = 0;
	X						}
	X			putc (*lptr, stdout);
	X			}
	X		}
	X	else /* just output the line */
	X		for (lptr = line; *lptr != EOS; lptr++)
	X			putc (*lptr, stdout);
	X
	X	Justpos = 0; /* reset buffer position for next line */
	X	}
	X
	X/*FUNCTION println: print lines while watching for page boundaries */
	Xvoid
	Xprintln (count)
	Xint 	count;    /* how many lines to print (== Spacing) */
	X	{
	X	Curpos = 0;
	X	while (count-- > 0)
	X		{
	X		putc (EOL, stdout);
	X		Pageline++;
	X		if (Paginate == TRUE && ((Pagesize - Pageline) == Footsize))
	X			{
	X			endpage (TRUE);
	X			return;
	X			}
	X		}
	X	}
	X
	X/*FUNCTION beginline: do any needed justification, paginate if requested, */
	X/*  handle line numbering, temp and regular indents based on prev. filling */
	Xvoid
	Xbeginline (filling)
	XBoole	filling;     /* are we filling now? */
	X	{
	X	int 	count;
	X	Boole	newfill = (Filling == FALSE && filling == TRUE);
	X
	X	Filling = filling;
	X	if (Justify == TRUE)
	X		dojustify ();
	X	Outline++;
	X	Curpos = 0;
	X
	X	if (Paginate == TRUE && Pageline == 0)
	X		beginpage ();
	X	else if (Outline > 1)
	X		println (Spacing);
	X
	X	if (Numlines == TRUE)
	X		{
	X		char	*ptr = itoa (Outline, Numwidth - 1);
	X		Curpos += Numwidth;
	X		while (*ptr)
	X			putc (*ptr++, stdout);
	X		putc (SP, stdout);
	X		}
	X
	X	count = Indent;
	X	if (newfill == TRUE)
	X		count += Tindent;
	X	Curpos += count;
	X
	X	if (Justify == TRUE)
	X		while (count-- > 0)
	X			justchar (SP);
	X	else
	X		repeat (SP, count);
	X	}
	X
	X/*FUNCTION itoa: integer to ascii conversion */
	Xchar *
	Xitoa (n, pad)
	Xregister int n;    /* the integer to be printed as a string */
	Xint 	pad;       /* amount of space to pad number to */
	X	{
	X	static char numbuf[MAXLEN]; /* answer built in here */
	X	register char *nptr;        /* will be pointer to beginning of number */
	X	Boole	negflg = FALSE;     /* is the number a negative value? */
	X
	X	/* static numbuf is initialized to 0's, so numbuf[MAXLEN-1] == EOS */
	X	if (n == 0)
	X		{
	X		nptr = &numbuf[MAXLEN-1];
	X		*--nptr = '0';
	X		}
	X	else
	X		{
	X		if (n < 0)
	X			{
	X			n = (-n);
	X			negflg = TRUE;
	X			}
	X		for (nptr = &numbuf[MAXLEN-1]; n != 0; n /= 10)
	X			*--nptr = (n % 10) + '0';
	X		if (negflg == TRUE)
	X			*--nptr = '-';
	X		}
	X
	X	while (pad > numbuf+MAXLEN-1-nptr)
	X		*--nptr = SP;
	X
	X	return (nptr);
	X	}
	X
	X/*FUNCTION expand: insert file/page for characters in field of 3part title */
	Xchar *
	Xexpand (title, page, file)
	Xregister	char	*title;   /* the title to be expanded */
	Xint 	page;                 /* the current page number */
	Xchar	*file;                /* the name of the current file */
	X	{
	X	static 	char answer[MAXLEN];  /* title expanded into this buffer */
	X	register 	char *aptr;       /* pointer to answer buf */
	X	register	char *ptr;        /* generic string handling pointer */
	X
	X	for (aptr = answer; *title != EOS; title++)
	X		switch (*title)
	X		{
	X		default: 
	X			*aptr++ = *title;
	X			break;
	X
	X		case PAGENUM:
	X			ptr = itoa (page, 0);
	X			while (*ptr != EOS)
	X				*aptr++ = *ptr++;
	X			break;
	X
	X		case FILENAME:
	X			for (ptr = file; *ptr != EOS; ptr++)
	X				*aptr++ = *ptr;
	X			break;
	X		}
	X	*aptr = EOS;
	X	return (answer);
	X	}
	X
	X/*FUNCTION threepart: 3-part title with left/center/right justified fields */
	X/*  any punctuation character can be the title delimiter: see nroff(1) */
	Xchar *
	Xthreepart (title, page, file, width)
	Xchar	*title;   /* the three part title */
	Xint 	page;     /* the current page number */
	Xchar	*file;    /* the current file name */
	Xint 	width;    /* the current page width */
	X	{
	X	static char answer[MAXLEN];   /* answer stuffed in here */
	X	register char *aptr;          /* pointer to answer buffer */
	X	int 	delim;                /* title delimiter character */
	X
	X	title = expand (title, page, file);
	X	if (!ispunct (*title))
	X		return (title);
	X	for (aptr = answer; aptr < answer + width; aptr++)
	X		*aptr = SP;
	X	aptr = answer;
	X	delim = *title++;
	X	while (*title != EOS && *title != delim)
	X		*aptr++ = *title++;
	X	if (*title++ != EOS) /* now do center */
	X		{
	X		char	*lptr = title;
	X		while (*lptr != EOS && *lptr != delim)
	X			lptr++;
	X		aptr = answer + (width - (lptr - title)) / 2;
	X		if (aptr >= answer)
	X			while (*title != EOS && *title != delim)
	X				*aptr++ = *title++;
	X		else
	X			while (*title != EOS && *title != delim)
	X				title++;
	X		if (*title++ != EOS) /* now do left part */
	X			{
	X			char	*eptr = title;
	X			while (*eptr != EOS && *eptr != delim)
	X				eptr++;
	X			eptr--;
	X			aptr = answer + width - 1;
	X			while (eptr >= title)
	X				*aptr-- = *eptr--;
	X			}
	X		}
	X	answer[width] = EOS;
	X	return (answer);
	X	}
	X
	X/*FUNCTION beginpage: handle page header */
	Xvoid
	Xbeginpage ()
	X	{
	X	Pagenum++;
	X	if (Paginate == TRUE && Headsize > 0)
	X		{
	X		int 	space1 = Headsize / 2;
	X		int 	space2 = Headsize - space1;
	X		char	*optr = threepart (Header, Pagenum, Filename, Width);
	X
	X		repeat (EOL, space1);
	X		while (*optr != EOS)
	X			putc (*optr++, stdout);
	X		repeat (EOL, space2);
	X		Pageline = Headsize;
	X		}
	X	}
	X
	X/*FUNCTION endpage: break filling (output justified text) print footer */
	X/* begin a new page if there is more */
	Xvoid
	Xendpage (more)
	XBoole	more;
	X	{
	X	if (Justify == TRUE)
	X		dojustify ();
	X
	X	if (Paginate == TRUE)
	X		{
	X		int 	space1 = Footsize / 2;
	X		int 	space2 = Footsize - space1;
	X		char	*optr = threepart (Footer, Pagenum, Filename, Width);
	X
	X		repeat (EOL, Pagesize - Pageline - space2);
	X		while (*optr != EOS)
	X			putc (*optr++, stdout);
	X		repeat (EOL, space2);
	X		Pageline = 0;
	X		}
	X	else if (Curpos > 0 || Indent > 0 || Numlines == TRUE)
	X		putc (EOL, stdout);
	X
	X	if (more == TRUE)
	X		beginpage ();
	X	}
	X
	X/*FUNCTION preprocess: trim space, find blank lines, do titling */
	Xchar *
	Xpreprocess (line)
	Xregister	char	*line;
	X	{
	X	register	char	*lptr;
	X	if (Paginate == TRUE && *line == FF)
	X		{
	X		line++;
	X		endpage (TRUE);
	X		}
	X	if (Delspace == TRUE) /* delete blank space */
	X		{
	X		while (isspace (*line))
	X			line++;
	X		for (lptr = line; *lptr != EOS; lptr++);
	X		while (lptr > line && isspace (*(lptr-1)))
	X			lptr--;
	X		*lptr = EOS;
	X		}
	X	if (Delline == TRUE && (*line == EOL || *line == EOS))
	X		return (NULL);
	X	if (Uppercase == TRUE)
	X		{
	X		Boole 	newword;    /* are we at the start of a new word? */
	X		for (lptr = line, newword = TRUE; *lptr != EOS; lptr++)
	X			{
	X			if (newword && islower (*lptr))
	X				*lptr = toupper (*lptr);
	X			newword = !isalnum (*lptr);
	X			}
	X		}
	X	return (line);
	X	}
	X
	X/*FUNCTION dobreak: process broken line & return success status */
	XStatus
	Xdobreak (lptr)
	Xregister char *lptr;    /* line to print out */
	X	{
	X	/* break: do tabs, or centering, and then dump the line out */
	X	beginline (FALSE);
	X	if (Alltabs > 0 || Ntabs > 0) /* some tabs have been set */
	X		{
	X		if ((lptr = dotab (lptr)) == NULL)
	X			{
	X			fprintf (stderr, "%s: malformed tab in %s at line %d\n",
	X				Argv0, Filename, Outline);
	X			return (FAILURE);
	X			}
	X		}
	X	else if (Center == TRUE && *lptr != EOS && *lptr != EOL)
	X		repeat (SP, (Width - strlen (lptr)) / 2);
	X	while (*lptr != EOS && *lptr != EOL)
	X		putc (*lptr++, stdout);
	X	Curpos = Width; /* signal end of line */
	X	return (SUCCESS);
	X	}
	X
	X/*FUNCTION dofill: do line filling */
	Xvoid
	Xdofill (lptr)
	Xregister	char	*lptr;
	X	{
	X	register char *eptr;       /* pointer to end of filled words */
	X	register int wordlen;      /* length of words */
	X
	X	while (isspace (*lptr))
	X		lptr++;
	X	while (*lptr != EOS) /* fill text by picking up word by word */
	X		{
	X		eptr = lptr;
	X		while (*eptr != EOS && !isspace (*eptr))
	X			eptr++;
	X		wordlen = eptr - lptr;
	X		if ((Outline == 0) || (Curpos + wordlen) >= Width)
	X			beginline (TRUE);
	X		else if (Curpos < Width) /* space before word */
	X			{
	X			fillchar (SP);
	X			Curpos++;
	X			}
	X		for (Curpos += wordlen; lptr < eptr; lptr++)
	X			fillchar (*lptr);
	X		while (isspace (*lptr))
	X			lptr++;
	X
	X		/* extra space at sentence ends (.?!) */
	X		if ((Curpos < Width) && isendsent (*(eptr-1)) && wordlen > 2)
	X			{
	X			fillchar (SP);
	X			Curpos++;
	X			}
	X		}
	X	}
	X
	X/*FUNCTION ff: main formatting routine */
	X/*
	X	initializes for each new file, reads lines, trims space and blank lines
	X	switches between filling and non filling based on breakchars
	X*/
	XStatus
	Xff (file, ioptr)
	Xchar	*file;    /* file name */
	XFILE	*ioptr;   /* opened input pointer */
	X	{
	X	char	line[BUFSIZ];      /* lines read in here */
	X	register char *lptr;       /* pointer used to go through line */
	X	Status	status = SUCCESS;
	X
	X	Outline = Pagenum = Pageline = Curpos = 0;
	X	Filename = file;
	X	Filling = FALSE;
	X
	X	while (fgets (lptr = line, sizeof (line), ioptr))
	X		{
	X		if ((lptr = preprocess (lptr)) == NULL)
	X			continue;
	X
	X		if ((Breaklines == TRUE)
	X		|| (*lptr == EOL)
	X		|| (Breakchars ? index (Breakchars, *lptr) != NULL : !isalnum (*lptr)))
	X			{
	X			if (dobreak (lptr) == FAILURE)
	X				return (FAILURE);
	X			}
	X
	X		else
	X
	X			dofill (lptr);
	X		}
	X
	X	Filling = FALSE;
	X	endpage (FALSE);
	X	return (status);
	X	}
SHAR_EOF
if test 29326 -ne "`wc -c < 'ff.c'`"
then
	echo shar: "error transmitting 'ff.c'" '(should have been 29326 characters)'
fi
fi
exit 0
#	End of shell archive



More information about the Mod.sources mailing list