|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T f
Length: 21308 (0x533c)
Types: TextFile
Names: »ff.c«
└─⟦db229ac7e⟧ Bits:30007240 EUUGD20: SSBA 1.2 / AFW Benchmarks
└─⟦this⟧ »EUUGD20/AFUU-ssba1.21/ssba1.21E/musbus/ff.c«
└─⟦this⟧ »EUUGD20/AFUU-ssba1.21/ssba1.21F/musbus/ff.c«
/*COPYRIGHT (c) 1985 Wang Institute, Tyngsboro, MA 01879 USA */
/*DISCLAIMER: No guarantees of performance are made. */
/*MODULE ff: "fast formatter" "Sun 01 Sep 1985" */
/*PGMR ff: "Gary Perlman" "Wang Institute, Tyngsboro, MA 01879 USA" */
/*VER $Header: ff.c,v 1.3 85/09/01 21:23:38 perlman Exp $ */
#include <stdio.h>
#include <ctype.h>
#include <string.h>
typedef int Status;
#define SUCCESS ((Status) 0)
#define FAILURE ((Status) 1)
typedef int Boole;
#define TRUE ((Boole) 1)
#define FALSE ((Boole) 0)
#define TAB '\t'
#define EOL '\n'
#define FF '\f'
#define EOS '\0'
#define SP ' '
#define MAXLEN 128 /* max length of lines */
#define MAXLINES 200 /* max # lines on pages */
/* Alphabetical listing of this file's functions */
void beginline (); /* process text at the beginning of lines */
void beginpage (); /* handle pagination at page breaks */
Status dobreak (); /* handle broken lines, if appropriate */
void dofill (); /* do the text filling */
char *dotab (); /* return expanded tabs in line */
void endpage (); /* handle pagination at page ends */
char *expand (); /* expand strings in three part titles */
Status ff (); /* main formatting routine */
int initial (); /* set options and check consistency */
char *itoa (); /* convert integer to ascii format, with padding */
void dojustify (); /* even out (justify) the right margin of filled lines */
char *preprocess ();/* handle blank trimming and titling */
void println (); /* print a line, watching for page boundaries */
void repeat (); /* repeatedly print a character */
Status setint (); /* check type & convert a string to an integer */
char *threepart (); /* build three part titles */
void usage (); /* print usage summary */
/* GLOBALS */
char *Argv0; /* will be name of program */
int Curpos; /* current position on output line */
char *Filename; /* current input file name */
Boole Filling; /* is text being filled right now */
char Justbuf[MAXLEN]; /* buffer for justified text */
int Justpos; /* current position in justification buffer */
int Outline; /* output line number */
int Pageline; /* line number on current output page */
int Pagenum; /* current page number */
/* Default values of options */
#define MAXTAB 20 /* max # of tab stops */
#define FOOTSIZE 5 /* default footer size */
#define HEADSIZE 5 /* default header size */
#define NUMWIDTH 4 /* default width of line numbers */
#define PAGESIZE 66 /* default length of page */
#define WIDTH 72 /* default width of page */
#define PAGENUM '%' /* expands to page number in titles */
#define FILENAME '*' /* expands to file name in title */
#define HEADER "|File: *||Page: %|" /* default page header */
Boole Breaklines = FALSE;
char *Breakchars = "";
Boole Center = FALSE;
Boole Delspace = FALSE;
Boole Delline = FALSE;
char *Footer = "";
int Footsize = FOOTSIZE;
char *Header = HEADER;
int Headsize = HEADSIZE;
int Indent = 0;
int Tindent = 0;
Boole Justify = FALSE;
Boole Numlines = FALSE;
int Numwidth = NUMWIDTH;
Boole Paginate = FALSE;
int Pagesize = PAGESIZE;
int Spacing = 1;
int Tab[MAXTAB];
int Ntabs = 0;
int Alltabs = 0;
Boole Uppercase = FALSE;
int Width = WIDTH;
/*MACRO isendsent: is the character one that ends a sentence? */
#define isendsent(c) ((c) == '.' || (c) == '?' || (c) == '!')
/*MACRO justchar: add char to a buffer that will later be flushed */
#define justchar(c) (Justbuf[Justpos++] = (c))
/*MACRO fillchar: save to justify if necessary, else output */
#define fillchar(c) \
{ \
if (Justify == TRUE) justchar (c); \
else putc (c, stdout); \
}
/*FUNCTION main: loop through files in classic UNIX filter style */
main (argc, argv)
int argc; /* argument count */
char **argv; /* argument vector */
{
Status ff (); /* ff (file, ioptr) will filter files */
Status status; /* return status of filter () */
int firstfile; /* first file name index returned by initial */
firstfile = initial (argc, argv);
status = filter (argc, argv, firstfile, ff);
exit (status);
}
/*FUNCTION setint: check type, convert string, and set integer option */
Status
setint (flag, value, var, min, max)
int flag; /* the single character option name */
char *value; /* the candidate value, in string format */
int *var; /* ptr to variable to stuff in answer */
int min; /* minimum allowed value */
int max; /* maximum allowed value */
{
int tmpvar;
if (number (value) == 1) /* number returns 1 for integers, 2 for reals */
{
tmpvar = atoi (value);
if (tmpvar >= min && tmpvar <= max)
{
*var = tmpvar;
return (SUCCESS);
}
fprintf (stderr, "%s: -%c option value must be between %d and %d\n",
Argv0, flag, min, max);
return (FAILURE);
}
fprintf (stderr, "%s: -%c option requires an integer value\n", Argv0, flag);
return (FAILURE);
}
/*FUNCTION usage: print help menu */
void
usage (ioptr)
FILE *ioptr;
{
fprintf (ioptr, "%s: fast text formatter options:\n", Argv0);
fprintf (ioptr, "-b break all lines of text--do no filling\n");
fprintf (ioptr, "-B s line break characters\n");
fprintf (ioptr, "-c center all text lines\n");
fprintf (ioptr, "-d delete blank space around input lines\n");
fprintf (ioptr, "-D delete blank input lines\n");
fprintf (ioptr, "-f s page footer three-part title\n");
fprintf (ioptr, "-F i page footer size (%d lines)\n", Footsize);
fprintf (ioptr, "-h s page header three-part title (%s)\n", Header);
fprintf (ioptr, "-H i page header size (%d lines)\n", Headsize);
fprintf (ioptr, "-i i text indentation (%d spaces)\n", Indent);
fprintf (ioptr, "-I i indent after line breaks (%d spaces)\n", Tindent);
fprintf (ioptr, "-j justify the right margin of the text\n");
fprintf (ioptr, "-n number output text lines\n");
fprintf (ioptr, "-N i width of line numbers (%d spaces)\n", Numwidth);
fprintf (ioptr, "-p paginate output\n");
fprintf (ioptr, "-P i page size (%d lines)\n", Pagesize);
fprintf (ioptr, "-s i line spacing (%d line)\n", Spacing);
fprintf (ioptr, "-t i absolute or relative tab stop\n");
fprintf (ioptr, "-T i uniform tab stops\n");
fprintf (ioptr, "-u show text with upper-case initial letters\n");
fprintf (ioptr, "-U print long usage synopsis for this command\n");
fprintf (ioptr, "-w i page line width (%d spaces)\n", Width);
}
/*FUNCTION initial: set options */
int
initial (argc, argv) char **argv;
{
extern char *optarg; /* string value to option set by getopt */
extern int optind; /* will be index of first command operand */
int errcount = 0; /* count of number of errors */
int flag; /* options flag names read in here */
char *optstring = /* Boolean flags and integer options with : */
"bcdDjnpuUB:f:F:h:H:i:I:N:P:s:t:T:w:";
Argv0 = argv[0];
while ((flag = getopt (argc, argv, optstring)) != EOF)
switch (flag)
{
default:
errcount++;
break;
case 'b':
Breaklines = TRUE;
break;
case 'B':
Breakchars = optarg;
break;
case 'c':
Center = TRUE;
Breaklines = TRUE;
break;
case 'd':
Delspace = TRUE;
break;
case 'D':
Delline = TRUE;
break;
case 'f':
Footer = optarg;
Paginate = TRUE;
break;
case 'F':
if (setint (flag, optarg, &Footsize, 0, MAXLINES) == FAILURE)
errcount++;
Paginate = TRUE;
break;
case 'h':
Header = optarg;
Paginate = TRUE;
break;
case 'H':
if (setint (flag, optarg, &Headsize, 0, MAXLINES) == FAILURE)
errcount++;
Paginate = TRUE;
break;
case 'i':
if (setint (flag, optarg, &Indent, 0, MAXLEN) == FAILURE)
errcount++;
break;
case 'I':
if (setint (flag, optarg, &Tindent, -MAXLEN, MAXLEN) == FAILURE)
errcount++;
break;
case 'j':
Justify = TRUE;
break;
case 'N':
if (setint (flag, optarg, &Numwidth, 1, MAXLEN) == FAILURE)
errcount++;
/* FALLTHROUGH */
case 'n':
Numlines = TRUE;
break;
case 'P':
if (setint (flag, optarg, &Pagesize, 1, MAXLINES) == FAILURE)
errcount++;
/* FALLTHROUGH */
case 'p':
Paginate = TRUE;
break;
case 's':
if (setint (flag, optarg, &Spacing, 1, MAXLINES) == FAILURE)
errcount++;
break;
case 't':
if (Ntabs >= MAXTAB)
{
fprintf (stderr, "%s: at most %d -%c options allowed\n",
Argv0, MAXTAB, flag);
errcount++;
}
else if (setint (flag, optarg, &Tab[Ntabs], 0, MAXLEN) == FAILURE)
errcount++;
else if (Ntabs > 0)
{
if (*optarg == '+')
Tab[Ntabs] += Tab[Ntabs-1];
else if (Tab[Ntabs] <= Tab[Ntabs-1])
{
fprintf (stderr, "%s: -%c values must increase\n",
Argv0, flag);
errcount++;
}
}
if (Tab[Ntabs] >= MAXLEN)
{
fprintf (stderr, "%s: -%c values must be < %d\n",
Argv0, flag, MAXLEN);
errcount++;
}
Ntabs++;
break;
case 'T':
if (setint (flag, optarg, &Alltabs, 1, MAXLEN) == FAILURE)
errcount++;
break;
case 'u':
Uppercase = TRUE;
break;
case 'U':
usage (stdout);
exit (0);
case 'w':
if (setint (flag, optarg, &Width, 1, MAXLEN) == FAILURE)
errcount++;
break;
}
/* Now check validity of option settings */
if (Tindent < 0 && Indent < (-Tindent))
Indent = (-Tindent);
if (Ntabs > 0 && Alltabs > 0)
{
fprintf (stderr, "%s: can't set individual and all tabs\n", Argv0);
errcount++;
}
if (Center == TRUE && Justify == TRUE)
{
fprintf (stderr, "%s: centering and justifying incompatible\n", Argv0);
errcount++;
}
else if (Breaklines == TRUE && Justify == TRUE)
{
fprintf (stderr, "%s: breaking and justifying incompatible\n", Argv0);
errcount++;
}
if (Ntabs > 0 && Center == TRUE)
{
fprintf (stderr,"%s: centering and setting tabs incompatible\n", Argv0);
errcount++;
}
if ((Ntabs > 0 || Alltabs > 0) && (Justify == TRUE))
{
fprintf (stderr, "%s: tabstops and justifying incompatible\n", Argv0);
errcount++;
}
/* Print an error message and exit or return index to first file name */
if (errcount > 0)
{
fprintf (stderr, "Usage: %s [options] [-] [files]\n", Argv0);
exit (FAILURE);
}
return (optind);
}
/*FUNCTION repeat: repeat a character some number of times */
void
repeat (c, n)
int c; /* character to print */
int n; /* number of times to print c */
{
while (n-- > 0)
putc (c, stdout);
}
/*FUNCTION dotab: expand tabs to spaces to tab stops, returns static buffer */
char *
dotab (line)
register char *line;
{
static char outline[MAXLEN]; /* new line will be built here */
register char *lptr; /* pointer to current position in outline */
register char *nextptr; /* position of next tab stop */
int tabno = 0; /* how many tabs have been processed */
for (lptr = outline; *line != EOS && *line != EOL; line++)
{
if (*line == TAB)
{
if (Alltabs > 0)
nextptr = lptr + Alltabs - ((lptr - outline) % Alltabs);
else if (Ntabs > tabno) /* move to next set tab */
nextptr = outline + Tab[tabno++];
else
nextptr = lptr + 1;
if (lptr < nextptr)
do {
*lptr++ = SP;
} while (lptr < nextptr);
else lptr = nextptr;
}
else
*lptr++ = *line;
/* check for line overflow */
if (lptr >= (outline + MAXLEN))
return (NULL);
}
/* end the expanded tab string and return */
*lptr = EOS;
return (outline);
}
/*FUNCTION dojustify: even the right margin for all lines */
void
dojustify ()
{
register char *line; /* will point to first non-space char on line */
int width; /* width of line to pad - #'s and indent */
register char *lptr; /* zips through the line */
int pad; /* will need to pad with this many spaces */
int spaces = 0; /* will be number of embedded spaces in line */
register int i; /* used inside inner loop */
int n = 0;
if (Justpos == 0) /* nothing to justify, so bail out */
return;
/* strip spaces from end of line and end with EOS */
for (lptr = Justbuf+Justpos; lptr>Justbuf && isspace(lptr[-1]); lptr--);
*lptr = EOS;
width = Width - (Numlines == TRUE ? Numwidth : 0);
pad = width - (lptr - Justbuf);
for (line = Justbuf; *line == SP; line++)
putc (*line, stdout);
if (Filling == TRUE && pad > 0) /* might not fill last line of output */
for (lptr = line; *lptr != EOS; lptr++)
if (*lptr == SP)
spaces++;
if (spaces > 0) /* we have places to insert spaces */
{
for (lptr = line; *lptr != EOS; lptr++)
{
if (*lptr == SP)
for (i = 0; i < pad; i++)
if (++n == spaces)
{
putc (SP, stdout);
n = 0;
}
putc (*lptr, stdout);
}
}
else /* just output the line */
for (lptr = line; *lptr != EOS; lptr++)
putc (*lptr, stdout);
Justpos = 0; /* reset buffer position for next line */
}
/*FUNCTION println: print lines while watching for page boundaries */
void
println (count)
int count; /* how many lines to print (== Spacing) */
{
Curpos = 0;
while (count-- > 0)
{
putc (EOL, stdout);
Pageline++;
if (Paginate == TRUE && ((Pagesize - Pageline) == Footsize))
{
endpage (TRUE);
return;
}
}
}
/*FUNCTION beginline: do any needed justification, paginate if requested, */
/* handle line numbering, temp and regular indents based on prev. filling */
void
beginline (filling)
Boole filling; /* are we filling now? */
{
int count;
Boole newfill = (Filling == FALSE && filling == TRUE);
Filling = filling;
if (Justify == TRUE)
dojustify ();
Outline++;
Curpos = 0;
if (Paginate == TRUE && Pageline == 0)
beginpage ();
else if (Outline > 1)
println (Spacing);
if (Numlines == TRUE)
{
char *ptr = itoa (Outline, Numwidth - 1);
Curpos += Numwidth;
while (*ptr)
putc (*ptr++, stdout);
putc (SP, stdout);
}
count = Indent;
if (newfill == TRUE)
count += Tindent;
Curpos += count;
if (Justify == TRUE)
while (count-- > 0)
justchar (SP);
else
repeat (SP, count);
}
/*FUNCTION itoa: integer to ascii conversion */
char *
itoa (n, pad)
register int n; /* the integer to be printed as a string */
int pad; /* amount of space to pad number to */
{
static char numbuf[MAXLEN]; /* answer built in here */
register char *nptr; /* will be pointer to beginning of number */
Boole negflg = FALSE; /* is the number a negative value? */
/* static numbuf is initialized to 0's, so numbuf[MAXLEN-1] == EOS */
if (n == 0)
{
nptr = &numbuf[MAXLEN-1];
*--nptr = '0';
}
else
{
if (n < 0)
{
n = (-n);
negflg = TRUE;
}
for (nptr = &numbuf[MAXLEN-1]; n != 0; n /= 10)
*--nptr = (n % 10) + '0';
if (negflg == TRUE)
*--nptr = '-';
}
while (pad > numbuf+MAXLEN-1-nptr)
*--nptr = SP;
return (nptr);
}
/*FUNCTION expand: insert file/page for characters in field of 3part title */
char *
expand (title, page, file)
register char *title; /* the title to be expanded */
int page; /* the current page number */
char *file; /* the name of the current file */
{
static char answer[MAXLEN]; /* title expanded into this buffer */
register char *aptr; /* pointer to answer buf */
register char *ptr; /* generic string handling pointer */
for (aptr = answer; *title != EOS; title++)
switch (*title)
{
default:
*aptr++ = *title;
break;
case PAGENUM:
ptr = itoa (page, 0);
while (*ptr != EOS)
*aptr++ = *ptr++;
break;
case FILENAME:
for (ptr = file; *ptr != EOS; ptr++)
*aptr++ = *ptr;
break;
}
*aptr = EOS;
return (answer);
}
/*FUNCTION threepart: 3-part title with left/center/right justified fields */
/* any punctuation character can be the title delimiter: see nroff(1) */
char *
threepart (title, page, file, width)
char *title; /* the three part title */
int page; /* the current page number */
char *file; /* the current file name */
int width; /* the current page width */
{
static char answer[MAXLEN]; /* answer stuffed in here */
register char *aptr; /* pointer to answer buffer */
int delim; /* title delimiter character */
title = expand (title, page, file);
if (!ispunct (*title))
return (title);
for (aptr = answer; aptr < answer + width; aptr++)
*aptr = SP;
aptr = answer;
delim = *title++;
while (*title != EOS && *title != delim)
*aptr++ = *title++;
if (*title++ != EOS) /* now do center */
{
char *lptr = title;
while (*lptr != EOS && *lptr != delim)
lptr++;
aptr = answer + (width - (lptr - title)) / 2;
if (aptr >= answer)
while (*title != EOS && *title != delim)
*aptr++ = *title++;
else
while (*title != EOS && *title != delim)
title++;
if (*title++ != EOS) /* now do left part */
{
char *eptr = title;
while (*eptr != EOS && *eptr != delim)
eptr++;
eptr--;
aptr = answer + width - 1;
while (eptr >= title)
*aptr-- = *eptr--;
}
}
answer[width] = EOS;
return (answer);
}
/*FUNCTION beginpage: handle page header */
void
beginpage ()
{
Pagenum++;
if (Paginate == TRUE && Headsize > 0)
{
int space1 = Headsize / 2;
int space2 = Headsize - space1;
char *optr = threepart (Header, Pagenum, Filename, Width);
repeat (EOL, space1);
while (*optr != EOS)
putc (*optr++, stdout);
repeat (EOL, space2);
Pageline = Headsize;
}
}
/*FUNCTION endpage: break filling (output justified text) print footer */
/* begin a new page if there is more */
void
endpage (more)
Boole more;
{
if (Justify == TRUE)
dojustify ();
if (Paginate == TRUE)
{
int space1 = Footsize / 2;
int space2 = Footsize - space1;
char *optr = threepart (Footer, Pagenum, Filename, Width);
repeat (EOL, Pagesize - Pageline - space2);
while (*optr != EOS)
putc (*optr++, stdout);
repeat (EOL, space2);
Pageline = 0;
}
else if (Curpos > 0 || Indent > 0 || Numlines == TRUE)
putc (EOL, stdout);
if (more == TRUE)
beginpage ();
}
/*FUNCTION preprocess: trim space, find blank lines, do titling */
char *
preprocess (line)
register char *line;
{
register char *lptr;
if (Paginate == TRUE && *line == FF)
{
line++;
endpage (TRUE);
}
if (Delspace == TRUE) /* delete blank space */
{
while (isspace (*line))
line++;
for (lptr = line; *lptr != EOS; lptr++);
while (lptr > line && isspace (*(lptr-1)))
lptr--;
*lptr = EOS;
}
if (Delline == TRUE && (*line == EOL || *line == EOS))
return (NULL);
if (Uppercase == TRUE)
{
Boole newword; /* are we at the start of a new word? */
for (lptr = line, newword = TRUE; *lptr != EOS; lptr++)
{
if (newword && islower (*lptr))
*lptr = toupper (*lptr);
newword = !isalnum (*lptr);
}
}
return (line);
}
/*FUNCTION dobreak: process broken line & return success status */
Status
dobreak (lptr)
register char *lptr; /* line to print out */
{
/* break: do tabs, or centering, and then dump the line out */
beginline (FALSE);
if (Alltabs > 0 || Ntabs > 0) /* some tabs have been set */
{
if ((lptr = dotab (lptr)) == NULL)
{
fprintf (stderr, "%s: malformed tab in %s at line %d\n",
Argv0, Filename, Outline);
return (FAILURE);
}
}
else if (Center == TRUE && *lptr != EOS && *lptr != EOL)
repeat (SP, (Width - strlen (lptr)) / 2);
while (*lptr != EOS && *lptr != EOL)
putc (*lptr++, stdout);
Curpos = Width; /* signal end of line */
return (SUCCESS);
}
/*FUNCTION dofill: do line filling */
void
dofill (lptr)
register char *lptr;
{
register char *eptr; /* pointer to end of filled words */
register int wordlen; /* length of words */
while (isspace (*lptr))
lptr++;
while (*lptr != EOS) /* fill text by picking up word by word */
{
eptr = lptr;
while (*eptr != EOS && !isspace (*eptr))
eptr++;
wordlen = eptr - lptr;
if ((Outline == 0) || (Curpos + wordlen) >= Width)
beginline (TRUE);
else if (Curpos < Width) /* space before word */
{
fillchar (SP);
Curpos++;
}
for (Curpos += wordlen; lptr < eptr; lptr++)
fillchar (*lptr);
while (isspace (*lptr))
lptr++;
/* extra space at sentence ends (.?!) */
if ((Curpos < Width) && isendsent (*(eptr-1)) && wordlen > 2)
{
fillchar (SP);
Curpos++;
}
}
}
/*FUNCTION ff: main formatting routine */
Status
ff (file, ioptr)
char *file; /* file name */
FILE *ioptr; /* opened input pointer */
{
char line[BUFSIZ]; /* lines read in here */
register char *lptr; /* pointer used to go through line */
Status status = SUCCESS;
Outline = Pagenum = Pageline = Curpos = 0;
Filename = file;
Filling = FALSE;
while (fgets (lptr = line, sizeof (line), ioptr))
{
if ((lptr = preprocess (lptr)) == NULL)
continue;
if ((Breaklines == TRUE)
|| (*lptr == EOL)
|| (Breakchars ? index (Breakchars, *lptr) != NULL : !isalnum (*lptr)))
{
if (dobreak (lptr) == FAILURE)
return (FAILURE);
}
else
dofill (lptr);
}
Filling = FALSE;
endpage (FALSE);
return (status);
}