rsalz@uunet.uu.net (Rich Salz) (11/12/88)
Submitted-by: lee@uhccux.uhcc.hawaii.edu (Greg Lee) Posting-number: Volume 16, Issue 71 Archive-name: xfmt [ This will be the last one of these, unless anyone has an nroff emulator, as we're moving past the "simple" stage now. Note that it uses FLEX, which appeared here several months ago. --r$ ] Xfmt fills out lines by paragraphs, like the BSD fmt program. The first version of xfmt, 'extended fmt', was written by Bill Gray (bgray@marque.mu.edu) and appeared in comp.sources.misc as "fmt". This version interprets a few nroff -man commands or a (very) few TeX commands, or both, if you ask it to (by using the -m or -x flags). It does a more complete job of interpreting fonts in terms of screen attributes than can be done nroff(1) and ul(1). There is also a -c flag for displaying C code with comments highlighted and keywords shown with various screen attributes. Many man pages are not correctly processed, since many have nroff commands not interpreted by xfmt. The addition of -man interpretation and other features to xfmt will not be to everyone's taste, especially since they are incompletely implemented. The BSD termcap facility is used in this version of xfmt. Also, you need flex, by Vern Paxson et al. to make xfmt. Unless a second version of flex has been distributed by now, you will need to modify flex's skeleton files by making the changes described in the REAMDE file. -- Greg Lee U.S.mail: 562 Moore Hall, Dept. of Linguistics, Univ. of Hawaii, HONO, HI 96822 INTERNET: lee@uhccux.uhcc.hawaii.edu UUCP: {ihnp4,dcdwest,ucbvax}!sdcsvax!nosc!uhccux!lee BITNET: lee@uhccux #! /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 archive 1 (of 1)." # Contents: MANIFEST Makefile README cmds.tex flex.skel.diff xfmt.1 xfmt.l PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'MANIFEST' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'MANIFEST'\" else echo shar: Extracting \"'MANIFEST'\" \(402 characters\) sed "s/^X//" >'MANIFEST' <<'END_OF_FILE' X File Name Archive # Description X----------------------------------------------------------- X MANIFEST 1 X Makefile 1 X README 1 X cmds.tex 1 list of formatting commands X flex.skel.diff 1 patch for flex distribution file X xfmt.1 1 man page X xfmt.l 1 (f)lex source for xfmt END_OF_FILE if test 402 -ne `wc -c <'MANIFEST'`; then echo shar: \"'MANIFEST'\" unpacked with wrong size! fi # end of 'MANIFEST' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(791 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X# file: xfmt/Makefile X# 04/88 bgray, rev. 05/88 by Greg Lee X X BINDIR = /usr/lbin MANDIR = /usr/man/u_man/man1 CATMAN = /usr/catman/u_man/man1 X LIBS = -ltermcap CFLAGS = -O LDFLAGS = -s CC = /bin/cc RM = /bin/rm -f CP = /bin/cp X OBJS = X X all: xfmt X xfmt: xfmt.c X $(CC) $(CFLAGS) $(LDFLAGS) -o xfmt xfmt.c $(LIBS) X xfmt.c: xfmt.l X @rm -f xfmt.c X flex -t xfmt.l >xfmt.c X xfmt.doc: xfmt.1 xfmt X xfmt -jmo xfmt.1 >xfmt.doc X shar: xfmt.l xfmt.1 README Makefile MANIFEST cmds.tex flex.skel.diff X @rm -f xfmt.shar X makekit -m -nxfmt.shar. X install: all xfmt.doc X $(CP) xfmt $(BINDIR) X chown bin $(BINDIR)/xfmt X chgrp bin $(BINDIR)/xfmt X chmod 755 $(BINDIR)/xfmt X $(CP) xfmt.doc $(CATMAN)/xfmt.1 X chown bin $(CATMAN)/xfmt.1 X chgrp bin $(CATMAN)/xfmt.1 X chmod 644 $(CATMAN)/xfmt.1 X clean: X rm xfmt.c END_OF_FILE if test 791 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README'\" else echo shar: Extracting \"'README'\" \(2168 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' X The first version of xfmt, 'extended fmt', was written by Bill Gray X(bgray@marque.mu.edu) and appeared in comp.sources.misc as "fmt". Since it is nearly downward compatible with the BSD fmt program X(treatment of ending sentence punctuation is a little different), you might choose to name your version "xfmt" -- or not. X This version interprets a few nroff -man commands or a (very) few TeX commands, or both, if you ask it to (by using the -m or -x flags). It does a more complete job of interpreting fonts in terms of screen attributes than can be done nroff(1) and ul(1). There is also a -c flag for displaying C code with comments highlighted and keywords shown with various screen attributes. X Many man pages are not correctly processed, since many have nroff commands not interpreted by xfmt. The addition of -man interpretation and other features to xfmt will not be to everyone's taste, especially since they are incompletely implemented. X The BSD termcap facility is used in this version of xfmt. Also, you need flex, by Vern Paxson et al. to make xfmt. Unless a second version of flex has been distributed by now, you will need to modify flex's skeleton files by making the following changes: X CHANGE static int yy_start; /* start state number */ TO static int yy_start = 0; /* start state number */ X CHANGE X yy_start = 1; /* first start state */ TO X if (!yy_start) yy_start = 1; /* first start state */ X Or you can try "patch < flex.skel.diff" to make the changes automatically in the distributed version of the file flex.skel. (This patch file includes another patch concerning the reject action.) The change to flex is required so xfmt can choose a start condition in its main() procedure depending on what flags it sees on the command line. X Once you have made xfmt, the accompanying documents can be displayed with: X xfmt -mu xfmt.1 X xfmt -xu cmds.tex X xfmt -c xfmt.l X X The amount of pattern matching done in this version of xfmt exceeds the capacity of lex by quite a bit. This kind of program is now easy to do thanks to the implementors of flex: Vern Paxson, Kevin Gong, Jef Poskanzer, Van Jacobson. X X Greg Lee, lee@uhccux.uhcc.hawaii.edu END_OF_FILE if test 2168 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'cmds.tex' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'cmds.tex'\" else echo shar: Extracting \"'cmds.tex'\" \(5328 characters\) sed "s/^X//" >'cmds.tex' <<'END_OF_FILE' X X{\it xfmt} formatting commands.} X\bigskip X X\centerline{\it Nroff/man~commands with \tt xfmt~-mu} X\medskip X X\item{\tt .sp~(n)} Skip 1 (or n) lines. X\item{\tt \\fI} Start {\it underlining} of text (termcap "ul"). X\item{\tt \\fB} Start {\bf bold} text (termcap "md"). X\item{\tt \\fS} Start {\tt reversed} text (termcap "mr"). X\item{\tt \\fG} Start {\sl blinking} text (termcap "mb"). X\item{\tt \\fR} End {\it underlining} or other special text X (termcap "me"/"ue"). X\item{\tt \\fP} Same as {\tt \\fR} (bug). X\item{\tt .nf} Stop filling lines to maximum width. X\item{\tt .fi} Resume filling lines to maximum width. X\item{\tt .I~<line>} Display <line> {\it underlined}. X\item{\tt .B~<line>} Display <line> in {\bf bold}. X\item{\tt .S~<line>} Display <line> {\tt reversed}. X\item{\tt .G~<line>} Display <line> {\sl blinking}. X\item{\tt .SM~<line>} Display <line> {\tt reversed}. X\item{\tt .R~<line>} Display <line> plain. X\item{\tt .CT~<char>} Display <char> reversed or "<CTRL/<char>>" X in case neither -u or -o was given. X\item{\tt \\*(lq} Display "`". X\item{\tt \\*(rq} Display "'". X\item{\tt \\(*<char>} Display <char> reversed. X\item{\tt \\(<char><char>} X Display <char><char> reversed. X\item{\tt \\s(-)<digit>} X Ignored. X\item{\tt \\| \\\^ \\\& \\! \\\{ \\\} \\a \\c \\d \\e \\p \\r \\t \\u \\z} X Ignored. X\item{\tt \\} Display following character (except as above). X\item{\tt .br} Terminate preceding paragraph. X\item{\tt .PP} Terminate preceding paragraph. X\item{\tt .P} Terminate preceding paragraph. X\item{\tt .LP} Terminate preceding paragraph. X\item{\tt .TP~(n)} Begin hanging paragraph with 5 (or n) extra X spaces of indentation at left, with first X following line in left margin. X\item{\tt .IP~<word>~(0.3i)~...} X Begin hanging paragraph with 5 extra X spaces of indentation at left, with <word> ... X in left margin. X\item{\tt .HP~(n)} Begin hanging paragraph with 5 extra X spaces of indentation at left. X\item{\tt .RS} Indent 5 extra spaces until {\tt .RE}. X\item{\tt .RE} Resume normal indent after {\tt .RS}. X\item{\tt .DS} Skip a line; preserve lines and spacing; X indent 5 extra spaces until {\tt .DE}. X\item{\tt .DE} Resume filling and normal indent after {\tt .DS}. X\item{\tt .EX} Skip a line; preserve lines and spacing; X indent 5 extra spaces until {\tt .EE}. X\item{\tt .EE} Skip a line; resume filling and normal indent X after {\tt .EX}. X\item{\tt .VS~<line>} Ignored. X\item{\tt .VE~<line>} Ignored. X\item{\tt .NT~(<line>)} Skip a line, indent 5 extra spaces, shorten X line length by 5, display {\bf NOTE} bold and X centered (or <line>), continue until {\tt .NE}. X\item{\tt .NE} Resume normal indent and line length after X {\tt .NT}. X\item{\tt .IR~<words>} Join words alternating {\it underlined} and plain. X\item{\tt .BR~<words>} Join words alternating {\bf bold} and plain. X\item{\tt .RI~<words>} Join words alternating plain and {\it underlined}. X\item{\tt .BI~<words>} Join words alternating {\bf bold} and {\it underlined}. X\item{\tt .RB~<words>} Join words alternating plain and {\bf bold}. X\item{\tt .IB~<words>} Join words alternating {\it underlined} and {\bf bold}. X\item{\tt .SH~<line>} Skip a line, and display <line> left adjusted X and {\bf bold}. X\item{\tt .SS~<line>} Skip a line, and display <line> {\bf bold}. X\item{\tt .TH~<name>~<n>~(<text>)} X Right adjust {\bf <name>(<n>)} (followed by <text>). X\item{\tt .UC~(<digit>)} X Ignored. X\item{\tt .\\"~<line>} Ignore <line>. X\item{\tt .PN~<line>} Underline <line>. X\item{\tt .ta~<line>} Ignore <line>. X\item{\tt .PD~<line>} Ignore <line>. X\item{\tt .NX<cap>~<line>} X Ignore <line>. X\item{\tt .DT} Ignored. X\item{\tt .ti~+n~<line>} X n extra spaces of indentation at left of <line>. X\item{\tt .MS~<word>~<n>} X Display {\it <word>(<n>)}. X X X\bigskip X\centerline{\it \TeX ~commands with \tt xfmt~-xu} X\medskip X X\item{\tt \\vskip} Skip a line. X\item{\tt \\bigskip} Skip a line. X\item{\tt \\medskip} Skip a line. X\item{\tt \\smallskip} Skip a line. X\item{\tt \\\$ \\\# \\\{ \\\} \\\& \\\% \\^ \\_ \\\~ \\' \\" \\\\} X Display character following \\. X\item{\tt\\backslash} Display \backslash. X\item{\tt \\it} Begin {\it underlining} (termcap "ul"). X\item{\tt \\sl} Begin {\sl blinking} (termcap "mb"). X\item{\tt \\bf} Begin {\bf bold} (termcap "md"). X\item{\tt \\rm} Begin plain. X\item{\tt \\tt} Begin {\tt reverse} (termcap "mr"). X\item{\tt \\TeX} Display \TeX. X\item{\tt \\centerline~<line>} X Display <line> centered. X\item{\tt\\beginsection~<line>} X Skip a line, display <line> in bold. X\item{\tt \\rightline~<line>} X Display <line> right adjusted. X\item{\tt \\raggedright} X Stop justifying (for current \{...\} group). X\item{\tt \\obeylines} Stop filling lines and preserve spacing X (for current \{...\} group). X\item{\tt \\obeyspaces} Stop filling lines and preserve spacing X (for current \{...\} group). X\item{\tt \\item\{...\}} X Start hanging paragraph with 10 extra X spaces of left indentation and ... displayed in X left margin and indented 5. X\item{\tt \\itemitem\{...\}} X Same as {\tt \\item}. X\item{\tt \\<space-character>} X Break between words. X\item{\tt \~} Space that does not break between words and X is displayed with current display attribute. X\item{\tt \$} Ignored. X\item{\tt \#} Ignored. X X\bigskip X\rightline{Greg Lee, May, 1988} X\bye END_OF_FILE if test 5328 -ne `wc -c <'cmds.tex'`; then echo shar: \"'cmds.tex'\" unpacked with wrong size! fi # end of 'cmds.tex' fi if test -f 'flex.skel.diff' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'flex.skel.diff'\" else echo shar: Extracting \"'flex.skel.diff'\" \(1605 characters\) sed "s/^X//" >'flex.skel.diff' <<'END_OF_FILE' X*** flex.skel.orig Tue May 31 16:32:11 1988 X--- flex.skel Tue May 31 16:35:25 1988 X*************** X*** 12,18 X /* these variables are all declared out here so that section 3 code can X * manipulate them X */ X! static int yy_start, yy_b_buf_p, yy_c_buf_p, yy_e_buf_p; X static int yy_saw_eof, yy_init = 1; X X /* yy_ch_buf has to be 1 character longer than YY_BUF_SIZE, since when X X--- 12,18 ----- X /* these variables are all declared out here so that section 3 code can X * manipulate them X */ X! static int yy_start = 0, yy_b_buf_p, yy_c_buf_p, yy_e_buf_p; X static int yy_saw_eof, yy_init = 1; X X /* yy_ch_buf has to be 1 character longer than YY_BUF_SIZE, since when X*************** X*** 28,33 X YY_DECL X { X int yy_n_chars, yy_lp, yy_iii, yy_buf_pos, yy_act; X X %% user's declarations go here X X X--- 28,36 ----- X YY_DECL X { X int yy_n_chars, yy_lp, yy_iii, yy_buf_pos, yy_act; X+ #ifdef FLEX_REJECT_ENABLED X+ int yy_full_match; X+ #endif X X %% user's declarations go here X X*************** X*** 34,40 X if ( yy_init ) X { X YY_INIT; X! yy_start = 1; X yy_init = 0; X } X X X--- 37,43 ----- X if ( yy_init ) X { X YY_INIT; X! if (!yy_start) yy_start = 1; X yy_init = 0; X } X X*************** X*** 41,46 X goto get_next_token; X X do_action: X for ( ; ; ) X { X YY_DO_BEFORE_ACTION X X--- 44,55 ----- X goto get_next_token; X X do_action: X+ X+ #ifdef FLEX_REJECT_ENABLED X+ /* remember matched text in case we back up due to trailing context */ X+ yy_full_match = yy_c_buf_p; X+ #endif X+ X for ( ; ; ) X { X YY_DO_BEFORE_ACTION END_OF_FILE if test 1605 -ne `wc -c <'flex.skel.diff'`; then echo shar: \"'flex.skel.diff'\" unpacked with wrong size! fi # end of 'flex.skel.diff' fi if test -f 'xfmt.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'xfmt.1'\" else echo shar: Extracting \"'xfmt.1'\" \(4161 characters\) sed "s/^X//" >'xfmt.1' <<'END_OF_FILE' X.TH XFMT 1 LOCAL X.SH NAME xfmt \- a simple text formatter X.SH SYNOPSIS X.B xfmt X[ X.B \-i X] [ X.B \-j X] [ X.B \-m X] [ X.B \-x X] [ X.B \-o X] [ X.B \-u X] [ X.B \-c X] [ X.B \-l n X] [ X.B \-p n X] [ X.B \-t n X] [ filenames ] X.SH DESCRIPTION X.I Xfmt is a simple text formatter. With no options present, the default behavior of X.I xfmt is to copy its input (from specified files or from stdin, if no files are specified) to its output but with input reformatted into lines no longer than 72 characters long. A blank line is taken to indicate the beginning of a new paragraph. Lines that begin with a period are preserved. X.PP The following options modify this behavior: X.TP X.B \-i This option will cause X.I xfmt to preserve indentations. Blanks or tabs at the beginning of a line will be considered the beginning of a new paragraph. X.TP X.B \-j Justify output lines. (The default behavior of X.I xfmt is to output lines with a ragged right margin). X.TP X.B \-m Interpret a few commonly used X.I nroff X-man commands. Those understood (in some fashion) are: X.DS X .B .I .R .S .G .SM .C X .IR .BR .RI .BI .RB .IB X .SH .SS .TH .PP .P .LP .TP .IP .HP X .RS .RE .DS .DE .NT .NE .VS .VE X .CT .PN .MS X .UC (ignored) .DT (ignored) .PD (ignored) X.DE X.sp And a few other nroff commands that occur commonly in man pages are recognized: X.DS X \\fI \\fB \\fR \\fP \\fC X .sp .br .nf .fi .ti X .\\" \\*(lq \\*(rq .ta (ignored) X.DE X.sp More details can be found in the document X.IR cmds.tex . X.TP X.B \-x Interpret a few commonly used X.I TeX commands. Those understood (in some fashion) are: X.DS X \\vskip \\bigskip \\medskip \\smallskip \\$ \\# \\{ \\} X \\& \\% \\^ \\_ \\~ \\' \\" \\\\ \\it \\sl \\bf \\rm \\tt X \\TeX \\centerline \\rightline \\raggedright \\obeylines \\item X { } \\(space) ~ $ (ignored) \\backslash \\beginsection X.DE X.TP X.B \-o Produce bold and underlined text with overstriking. If the terminal and termcap entries permit, the bold and underlined portions can be seen on the screen by feeding X.I xfmt output to X.MS ul 1 . Bold is produced by fonts B/bf, S/tt, and underlined by I/it, G/sl. X.TP X.B \-u Produce bold, underlined, reversed, and blinking text for terminal display (using termcap md, us, mr, and mb entries, respectively). This is useful only if one of the options -m or -x is also chosen. Bold is produced by font B/bf, underlined by I/it, reversed by S/tt, and blinking by G/sl. X.TP X.B \-c XFor C code, display comments reversed, flow-of-control keywords in bold, storage-class keywords underlined, and pre-processor keywords blinking. No formatting is done. The -u option is assumed unless the -o option is given. X.TP X.B \-l n This option can be used to change the line length from the default of 72 characters. X.TP X.B \-p n Change the page offset. This option will cause the output lines to be offset the indicated number of columns from the left. X.TP X.B \-t n Set tab size. This option is useful only with the X.B \-i or X.B \-c options, or for text in the scope of .nf, .EX, .DS, \obeylines or \obeyspaces, since otherwise tabs are treated the same as space characters. X.SH EXAMPLES Display a man page X.I binmail.1 on the screen with right justification, a page at a time: X.EX xfmt -jmu binmail.1 | more -f X.EE Display a man page with underlining, but no bold face: X.EX xfmt -mo binmail.1 | more -f X.EE Prepare a preformatted man page to be displayed with X.MS ul 1 : X.EX xfmt -mo binmail.1 >binmail.doc X.EE Display high-lighted C source code on the screen: X.EX xfmt -c \fIfile\fR.c X.EE X.SH TIPS In X.IR vi , you can define a macro that will reformat paragraphs by typing X.I ":map V {!}xfmt^M" or by putting the line X.RS X.I "map V {!}xfmt^M" X.RE in your X.I .exrc file. After defining this macro, pressing X.I V will cause the paragraph under the cursor to be reformatted. (Use the X.I u key to X.I undo if necessary. X.SH "SEE ALSO" nroff(1), vi(1), ul(1) X.SH BUGS TeX command interpretation doesn't have a chance of working except for files prepared with the limitations of xfmt in mind. Nroff -man interpretation has maybe a 50-50 chance. X.SH AUTHORS original version: bgray@marque.mu.edu (Bill Gray) X.br TeX, man, C mods: lee@uhccux.uhcc.hawaii.edu (Greg Lee) END_OF_FILE if test 4161 -ne `wc -c <'xfmt.1'`; then echo shar: \"'xfmt.1'\" unpacked with wrong size! fi # end of 'xfmt.1' fi if test -f 'xfmt.l' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'xfmt.l'\" else echo shar: Extracting \"'xfmt.l'\" \(21023 characters\) sed "s/^X//" >'xfmt.l' <<'END_OF_FILE' X%{ X X/* X * (was file: fmt.c) X * 04/88 bgray X * file: xfmt.l X * revised with (f)lex front end X * 05/88 Greg Lee X */ X X/* a simple text formatter */ X X#ifndef lint static char xfmt_sccsid[] = "@(#)xfmt.l <05/30/88>"; X#endif lint X X X#include <stdio.h> X#include <ctype.h> X#include <string.h> X X#ifndef TRUE X#define TRUE 1 X#endif X#ifndef FALSE X#define FALSE 0 X#endif X X/* character attributes controlled by font-changing commands */ X#define ROMAN 1 /* plain, from \rm or .R */ X#define ITALIC 2 /* underlined, from \it or .I */ X#define BOLD 3 /* bold, from \bf or .B */ X#define TTYPE 4 /* reversed, from \tt or .S */ X#define SLANTY 5 /* blinking, from \sl or .G */ X int attribute = ROMAN, /* current character attribute */ X nextattribute = 0; /* attribute to restore after next X * word for .RB, etc. or after line X * for \beginsection X */ char nest[80]; /* stack of attributes for each current */ int level = 1; /* TeX {}-group */ X X/* global state of formatter */ char iflag = FALSE, /* preserving left indentation (-i)? */ X jflag = FALSE, /* requested justification with -j? */ X oflag = FALSE, /* requested overprint with -o? */ X uflag = FALSE, /* requested terminal output with -u? */ X xflag = FALSE, /* requested use TeX commands w. -x? */ X mflag = FALSE, /* requested use man commands w. -m? */ X cflag = FALSE, /* requested format C code w. -c? */ X qtflag = FALSE, /* saw odd " in processing .RB etc.? */ X ceflag = FALSE, /* center next output line? */ X raflag = FALSE, /* right adjust next output line? */ X obflag = FALSE, /* not concatenating? */ X njflag = FALSE; /* not currently justifying? */ X int maxlen = 72, X tabsize = 8, X indent = 0, X offset = 0, X tpstate = 0, /* keep track for hanging indentation */ X tpvalue = 5, /* amount of hang, from arg of .TP,.HP */ X spaces = 0, /* space to leave after current word */ X tempi; /* misc. use in lex pattern section */ X char *progname = NULL; char *usage = "usage: %s [-ijcmxou] [-l n] [-p n] [-t n] [file ...]\n"; X int dir = FALSE; int holecnt = 0; char *holeptr[256]; /* holeptr[0] is unused */ X char oline[2048] = "\0", /* output line buffer */ X *olp = oline, X aline[2048] = "\0", /* output line attribute buffer */ X *alp = aline, X oword[512] = "\0", /* output word buffer */ X *owp = oword, X aword[512] = "\0", /* output word attribute buffer */ X *awp = aword; X extern char *optarg; /* from getopt */ extern int optind; X int max (); void exit (); char *basename (); void copyindent (); void puttc (); void putts (); void lbreak (); void putword (); void justifyline (); void putline (); void sputline (); void skipline (); void addparens (); void terminit (); void termattr (); X X%} X X/* lex start state for flags: -x, -m, (none), -mx, respectively */ X%s TEX MAN PLAIN ALL CCODE X X/* match end of TeX command */ wh [ \t]*/[^a-z] X X%% X X<MAN,ALL>^".sp" skipline(1); X X/* match various TeX skip commands */ X<TEX,ALL>\\[a-gi-z]+"skip"{wh} skipline(1); X X/* blank line in input gives blank line in output -- not like real TeX */ X\n$ skipline(1); X X<MAN,ALL>^".sp "[0-9]+ skipline(atoi(yytext+4)); X X/* traditional */ X<PLAIN>^\..* { X lbreak(); X (void)printf("%s\n",yytext); X} X X/* escaped special characters -- \\ for \ not like real TeX */ X<TEX,ALL>\\[$#{}&%^_~'"\\] puttc(yytext[1]); X X/* some font-changing commands */ X X<TEX,ALL>"\\it"{wh} | X<MAN,ALL>"\\f"("I"|"C") attribute = ITALIC; X X<TEX,ALL>"\\sl"{wh} | X<MAN,ALL>"\\fG" attribute = SLANTY; X X<TEX,ALL>"\\bf"{wh} | X<MAN,ALL>"\\fB" attribute = BOLD; X X<TEX,ALL>"\\rm"{wh} | X<MAN,ALL>"\\f"("R"|"P") attribute = ROMAN; /* \fP should not be like \fR */ X X<TEX,ALL>"\\tt"{wh} | X<MAN,ALL>"\\fS" attribute = TTYPE; X X X<TEX,ALL>"\\TeX"{wh} putts("TeX"); X X/* should these 4 TeX commands cause breaks? */ X<TEX,ALL>\\"centerline"{wh} ceflag = TRUE; X X<TEX,ALL>\\"rightline"{wh} raflag = TRUE; X X<TEX,ALL>\\"raggedright"{wh} njflag = level; X X<TEX,ALL>\\"obeylines"{wh} obflag = level; X X<MAN,ALL>^".nf" lbreak(); obflag = TRUE; X X<MAN,ALL>^".fi" lbreak(); obflag = FALSE; X X<TEX,ALL>"{" nest[level++] = attribute; /* push attr. onto stack */ X X<TEX,ALL>"}" { /* if emerging from {} in which \obeylines or X * \raggedright occurred, cancel (not a very general X * strategy) X */ X if (obflag == level) obflag = FALSE; X if (njflag == level) njflag = FALSE; X /* pop attribute off stack */ X if (level > 1) attribute = nest[--level]; X /* } after \item signals end of tag; will not X * work right with {} inside tag */ X if (tpstate == 1) { X tpstate = 2; X putword(); X } X} X X X^[ \t]+ { X putword(); X if (iflag || obflag) { X putline(); X tempi = attribute; X /* for comments with indentation */ X if (cflag) attribute = ROMAN; X copyindent(yytext); X attribute = tempi; X } X else if (mflag) X putline(); X} X X<TEX,ALL>"\\ " putword(); X X<MAN,ALL,CCODE>\n { /* for C code reverse all of multiline comments */ X if (!cflag) attribute = ROMAN; X nextattribute = qtflag = FALSE; X /* signal end of tag for hanging indent */ X if (tpstate == 1) tpstate = 2; X putword(); X if (obflag) putline(); X} X X/* more font-changing */ X X<MAN,ALL>^\.B" " attribute = BOLD; X X<MAN,ALL>^\.(I|C)" " attribute = ITALIC; X X<MAN,ALL>^\.R" " attribute = ROMAN; X X<MAN,ALL>^\.("S"|"SM")" " attribute = TTYPE; X X<MAN,ALL>^\.G" " attribute = SLANTY; X X<MAN,ALL>\\[\|\^&!{}\nacdeprtuz] ; X X<MAN,ALL>\\. puttc(yytext[1]); X X<MAN,ALL>^".ti +"[0-9]+ { X lbreak(); X for (tempi = 0; tempi < atoi(yytext+5) - 1; tempi++) X puttc(' '); X} X X<MAN,ALL>^\.br lbreak(); X X<MAN,ALL>^\.(P|L|"")P skipline(1); indent = 5; X X/* hanging indent stuff (awfully complicated) */ X X<MAN,ALL>^\.(T|H)"P "[0-9]+\n { X skipline(1); X if (yytext[1] == 'H') X tpstate = 4; X else tpstate = 1; X tpvalue = atoi(yytext+4); X indent = 5; X} X X<TEX,ALL>\\"item"("item")?{wh} | X<MAN,ALL>^".HP ".*\n | X<MAN,ALL>^".TP".*\n | X<MAN,ALL>^".IP"[ \t]*\n? { X skipline(1); X if (yytext[1] == 'I' && yytext[3] == '\n') X tpstate = 4; X else tpstate = 1; X tpvalue = 5; X indent = 5; X} X X/* various begin-end commands to set off blocks of text */ X X<MAN,ALL>^"."(R|D)(S|E) { X if (yytext[1] == 'D' && yytext[2] == 'S') { X skipline(1); X obflag = TRUE; X } X else lbreak(); X indent = 10; X if (yytext[2] == 'E') { X indent = 5; X obflag = FALSE; X } X} X X<MAN,ALL>^".E"(X|E) { X skipline(1); X if (yytext[2] == 'E') { X indent = 5; X obflag = FALSE; X } X else { indent = 10; X obflag = TRUE; X } X} X X X<MAN,ALL>^".N"(T|E).* { X skipline(1); X if (yytext[2] == 'E') { X indent = 5; X maxlen += 5; X } X else { indent = 10; X maxlen -= 5; X tempi = attribute; X attribute = ITALIC; X ceflag = TRUE; X if (yyleng < 5) putts("NOTE"); X else putts(yytext+4); X skipline(1); X } X} X X/* those curious -man commands to join words, alternating fonts */ X X<MAN,ALL>^\.("IR"|"PN")" " nextattribute = ROMAN; attribute = ITALIC; X X<MAN,ALL>^\."BR " nextattribute = ROMAN; attribute = BOLD; X X<MAN,ALL>^\."RI " nextattribute = ITALIC; attribute = ROMAN; X X<MAN,ALL>^\."BI " nextattribute = ITALIC; attribute = BOLD; X X<MAN,ALL>^\."RB " nextattribute = BOLD; attribute = ROMAN; X X<MAN,ALL>^\."IB " nextattribute = BOLD; attribute = ITALIC; X X/* section headings */ X X<TEX,ALL>\\"beginsection"{wh} { X skipline(1); X nextattribute = attribute; X attribute = BOLD; X} X X<MAN,ALL>^\."S"(H|S)" ".* { X skipline(1); X if (yytext[2] == 'H') X indent = 0; X attribute = BOLD; X putts(yytext+4); X lbreak(); X indent = 5; X attribute = ROMAN; X} X X<MAN,ALL>^\."TH ".* { X lbreak(); X indent = 0; X addparens(yytext+4, BOLD); X raflag = TRUE; X skipline(2); X indent = 5; X} X X/* "Manual Section" reference */ X<MAN,ALL>^".MS ".* addparens(yytext+4, ITALIC); X X<MAN,ALL>^".CT ". { X if (uflag || oflag) { X tempi = attribute; X attribute = TTYPE; X puttc(toupper(yytext[4])); X attribute = tempi; X } X else { X putts("<CTRL/"); X puttc(yytext[4]); X puttc('>'); X } X} X X<MAN,ALL>^".V"(S|E).* | X<MAN,ALL>^".UC"(..)? | X<MAN,ALL>^\.\\\".* ; X X/* for join-words commands, words can be quoted */ X<MAN,ALL>\" { X if (nextattribute || tpstate == 1) { X qtflag = !qtflag; X } X else puttc('"'); X} X X<MAN,ALL,CCODE>" " { X if (nextattribute) { X if (qtflag) puttc(' '); X else { X tempi = attribute; X attribute = nextattribute; X nextattribute = tempi; X } X } X else { X putword(); X if (obflag) copyindent(yytext); X } X} X X<TEX,ALL,CCODE>\n { X putword(); X if (obflag || nextattribute) putline(); X if (nextattribute) { X attribute = nextattribute; X nextattribute = 0; X } X} X X<TEX,ALL>"~" puttc(' '); X X[ \t]+ { X putword(); X if (obflag) copyindent(yytext); X} X X[\n\r\f] putword(); X X<TEX,ALL>\\"backslash"{wh} puttc('\\'); X X<TEX>\\ | X<TEX,ALL>\$|\# ; X X<TEX,ALL>\\[A-Za-z]+{wh} ; X X<MAN,ALL>\\"*(rq" puttc('\''); X X<MAN,ALL>\\"*(lq" puttc('`'); X X<MAN,ALL>\\"(".. { X tempi = attribute; X attribute = TTYPE; X if (yytext[2] != '*') puttc(yytext[2]); X puttc(yytext[3]); X attribute = tempi; X} X X<MAN,ALL>\\"s"("-")?[0-9] | X<MAN,ALL>"\\*S" | X<MAN,ALL>^".DT" | X<MAN,ALL>^".ta ".* | X<MAN,ALL>^".PD".* | X<MAN,ALL>^".NX".* ; X X<CCODE>\" { if (attribute != TTYPE) qtflag = !qtflag; X puttc('"'); X} X X<CCODE>"/*" { puttc('/'); X if (!qtflag) attribute = TTYPE; X puttc('*'); X} X X<CCODE>"*/" { puttc('*'); X if (!qtflag) attribute = ROMAN; X puttc('/'); X} X X/* control flow keywords are bold */ X<CCODE>"continue"|"default"|"do"|"goto"|"return" | X<CCODE>"if"|"else"|"while"|"break"|"switch"|"case"|"for" { X if (attribute != TTYPE && !qtflag) { X attribute = BOLD; X putts(yytext); X attribute = ROMAN; X } else putts(yytext); X} X X/* storage class keywords are underlined */ X<CCODE>("auto"|"char"|"double"|"enum"|"extern"|"float") | X<CCODE>("int"|"long"|"register"|"short"|"sizeof"|"static") | X<CCODE>("struct"|"typedef"|"union"|"unsigned"|"void") { X X if (attribute != TTYPE && !qtflag) { X attribute = ITALIC; X putts(yytext); X attribute = ROMAN; X } else putts(yytext); X} X X/* preprocessor keywords are blinking */ X<CCODE>"#"[ \t]*("define"|"undef"|"include"|"if"|"ifdef") | X<CCODE>"#"[ \t]*("ifndef"|"else"|"endif"|"line") { X X if (attribute != TTYPE && !qtflag) { X attribute = SLANTY; X putts(yytext); X attribute = ROMAN; X } else putts(yytext); X} X X/* identifiers that happen to contain keywords are plain */ X<CCODE>[a-zA-Z_]+ putts(yytext); X X. puttc(yytext[0]); X X X X%% X X/* X * Characters, along with the currently active "font"= screen X * attribute, are collected in a word buffer until we hit a X * word break (white space), then moved to a line buffer. X * Words are collected in the line buffer until we hit a line X * break (end of paragraph) or the line is long enough, then X * the line is output. X */ X main (argc, argv) int argc; char *argv[]; X{ X int c, i; X X progname = basename (argv[0]); X while ((c = getopt (argc, argv, "ijcxmoul:p:t:")) != EOF) X switch (c) { X case 'i': iflag = TRUE; break; X case 'j': jflag = TRUE; break; X case 'c': cflag = TRUE; break; X case 'x': xflag = TRUE; break; X case 'm': mflag = TRUE; break; X case 'o': oflag = TRUE; break; X case 'u': uflag = TRUE; break; X case 'l': maxlen = max (0, atoi (optarg)); X break; X case 'p': offset = max (0, atoi (optarg)); X break; X case 't': tabsize = max (1, atoi (optarg)); X break; X default: (void) fprintf (stderr, usage, progname); X exit (1); X break; X } X X X/* set lex start state */ X if (xflag && mflag) { X BEGIN (ALL); X } X else if (xflag) { X BEGIN (TEX); X } X else if (mflag) { X indent = 5; X BEGIN (MAN); X } X else if (cflag) { X obflag = TRUE; X if (!oflag) uflag = TRUE; X BEGIN (CCODE); X } X else { X BEGIN (PLAIN); X } X X/* consult termcap for terminal controls */ X if (uflag) X terminit (); X X X/* call lex scanner */ X if (optind >= argc) { X (void) yylex (); X lbreak (); X } X else X for (; (optind < argc); optind++) { X if (freopen (argv[optind], "r", yyin) != NULL) { X /* unstructured -- couldn't find any other X * way to get flex to look at > 1 file */ X yy_init = 1; X (void) yylex (); X lbreak (); X } X else { X (void) fprintf (stderr, X "Couldn't open file: %s", argv[optind]); X exit (1); X } X } X X return (0); X} /* main */ X X X/* preserve spacing due to spaces or tabs */ void copyindent (ilp) char *ilp; X{ X int col; X X col = (olp - oline) + 1; X X for (; (isspace (*ilp)); col++) { X if (*ilp++ == '\t') X for (; (col % tabsize); col++) { X *olp++ = ' '; X *alp++ = (cflag) ? attribute : ROMAN; X } X *olp++ = ' '; X *alp++ = (cflag) ? attribute : ROMAN; X } X} /* copyindent */ X X/* one character goes into word buffer */ void puttc (ch) char ch; X{ X *owp++ = ch; X *awp++ = attribute; X} /* puttc */ X X/* put string in word buffer (might have spaces) */ void putts (s) char *s; X{ X while (*s) X puttc (*s++); X} /* putts */ X X/* finish pending word and line and put it out (no justification) */ void lbreak () { X putword (); X putline (); X tpstate = 0; X} /* lbreak */ X X/* append pending word to line buffer */ void putword () { X int plen; X char *p; X char *q; X static char started = 0; X X /* just return if no characters have been accumulated yet */ X if (owp == oword) { X /* this is for the special case in which a file X * starts with \n, which should count as a "blank line" X */ X if (!started) { X putchar ('\n'); X started = 1; X } X return; X } X started = 1; X X puttc ('\0'); X p = oword; X q = aword; X plen = strlen (p); X X /* ugly way to ignore "0.3i" arg of .IP */ X if (tpstate == 2 && *p == '0' && p[plen - 1] == 'i') { X spaces = plen = 0; X *p = '\0'; X } X X /* finish pending line if pending word won't fit */ X if (!obflag && (olp - oline) + spaces + plen > maxlen - indent) { X if ((jflag) && (holecnt) && !njflag) X justifyline (); X putline (); X } X X /* append spaces which were previously decided to go after X * last word put in line buffer */ X if (spaces) { X /* don't use space inside tag of hanging indent to X * right justify */ X if (!tpstate || tpstate > 3) X holeptr[++holecnt] = olp; X /* if tag already padded out, permit justification X * of space after next word */ X if (tpstate == 3) X tpstate = 4; X for (; (spaces > 0); spaces--) { X *olp++ = ' '; X /* a matter of taste -- put just " = ROMAN" X * for no underlined spaces between words */ X *alp++ = (*(alp-1) == ITALIC && *q == ITALIC) ? X ITALIC : ROMAN; X } X } X X /* figure spaces which should go after pending word which X * is just about to be appended in line buffer -- remember X * so they can be put before next word (cf. just above) */ X if (!obflag) spaces = 1 + endofsentence (p, plen); X /* (but if spacing is being preserved, as signaled by X * obflag, we don't want extra spaces) */ X X /* append pending word in line buffer */ X while (*p) { X *olp++ = *p++; X *alp++ = *q++; X } X X /* part of tortuous way of handling hanging indent */ X /* tpstate = 0: no hanging indent X * 1: scanning tag to go in left margin X * 2: have seen end of tag, time to X * pad out tag to hanging indent value X * 3: finished padding X * 4: finished first line of hanging par.; X * subsequent lines should be indented X * to hanging indent value X */ X if (tpstate == 2) { /* time to pad tag? */ X tpstate = 3; /* signal padding done */ X if ((olp - oline) + spaces > tpvalue) /* will tag fit? */ X putline (); /* no it won't, so start new line */ X else /* yes it will, so pad it out */ X while ((olp - oline) + spaces < tpvalue) X spaces++; X } X X /* purge word buffer -- get ready for next word */ X owp = oword; X awp = aword; X} /* putword */ X X X/* increase inter-word spacings for right justification */ void justifyline () { X int n; X char *fp, X *tp, X *fa, X *ta; X X dir = (!(dir)); X fp = olp - 1; X fa = alp - 1; X olp = &oline[maxlen - indent]; X alp = &aline[maxlen - indent]; X tp = olp - 1; X ta = alp - 1; X while (tp > fp) { X while (fp >= holeptr[holecnt]) { X *tp-- = *fp--; X *ta-- = *fa--; X } X if (dir) X n = ((tp - fp) - 1) / holecnt + 1; X else X n = (tp - fp) / holecnt; X while (n--) { X *tp-- = ' '; X *ta-- = ta[1]; X } X holecnt--; X } X} /* justifyline */ X X X/* put out pending line in line buffer */ void putline () X{ X if (ceflag) { X spaces = max ((maxlen - (olp - oline)) / 2, 1) + offset; X ceflag = FALSE; X } X else if (raflag) { X spaces = max ((maxlen - (olp - oline)), 1) + offset; X raflag = FALSE; X } X else spaces = indent + offset; X X *olp = '\0'; X X if (*oline) X /* if -u or -x options, have to do it character X * by character */ X if (oflag || uflag) X sputline (); X else X (void) printf ("%*s\n", spaces + strlen (oline), oline); X X /* purge line buffer -- get ready for new line */ X *oline = '\0'; X olp = oline; X alp = aline; X spaces = 0; X holecnt = 0; X X /* if finished with first line of hanging par., increase X * left indent for subsequent lines */ X if (tpstate > 2) { X indent = tpvalue + 5; X tpstate = 4; X } X} /* putline */ X X X/* display characters of line with overstriking or with special X * terminal attributes */ void sputline () { X char *p; X char *q; X char last = ROMAN; X X if (spaces) X (void) printf ("%*s", spaces, NULL); X X for (p = oline, q = aline; *p; p++, q++) X if (uflag) { X last = newattr (last, *q); X (void) printf ("%c", *p); X } else X switch (*q) { X case ROMAN: X (void) printf ("%c", *p); X break; X case BOLD: X case TTYPE: X if (*p == ' ') X printf("%c", *p); X else (void) printf ("%c%c%c", *p, 8, *p); X break; X case ITALIC: X case SLANTY: X (void) printf ("_%c%c", 8, *p); X break; X } X if (uflag) X last = newattr (last, ROMAN); X (void) printf ("\n"); X X} /* sputline */ X X/* put blank lines */ void skipline (n) int n; X{ X lbreak (); X for (; (n > 0); n--) X (void) printf ("\n"); X if (xflag) X indent = 0; X} /* skipline */ X X X/* decide how many spaces go after word */ int endofsentence (p, plen) char *p; int plen; X{ X if (plen < 3) X return (FALSE); X if (!strchr (".:?!", *(p + plen - 1))) X return (FALSE); X if (abbr (p)) X return (FALSE); X return (TRUE); X} /* endofsentence */ X X X/* detect "." which is not real end of sentence */ int abbr (s) char *s; X{ X char *p, X *q, X *r; X X while (*s == '(') X s++; X q = ".i.e.g.dr.mr.mrs.st."; X for (; (*q); q++) { X p = q; X r = s; X while ((*r) && (*p++ == (*r++ | 0x20))); X if (!*r) X return (TRUE); X } X return (FALSE); X} /* abbr */ X X X char *basename (s) char *s; X{ X char *p; X X if (p = strrchr (s, '/')) X return (++p); X else X return (s); X} /* basename */ X X X int max (a, b) int a, X b; X{ X return ((a > b) ? a : b); X} /* max */ X X X/* put parentheses around number of manual section */ void addparens (s, a) char *s; int a; X{ X nextattribute = attribute; X attribute = a; X while (*s && *s != ' ') X puttc (*s++); X if (*s == ' ') X s++, puttc ('('); X while (*s && *s != ' ') X puttc (*s++); X if (*s == ' ') X s++; X puttc (')'); X attribute = nextattribute; X nextattribute = 0; X if (*s && isalpha (*s)) X puttc (' '); X while (*s) X puttc (*s++); X} /* addparens */ X X/* terminal commands -- accessing routines */ X X/* X * following derived from: X * tcap v1.0 Enhanced terminal control program X * Author: Eric Lorenzo Lim X * Modified by: Becca Thomas and Rik Farrow X * (appeared in Nov. '87 Unix World) X */ X X#define SO 0 X#define SE 1 X#define MB 2 X#define MD 3 X#define MR 4 X#define MH 5 X#define ME 6 X#define US 7 X#define UE 8 char *id[] = { X "so", "se", "mb", "md", "mr", "mh", "me", "us", "ue", X (char *) NULL, X}; X char *area[50]; char bp[1024], X strbuf[1024]; X X/* get for later use terminal handling commands we need */ void terminit () { X int id_size = 0; X char *str, X *tmpptr; X extern char *getenv (), *tgetstr (), *tgoto (); X X if ((tmpptr = getenv ("TERM")) == (char *) NULL) { X (void) fprintf (stderr, "xfmt: TERM variable not set\n"); X exit (1); X } X X str = strbuf; X X if (tgetent (bp, tmpptr)) X while (id[id_size] != (char *) NULL) { X area[id_size] = tgetstr (id[id_size], &str); X if (area[id_size] == (char *) NULL) X area[id_size] = ""; X id_size++; X } X X X} /* terminit */ X X/* put out a terminal handing command */ void termattr (i) int i; X{ X (void) printf ("%s", area[i]); X} /* termattr */ X X/* check for change of "font" and send command to terminal X * when there is a change */ int newattr (l, a) int l, /* last attribute */ X a; /* new attribute */ X{ X if (l != a) { X if (l == BOLD || l == TTYPE || l == SLANTY) X termattr (ME); X else if (l == ITALIC) X termattr (UE); X X switch (a) { X case BOLD: termattr (MD); break; X case ITALIC: termattr (US); break; X case TTYPE: termattr (MR); break; X case SLANTY: termattr (MB); break; X } X } X return (a); X} /* newattr */ X END_OF_FILE if test 21023 -ne `wc -c <'xfmt.l'`; then echo shar: \"'xfmt.l'\" unpacked with wrong size! fi # end of 'xfmt.l' fi echo shar: End of archive 1 \(of 1\). cp /dev/null ark1isdone MISSING="" for I in 1 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have the archive. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Greg, lee@uhccux.uhcc.hawaii.edu -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.