diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/beebe/utils |
Initial commit
Diffstat (limited to 'dviware/beebe/utils')
-rw-r--r-- | dviware/beebe/utils/hd.c | 100 | ||||
-rw-r--r-- | dviware/beebe/utils/lpt.ps | 147 | ||||
-rw-r--r-- | dviware/beebe/utils/lptops.1l | 213 | ||||
-rw-r--r-- | dviware/beebe/utils/lptops.c | 1860 | ||||
-rw-r--r-- | dviware/beebe/utils/lptops.hlp | 169 | ||||
-rw-r--r-- | dviware/beebe/utils/lw78.c | 753 | ||||
-rw-r--r-- | dviware/beebe/utils/texidx.c | 1766 | ||||
-rw-r--r-- | dviware/beebe/utils/texidx.hlp | 183 | ||||
-rw-r--r-- | dviware/beebe/utils/unhd.c | 55 | ||||
-rw-r--r-- | dviware/beebe/utils/vms/streamlf.fdl | 13 | ||||
-rw-r--r-- | dviware/beebe/utils/vms/variable.fdl | 13 | ||||
-rw-r--r-- | dviware/beebe/utils/ws87.pas | 45 | ||||
-rw-r--r-- | dviware/beebe/utils/wsltex.c | 948 | ||||
-rw-r--r-- | dviware/beebe/utils/wsltex.let | 72 | ||||
-rw-r--r-- | dviware/beebe/utils/wsltex.pas | 537 | ||||
-rw-r--r-- | dviware/beebe/utils/xref | 25 | ||||
-rw-r--r-- | dviware/beebe/utils/xref1.awk | 56 | ||||
-rw-r--r-- | dviware/beebe/utils/xref2.awk | 74 | ||||
-rw-r--r-- | dviware/beebe/utils/xref3.awk | 83 | ||||
-rw-r--r-- | dviware/beebe/utils/xxu.c | 172 |
20 files changed, 7284 insertions, 0 deletions
diff --git a/dviware/beebe/utils/hd.c b/dviware/beebe/utils/hd.c new file mode 100644 index 0000000000..a4bc2a4359 --- /dev/null +++ b/dviware/beebe/utils/hd.c @@ -0,0 +1,100 @@ +/*********************************************************************** +Dump one or more files to stdout, translating unprintable characters to +\ooo octal sequences, and starting newlines at each ESC, or when line +length would exceed 72 characters. + +Usage: + hd filelist + +Both 7-bit and 8-bit input files are supported, and the output contains +the file name and its last-write date at the top of the page. + +Outside of TOPS-20, it will be necessary to provide (possibly dummy) +definitions of fileof() and timeof(), which are intended to return +character strings containing the file name and last read or write time, +given the file pointer. + +[15-Aug-87] + +***********************************************************************/ + +#define MAXLINE 72 +#define COMMENT '!' /* marks start of comment to end-of-line */ + +#include <stdio.h> + +char* fileof(); +char* timeof(); +void hd(); + +FILE* tty; + + +main(argc,argv) +int argc; +char* argv[]; +{ + int k; + + tty = stdout; + for (k = 1; k < argc; ++k) + hd(argv[k]); +} + +void +hd(filename) +char* filename; +{ + register int c; + register FILE* fp; + register int hpos; + + if ((fp = fopen(filename,"rb")) == (FILE*)NULL) + exit(2); + + (void)fprintf(tty,"%c%s [%s]\n", + COMMENT,fileof(fileno(fp)),timeof(fileno(fp),"w")); + + hpos = 0; + while ((c = getc(fp)) != EOF) + { + if ((c < 040) || (c > 0176) || (c == '\\') || (c == COMMENT)) + { /* use octal encoding */ + if (c == 033) + { + putc('\n',tty); + hpos = 0; + } + else if (hpos > (MAXLINE-4)) + { + putc('\n',tty); + putc('\t',tty); + hpos = 8; + } + + (void)fprintf(tty,"\\%03o",c); + hpos += 4; + if (c == '\n') + { + putc('\n',tty); + hpos = 0; + } + } + else /* printable character */ + { + if (hpos > (MAXLINE-1)) + { + putc('\n',tty); + putc('\t',tty); + hpos = 8; + } + putc(c,tty); + hpos++; + } + } + putc('\n',tty); + putc('\f',tty); + + (void)fflush(tty); + (void)fclose(fp); +} diff --git a/dviware/beebe/utils/lpt.ps b/dviware/beebe/utils/lpt.ps new file mode 100644 index 0000000000..51d751863a --- /dev/null +++ b/dviware/beebe/utils/lpt.ps @@ -0,0 +1,147 @@ +%!PS-Adobe-1.0 +%%Title: printfile.ps +%%Creator: Glenn Reid, Adobe Systems Incorporated +%%CreationDate: Tue Apr 22 15:35:53 1986 +%%Pages: 0 +%% Copyright (c) 1986 Glenn Reid and Adobe Systems Incorporated. +%% Use it, distribute it (with this message), but don't sell it. +%% +%%====================================================================== +%% Updated [06-Feb-88] by Nelson H.F. Beebe (beebe@science.utah.edu) +%% to recognize formfeeds (Ctl-L) and expand horizontal tabs (Ctl-I) +%% to the next column which is a multiple of 8. +%%====================================================================== +%% +%% This program will take miscellaneous text concatenated at its +%% end and print it in some default font. It is designed to be +%% minimal in its functionality, but flexible enough to be easily +%% adapted to other uses. + +/in. {72 mul} def +/line 512 string def % for input line buffering +/buff 10 string def % for page number conversion + +%% CHANGE THESE IF YOU LIKE + +%% If any of these parameters are defined ahead of this file, then +%% those values will be used. A typical way to use this is to +%% allow an application to redefine some of the parameters by +%% inserting definitions ahead of this file in the print stream. +%% Examples of redefinitions look like: +%% +%% /fontname /Palatino-Roman def +%% /pointsize /13 def +%% /header (document.ps) def +%% /pagenumber false def +%% /leftmargin 36 def +%% +%% Any number (including 0) of these parameters may be defined to +%% be different from the defaults. The defaults are quite +%% reasonable for general use, and will print in 11-point Courier +%% with a 12-point Courier-Bold header (only prints a header of +%% /header string is defined by the user). Margins top, left and +%% bottom are: .75 in., .75 in., and .5 in. +%% +%% Otherwise, the following defaults will be used: + +/leftmargin where not + { /leftmargin .75 in. def } {pop} ifelse +/bottom where not + { /bottom .5 in. def } {pop} ifelse +/startX where not + { /startX leftmargin def } {pop} ifelse +/startY where not + { /startY 10 in. def } {pop} ifelse +/fontname where not + { /fontname /Courier def } {pop} ifelse +/pointsize where not + { /pointsize 11 def } {pop} ifelse +/leading where not + { /leading pointsize 2 add def } {pop} ifelse +/headerfontname where not + { /headerfontname /Courier-Bold def } {pop} ifelse +/headerpointsize where not + { /headerpointsize 12 def } {pop} ifelse +/headerfont + headerfontname findfont headerpointsize scalefont +def +/page where not + { /page 1 def } {pop} ifelse +/pagenumber where not + { /pagenumber true def } {pop} ifelse + +% This routine will print a header at the top of each page +/printheader { + gsave + currentdict /header known { + 36 10.5 in. moveto + headerfont setfont + header show + } if + pagenumber { + 8 in. 10.5 in. moveto + headerfont setfont + page buff cvs show + /page page 1 add def + } if + grestore + startX startY moveto +} bind def + +/crlf { + leftmargin currentpoint exch pop % replace X with leftmargin + leading sub + dup bottom le + { pop pop showpage printheader } + { moveto } ifelse +} bind def + +/printfile { + line readline % read a line from the file + { % 'if' procedure body (+boolean) + { % 'while' procedure body + +% ====================================================================== +% Add code to check for FF (and later, HT) + dup (\f) search + { pop pop pop showpage printheader } { pop } ifelse + /col 0 def + { + (\t) search +% col := col + length(pre) +% tab expands to padding string of (8 - and(col,7)) blanks + + { % then: STACK = (post) (match) (pre) true + dup % (pre) (pre) + show % (pre) + length col add % col + length(pre) + /col exch def % col := col + length(pre) + 8 col 7 and sub % (8 - and(col,7)) + dup % save for updating col + {( ) show} repeat % print tab expansion + col add /col exch def + pop % discard (match) == (HT) + } % end then part + { % else: STACK = (string) false + show exit % display string and exit untab loop + } % end else part + ifelse + } loop % exits when string printed + crlf +% ====================================================================== +% show crlf % show what's left by readline + currentfile cvlit % use as operand + line readline % and read the next line + not {exit} if % exit if no more input to be had + } loop % end of while-proc + } if + showpage % when input file is exhausted +} bind def % /printfile + +fontname findfont pointsize scalefont setfont + +printheader % execute header +currentfile cvlit % uses rest of this file as input + +% everything following 'PrintFile' is treated as data, through EOF +printfile diff --git a/dviware/beebe/utils/lptops.1l b/dviware/beebe/utils/lptops.1l new file mode 100644 index 0000000000..4e8e508dcc --- /dev/null +++ b/dviware/beebe/utils/lptops.1l @@ -0,0 +1,213 @@ +.\".VA +.TH LPTOPS 1L "3 May 1988" +.ds Ps P\s-2OST\s+2S\s-2CRIPT\s+2 +.ds Ts T\s-2RAN\s+2S\s-2CRIPT\s+2 +.SH NAME +lptops \- convert an ascii text file into a printable +P\s-2OST\s+2S\s-2CRIPT\s+2 file +.SH SYNOPSIS +.B lptops +\fB[-a] [-b\fP\0\fI#\fP\fB] [-c\fP\0\fInum\fP\fB] [-f\fP\0\fIfont\fP\fB] [-h] [-i\fP \fI#\fP\fB] [-l\fP\0\fI#\fP\fB] [-m\fP\0\fInum\fP\fB] [-n\fP\0[\fItb\fP][\fIlcr\fP]\fInum\fP\fB] [-o\fP\0[\fI#\fP]\fB] [-p\fP\0\fI#\fP\fB] [-r\fP\0\fI#\fP\fB] [-s\fP\0\fI +num\fP\fB] [-t\fP\0\fI#\fP\fB] [-u]\fP < \fIinfile\fP > \fIoutfile\fP +.sp 0.5 +.B lptops +\fB[-a] [-b\fP\0\fI#\fP\fB] [-c\fP\0\fInum\fP\fB] [-f\fP\0\fIfont\fP\fB] [-h] [-i\fP\0\fI#\fP\fB] [-l\fP\0\fI#\fP\fB] [-m\fP\0\fInum\fP\fB] [-n\fP\0[\fItb\fP][\fIlcr\fP]\fInum\fP\fB] [-o\fP\0[\fI#\fP]\fB] [-p\fP\0\fI#\fP\fB] [-r\fP\0\fI#\fP\fB] [-s\fP\0\f +Inum\fP\fB] [-t\fP\0\fI#\fP\fB] [-u]\fP \fIfile1\fP \fIfile2\fP ... > \fIoutfile\fP +.SH DESCRIPTION +.I Lptops +converts normal text files into \*(Ps +for printing on the Apple LaserWriter, or any other +\*(Ps compatible printing device. +It supports selection of a variety of fonts at arbitrary point sizes, +margin specification, portrait and landscape page orientation, automatic +page numbering, page outlining, and multi-column printing. It can also +overstrike text (used by many text formatters for underlining). +.PP +This program is distributed with the <PLOT79> system. The \*(Ts system +provides a program of similar intent, known as \fIenscript\fP(1L). +.SH OPTIONS +Letter case is ignored (except in the case of font codes). +.TP +.B \-a +Turn Scribe-like bold and italic requests (@b[...] and @i[...]) into +bold or italic text. +.TP +.B \-b # +Set bottom margin to # (default is 1.0in). +.TP +.BI \-c " num" +Print \fInum\fP copies of each page (default 1). +.TP +.BI \-f " font" +Set \*(Ps font. The full name or an abbreviation for the +desired font type is given as \fIfont\fP. Default is +Courier. The following 13 fonts are available on all \*(Ps +printers. The second column provides font abbreviations +used by this and earlier versions of \fIlptops\fP; the third +column contains \fIditroff\fP(1L) font abbreviations, and +the fourth column, Adobe \*(Ts font abbreviations. Any of +these abbreviations may be used to specify \fIfont\fP. +.ta 0.25i 3.25i 4.25i 5.25i +.nf + Courier C C C + Courier-Bold CB CB CB + Courier-BoldOblique CBO CD CD + Courier-Oblique CO CO CO + Helvetica H he he + Helvetica-Bold HB He He + Helvetica-BoldOblique HBO HE HE + Helvetica-Oblique HO hE hE + Symbol S S S + Times-Bold TB R ti + Times-BoldItalic TBI BI TI + Times-Italic TI I tI + Times-Roman T R ti +.fi + +The remaining fonts are available only on enhanced printers, such as the +Apple LaserWriter Plus. + +.nf + AvantGarde-Book AGB ag ag + AvantGarde-BookOblique AGBO aG aG + AvantGarde-Demi AGD Ag Ag + AvantGarde-DemiOblique AGDO AG AG + Bookman-Demi BD Bo Bo + Bookman-DemiItalic BDI BO BO + Bookman-Light BL bo bo + Bookman-LightItalic BLI bO bO + Helvetica-Narrow HN hn hn + Helvetica-Narrow-Bold HNB Hn Hn + Helvetica-Narrow-BoldOblique HNBO HN HN + Helvetica-Narrow-Oblique HNO hN hN + NewCenturySchlbk-Bold NCSB Nc Nc + NewCenturySchlbk-BoldItalic NCSBI NC NC + NewCenturySchlbk-Italic NCSI nC nC + NewCenturySchlbk-Roman NCSR nc nc + Palatino-Bold PB Pa Pa + Palatino-BoldItalic PBI PA PA + Palatino-Italic PI pA pA + Palatino-Roman PR pa pa +.fi +.PP +Note that the \fIditroff\fP(1L) and \*(Ts abbreviations are identical +except for the Courier and Times fonts. The \*(Ts abbreviations are +based on two-letter mnemonics, where upper-case in the first letter +indicates bold, and upper-case in the second letter indicates italic. +.PP +Only the Courier fonts are fixed-width fonts. The others are +proportionally spaced and tabular material will not line up properly. +The Courier fonts have a width equal to 0.6 of their point size, so to +fill a line W inches wide with up to N characters, one must have point +size <= (W/(0.6 * N * 72)) = (W*120)/N pt. Equivalently, with a point +size P pt, the output spacing is 120/P char/inch. +.TP +.B \-h +Use horizontal page orientation (landscape mode) instead of vertical +(portrait mode). +.TP +.BI \-i # +Set top margin to # for initial page (for use with letterhead) +If not specified, the value given for the top margin will be used +(see the \fB\-t\fP command). +.TP +.BI \-l # +Set left margin to # (default is 1.0in). +.TP +.BI \-m num +Produce multiple column output (\fInum\fP columns). In multiple +column mode, formfeeds cause column breaks instead of page breaks. +Default value of \fInum\fP is 1. +.TP +.B \-n [\fItb\fP][\fIlcr\fP]\fInum\fP +Number output pages. The margin in which the number is placed can be +selected by \fIt\fP (top) or \fIb\fP (bottom), and the position of the +number can be further specified by \fIl\fP (left), \fIc\fP (center), +or \fIr\fP (right). The number is placed by default in the center of +the top margin, If \fInum\fP is given, start numbering with that +value, and otherwise with 1. If an initial top margin value is given +with the \fB-i\fP option, numbering will be omitted on the first page +if it is at the top. Pages are unnumbered if this option is not +specified. +.TP +.B \-o [\fI#\fP] +Outline pages (and columns) with a line which is # units wide. A +narrow line of 0.4pt width is assumed if # is omitted; this particular +width is what TeX uses in typesetting. +.TP +.BI \-p # +Set font point size (default 10bp). The baseline skip (spacing +between successive character baselines) is conventionally chosen to be +6/5 of this value, so that with 10bp type, we have 12bp between lines, +or 6 lines/inch, the same as standard printer output. +.TP +.BI \-r # +Set right margin to # (default is 1.0in). +.TP +.BI \-s num +Use manual feed tray (special handling) for the first \fInum\fP pages +of the output. If \fIN\fP multiple copies are in effect (see option +\fB-c\fP), then \fIN*num\fP sheets must be fed manually. If \fInum\fP +is omitted, then all pages are to be fed manually. Default value of +\fInum\fP is 0. +.TP +.BI \-t # +Set top margin to # (default value is 1.0in). +.TP +.B \-u +Produce pages in unsorted (first to last) order instead of in sorted +(page reversed) order; some \*(Ps printers have +page handlers that stack the paper in this order. The default is to +sort because this is appropriate for the most common +\*(Ps printer, the Apple LaserWriter. +.SH SPECIFICATION OF DIMENSIONAL VALUES +In the switch descriptions above, physical dimensions described as # may +be specified as a single number with an optional fractional part, and a +required two-letter unit designator. Possible forms are: +.LP +.ta 0.25i 1.0i 4.0i +.nf +#.##bp big point (1in = 72bp) [Courier: 120.000/Pbp cpi] +#.##cc cicero (1cc = 12dd) [Courier: 9.381/Pcc cpi] +#.##cm centimeter [Courier: 4.233/Pcm cpi] +#.##dd didot point (1157dd = 1238pt) [Courier: 112.569/Pdd cpi] +#.##in inch [Courier: 1.667/Pin cpi] +#.##mm millimeter (10mm = 1cm) [Courier: 42.333/Pmm cpi] +#.##pc pica (1pc = 12pt) [Courier: 10.038/Ppc cpi] +#.##pt point (72.27pt = 1in) [Courier: 120.450/Ppt cpi] +#.##sp scaled point (65536sp = 1pt) [Courier: 7.893/(Psp/1000000) cpi] +.fi +.LP +The bracketed values give the number of characters per inch (cpi) for a +point size of P units with the fixed-width Courier font. For example, +with point size 8bp, there are 120/8 = 15 characters per inch. With +point size 1000000sp, there are 7.893 characters/inch. +.SH FILES +.TP 2.2i +/usr/local/plot79/tex/dvi/lptops.c +source code +.TP +/usr/local/plot79/lptops +executable +.TP +/usr/local/plot79/define +various environment definitions, an appropriate subset of which should +be placed in the user's \fI.cshrc\fP or \fI.profile\fP file +.SH "SEE ALSO" +document (1L), drawit(1L), grapht(1L), graph3t(1L), pfort(1L), +piechtt(1L), plot79-intro(1L), plot79(1L), pluto(1L), pretty(1L), +rdinfo(1L), sf3(1L), slides(1L), tekalw(1L), tkvecs(1L), tmacro(1L), +world(1L) +.SH AUTHOR +Nelson H.F. Beebe, Ph.D. +.br +Center for Scientific Computing +.br +South Physics Building +.br +University of Utah +.br +Salt Lake City, Utah 84112 +.br +(Manual page by R. P. C. Rodgers, Computer Applications in Laboratory +Medicine Project, UCSF, San Francisco, CA 94143). diff --git a/dviware/beebe/utils/lptops.c b/dviware/beebe/utils/lptops.c new file mode 100644 index 0000000000..0ece9ff313 --- /dev/null +++ b/dviware/beebe/utils/lptops.c @@ -0,0 +1,1860 @@ +/* -*-C-*- LPTOPS.C */ +/*-->lptops*/ +/**********************************************************************/ +/******************************* lptops *******************************/ +/**********************************************************************/ + +/*********************************************************************** + +NB: In order to handle overprinting of input of the form + +...text...<CR>...overtext...<CR><LF> + +this must be loaded with a special version of the C library I/O routine +(PCC:IOCR.REL on the DEC-20) which permits reading and writing of <CR>. +No special action need be taken on Unix systems, since <CR> is not +filtered out, and is normally absent. On PC-DOS, open options of "rb" +will usually be necessary (this is the default on all systems but +TOPS-20). +***********************************************************************/ + +/*********************************************************************** + Line printer file to PostScript converter + [03-Jul-85] + [12-Nov-85] + [07-Apr-86] + [03-May-88] + +lptops converts normal text files into PostScript for printing on the +Apple LaserWriter, or any other PostScript-compatible printing device. +It supports selection of a variety of fonts at arbitrary point sizes, +margin specification, portrait and landscape page orientation, automatic +page numbering, page outlining, and multi-column printing. It can also +handle overstruck text used by many document formatters for underlining. + +Usage: + + lptops [switches] <infile >outfile + lptops [switches] filelist >outfile + +In the switch descriptions below, physical dimensions described as # may +be specified as a single number with an optional fractional part, and a +required two-letter unit designator. Letter case is ignored. Possible +forms are: + +#.##bp big point (1in = 72bp) [Courier: 120.000/Pbp cpi] +#.##cc cicero (1cc = 12dd) [Courier: 9.381/Pcc cpi] +#.##cm centimeter [Courier: 4.233/Pcm cpi] +#.##dd didot point (1157dd = 1238pt)[Courier: 112.569/Pdd cpi] +#.##in inch [Courier: 1.667/Pin cpi] +#.##mm millimeter (10mm = 1cm) [Courier: 42.333/Pmm cpi] +#.##pc pica (1pc = 12pt) [Courier: 10.038/Ppc cpi] +#.##pt point (72.27pt = 1in) [Courier: 120.450/Ppt cpi] +#.##sp scaled point (65536sp = 1pt) [Courier: 7.893/(Psp/1000000) cpi] + +The bracketed values give the number of characters per inch (cpi) for a +point size of P units with the fixed-width Courier font. For example, +with point size 8bp, there are 120/8 = 15 characters per inch. With +point size 1000000sp, there are 7.893 characters/inch. + +The optional switches are (letter case is ignored): + + -A Turn Scribe-like bold and italic requests (@b[...] and + @i[...]) into bold or italic text. + + -B# Bottom margin of #. + + -Cn Print n copies of each page. + + -Ffontname + PostScript fontname. Possible values with acceptable + short abbreviations formed from the upper-case letters + in the font names, and the ditroff and Adobe TranScript + abbreviations are as follows. The first 13 are + available on all PostScript printers; the remainder are + available only on enhanced printers, such as the Apple + LaserWriter Plus. + + ==================== ===== ====== ========== + full name short ditroff TranScript + ==================== ===== ====== ========== + Courier C C C + Courier-Bold CB CB CB + Courier-BoldOblique CBO CD CD + Courier-Oblique CO CO CO + Helvetica H he he + Helvetica-Bold HB He He + Helvetica-BoldOblique HBO HE HE + Helvetica-Oblique HO hE hE + Symbol S S S + Times-Bold TB R ti + Times-BoldItalic TBI BI TI + Times-Italic TI I tI + Times-Roman T R ti + + AvantGarde-Book AGB ag ag + AvantGarde-BookOblique AGBO aG aG + AvantGarde-Demi AGD Ag Ag + AvantGarde-DemiOblique AGDO AG AG + Bookman-Demi BD Bo Bo + Bookman-DemiItalic BDI BO BO + Bookman-Light BL bo bo + Bookman-LightItalic BLI bO bO + Helvetica-Narrow HN hn hn + Helvetica-Narrow-Bold HNB Hn Hn + Helvetica-Narrow-BoldOblique HNBO HN HN + Helvetica-Narrow-Oblique HNO hN hN + NewCenturySchlbk-Bold NCSB Nc Nc + NewCenturySchlbk-BoldItalic NCSBI NC NC + NewCenturySchlbk-Italic NCSI nC nC + NewCenturySchlbk-Roman NCSR nc nc + Palatino-Bold PB Pa Pa + Palatino-BoldItalic PBI PA PA + Palatino-Italic PI pA pA + Palatino-Roman PR pa pa + ZapfChancery-MediumItalic ZCMI ZC ZC + ZapfDingbats ZD ZD ZD + ==================== ===== ====== ========== + + The ditroff and TranScript abbreviations are the same, + except for the Courier and Times fonts. They are based + on two-letter mnemonics, where upper-case in the first + letter means bold, and upper-case in the second letter + means italic. + + Only the Courier fonts are fixed-width like typewriter + and line printer fonts are. The others are proportional + spaced for improved readability, and consequently, + tabular material will not line up properly with them. + The Courier fonts have a width equal to 0.6 of their + point size, so to fill a line W inches wide with up to N + characters, one must have point size <= (W/(0.6 * N * + 72)) = (W*120)/N pt. Equivalently, with a point size P + pt, the output spacing is 120/P char/inch. + + -H Horizontal page orientation (landscape mode) instead of + vertical page (portrait mode). + + -I# Top margin of # for initial page (for letterheads); if + not specified, it will default to the value given for + the top margin by default or by the -T# command. + + -L# Left margin of #. + + -Mn Multiple column output (n columns). In multiple column + mode, formfeeds cause column breaks instead of page + breaks. + + -N[tb][lcr]n + Number output pages. The number is placed by default in + the center of the top margin, but the margin can be + selected explicitly by t (top) or b (bottom), and the + position of the page number can be further specified by + l (left), c (center), or r (right). If n is given, + start numbering with that value, and otherwise with 1. + If an initial top margin value is given with the -I# + option, numbering will be omitted on the first page if + it is at the top. Pages are unnumbered if this option + is not specified. + + -O[#] Outline pages (and columns) with a # units wide. A + narrow line of 0.4pt width is assumed if # is omitted; + this particular width is what TeX uses in typesetting. + + -P# Font point size (default 10bp). The baseline skip + (spacing between successive character baselines) is + conventionally chosen to be 6/5 of this value, so that + with 10bp type, we have 12bp between lines, or 6 + lines/inch, the same as standard printer output. + + -R# Right margin of #. + + -S[n] special handling (i.e. manual paper feed) for the first + n pages of the output. If N multiple copies are in + effect, then N*n sheets must be fed manually. If n is + omitted, then all pages are to be fed manually. For + example, -S1 is convenient to get the first page of a + letter on letterhead paper fed manually, with remaining + pages from the paper cassette. + + -T# Top margin of #. + + -U Output pages in unsorted (first to last) order instead + of in sorted (page reversed) order; some PostScript + printers have page handlers that stack the paper in this + order. The default is sorted because this is + appropriate for the most common PostScript printer, the + Apple LaserWriter. + +Defaults are: + + -B1.0in -C1 -FCourier -L1.0in -M1 -P10bp -R1.0in -S0 -T1.0in + + +Revision history (reverse time order): + +[03-May-88] Add ditroff and Adobe TranScript font abbreviations. + +[19-Apr-86] Change page/line status report from output in End_Page() + only to output in Beg_Page() and End_Column(). + +[07-Apr-86] Fix some incorrect font names, put font names into + table, add font abbreviations and new font names, change + default font to Courier (because most printing expects + fixed-width fonts). Add usage message if bad options, + and print fontnames if bad font switch given. Allow + multiple filenames on command line instead of just using + stdin -- this added new function Do_File() and changed + argument lists of inchar() and Copy_Plist(). Add + save/restore around each page image following new 1986 + PostScript Language Reference Manual recommendation, and + change multiple copies sequence from repeat loop to + setting of standard variable #copies. Add -U option for + unsorted output. + +[03-Feb-86] Fix setting of final entry of page_table[]. It should + only be done when End_Page() is called, since otherwise + Beg_Page() has already set the final entry, and we just + have an empty page to be discarded. Without this fix, + this left a hole (0), so the entire file got copied in + its entirety to the last page of the sorted file. + +[18-Jan-86] Add (void) to fprintf()/printf(), test for disk storage + full at end of page, add OUTSTR() macro using fputs() + instead of fprintf() for efficiency. + +[20-Dec-85] Change getchar() to inchar(); the latter supplies a + trailing LF at EOF in the event it is missing. + Otherwise, the output PostScript has two tokens + jammed together (P 1 {copypage} --> P1 {copypage}) + +[20-Dec-85] Following recommendation of Allan Hetzel on LASER-LOVERS + ARPA BBOARD, added "() pop" at top of every page. This + is selected by the switch FIX31OCT85: + + -------------------------------------------------------- + From: Allan Hetzel <SYSAL%UKCC.BITNET@WISCVM.ARPA> + Subject: Re: Apple Laserwriter XON/XOFF problem + To: <LASER-LOVERS@WASHINGTON.ARPA> + + The note posted to Laser-Lovers on Oct 28 by Joseph + Goldstone of Symbolics Cambridge Research Center was + helpful but I didn't try his suggested fix correctly and + so I called Adobe. They were very helpful (much more so + than Apple) and explained the problem and how to bypass + it. + + My apologies to Adobe if this not an accurate + description of the problem. The problem apparently is + due to the PostScript interpreter getting confused by + what it thinks is an excess of white space characters. + + The bypass is to place a special character (parenthesis, + bracket, brace, slash, etc.) to the right of some token, + but without an intervening white space character. As the + PostScript scanner reads the token it also reads the + special character which acts as a delimiter. The scanner + then has to back up one character so that it can + reprocess the special character after it has processed + the preceding token. During this backing up process a + number of internal values are recalculated, including + some pointer into the input buffer. This causes the + XON/XOFF protocol to work properly. Doing this once per + page seems to keep everybody happy. + + Each page in the PostScript file built by our word + processing program is surrounded by a "save restore" + sequence. We changed the beginning save sequence + "/saveobj save def" to read "/saveobj save def() pop". + The "() pop" is effectively a no-op and we are assured + that the necessary recalculations are done on each page. + This seems to have corrected the problem completely. + + Allan Hetzel (sysal@ukcc.bitnet) + -------------------------------------------------------- + +[11-Dec-85] Fix problem with extra () around overstruck text. + +[13-Nov-85] Insert FASTIO conditional compilation option to speed up + page reversal. Under VAX 4.2BSD, fread() and fwrite() + are already fast enough, and need not be replaced. + +[12-Nov-85] Add reversal of pages, storing output on intermediate + file which is deleted before exiting. + +[02-Nov-85] Add code to write output on temporary file, then + retrieve in reverse page order and output on stdout. + +[30-Oct-85] Add code to handle overstruck lines: + ...text...<CR>...overtext...<CR><LF> + will appear as + (...text...) O + (...overtext...) P + + Macro definitions and font selection now repeated + on each page to allow selective reprinting. + +[07-Oct-85] Add code to discard input NUL's from word-padded files, + since the LaserWriter prints them as blanks. + +[27-Sep-85] Added missing 'N' switch, fixed Page_Switch() (it scanned + beyond last digit of page number) + +[11-Jul-85] Original version. + + +***********************************************************************/ + + +#ifndef OS_TOPS20 +#define OS_TOPS20 0 +#endif + +#ifndef KCC_20 +#define KCC_20 0 +#endif + +#ifndef PCC_20 +#define PCC_20 0 +#endif + +#if (KCC_20 | PCC_20) +#ifndef OS_TOPS20 +#define OS_TOPS20 1 +#endif +#endif + +#ifndef OS_VAXVMS +#define OS_VAXVMS 0 +#endif + +#ifndef OS_ATARI +#define OS_ATARI 0 +#endif + +#ifndef OS_PCDOS +#define OS_PCDOS 0 +#endif + +#ifndef IBM_PC_AZTEC +#define IBM_PC_AZTEC 0 +#endif + +#ifndef IBM_PC_LATTICE +#define IBM_PC_LATTICE 0 +#endif + +#ifndef IBM_PC_MICROSOFT +#define IBM_PC_MICROSOFT 0 +#endif + +#ifndef IBM_PC_WIZARD +#define IBM_PC_WIZARD 0 +#endif + +#if (IBM_PC_AZTEC | IBM_PC_LATTICE | IBM_PC_MICROSOFT | IBM_PC_WIZARD) +#ifndef OS_PCDOS +#define OS_PCDOS 1 +#endif +#endif + +#if (OS_ATARI | OS_TOPS20 | OS_PCDOS | OS_VAXVMS) +#define OS_UNIX 0 +#else +#define OS_UNIX 1 +#endif + +#if (OS_ATARI | PCC_20) +#define DISKFULL(fp) ferror(fp) /* PCC-20 does not always set errno */ +#else +#define DISKFULL(fp) (ferror(fp) && (errno == ENOSPC)) +#endif + +#if OS_VAXVMS +#define EXIT vms_exit +#else +#define EXIT exit +#endif + +#if IBM_PC_LATTICE +typedef int void; /* Lattice C does not have this */ +#endif + +#if IBM_PC_MICROSOFT +#define ANSI_PROTOTYPES 1 +#endif + +#ifndef ANSI_PROTOTYPES +#define ANSI_PROTOTYPES 0 +#endif + +#ifndef ANSI_LIBRARY +#define ANSI_LIBRARY 0 +#endif + +/* +************************************************************************ +On TOPS-20, fread()/fwrite() are implemented as loops around +getc()/putc() calls, and these in turn also do CR/LF translation. Calls +to _read() and _write() translate into direct calls to the Monitor for +fast efficient block I/O. FASTIO selects this option. It is used in +Copy_Block when the temporary file is output in reverse page order to +stdout. +************************************************************************ +*/ + +#if OS_TOPS20 +#if PCC_20 +#define FASTIO 1 /* TOPS-20 use only */ +#undef DISKFULL +#define DISKFULL(fp) ferror(fp) /* PCC-20 does not always set errno */ +extern int strcmp(); +#endif +#endif + +#define FIX31OCT85 1 /* Allan Hetzel's XON/XOFF fix */ + +typedef int BOOLEAN; + +#define FALSE 0 +#define TRUE 1 + +#ifndef FASTIO +#define FASTIO 0 +#endif + +#define PXLID 0 /* used in inch.h */ + +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> + +#if IBM_PC_MICROSOFT +/* int errno; */ /* not in errno.h */ +#include <stdlib.h> +#include <time.h> +#endif + +#if OS_TOPS20 +#include <time.h> +#endif + +#if FASTIO +#include <file.h> +#include <jsys.h> +#include <mon_s.h> +#endif + +#if (OS_TOPS20 | OS_UNIX | OS_VAXVMS | IBM_PC_AZTEC) +#define FOPEN_W "w" +#define FOPEN_R "r" +#else +#define FOPEN_W "wb" +#define FOPEN_R "rb" +#endif + +/*********************************************************************** +PostScript's basic units are big points (72bp = 1in). Everything in +this routine works in terms of "Quite Small Units": 1 inch = QSU qsu. +***********************************************************************/ + + +#define NUL '\0' + +#define QSU 100000L /* quite small units per inch -- */ + /* should be large to avoid */ + /* truncation error accumulation */ + +#define INCH_TO_QSU(x) ((COORDINATE)(x * (float)QSU)) + /* inch to QSU conversion */ + +#define LEFT_X (left_margin + col_margin) +#define BOT_Y (bottom_margin + col_margin) +#define TOP_Y(margin) (page_height - (margin) - baseline_skip - col_margin) + +#if OS_TOPS20 /* want <CR><LF> */ +#define NEWLINE(fp) {(void)putc((char)'\r',fp);(void)putc((char)'\n',fp);} +#else +#define NEWLINE(fp) (void)putc((char)'\n',fp) /* want bare <LF> */ +#endif + +#define OUTCHAR(c) (void)putc((char)(c),tf) +#define OUTOCTAL(c) (void)fprintf(tf,"\\%03o",(c)) +#define OUTSTR(s) (void)fputs(s,tf) + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +#define HEIGHT (11L * QSU) /* page height in QSU */ +#define MAXBLOCK 4096L /* block size for file copy */ +#define MAXLEN 256 /* font name length */ +#define MAXPAGE 1024 /* size of page location table */ +#define WIDTH ((85L * QSU)/10L) /* page width in QSU */ +#define COL_TWIDDLE 40L /* 1/fraction of column width for */ + /* column margin */ + +#define PAGE_T 001 /* flag bits for page_flag */ +#define PAGE_B 002 +#define PAGE_L 010 +#define PAGE_R 020 +#define PAGE_C 040 + +#define TEMPFILE "lptops.tmp" /* temporary output file */ + + + /* global functions */ +#if ANSI_PROTOTYPES +int main(int ,char *[]); +void Beg_Column(void); +void Beg_Line(void); +void Beg_Page(void); +void Beg_Text(char); +void Copy_Block(long ,long); +void Copy_Plist(char, FILE *); +void Do_File(FILE *); +void End_Column(void); +void End_Page(void); +void End_Line(void); +void End_Text(char); +float inch(char *); +int inchar(FILE *); +void Page_Switch(char *); + +#if ANSI_LIBRARY +int atoi(const char *); +char* ctime(const time_t *); +#else /* NOT ANSI_LIBRARY */ +int atoi(char *); +char* ctime(long *); +#endif /* ANSI_LIBRARY */ + +char *cuserid(char *); +void EXIT(int); +char *getlogin(void); + +#if ANSI_LIBRARY +void perror(const char *); +char *strcpy(char *,const char *); +int strcm2(char *,char *); +size_t strlen(const char *); +char *strncpy(char *,const char *,size_t); +time_t time(time_t *); +int unlink(const char *); +#else /* NOT ANSI_LIBRARY */ +void perror(char *); +char *strcpy(char *,char *); +int strcm2(char *,char *); +int strlen(char *); +char *strncpy(char *,char *,int); +long time(long *); +int unlink(char *); +#endif /* ANSI_LIBRARY */ + +#else +void Beg_Column(); +void Beg_Line(); +void Beg_Page(); +void Beg_Text(); +void Copy_Block(); +void Copy_Plist(); +void Do_File(); +void End_Column(); +void End_Page(); +void End_Line(); +void End_Text(); +float inch(); +int inchar(); +int main(); +void Page_Switch(); + +int atoi(); +char *ctime(); +char *cuserid(); +void EXIT(); +char *getlogin(); +void perror(); +char *strcpy(); +int strcm2(); +int strlen(); +char* strncpy(); +long time(); +int unline(); +#endif + +typedef long COORDINATE; /* variables in QSU need >=32 bits */ + + + /* global variables */ + +FILE *tf; /* temporary output file */ +BOOLEAN bad_option; /* bad option flag */ +COORDINATE baseline_skip; /* inter-line spacing */ +COORDINATE bottom_margin; /* bottom margin width in QSU */ +int column; /* current text column (1..numcol) */ +COORDINATE col_margin; /* column margin (extra space */ + /* between column borders in */ + /* multi-column mode) */ +COORDINATE col_width; /* column width in QSU */ +int copies; /* number of copies of each page */ +BOOLEAN do_page_number; /* page numbering flag */ +char font_name[MAXLEN+1]; /* font name -- normal */ +char font_bold[MAXLEN+1]; /* font name -- bold */ +char font_italic[MAXLEN+1]; /* font name -- italic */ +BOOLEAN found; /* search flag */ +int in_col; /* input line column */ +int init_page_number; /* initial page number */ +COORDINATE init_top_margin; /* initial page top margin in QSU */ +BOOLEAN landscape_mode; /* horizontal landscape mode output */ +COORDINATE left_margin; /* left margin in QSU */ +int level; /* parenthesis level */ +int line_number; /* current line number */ +int manual_feed; /* manual feed page count */ +int numcol; /* number of text columns */ +COORDINATE outline; /* page and column outline linewidth */ +int page_flag; /* page number location flag */ +COORDINATE page_height; /* page height in QSU */ +int page_number; /* current page number */ +long page_table[MAXPAGE+1]; /* page location table (with space */ + /* for extra entry marking EOF) */ +COORDINATE page_width; /* page width in QSU */ +COORDINATE point_size; /* font point size in big points */ +BOOLEAN reverse; /* page reversal flag */ +COORDINATE right_margin; /* right margin in QSU */ +BOOLEAN scribe; /* recognize bold/italic sequences */ +COORDINATE top_margin; /* top margin in QSU */ +COORDINATE x; /* current horizontal coordinate */ +COORDINATE y; /* current vertical coordinate */ + +/*********************************************************************** +Built-in PostScript font tables. The first column in each list contains +the full (case sensitive) PostScript names, the second column contains +convenient short abbreviations which can be used in the command line +-ffontname option, the third and fourth columns contain ditroff and +Adobe TranScript abbreviations. + +The first four lines of entries are available on the regular +LaserWriter, and the remainder are available only on the LaserWriter +Plus. +***********************************************************************/ + +char* ps_normal[] = +{ + /* fullname short ditroff TranScript */ + "Courier", "C", "C", "C", + "Helvetica", "H", "he", "he", + "Times-Roman", "T", "R", "ti", + "Symbol", "S", "S", "S", + "AvantGarde-Book", "AGB", "ag", "ag", + "AvantGarde-Demi", "AGD", "Ag", "Ag", + "Bookman-Demi", "BD", "Bo", "Bo", + "Bookman-Light", "BL", "bo", "bo", + "Helvetica-Narrow", "HN", "hn", "hn", + "NewCenturySchlbk-Roman", "NCSR", "nc", "nc", + "Palatino-Roman", "PR", "pa", "pa", + "ZapfChancery-MediumItalic", "ZCMI", "ZC", "ZC", + "ZapfDingbats", "ZD", "ZD", "ZD" +}; + +char* ps_bold[] = +{ + /* fullname short ditroff TranScript */ + "Courier-Bold", "CB", "CB", "CB", + "Helvetica-Bold", "HB", "He", "He", + "Times-Bold", "TB", "B", "Ti", + "Symbol", "S", "S", "S", + "AvantGarde-Book", "AGB", "ag", "ag", + "AvantGarde-Demi", "AGD", "Ag", "Ag", + "Bookman-Demi", "BD", "Bo", "Bo", + "Bookman-Light", "BL", "bo", "bo", + "Helvetica-Narrow-Bold", "HNB", "Hn", "Hn", + "NewCenturySchlbk-Bold", "NCSB", "Nc", "Nc", + "Palatino-Bold", "PB", "Pa", "Pa", + "ZapfChancery-MediumItalic", "ZCMI", "ZC", "ZC", + "ZapfDingbats", "ZD", "ZD", "ZD" +}; + +char* ps_italic[] = +{ + /* fullname short ditroff TranScript */ + "Courier-Oblique", "CO", "CO", "CO", + "Helvetica-Oblique", "HO", "hE", "hE", + "Times-Italic", "TI", "I", "tI", + "Symbol", "S", "S", "S", + "AvantGarde-BookOblique", "AGBO", "aG", "aG", + "AvantGarde-DemiOblique", "AGDO", "AG", "AG", + "Bookman-DemiItalic", "BDI", "BO", "BO", + "Bookman-LightItalic", "BLI", "bO", "bO", + "Helvetica-Narrow-Oblique", "HNO", "hN", "hN", + "NewCenturySchlbk-Italic", "NCSI", "nC", "nC", + "Palatino-Italic", "PI", "pA", "pA", + "ZapfChancery-MediumItalic", "ZCMI", "ZC", "ZC", + "ZapfDingbats", "ZD", "ZD", "ZD" +}; + +char* ps_both[] = +{ + /* fullname short ditroff TranScript */ + "Courier-BoldOblique", "CBO", "CD", "CD", + "Helvetica-BoldOblique", "HBO", "HE", "HE", + "Times-BoldItalic", "TBI", "BI", "TI", + "Symbol", "S", "S", "S", + "AvantGarde-BookOblique", "AGBO", "aG", "aG", + "AvantGarde-DemiOblique", "AGDO", "AG", "AG", + "Bookman-DemiItalic", "BDI", "BO", "BO", + "Bookman-LightItalic", "BLI", "bO", "bO", + "Helvetica-Narrow-BoldOblique", "HNBO", "HN", "HN", + "NewCenturySchlbk-BoldItalic", "NCSBI","NC", "NC", + "Palatino-BoldItalic", "PBI", "PA", "PA", + "ZapfChancery-MediumItalic", "ZCMI", "ZC", "ZC", + "ZapfDingbats", "ZD", "ZD", "ZD" +}; + + +#define PS_DEFAULT 0 /* index of default font in ps_normal[] */ +#define MAXFONT (sizeof(ps_normal)/sizeof(char *)) /* size of font table */ + + +int +main(argc,argv) +int argc; +char* argv[]; +{ + register int k; /* loop index */ + register char *p; /* temporary pointer */ + register int m,n; /* loop indices */ + FILE *fp; /* input file pointer */ + char timestr[27]; /* result of ctime() */ + long timeval; /* result of time() */ + long last,next; /* result of fseek() for */ + /* page_table[] construction */ + int (*compare)(); + + /* establish defaults for all parameters */ + bottom_margin = 1L * QSU; + column = 1; + col_margin = 0L; + copies = 1; + do_page_number = FALSE; + init_page_number = 1; + init_top_margin = -1; /* negative value flags unset state */ + in_col = 0; + landscape_mode = FALSE; + left_margin = 1L * QSU; + manual_feed = 0; + numcol = 1; + outline = 0L; + page_height = HEIGHT; + page_number = init_page_number; + page_width = WIDTH; + point_size = INCH_TO_QSU(inch("10bp")); + reverse = TRUE; + right_margin = 1L * QSU; + scribe = FALSE; + top_margin = 1L * QSU; + + strcpy(font_name,ps_normal[PS_DEFAULT]); + strcpy(font_bold,ps_bold[PS_DEFAULT]); + strcpy(font_italic,ps_italic[PS_DEFAULT]); + + bad_option = FALSE; + for (k = 1; k < argc; ++k) + { + p = argv[k]; + if (argv[k][0] == '-') + { + switch(argv[k][1]) + { + case 'a': + case 'A': + scribe = TRUE; + break; + + case 'b': + case 'B': + bottom_margin = INCH_TO_QSU(inch(&argv[k][2])); + break; + + case 'c': + case 'C': + copies = atoi(&argv[k][2]); + break; + + case 'f': + case 'F': + (void)strncpy(font_name,&argv[k][2],MAXLEN); + font_name[MAXLEN] = '\0'; + found = FALSE; + for (n = 0; n < MAXFONT; n += 4) + { + for (m = 3; m >= 0; --m) + { + /* compare case-sensitive ditroff and TranScript + names before case-insensitive ones */ + compare = (m > 1) ? strcmp : strcm2; + if ((*compare)(font_name,ps_normal[n+m]) == 0) + { + strcpy(font_name,ps_normal[n]); + strcpy(font_bold,ps_bold[n]); + strcpy(font_italic,ps_italic[n]); + found = TRUE; + break; + } + else if ((*compare)(font_name,ps_bold[n+m]) == 0) + { + strcpy(font_name,ps_bold[n]); + strcpy(font_bold,ps_bold[n]); + strcpy(font_italic,ps_italic[n]); + found = TRUE; + break; + } + else if ((*compare)(font_name,ps_italic[n+m]) == 0) + { + strcpy(font_name,ps_italic[n]); + strcpy(font_bold,ps_both[n]); + strcpy(font_italic,ps_normal[n]); + found = TRUE; + break; + } + else if ((*compare)(font_name,ps_both[n+m]) == 0) + { + strcpy(font_name,ps_both[n]); + strcpy(font_bold,ps_italic[n]); + strcpy(font_italic,ps_normal[n]); + found = TRUE; + break; + } + } + } + if (!found) + { + NEWLINE(stderr); + (void)fprintf(stderr, + "?Illegal font name [%s]. Possible values are:", + font_name); + NEWLINE(stderr); + + NEWLINE(stderr); + (void)fprintf(stderr,"Normal fonts"); + NEWLINE(stderr); + for (m = 0; m < MAXFONT; m += 4) + { + (void)fprintf(stderr,"\t%-30s %-10s %-10s %-10s", + ps_normal[m],ps_normal[m+1],ps_normal[m+2], + ps_normal[m+3]); + NEWLINE(stderr); + } + + NEWLINE(stderr); + (void)fprintf(stderr,"Bold fonts"); + NEWLINE(stderr); + for (m = 0; m < MAXFONT; m += 4) + { + (void)fprintf(stderr,"\t%-30s %-10s %-10s %-10s", + ps_bold[m],ps_bold[m+1],ps_bold[m+2], + ps_bold[m+3]); + NEWLINE(stderr); + } + + NEWLINE(stderr); + (void)fprintf(stderr,"Oblique/Italic fonts"); + NEWLINE(stderr); + for (m = 0; m < MAXFONT; m += 4) + { + (void)fprintf(stderr,"\t%-30s %-10s %-10s %-10s", + ps_italic[m],ps_italic[m+1],ps_italic[m+2], + ps_italic[m+3]); + NEWLINE(stderr); + } + + NEWLINE(stderr); + (void)fprintf(stderr,"BoldOblique/BoldItalic fonts"); + NEWLINE(stderr); + for (m = 0; m < MAXFONT; m += 4) + { + (void)fprintf(stderr,"\t%-30s %-10s %-10s %-10s", + ps_both[m],ps_both[m+1],ps_both[m+2], + ps_both[m+3]); + NEWLINE(stderr); + } + NEWLINE(stderr); + bad_option = TRUE; + } + break; + + case 'h': + case 'H': + landscape_mode = TRUE; + break; + + case 'i': + case 'I': + init_top_margin = INCH_TO_QSU(inch(&argv[k][2])); + break; + + case 'l': + case 'L': + left_margin = INCH_TO_QSU(inch(&argv[k][2])); + break; + + case 'm': + case 'M': + numcol = atoi(&argv[k][2]); + break; + + case 'n': + case 'N': + Page_Switch(&argv[k][1]); + break; + + case 'o': + case 'O': + if (argv[k][2]) /* have -O# */ + outline = INCH_TO_QSU(inch(&argv[k][2])); + else /* have -O, so give default */ + outline = INCH_TO_QSU(inch("0.4pt")); /* from TeX */ + break; + + case 'p': + case 'P': + point_size = INCH_TO_QSU(inch(&argv[k][2])); + break; + + case 'r': + case 'R': + right_margin = INCH_TO_QSU(inch(&argv[k][2])); + break; + + case 's': + case 'S': + if (argv[k][2]) /* have count field */ + manual_feed = atoi(&argv[k][2]); + else /* omitted count ==> large number */ + manual_feed = 32767; + break; + + case 't': + case 'T': + top_margin = INCH_TO_QSU(inch(&argv[k][2])); + break; + + case 'u': + case 'U': + reverse = FALSE; + break; + + default: + NEWLINE(stderr); + (void)fprintf(stderr,"?Unrecognized option [%s]",p); + NEWLINE(stderr); + bad_option = TRUE; + } + } + } + + if (bad_option) + { + (void)fprintf(stderr, + "Usage: %s -A -B# -Cn -Ffontname -H -I# -L# -Mn -N[tb][lcr]n \ +-O[#] -P# -R# -S[n] -T# -U filelist >outfile",argv[0]); + NEWLINE(stderr); + + (void)fprintf(stderr,"Default options: -B1.0in -C1 -FCourier -L1.0in \ +-M1 -P10bp -R1.0in -S0 -T1.0in"); + NEWLINE(stderr); + + EXIT(1); + } + + + if (reverse) + { + if ((tf = fopen(TEMPFILE,FOPEN_W)) == (FILE *)NULL) + { + NEWLINE(stderr); + (void)fprintf(stderr,"?Cannot open temporary file [%s]",TEMPFILE); + NEWLINE(stderr); + (void)perror("?perror() says"); + EXIT(1); + } + } + else + tf = stdout; + + /******************************************************************* + Make the PostScript File Structure header according to Version 1.0, + First Edition (January 1985) of the PostScript File Structuring + Conventions manual. We add one additional field at the end after + the %%Pages: n field: + + %%PageTable: m1 n1 p1 ... mk nk pk + + where the triples (mj nj pj) contain the page number pair (mj nj) + like the field + + %%Page: mj nj + + and pj is the byte position in the file of the beginning of that + "%%Page" command. A spooler can then easily position to arbitrary + pages in the file for reprinting. + *******************************************************************/ + + OUTSTR("%!PS-Adobe-1.0"); /* magical file header */ + NEWLINE(tf); + + OUTSTR("%%DocumentFonts: "); + OUTSTR(font_name); /* only use one font */ + NEWLINE(tf); + + OUTSTR("%%Dimensions: 0 0 612 792"); /* 8.5 x 11 inch page size */ + NEWLINE(tf); + + OUTSTR("%%Title:"); /* this contains our command line */ + for (k = 0; k < argc; ++k) + { + OUTCHAR(' '); + OUTSTR(argv[k]); + } + NEWLINE(tf); /* end of %%Title line */ + + timeval = time((long *)NULL); + strcpy(timestr,ctime(&timeval)); + k = strlen(timestr) - 1; /* ctime has its own \n */ + timestr[k] = NUL; /* so kill it */ + OUTSTR("%%CreationDate: "); + OUTSTR(timestr); + NEWLINE(tf); + + /* Under TOPS-20, JSYS GFUST% cannot be used to obtain file owner string + of a terminal file, which stdout always is, so just use job login name */ + + OUTSTR("%%Creator: "); + if (cuserid((char*)NULL) != (char*)NULL) + OUTSTR(cuserid((char*)NULL)); + NEWLINE(tf); + + OUTSTR("%%Pages: (atend)"); + NEWLINE(tf); + OUTSTR("%%EndComments"); + NEWLINE(tf); + OUTSTR("save"); /* has matching "restore" at end */ + NEWLINE(tf); + OUTSTR("%%EndProlog"); + NEWLINE(tf); + + /* validate input settings */ + copies = MAX(1,copies); + numcol = MAX(1,numcol); + point_size = MAX(INCH_TO_QSU(inch("3bp")),point_size); + if (point_size > INCH_TO_QSU(0.25)) + { + NEWLINE(stderr); + (void)fprintf(stderr, + "%warning -- font point size > 18pt is unusually large!"); + NEWLINE(stderr); + } + outline = MAX(0L,outline); + + if (landscape_mode) /* switch sizes for landscape mode */ + { + page_height = WIDTH; + page_width = HEIGHT; + } + if (((left_margin + right_margin) >= page_width) || + ((top_margin + bottom_margin) >= page_height) || + ((init_top_margin + bottom_margin) >= page_height)) + { + NEWLINE(stderr); + (void)fprintf(stderr,"?Margin values too large for page"); + NEWLINE(stderr); + EXIT(1); + } + + col_width = (page_width - left_margin - right_margin)/numcol; + col_margin = ((numcol == 1) && (outline == 0)) ? + 0L : (col_width/COL_TWIDDLE); + + /* TeX's baselineskip is 12pt for 10pt type; we preserve the same ratio */ + baseline_skip = (point_size * 12L) / 10L; + + m = 0; /* count of file names */ + for (k = 1; k < argc; ++k) + { + if (*argv[k] != '-') + { + m++; /* count file name */ + if ((fp = fopen(argv[k],FOPEN_R)) != (FILE *)NULL) + { + Do_File(fp); + (void)fclose(fp); + } + else + { + (void)fprintf(stderr,"?Open failure on [%s] -- file skipped", + argv[k]); + NEWLINE(stderr); + } + } + } + if (m == 0) + Do_File(stdin); + + if (reverse) + { + /* Now close the temporary file and reopen for input, then transfer */ + /* complete pages in reverse order to stdout using large blocks */ + + if (fclose(tf)) + { + NEWLINE(stderr); + (void)fprintf(stderr,"?Close failure on temporary file [%s]", + TEMPFILE); + NEWLINE(stderr); + (void)perror("?perror() says"); + EXIT(1); + } + + if ((tf = fopen(TEMPFILE,FOPEN_R)) == (FILE *)NULL) + { + NEWLINE(stderr); + (void)fprintf(stderr,"?Cannot reopen temporary file [%s]",TEMPFILE); + NEWLINE(stderr); + (void)perror("?perror() says"); + EXIT(1); + } + + NEWLINE(stderr); + (void)fprintf(stderr,"[Reversing pages"); + Copy_Block(0L,page_table[0]-1); /* first page is file header stuff */ + last = page_table[MIN(MAXPAGE,page_number-init_page_number+1)]; + for (k = MIN(MAXPAGE,page_number-init_page_number+1)-1; k >= 0; --k) + { /* copy remainder in reverse order */ + (void)putc('.',stderr); + next = (long)ftell(stdout); + Copy_Block(page_table[k],last-1); + last = page_table[k]; + page_table[k] = next; + } + (void)putc(']',stderr); + if (fclose(tf)) + { + NEWLINE(stderr); + (void)fprintf(stderr,"?Close failure on temporary file [%s]", + TEMPFILE); + NEWLINE(stderr); + (void)perror("?perror() says"); + EXIT(1); + } + + unlink(TEMPFILE); /* delete the temporary file */ + } + /* add file trailer stuff */ + + tf = stdout; /* so OUTSTR() macro works */ + + OUTSTR("%%Trailer"); + NEWLINE(stdout); + OUTSTR("restore"); /* matches "save" in prolog */ + NEWLINE(stdout); + (void)printf("%%%%Pages: %d",page_number-init_page_number); + NEWLINE(stdout); + OUTSTR("%%PageTable: "); + for (k = 0; k < MIN(MAXPAGE,page_number-init_page_number+1); ++k) + (void)printf(" %d %d %ld",init_page_number+k,init_page_number+k, + page_table[k]); + NEWLINE(stdout); + if (putchar('\004') == EOF) /* CTL-D for EOF signal */ + { + NEWLINE(stderr); + (void)fprintf(stderr,"?Output error -- disk storage probably full"); + NEWLINE(stderr); + (void)perror("?perror() says"); + EXIT(1); + } + (void)fprintf(stderr," [ok]"); + NEWLINE(stderr); + EXIT(0); + return (0); /* keep lint and compilers happy */ +} + +void +Beg_Column() +{ + (void)fprintf(tf,"%ld %ld moveto",x,y); + NEWLINE(tf); +} + +void +Beg_Line() +{ + if (scribe) + { + OUTCHAR('S'); + OUTCHAR(' '); + } +} + +void +Beg_Page() +{ + int k; + + column = 1; + (void)fflush(tf); + k = page_number-init_page_number; + if (k < MAXPAGE) + page_table[k] = (long)ftell(tf); + (void)fprintf(tf,"%%%%Page: %d %d",k+1,page_number); + NEWLINE(tf); + OUTSTR("save"); /* will be matched by "restore" from End_Page() */ + NEWLINE(tf); + if (scribe) + { + (void)fprintf(tf,"/B {/%s findfont %ld scalefont setfont} def", + font_bold,point_size); + NEWLINE(tf); + + (void)fprintf(tf,"/E {grestore 0 %ld rmoveto} def", + -baseline_skip); /* End of line */ + NEWLINE(tf); + + (void)fprintf(tf,"/I {/%s findfont %ld scalefont setfont} def", + font_italic,point_size); + NEWLINE(tf); + + (void)fprintf(tf,"/N {/%s findfont %ld scalefont setfont} def", + font_name,point_size); + NEWLINE(tf); + + OUTSTR("/O {gsave show grestore} def"); /* OverPrint macro */ + NEWLINE(tf); + + OUTSTR("/S {gsave} def"); /* Start of line */ + NEWLINE(tf); + + OUTSTR("/W {show} def"); /* show text */ + NEWLINE(tf); + } + else + { + OUTSTR("/O {gsave show grestore} def"); /* OverPrint macro */ + NEWLINE(tf); + + (void)fprintf(tf,"/P {gsave show grestore 0 %ld rmoveto} def", + -baseline_skip); /* Print macro */ + NEWLINE(tf); + + (void)fprintf(tf,"/N {/%s findfont %ld scalefont setfont} def", + font_name,point_size); + NEWLINE(tf); + } + (void)fprintf(tf,"72 %ld div 72 %ld div scale",QSU,QSU); + NEWLINE(tf); + OUTCHAR('N'); /* select normal font */ + +#if FIX31OCT85 + OUTSTR("()pop"); /* no-op for XON/XOFF bug workaround */ +#endif + + NEWLINE(tf); + + if (landscape_mode) + { + (void)fprintf(tf,"%ld %ld translate",0L,HEIGHT); + NEWLINE(tf); + OUTSTR("-90 rotate"); + NEWLINE(tf); + } + (void)fprintf(stderr, + " [%d",page_number); /* begin [p.l.l...] status report */ +} + +void +Beg_Text(c) +char c; +{ + if (c) + { + OUTCHAR(' '); + OUTCHAR(c); + OUTCHAR(' '); + } + OUTCHAR('('); + level++; +} + +void +Copy_Block(b1,b2) /* copy bytes b1..b2 from tf to stdout */ +long b1,b2; /* start,end byte positions */ +{ + static char block[MAXBLOCK]; /* static to save stack space */ + long k; /* loop index */ + long length; /* number of bytes to copy */ + +#if FASTIO + (void)fflush(stdout); /* empty any buffered output */ +#endif + for (k = b1; k <= b2; k += MAXBLOCK) + { + length = MIN(MAXBLOCK,b2-k+1); + + (void)fseek(tf,k,0); /* position to desired block */ + +#if FASTIO + if (_read(jfnof(fileno(tf)),block,(int)length) != (int)length) +#else + if (fread(block,1,(int)length,tf) != (int)length) +#endif + { + NEWLINE(stderr); + (void)fprintf(stderr, + "?Input block length error on temporary file [%s]",TEMPFILE); + NEWLINE(stderr); + (void)perror("?perror() says"); + EXIT(1); + } +#if FASTIO + if (_write(jfnof(fileno(stdout)),block,(int)length) != (int)length) +#else + if (fwrite(block,1,(int)length,stdout) != (int)length) +#endif + { + NEWLINE(stderr); + (void)fprintf(stderr, + "?Output block length error on stdout"); + NEWLINE(stderr); + (void)perror("?perror() says"); + EXIT(1); + } + } + (void)fflush(stdout); +} + +void +Copy_Plist(fontc,fp) /* copy parenthesized list to tf */ +char fontc; +FILE *fp; +{ + static char p_open[] = {'(','[','<','{',NUL}; + static char p_close[] = {')',']','>','}',NUL}; + register int match; + register int c; + + c = inchar(fp); + match = 0; + while (p_open[match] && (p_open[match] != (char)c)) + match++; + + if (!p_open[match]) + { + NEWLINE(stderr); + (void)fprintf(stderr,"?@b or @i not followed by open parenthesis!"); + NEWLINE(stderr); + EXIT(1); + } + + Beg_Text(fontc); + while (((c = inchar(fp)) != EOF) && ((char)c != p_close[match])) + { + if (c < ' ') + { + NEWLINE(stderr); + (void)fprintf(stderr, + "?@b[...] or @i[...] contains control character!"); + NEWLINE(stderr); + EXIT(1); + } + in_col++; + switch(c) + { + case '(': + OUTCHAR('\\'); + OUTCHAR(c); + break; + + case ')': + OUTCHAR('\\'); + OUTCHAR(c); + break; + + case '\\': + OUTCHAR('\\'); + OUTCHAR(c); + break; + + default: + OUTCHAR(c); + break; + } + } + End_Text('N'); + OUTCHAR(' '); +} + +void +Do_File(fp) +FILE *fp; +{ + register int c; /* character */ + +/**********************************************************************/ +/* PostScript Output Section */ +/**********************************************************************/ + + x = LEFT_X; + if (init_top_margin > 0) + y = TOP_Y(init_top_margin); + else + y = TOP_Y(top_margin); + + Beg_Page(); + Beg_Column(); + level = 0; + in_col = 0; + line_number = 1; + + if ((c = inchar(fp)) != '\f') /* discard any initial FF */ + (void)ungetc(c,fp); + + while ((c = inchar(fp)) != EOF) + { + switch (c) + { + case NUL: + break; /* discard NUL's from word-padded files */ + + case '\b': + if (in_col > 0) + { + in_col--; + OUTCHAR('\\'); + OUTCHAR('b'); + } + break; + + case '\f': + in_col = 0; + End_Text(NUL); + NEWLINE(tf); + End_Column(); + if (column > numcol) + Beg_Page(); + Beg_Column(); + line_number = 1; + break; + + case '\n': + line_number++; + if (in_col == 0) + { + Beg_Line(); + Beg_Text(NUL); + } + End_Text(NUL); + End_Line(); + in_col = 0; + y -= baseline_skip; + if (y < BOT_Y) + { + End_Column(); + if (column > numcol) + Beg_Page(); + Beg_Column(); + line_number = 1; + } + break; + + + case '\r': /* check for special case of overprinting */ + if ((c = inchar(fp)) != '\n') /* peek ahead one character */ + { /* and if not LF, have overstrike */ + while (level > 0) + { + OUTCHAR(')'); + level--; + } + in_col = 0; + OUTCHAR('O'); + NEWLINE(tf); /* this lines up under previous line */ + } + (void)ungetc(c,fp); /* put back the peeked-at character */ + break; + + case '\t': + if (in_col == 0) + { + Beg_Line(); + Beg_Text(NUL); + } + do + { + in_col++; + OUTCHAR(' '); + } + while (in_col & 07); /* blank fill to multiple of 8 columns */ + break; + + case '(': + if (in_col == 0) + { + Beg_Line(); + Beg_Text(NUL); + } + in_col++; + OUTCHAR('\\'); + OUTCHAR('('); + break; + + case ')': + if (in_col == 0) + { + Beg_Line(); + Beg_Text(NUL); + } + in_col++; + OUTCHAR('\\'); + OUTCHAR(')'); + break; + + case '\\': + if (in_col == 0) + { + Beg_Line(); + Beg_Text(NUL); + } + in_col++; + OUTCHAR('\\'); + OUTCHAR('\\'); + break; + + case '@': + if (scribe) + { + c = inchar(fp); + if ((c == 'b') || (c == 'B')) + { + if (in_col == 0) + Beg_Line(); + else + End_Text(NUL); + Copy_Plist('B',fp); + Beg_Text(NUL); + break; + } + else if ((c == 'i') || (c == 'I')) + { + if (in_col == 0) + Beg_Line(); + else + End_Text(NUL); + Copy_Plist('I',fp); + Beg_Text(NUL); + break; + } + (void)ungetc(c,fp); /* put back the peeked-at character */ + c = (int)'@'; /* and restore original character */ + } + /* ELSE fall through to default! */ + + default: + if (in_col == 0) + { + Beg_Line(); + Beg_Text(NUL); + } + in_col++; + if ((c < 040) || (0176 < c)) + OUTOCTAL(c); + else + OUTCHAR(c); + break; + } + } + if (in_col > 0) + End_Line(); + End_Text(NUL); + column = numcol; /* to force End_Page() action */ + End_Column(); + + /* Normally, Beg_Page() sets the page_table[] entry. Since this is + the last output for this file, we must set it here manually. If + more files are printed, this entry will be overwritten (with the + same value) at the next call to Beg_Page(). */ + page_table[page_number-init_page_number] = (long)ftell(tf); +} + +void +End_Column() +{ + if (outline > 0) + { + NEWLINE(tf); + OUTSTR("gsave"); + NEWLINE(tf); + (void)fprintf(tf,"%ld setlinewidth",outline); + NEWLINE(tf); + (void)fprintf(tf,"newpath %ld %ld moveto",x - col_margin,bottom_margin); + (void)fprintf(tf, + " %ld %ld rlineto %ld %ld rlineto %ld %ld rlineto closepath stroke", + col_width,0, + 0,page_height-bottom_margin-top_margin, + -col_width,0); + NEWLINE(tf); + OUTSTR("grestore"); + NEWLINE(tf); + } + (void)fprintf(stderr, + ".%d",line_number); /* continue [p.l.l...] status report */ + if (++column > numcol) /* columns filled, so start new page */ + { + (void)putc(']',stderr); /* close [p.l.l...] report */ + End_Page(); + } + else /* just start new column */ + { + x += col_width; + y = TOP_Y(top_margin); + } +} + +void +End_Page() +{ + register int k; + + if (do_page_number) + { + if ((init_top_margin > 0) && (page_number == init_page_number) + && (page_flag | PAGE_T)) + ; /* omit leading top pagenumber */ + else + switch (page_flag) + { + case (PAGE_T | PAGE_L): + NEWLINE(tf); + (void)fprintf(tf,"%ld %ld moveto",left_margin, + page_height-top_margin/2-baseline_skip/2); + (void)fprintf(tf," (%d) show",page_number); + break; + + case (PAGE_T | PAGE_C): + NEWLINE(tf); + (void)fprintf(tf,"%ld %ld moveto",page_width/2, + page_height-top_margin/2-baseline_skip/2); + (void)fprintf(tf, + " (- %d -) stringwidth pop 2 div neg 0 rmoveto", + page_number); + (void)fprintf(tf," (- %d -) show",page_number); + NEWLINE(tf); + break; + + case (PAGE_T | PAGE_R): + NEWLINE(tf); + (void)fprintf(tf,"%ld %ld moveto",page_width-left_margin, + page_height-top_margin/2-baseline_skip/2); + (void)fprintf(tf," (%d) stringwidth pop neg 0 rmoveto", + page_number); + (void)fprintf(tf," (%d) show",page_number); + NEWLINE(tf); + break; + + case (PAGE_B | PAGE_L): + NEWLINE(tf); + (void)fprintf(tf,"%ld %ld moveto",left_margin, + bottom_margin/2-baseline_skip/2); + (void)fprintf(tf," (%d) show",page_number); + break; + + case (PAGE_B | PAGE_C): + NEWLINE(tf); + (void)fprintf(tf,"%ld %ld moveto",page_width/2, + bottom_margin/2-baseline_skip/2); + (void)fprintf(tf, + " (- %d -) stringwidth pop 2 div neg 0 rmoveto", + page_number); + (void)fprintf(tf," (- %d -) show",page_number); + NEWLINE(tf); + break; + + case (PAGE_B | PAGE_R): + NEWLINE(tf); + (void)fprintf(tf,"%ld %ld moveto",page_width-left_margin, + bottom_margin/2-baseline_skip/2); + (void)fprintf(tf," (%d) stringwidth pop neg 0 rmoveto", + page_number); + (void)fprintf(tf," (%d) show",page_number); + NEWLINE(tf); + break; + + default: /* else no numbering */ + break; + } + } + page_number++; + + if (manual_feed > 0) + { + OUTSTR("statusdict begin"); + NEWLINE(tf); + OUTSTR("statusdict /manualfeed true put"); + NEWLINE(tf); + } + + if ((fprintf(tf,"/#copies %d def showpage",copies) == EOF) || + DISKFULL(tf)) + { + NEWLINE(stderr); + (void)fprintf(stderr,"?Output error -- disk storage probably full"); + NEWLINE(stderr); + (void)perror("?perror() says"); + EXIT(1); + } + NEWLINE(tf); + + if (manual_feed > 0) + { + OUTSTR("end"); + NEWLINE(tf); + } + manual_feed--; + + OUTSTR("restore"); + NEWLINE(tf); + + for (k = 1; k <= copies; ++k) + OUTCHAR('\f'); /* output FF's for print spooler page accounting */ + + x = LEFT_X; + y = TOP_Y(top_margin); +} + +void +End_Line() +{ + if (scribe) + { + OUTCHAR(' '); + OUTCHAR('E'); + } + NEWLINE(tf); +} + + +void +End_Text(c) +char c; +{ + register int k; + + k = level; + while (level > 0) + { + OUTCHAR(')'); + level--; + } + if (k > 0) + { + if (scribe) + OUTCHAR('W'); + else + OUTCHAR('P'); + } + if (c) + { + OUTCHAR(' '); + OUTCHAR(c); + } +} + +#include "inch.h" + +int +inchar(fp) +FILE *fp; +{ + static int lastc = NUL; /* memory of previous input character */ + register int c; + + /* output is incorrect if the file does not end with a LF; this + routine supplies one at EOF if it is lacking */ + + c = getc(fp); + if ((c == EOF) && (lastc != '\n')) + c = '\n'; + lastc = c; + return (c); +} + +void +Page_Switch(parg) /* parg -> "Nxxxnnn" */ +register char *parg; +{ + register char *porg; + + porg = parg; + do_page_number = TRUE; + init_page_number = 1; + page_flag = (PAGE_T | PAGE_C); /* default location */ + while (*++parg) + { + switch(*parg) + { + case 't': + case 'T': + page_flag &= ~(PAGE_B | PAGE_T); + page_flag |= PAGE_T; + break; + + case 'b': + case 'B': + page_flag &= ~(PAGE_B | PAGE_T); + page_flag |= PAGE_B; + break; + + case 'l': + case 'L': + page_flag &= ~(PAGE_L | PAGE_C | PAGE_R); + page_flag |= PAGE_L; + break; + + case 'c': + case 'C': + page_flag &= ~(PAGE_L | PAGE_C | PAGE_R); + page_flag |= PAGE_C; + break; + + case 'r': + case 'R': + page_flag &= ~(PAGE_L | PAGE_C | PAGE_R); + page_flag |= PAGE_R; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + init_page_number = atoi(parg); + while (isdigit(*parg)) + ++parg; + if (*parg == NUL) + break; + /* else fall through to error exit */ + default: + NEWLINE(stderr); + (void)fprintf(stderr, + "?Unrecognized page number field [%s]",porg); + NEWLINE(stderr); + EXIT(1); + } + if (*parg == NUL) + break; + } +} + +#include "strcm2.h" diff --git a/dviware/beebe/utils/lptops.hlp b/dviware/beebe/utils/lptops.hlp new file mode 100644 index 0000000000..5842ce24fc --- /dev/null +++ b/dviware/beebe/utils/lptops.hlp @@ -0,0 +1,169 @@ + Line printer file to PostScript converter + [03-Jul-85] + [12-Nov-85] + [07-Apr-86] + [03-May-88] + +lptops converts normal text files into PostScript for printing on the +Apple LaserWriter, or any other PostScript-compatible printing device. +It supports selection of a variety of fonts at arbitrary point sizes, +margin specification, portrait and landscape page orientation, automatic +page numbering, page outlining, and multi-column printing. It can also +handle overstruck text used by many document formatters for underlining. + +Usage: + + lptops [switches] <infile >outfile + lptops [switches] filelist >outfile + +In the switch descriptions below, physical dimensions described as # may +be specified as a single number with an optional fractional part, and a +required two-letter unit designator. Letter case is ignored. Possible +forms are: + +#.##bp big point (1in = 72bp) [Courier: 120.000/Pbp cpi] +#.##cc cicero (1cc = 12dd) [Courier: 9.381/Pcc cpi] +#.##cm centimeter [Courier: 4.233/Pcm cpi] +#.##dd didot point (1157dd = 1238pt)[Courier: 112.569/Pdd cpi] +#.##in inch [Courier: 1.667/Pin cpi] +#.##mm millimeter (10mm = 1cm) [Courier: 42.333/Pmm cpi] +#.##pc pica (1pc = 12pt) [Courier: 10.038/Ppc cpi] +#.##pt point (72.27pt = 1in) [Courier: 120.450/Ppt cpi] +#.##sp scaled point (65536sp = 1pt) [Courier: 7.893/(Psp/1000000) cpi] + +The bracketed values give the number of characters per inch (cpi) for a +point size of P units with the fixed-width Courier font. For example, +with point size 8bp, there are 120/8 = 15 characters per inch. With +point size 1000000sp, there are 7.893 characters/inch. + +The optional switches are (letter case is ignored): + + -A Turn Scribe-like bold and italic requests (@b[...] and + @i[...]) into bold or italic text. + + -B# Bottom margin of #. + + -Cn Print n copies of each page. + + -Ffontname + PostScript fontname. Possible values with acceptable + short abbreviations (formed from the upper-case letters + in the font names) are as follows. The first 13 are + available on all PostScript printers; the remainder are + available only on enhanced printers, such as the Apple + LaserWriter Plus. + + ==================== ===== ====== ========== + full name short ditroff TranScript + ==================== ===== ====== ========== + Courier C C C + Courier-Bold CB CB CB + Courier-BoldOblique CBO CD CD + Courier-Oblique CO CO CO + Helvetica H he he + Helvetica-Bold HB He He + Helvetica-BoldOblique HBO HE HE + Helvetica-Oblique HO hE hE + Symbol S S S + Times-Bold TB R ti + Times-BoldItalic TBI BI TI + Times-Italic TI I tI + Times-Roman T R ti + + AvantGarde-Book AGB ag ag + AvantGarde-BookOblique AGBO aG aG + AvantGarde-Demi AGD Ag Ag + AvantGarde-DemiOblique AGDO AG AG + Bookman-Demi BD Bo Bo + Bookman-DemiItalic BDI BO BO + Bookman-Light BL bo bo + Bookman-LightItalic BLI bO bO + Helvetica-Narrow HN hn hn + Helvetica-Narrow-Bold HNB Hn Hn + Helvetica-Narrow-BoldOblique HNBO HN HN + Helvetica-Narrow-Oblique HNO hN hN + NewCenturySchlbk-Bold NCSB Nc Nc + NewCenturySchlbk-BoldItalic NCSBI NC NC + NewCenturySchlbk-Italic NCSI nC nC + NewCenturySchlbk-Roman NCSR nc nc + Palatino-Bold PB Pa Pa + Palatino-BoldItalic PBI PA PA + Palatino-Italic PI pA pA + Palatino-Roman PR pa pa + ZapfChancery-MediumItalic ZCMI ZC ZC + ZapfDingbats ZD ZD ZD + ==================== ===== ====== ========== + + The ditroff and TranScript abbreviations are the same, + except for the Courier and Times fonts. They are based + on two-letter mnemonics, where upper-case in the first + letter means bold, and upper-case in the second letter + means italic. + + Only the Courier fonts are fixed-width like typewriter + and line printer fonts are. The others are proportional + spaced for improved readability, and consequently, + tabular material will not line up properly with them. + The Courier fonts have a width equal to 0.6 of their + point size, so to fill a line W inches wide with up to N + characters, one must have point size <= (W/(0.6 * N * + 72)) = (W*120)/N pt. Equivalently, with a point size P + pt, the output spacing is 120/P char/inch. + + -H Horizontal page orientation (landscape mode) instead of + vertical page (portrait mode). + + -I# Top margin of # for initial page (for letterheads); if + not specified, it will default to the value given for + the top margin by default or by the -T# command. + + -L# Left margin of #. + + -Mn Multiple column output (n columns). In multiple column + mode, formfeeds cause column breaks instead of page + breaks. + + -N[tb][lcr]n + Number output pages. The number is placed by default in + the center of the top margin, but the margin can be + selected explicitly by t (top) or b (bottom), and the + position of the page number can be further specified by + l (left), c (center), or r (right). If n is given, + start numbering with that value, and otherwise with 1. + If an initial top margin value is given with the -I# + option, numbering will be omitted on the first page if + it is at the top. Pages are unnumbered if this option + is not specified. + + -O[#] Outline pages (and columns) with a # units wide. A + narrow line of 0.4pt width is assumed if # is omitted; + this particular width is what TeX uses in typesetting. + + -P# Font point size (default 10bp). The baseline skip + (spacing between successive character baselines) is + conventionally chosen to be 6/5 of this value, so that + with 10bp type, we have 12bp between lines, or 6 + lines/inch, the same as standard printer output. + + -R# Right margin of #. + + -S[n] special handling (i.e. manual paper feed) for the first + n pages of the output. If N multiple copies are in + effect, then N*n sheets must be fed manually. If n is + omitted, then all pages are to be fed manually. For + example, -S1 is convenient to get the first page of a + letter on letterhead paper fed manually, with remaining + pages from the paper cassette. + + -T# Top margin of #. + + -U Output pages in unsorted (first to last) order instead + of in sorted (page reversed) order; some PostScript + printers have page handlers that stack the paper in this + order. The default is sorted because this is + appropriate for the most common PostScript printer, the + Apple LaserWriter. + +Defaults are: + + -B1.0in -C1 -FCourier -L1.0in -M1 -P10bp -R1.0in -S0 -T1.0in diff --git a/dviware/beebe/utils/lw78.c b/dviware/beebe/utils/lw78.c new file mode 100644 index 0000000000..3f30e01f9b --- /dev/null +++ b/dviware/beebe/utils/lw78.c @@ -0,0 +1,753 @@ +/* -*-C-*- lw78.c */ +/*-->lw78*/ +/**********************************************************************/ +/******************************** lw78 ********************************/ +/**********************************************************************/ +/* <BEEBE.TEX.DVI>LW78.C.27, 29-Oct-87 16:01:55, Edit by BEEBE */ +/* Added DOBE JSYS (dismiss process until output buffer empty) in */ +/* Put_Packet(); this seems to have completely eliminated the I/O error */ +/* conditions previously experienced; they were probably due to ALW+ */ +/* buffer overruns. A straight "COPY foo.ps ttynn:" got only 3 pages */ +/* out before the ALW+ said "I/O error", which is what led me to */ +/* suspect that overrun might be responsible for our ALW+ miserable */ +/* performance. */ +/* <BEEBE.TEX.DVI.NEW>LW78.C.9, 24-Sep-86 22:49:07, Edit by BEEBE */ +/* Add -n (notify user) option */ +/* <BEEBE.TEX.DVI.NEW>LW78.C.5, 19-Aug-86 14:13:53, Edit by BEEBE */ +/* Change check for PostScript header to "%!" and add PShdrfile (-h) */ +/* option support. */ +/* <BEEBE.TEX.DVI>LW78.C.15, 2-Dec-85 18:41:26, Edit by BEEBE */ +/* Add check for PostScript header in Copy_File */ +/* <BEEBE.TEX.DVI>LW78.C.11, 21-Nov-85 12:05:20, Edit by BEEBE */ +/* Add Time_Stamp() and calls thereto for each output line */ +/*********************************************************************** +Apple LaserWriter copy utility. + +Copy one or more 7-bit files in binary mode to an 8-bit file, halting on +input from the output device after printing the contents of the input +buffer. + +Usage: + lw78 [-aAcctFile] [-d] [-en] [-hPShdrfile] [-n] [-r] \ + -oOutfile infile1 [infile2] ... [infilek] + +Letter case on the switch is ignored. + +The optional -a switch specifies a page accounting file to which a +single entry will be made recording a time stampe, username, and page +count for each file processed. + +The -d switch causes a delete and expunge of each file after processing +it. + +The -en switch optionally sends ASCII character n after each file. + +The -h switch defines an optional header file which will be prefixed +to non-PostScript files to allow them to be printed. + +The -n switch requests that each file owner be sent a message when the +file has been printed. + +The -r switch causes the files to be processed in reverse order (useful +because of the reversed stacking of the LaserWriter). + +[24-Sep-86] +***********************************************************************/ + +#include <stdio.h> + +#ifndef KCC_20 +#define KCC_20 0 +#endif + +#ifndef PCC_20 +#define PCC_20 0 +#endif + +#if (KCC_20 | PCC_20) +#else +#undef PCC_20 +#define PCC_20 1 +#endif + +#if KCC_20 +#include <jsys.h> + +/* KCC-20 and PCC-20 have similar enough JSYS interfaces that we just +define values for KCC-20 using PCC-20 names, and copy in definitions of +a few macros from PCC-20's tops20.h */ +#define JSbin BIN +#define JSbkjfn BKJFN +#define JSbout BOUT +#define JSbout BOUT +#define JSclosf CLOSF +#define JSdisms DISMS +#define JSdobe DOBE +#define JSdvchr DVCHR +#define JSgfust GFUST +#define JSgfust GFUST +#define JSjfns JFNS +#define JSmtopr MTOPR +#define JSmtopr MTOPR +#define JSmtopr MTOPR +#define JSopenf OPENF +#define JSsfcoc SFCOC +#define JSsfmod SFMOD +#define JSsibe SIBE +#define JSsout SOUT +#define JSstpar STPAR + +#define DVtty 012 /* terminal */ +#define DV_typ 0777:35-17 /* device type field */ + +#define GFlwr 01 /* get file last writer */ + +#define GJ_fou 01:35-0 /* file is for output use */ +#define GJ_sht 01:35-17 /* short call format */ + +#define MOslw 031 /* set width */ +#define MOsll 033 /* set length */ +#define MOsnt 034 /* set tty non-terminal status */ +#define MOsmn 01 /* no system messages(i.e. suppress) */ + +#define OF_bsz 077:35-5 /* byte size */ +#define OF_rd 01:35-19 /* read */ +#define OF_wr 01:35-20 /* write */ + +#define TT_mff 01:35-1 /* mechanical formfeed present */ +#define TT_tab 01:35-2 /* mechanical tab present */ +#define TT_lca 01:35-3 /* lower case capabilities present */ +#define TT_eco 01:35-24 /* echos on */ +#define TT_dam 03:35-29 /* data mode */ +#define TTbin 00 /* binary */ +#define TT_pgm 01:35-34 /* page mode */ + +#define Absmask(name) ( (1?name) << (0?name) ) /* maybe use this one */ +#define Getmask(name) ( 1?name ) +#define Getshift(name) ( 0?name ) + +#define getfield(var, name) ( (var) >> Getshift(name) & Getmask(name) ) +#define getright(b) ( (b) & 0777777 ) +#define makefield(name, value) ( ((value) & Getmask(name)) << Getshift(name) ) +#define makeword(l, r) ( ((l) << 18) | (r) ) +#define setfield(var, name, value) ( (var) = ((var) & ~Absmask(name)) |\ + makefield(name, value) ) +#else /* must be PCC_20 */ +#include <file.h> +#include <monsym.h> +#endif /* KCC_20 */ + +typedef int BOOLEAN; + +#define ACCOUNTING 1 /* define for accounting code */ + +#define TRUE 1 +#define FALSE 0 + +/* global constants */ + +#define INTERVAL (5*512) /* how often to check input buffer */ +#define MAXERRMSG 512 /* error message size */ +#define MAXFILENAME 144 /* longest filename */ +#define MAXIDLE (10*1000) /* msec to wait for idle status */ +#define MAXLINE 128 /* maximum id line size */ +#define MAXPACKET (5*512) /* packet size to output */ +#define MAXPAUSE (500) /* msec to wait for new byte */ +#define MAXUSERNAME 256 /* longest username */ +#define MAXWAIT (5*1000) /* msec to wait after each file */ + +#define PSHEADER "%!" /* what every PostScript file has */ + +/* global variables */ + +char author[MAXUSERNAME+1]; +BOOLEAN del_flag; /* file delete flag */ +int eof_char; /* end-of-file character */ +char errmsg[MAXERRMSG+1]; /* string from output device */ +int nbytes; /* global input byte count */ +BOOLEAN notify_owner; /* notify file owner when printed */ +int npacket; /* packet[] index */ +int packet[MAXPACKET+1]; /* want space for 1 extra eof_char */ +char timestr[27]; +long timeval; + +#if ACCOUNTING +FILE *acctfile; /* accounting file */ +#endif + +FILE *PShdrfile = (FILE *)NULL; /* PostScript header file */ + +/* Function macro definitions */ + +#define BYTEPTR(x) (0004400000000 | (int)((x)-1)) /* x must be int*, not int */ + /* PCC uses 36-bit bytes */ +#define CTL(c) ((char)(((int)(c)) & 037)) +#define GETBYTE(thejfn) (ac1 = thejfn, (void)jsys(JSbin, acs), ac2) +#define HAVE_INPUT(thejfn) (ac1 = thejfn, (void)jsys(JSsibe, acs), (ac2 > 0)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +/* Procedure macro definitions */ + +#define WAITMS(msec) {ac1 = msec; (void)jsys(JSdisms, acs);} + +/* Function/Procedure declarations */ + +void Copy_File(); +char *ctime(); +char *fgetname(); +int Get_Byte(); +void Get_Msg(); +void Init_Terminal(); +BOOLEAN Input_Error(); +void Put_Packet(); +long time(); +void Time_Stamp(); +void Wait_For_Printer_Ready(); + +/*********************************************************************** +It would be nice to have done this entirely with getc/putc, but alas, +PCC will not open an 8-bit file to a terminal, because it attempts to +issue an illegal SFBSZ% JSYS to set the file byte size, instead of +checking to see if it is a terminal, and then just setting the byte size +in the OPENF% JSYS. We therefore use the JSYS interface routines to do +our own GTJFN%, OPENF%, and BOUT% calls. + +Sigh.... + +***********************************************************************/ + +main(argc,argv) +int argc; +char* argv[]; +{ + BOOLEAN reverse_order; + register int c,k,len; + int fp,outjfn,nfile,kfile; + register FILE* infile; /* 7-bit file */ + + if (argc < 2) + { + (void)fprintf(stderr, + "%%Usage: %s [-aAcctFile] [-d] [-en] [-hPShdrfile] [-n] [-r] \ +-ooutfile infile1 [infile2] ... [infilek]\n", + argv[0]); + exit(1); + } + + del_flag = FALSE; + eof_char = -1; + nfile = 0; + notify_owner = FALSE; + outjfn = -1; + reverse_order = FALSE; + PShdrfile = (FILE *)NULL; + +#if ACCOUNTING + acctfile = (FILE *)NULL; +#endif + + for (k = 1; k < argc; ++k) + { + if (*argv[k] != '-') /* not switch, must be file name */ + nfile++; +#if ACCOUNTING + else if ((strncmp("-a",argv[k],2) == 0) || + (strncmp("-A",argv[k],2) == 0)) + { + if ((acctfile = fopen(argv[k]+2,"a")) == (FILE *)NULL) + { + (void)fprintf(stderr,"?Cannot open accounting file [%s]\n", + argv[k]+2); + exit(1); + } + } +#endif + else if ((strncmp("-d",argv[k],2) == 0) || + (strncmp("-D",argv[k],2) == 0)) + del_flag = TRUE; + else if ((strncmp("-e",argv[k],2) == 0) || + (strncmp("-E",argv[k],2) == 0)) + eof_char = atoi(argv[k]+2); + else if ((strncmp("-h",argv[k],2) == 0) || + (strncmp("-H",argv[k],2) == 0)) + { + if ((PShdrfile = fopen(argv[k]+2,"r")) == (FILE *)NULL) + { + (void)fprintf(stderr,"?Cannot open PShdrfile [%s]\n", + argv[k]+2); + exit(1); + } + } + else if ((strncmp("-n",argv[k],2) == 0) || + (strncmp("-N",argv[k],2) == 0)) + notify_owner = TRUE; + else if ((strncmp("-r",argv[k],2) == 0) || + (strncmp("-R",argv[k],2) == 0)) + reverse_order = TRUE; + else if ((strncmp("-o",argv[k],2) == 0) || + (strncmp("-O",argv[k],2) == 0)) + { + if ((outjfn = _gtjfn(argv[k]+2, makefield(GJ_fou,1) | + makefield(GJ_sht,1))) != -1) /* then got valid jfn */ + { + ac1 = outjfn = getright(outjfn); + ac2 = makefield(OF_bsz, 8); + ac2 = setfield(ac2,OF_wr,1); + ac2 = setfield(ac2,OF_rd,1); + if (jsys(JSopenf, acs) != JSok) + outjfn = -1; /* open failed */ + } + } + else + { + (void)fprintf(stderr,"?Unknown switch [%s]\n",argv[k]); + exit(1); + } + } + if (outjfn == -1) + { + (void)fprintf(stderr,"?Cannot open output file\n"); + exit(1); + } + else /* open okay */ + Init_Terminal(outjfn); + + kfile = 0; + for (k = (reverse_order ? (argc-1) : 1); + (0 < k) && (k < argc); + (reverse_order ? --k : ++k)) + { + if (*argv[k] == '-') + ; /* ignore switch field */ + +#if KCC_20 + else if ((infile = fopen(argv[k],"rb7")) != (FILE*)NULL) +#endif +#if PCC_20 + else if ((fp = open(argv[k], + FATT_RDONLY | FATT_SETSIZE | FATT_BINARY,7)) >= 0) +#endif + { +#if PCC_20 + infile = fdopen(fp,"rb"); +#endif + Wait_For_Printer_Ready(outjfn); + + Time_Stamp(stderr); + (void)fprintf(stderr,"[%d of %d: %s]",++kfile,nfile,argv[k]); + Copy_File(infile,outjfn); + if (notify_owner) + { + ac1 = makeword(GFlwr,jfnof(fileno(infile))); + ac2 = POINT(author); + (void)jsys(JSgfust, acs); + timeval = time((long*)NULL); + strcpy(timestr,ctime(&timeval)); + len = strlen(timestr) - 1; /* ctime has its own \n */ + timestr[len] = '\0'; /* so kill it */ + (void)sprintf(errmsg, + "send %s %s: %s printed on LaserWriter\n", + author,timestr,argv[k]); + (void)system(errmsg); + } + (void)fclose(infile); + + if (del_flag) + { + (void)unlink(argv[k]); /* delete the file */ + (void)fprintf(stderr," [OK - deleted]"); + } + else + (void)fprintf(stderr," [OK]"); + + if (kfile < nfile) /* delay next output to try to */ + WAITMS(MAXWAIT); /* avoid timeout bug! */ + } + else + { + Time_Stamp(stderr); + (void)fprintf(stderr,"?Cannot open input file [%s]",argv[k]); + } + } + + ac1 = outjfn; + (void)jsys(JSclosf, acs); + Time_Stamp(stderr); + (void)fprintf(stderr,"Spooler terminated\n\n\n\n"); +} + +void +Copy_File(infile,outjfn) +register FILE* infile; +register int outjfn; +{ + register int c; + register int k; + char filename[MAXFILENAME+1]; + char idline[MAXLINE+1]; + +#if ACCOUNTING + int page_count; + int *pbyte; +#endif + + (void) + fgets(idline,MAXLINE,infile); /* peek at first line */ + rewind(infile); + + if (strncmp(idline,PSHEADER,strlen(PSHEADER)) != 0) + { + if (PShdrfile != (FILE *)NULL) + { + rewind(PShdrfile); + nbytes = 0; + while ((npacket = read(fileno(PShdrfile),packet,MAXPACKET)) > 0) + { + nbytes += npacket; + Put_Packet(outjfn,packet,npacket); + if (Input_Error(PShdrfile,outjfn)) + return; + } + } + else /* reject non-PostScript file */ + { + k = MAX(2,strlen(idline)); + if (idline[k-1] == '\n') + idline[k-1] = '\0'; /* kill NL */ + if (idline[k-2] == '\r') + idline[k-2] = '\0'; /* kill CR */ + Time_Stamp(stderr); + (void)fprintf(stderr, + "?File may not contain PostScript. First line has\n"); + (void)fprintf(stderr,"\t[%s] instead of [%s] -- file discarded", + idline,PSHEADER); + return; + } + } + +#if ACCOUNTING + page_count = 0; +#endif + + nbytes = 0; +#if (INTERVAL-MAXPACKET) /* copy one at a time */ + npacket = 0; + while ((c = getc(infile)) != EOF) + { +#if ACCOUNTING + if (c == '\f') + page_count++; /* each FF counts one page */ +#endif + if ((!((++nbytes) % INTERVAL)) && Input_Error(infile,outjfn)) + return; + if (npacket >= MAXPACKET) + { + Put_Packet(outjfn,packet,npacket); + npacket = 0; + } + packet[npacket++] = c; + } +#else /* copy in block mode */ + while ((npacket = read(fileno(infile),packet,MAXPACKET)) > 0) + { + nbytes += npacket; + Put_Packet(outjfn,packet,npacket); + +#if ACCOUNTING + if (acctfile != (FILE*)NULL) + { + for ((pbyte = packet, k = npacket); k; (--k, ++pbyte)) + if (*pbyte == '\f') + page_count++; /* each FF counts one page */ + } +#endif + + if (Input_Error(infile,outjfn)) + return; + } + if (npacket < 0) + { + Time_Stamp(stderr); + (void)fprintf(stderr,"?I/O error on input file"); + } + npacket = 0; +#endif + + if (eof_char >= 0) + packet[npacket++] = eof_char; + if (npacket > 0) + + Put_Packet(outjfn,packet,npacket); + +#if ACCOUNTING + if (acctfile != (FILE*)NULL) + { + ac1 = makeword(GFlwr,jfnof(fileno(infile))); + ac2 = POINT(author); + (void)jsys(JSgfust, acs); + Time_Stamp(acctfile); + (void)fprintf(acctfile,"%8d\t%s\t%s", + MAX(1,page_count),author,fgetname(infile,filename)); + } +#endif + +} + +int +Get_Byte(thejfn) /* get byte (maybe waiting) */ +register int thejfn; /* returns EOF if no input */ +{ + if (HAVE_INPUT(thejfn)) + return(GETBYTE(thejfn)); + + WAITMS(MAXPAUSE); + + if (HAVE_INPUT(thejfn)) + return(GETBYTE(thejfn)); + else /* still no input */ + return(EOF); +} + +void +Get_Msg(thejfn) +int thejfn; +{ + register int cm1,cm2,c,k; + + Time_Stamp(stderr); + k = 0; + c = 0; + cm1 = 0; + cm2 = 0; + while (!((cm2 == ']') && (cm1 == '%') && (c == '%'))) /* until "]%%" */ + { /* skip <garbage> and collect %%[ ... ]%% */ + cm2 = cm1; + cm1 = c; + if ((c = Get_Byte(thejfn)) == EOF) + break; /* no input yet */ + if ((cm2 == '%') && (cm1 == '%') && (c == '[')) + { /* restart message collection */ + k = 2; + errmsg[0] = '%'; + errmsg[1] = '%'; + } + if (k < MAXERRMSG) + errmsg[k++] = c; + putc(c,stderr); + } + + + errmsg[k] = '\0'; /* terminate string */ + + while (TRUE) /* "infinite" loop to discard any */ + /* remaining input up to start of */ + /* next message */ + { + + if ((c = Get_Byte(thejfn)) == EOF) + break; /* no input, so exit loop */ + + if (c == '%') /* if start of new message then */ + { /* put character back and exit */ + ac1 = thejfn; + (void)jsys(JSbkjfn,acs); + break; + } + + if (!((c == '\r') || (c == '\n')))/* echo the character */ + putc(c,stderr); /* but discard terminal CR LF */ + } /* to avoid unwanted blank lines */ +} + +void +Init_Terminal(thejfn) +register int thejfn; +{ + ac1 = thejfn; + (void)jsys(JSdvchr, acs); /* get device characteristics */ + + if (getfield(ac2,DV_typ) == DVtty) + { /* have terminal, set its features */ + ac1 = thejfn; + ac2 = MOsnt; + ac3 = MOsmn; /* no system messages */ + (void)jsys(JSmtopr, acs); + + ac1 = thejfn; + ac2 = makefield(TT_mff,1); /* has formfeed */ + ac2 = setfield(ac2,TT_tab,1); /* has tab */ + ac2 = setfield(ac2,TT_lca,1); /* has lowercase */ + ac2 = setfield(ac2,TT_pgm,1); /* has X-on/X-off */ + (void)jsys(JSstpar, acs); + + ac1 = thejfn; + ac2 = makefield(TT_dam,TTbin); /* binary output */ + ac2 = setfield(ac2,TT_eco,0); /* no echo */ + (void)jsys(JSsfmod, acs); + + ac1 = thejfn; + ac2 = 0525252525252; + ac3 = 0525252525252; /* no CTL-char translation */ + (void)jsys(JSsfcoc, acs); + + ac1 = thejfn; + ac2 = MOslw; + ac3 = 0; /* line width = 0 */ + (void)jsys(JSmtopr, acs); + + ac1 = thejfn; + ac2 = MOsll; + ac3 = 0; /* page length = 0 */ + (void)jsys(JSmtopr, acs); + } +} + +BOOLEAN +Input_Error(infile,thejfn) /* return TRUE if error */ +register FILE* infile; +register int thejfn; +{ + register int c; + + if (HAVE_INPUT(thejfn)) + { + Get_Msg(thejfn); + if (strncmp(errmsg,"%%[ Error: timeout;",19) == 0) + { + Time_Stamp(stderr); + (void)fprintf(stderr,"[Error occurred in input byte range %d..%d]", + MAX(0,nbytes-32),nbytes); + Time_Stamp(stderr); + (void)fprintf(stderr, + "Attempting to recover from Apple LaserWriter BUG of \ +timeout error"); + (void)fflush(stderr); + return(FALSE); + } + else if (strncmp(errmsg,"%%[ PrinterError: out of paper",30) == 0) + { + Time_Stamp(stderr); + (void)fprintf(stderr,"\t[Waiting 10 sec for paper]"); + (void)fflush(stderr); + WAITMS(10000); + return(FALSE); + } + else if (strncmp(errmsg,"%%[ PrinterError: no paper tray",31) == 0) + { + Time_Stamp(stderr); + (void)fprintf(stderr,"\t[Waiting 10 sec for paper tray]"); + (void)fflush(stderr); + WAITMS(10000); + return(FALSE); + } + else if (strncmp(errmsg,"%%[ Error: VMerror;",19) == 0) + { + Time_Stamp(stderr); + (void)fprintf(stderr, + "Attempting to recover from Apple LaserWriter BUG of VMerror"); + (void)fflush(stderr); + Wait_For_Printer_Ready(thejfn); + do /* skip to next page or end-of-job */ + { + c = getc(infile); + } + while ((c != EOF) && (c != CTL('D')) && (c != CTL('L'))); + npacket = 0; /* discard last packet */ + return(FALSE); + } + else if (strcmp(errmsg,"%%[ status: idle ]%%") == 0) + return(FALSE); + else + { + Time_Stamp(stderr); + (void)fprintf(stderr,"[Error occurred in input byte range %d..%d]", + MAX(0,nbytes-32),nbytes); + Time_Stamp(stderr); + (void)fprintf(stderr,"[Job flushed]"); + (void)fflush(stderr); + return(TRUE); + } + } + else /* no input yet */ + return(FALSE); +} + +void +Put_Packet(thejfn,packet,n) +int thejfn; +int packet[]; +int n; +{ + ac1 = thejfn; + (void)jsys(JSdobe, acs); /* wait until output buffer empty */ + + ac1 = thejfn; + ac2 = BYTEPTR(packet); + ac3 = -n; /* exact byte count */ + ac4 = 0; + if (n > 0) + { + if (jsys(JSsout, acs) != JSok) + { + Time_Stamp(stderr); + (void)fprintf(stderr,"?SOUT error"); + exit(1); + } + } + +} + +void +Time_Stamp(fp) +FILE *fp; +{ + int k; + + timeval = time((long*)NULL); + strcpy(timestr,ctime(&timeval)); + k = strlen(timestr) - 1; /* ctime has its own \n */ + timestr[k] = '\0'; /* so kill it */ + (void)fprintf(fp,"\n%s\t",timestr); +} + +void +Wait_For_Printer_Ready(thejfn) +register int thejfn; +{ + while (TRUE) /* "infinite" loop */ + { + ac1 = thejfn; + ac2 = CTL('T'); /* CTL-T for status message */ + (void)jsys(JSbout, acs); + + ac1 = thejfn; + (void)jsys(JSdobe, acs); /* wait until output sent */ + + Get_Msg(thejfn); + if (strcmp(errmsg,"%%[ status: idle ]%%") == 0) + break; /* printer ready to go */ + + ac1 = thejfn; + ac2 = CTL('D'); /* CTL-D to terminate previous job */ + (void)jsys(JSbout, acs); + + Time_Stamp(stderr); + (void)fprintf(stderr,"\t[Waiting %d sec]",MAXIDLE/1000); + + WAITMS(MAXIDLE); + } +} + +char * +fgetname(fp,buffer) +FILE *fp; +char buffer[]; +{ + ac1 = POINT(buffer); + ac2 = jfnof(fileno(fp)); + ac3 = 0; + ac4 = 0; + buffer[0] = '\0'; + (void)jsys(JSjfns, acs); + return(buffer); +} diff --git a/dviware/beebe/utils/texidx.c b/dviware/beebe/utils/texidx.c new file mode 100644 index 0000000000..7cbe6a4849 --- /dev/null +++ b/dviware/beebe/utils/texidx.c @@ -0,0 +1,1766 @@ +/* <BEEBE.GNU>TEXID3.C.18, 28-Nov-86 16:28:02, Edit by BEEBE */ +/* Fix incorrect isalnum() comparison in compare_prepared */ +/* <BEEBE.GNU>TEXID3.C.12, 5-Nov-86 12:12:51, Edit by BEEBE */ +/* (1) Modify indexify() to support pagenumber range output */ +/* (2) Complete forward function declarations */ +/* (3) Change type of xmalloc() and xrealloc() from int to char* */ +/* for portability (eventually, they will be void* with ANSI C) */ +/* <BEEBE.GNU>TEXIDX.C.11, 26-Sep-86 18:38:51, Edit by BEEBE */ +/* (1) Change num_keyfields-1 in comparisons to num_keyfields, so this */ +/* works for secondary entries too. */ +/* (2) Add initializations of 0 keyfield[] fields. */ +/* (3) Replace 5 instances of "if (keyfields->xxx)" with */ +/* "if (keyfields[0].xxx)" */ +/* <BEEBE.GNU>TEXIDX.C.3, 20-Aug-86 11:58:19, Edit by BEEBE */ +/* All local changes under control of "tops20" preprocessor symbol.*/ +/* Added #define's for 6-char unique externals. */ +/* Changed union text member to keytext in order to have unique */ +/* structure names (this required a careful global edit). */ +/* Changed struct keyfield to struct keyfld for uniqueness. */ +/* Changed open() call to old PCC form */ + +/* Prepare Tex index dribble output into an actual index. + Copyright (C) Richard M. Stallman 1984 + + Permission is granted to anyone to make or distribute + verbatim copies of this program + provided that the copyright notice and this permission notice are preserved; + and provided that the recipient is not asked to waive or limit his right to + redistribute copies as permitted by this permission notice; + and provided that anyone possessing a machine-executable copy + is granted access to copy the source code, in machine-readable form, + in some reasonable manner. + + Permission is granted to distribute derived works or enhanced versions of + this program under the above conditions with the additional condition + that the entire derivative or enhanced work + must be covered by a permission notice identical to this one. + + Anything distributed as part of a package containing portions derived + from this program, which cannot in current practice perform its function + usefully in the absence of what was derived directly from this program, + is to be considered as forming, together with the latter, + a single work derived from this program, + which must be entirely covered by a permission notice identical to this one + in order for distribution of the package to be permitted. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#include <stdio.h> +#include <ctype.h> + +#define READ read +#define EXIT exit + +#ifdef KCC_20 +#include <file.h> +#define tops20 +#else +#ifdef OS_VAXVMS +#include <file.h> +#undef READ +#define READ vms_read +#undef EXIT +#define EXIT vms_exit +#else +#ifdef OS_ATARI +#else +#ifdef IBM_PC_MICROSOFT +#include <fcntl.h> +#include <io.h> +#else +#include <sys/file.h> +#endif +#endif +#endif +#endif + +#ifdef tops20 + +/* variables */ + +#define lastsecondarylength lstsln +#define lengthptr lengp +#define primarylength prilen +#define compare_field cmpfld +#define compare_general cmpgen +#define compare_prepared cmppre +#define keyfields keyfls +#define lastinitial lstini +#define lastinitial1 lstin1 +#define lastinitiallength lstiln +#define lastprimary lstpri +#define lastprimarylength lstpln +#define lastsecondary lstsec +#define length1 leng1 +#define length2 leng2 +#define secondarylength seclen +#define start_tempcount strtmc +#define tempcount tmpcnt + +/* functions */ + +#define compare_full cmpful +#define find_braced_end fndben +#define find_braced_pos fndbpo +#define find_field fndfld +#define find_pos fndpos +#define flush_tempfiles flstmp +#define maketempname makete +#define merge_direct mrgdir +#define merge_files mrgfil +#define parsefile prsfil +#define pfatal_with_name pfawna +#define readline rdline +#define sort_in_core srtcor +#define sort_offline srtoff +#define writelines writln + +int sys_nerr = 0; +char *sys_errlist[] = {"?"}; + +void +bzero (s,n) +register char *s; +register int n; +{ + while (n--) + *s++ = '\0'; +} + +#endif + +#ifdef VMS +void +bzero (s,n) +register char *s; +register int n; +{ + while (n--) + *s++ = '\0'; +} +#endif + +#ifdef IBM_PC_MICROSOFT +void +bzero (s,n) +register char *s; +register int n; +{ + while (n--) + *s++ = '\0'; +} +#endif + +#ifdef OS_ATARI +void +bzero (s,n) +register char *s; +register int n; +{ + while (n--) + *s++ = '\0'; +} +#endif + +#ifndef L_XTND +#define L_XTND 2 +#endif + +/* When sorting in core, this structure describes one line + and the position and length of its first keyfield. */ + +struct lineinfo + { + char *text; /* The actual text of the line */ + union + { /* The start of the key (for textual comparison) */ + char *keytext; + long number; /* or the numeric value (for numeric comparison) */ + } key; + long keylen; /* Length of key field */ + }; + +/* This structure describes a field to use as a sort key */ + +struct keyfld + { + int startwords; /* # words to skip */ + int startchars; /* and # additional chars to skip, to start */ + /* of field */ + int endwords; /* similar, from beg (or end) of line, to */ + /* find end of field */ + int endchars; + char ignore_blanks; /* Ignore spaces and tabs within the field */ + char fold_case; /* Convert upper case to lower before */ + /* comparing */ + char reverse; /* Compare in reverse order */ + char numeric; /* Parse text as an integer and compare the */ + /* integers */ + char positional; /* Sort according to position within the file */ + char braced; /* Count balanced-braced groupings as fields */ + }; + +/* Vector of keyfields to use */ + +struct keyfld keyfields[3]; + +/* Number of keyfields stored in that vector. */ + +int num_keyfields = 3; + +/* Vector of input file names, terminated with a zero (null pointer) */ + +char **infiles; + +/* Vector of corresponding output file names, or zero meaning default it */ + +char **outfiles; + +/* Length of `infiles' */ + +int num_infiles; + +/* Pointer to the array of pointers to lines being sorted */ + +char **linearray; + +/* The allocated length of `linearray'. */ + +long lines; + +/* Directory to use for temporary files */ + +char *tempdir; + +/* Start of filename to use for temporary files. It starts with a slash. */ + +char *tempbase; + +/* Number of last temporary file. */ + +int tempcount; + +/* Number of last temporary file already deleted. + Temporary files are deleted by `flush_tempfiles' in order of creation. */ + +int last_deleted_tempcount; + +/* During in-core sort, this points to the base of the data block + which contains all the lines of data. */ + +char *text_base; + +/* Additional command switches */ + +int keep_tempfiles; /* Nonzero means do not delete tempfiles -- for */ + /* debugging */ + +/* Forward declarations of functions in this file (alphabetical by function */ +/* name) */ + +int classify_arg(); +int compare_field(); +int compare_full(); +int compare_general(); +int compare_prepared(); +char* concat(); +void decode_command(); +void error(); +void fatal(); +char* find_braced_end(); +char* find_braced_pos(); +char* find_field(); +char* find_pos(); +long find_value(); +void finish_index(); +void flush_tempfiles(); +void indexify(); +void initbuffer(); +void init_index(); +int main(); +char* maketempname(); +int merge_direct(); +int merge_files(); +extern char* mktemp(); +char** parsefile(); +void pfatal_with_name(); +void put_range(); +long readline(); +void sort_in_core(); +void sort_offline(); +char* strchr(); +void writelines(); +char* xmalloc(); +char* xrealloc(); + +#define MAX_IN_CORE_SORT 500000 + +#ifdef KCC_20 +#undef MAX_IN_CORE_SORT +#define MAX_IN_CORE_SORT 4*512*128 +#endif + +#ifdef IBM_PC_MICROSOFT +#undef MAX_IN_CORE_SORT +#define MAX_IN_CORE_SORT 64000 +#endif + +#ifdef PCC_20 +#undef MAX_IN_CORE_SORT +#define MAX_IN_CORE_SORT 512*128 +#endif + +#ifdef OS_ATARI +#undef MAX_IN_CORE_SORT +#define MAX_IN_CORE_SORT 512*128 +long _stksize = 20000L; +#endif + +int +main (argc, argv) + int argc; + char **argv; +{ + int i; + + tempcount = 0; + last_deleted_tempcount = 0; + + /* Describe the kind of sorting to do. */ + /* The first keyfield uses the first braced field and folds case */ + keyfields[0].braced = 1; + keyfields[0].fold_case = 1; + keyfields[0].endwords = -1; + keyfields[0].endchars = -1; + + keyfields[0].ignore_blanks = 0; + keyfields[0].numeric = 0; + keyfields[0].positional = 0; + keyfields[0].reverse = 0; + keyfields[0].startchars = 0; + keyfields[0].startwords = 0; + + /* The second keyfield uses the second braced field, numerically */ + keyfields[1].braced = 1; + keyfields[1].numeric = 1; + keyfields[1].startwords = 1; + keyfields[1].endwords = -1; + keyfields[1].endchars = -1; + + keyfields[1].fold_case = 0; + keyfields[1].ignore_blanks = 0; + keyfields[1].positional = 0; + keyfields[1].reverse = 0; + keyfields[1].startchars = 0; + + /* The third keyfield (which is ignored while discarding duplicates) + compares the whole line */ + keyfields[2].endwords = -1; + keyfields[2].endchars = -1; + + keyfields[2].braced = 0; + keyfields[2].fold_case = 0; + keyfields[2].ignore_blanks = 0; + keyfields[2].numeric = 0; + keyfields[2].positional = 0; + keyfields[2].reverse = 0; + keyfields[2].startchars = 0; + keyfields[2].startwords = 0; + + decode_command (argc, argv); + +#ifdef OS_ATARI + tempbase = mktemp (concat ("\\TXIXXX\.", "", "")); +#else + tempbase = mktemp (concat ("/txiXXXXXX", "", "")); +#endif + + /* Process input files completely, one by one. */ + + for (i = 0; i < num_infiles; i++) + { + int desc; + long ptr; + char *outfile; + +#ifdef VMS + FILE* fp; +#endif + desc = open (infiles[i], 0, 0); + if (desc < 0) pfatal_with_name (infiles[i]); +#ifdef VMS + fp = fdopen(desc,"r"); +#endif + lseek (desc, 0L, L_XTND); +#ifdef VMS + ptr = ftell(fp); +#else +#ifdef OS_ATARI + ptr = ftell(desc); +#else + ptr = tell (desc); +#endif +#endif + close (desc); + + outfile = outfiles[i]; + if (!outfile) + { + outfile = concat (infiles[i], "s", ""); + } + + if (ptr < MAX_IN_CORE_SORT) + /* Sort a small amount of data */ + sort_in_core (infiles[i], ptr, outfile); + else + sort_offline (infiles[i], ptr, outfile); + } + + flush_tempfiles (tempcount); + EXIT (0); +} + +/* This page decodes the command line arguments to set the parameter variables + and set up the vector of keyfields and the vector of input files */ + +void +decode_command (argc, argv) + int argc; + char **argv; +{ + int i; + char **ip; + char **op; + + /* Store default values into parameter variables */ + +#ifdef OS_ATARI + tempdir = "\\TMP"; +#else + tempdir = "/tmp"; +#endif + + keep_tempfiles = 0; + + /* Allocate argc input files, which must be enough. */ + + infiles = (char **) xmalloc (argc * sizeof (char *)); + outfiles = (char **) xmalloc (argc * sizeof (char *)); + ip = infiles; + op = outfiles; + + /* First find all switches that control the default kind-of-sort */ + + for (i = 1; i < argc; i++) + { + int tem = classify_arg (argv[i]); + char c; + char *p; + + if (tem <= 0) + { + *ip++ = argv[i]; + *op++ = 0; + continue; + } + if (tem > 1) + { + if (i + 1 == argc) + fatal ("switch %s given with no argument following it", argv[i]); + else if (!strcmp (argv[i], "-T")) + tempdir = argv[i + 1]; + else if (!strcmp (argv[i], "-o")) + *(op - 1) = argv[i + 1]; + i += tem - 1; + continue; + } + + p = &argv[i][1]; + while (c = *p++) + switch (c) + { + case 'k': + keep_tempfiles = 1; + break; + + default: + fatal ("invalid command switch %c", c); + } + } + + /* Record number of keyfields, terminate list of filenames */ + + num_infiles = ip - infiles; + *ip = 0; +} + +/* Return 0 for an argument that is not a switch; + for a switch, return 1 plus the number of following arguments that the switch + swallows. +*/ + +int +classify_arg (arg) + char *arg; +{ + if (!strcmp (arg, "-T") || !strcmp (arg, "-o")) + return 2; + if (arg[0] == '-') + return 1; + return 0; +} + +/* Create a name for a temporary file */ + +char * +maketempname (count) + int count; +{ + char tempsuffix[10]; + (void)sprintf (tempsuffix, "%d", count); + return concat (tempdir, tempbase, tempsuffix); +} + +/* Delete all temporary files up to the specified count */ + +void +flush_tempfiles (to_count) + int to_count; +{ + if (keep_tempfiles) return; + while (last_deleted_tempcount < to_count) + unlink (maketempname (++last_deleted_tempcount)); +} + + +/* Compare two lines, provided as pointers to pointers to text, + according to the specified set of keyfields */ + +int +compare_full (line1, line2) + char **line1, **line2; +{ + int i; + + /* Compare using the first keyfield; + if that does not distinguish the lines, try the second keyfield; and so + on. */ + + for (i = 0; i < num_keyfields; i++) + { + long length1, length2; + char *start1 = find_field (&keyfields[i], *line1, &length1); + char *start2 = find_field (&keyfields[i], *line2, &length2); + int tem = compare_field (&keyfields[i], + start1, length1, *line1 - text_base, + start2, length2, *line2 - text_base); + if (tem) + { + if (keyfields[i].reverse) + return - tem; + return tem; + } + } + + return 0; /* Lines match exactly */ +} + +/* Compare two lines described by structures + in which the first keyfield is identified in advance. + For positional sorting, assumes that the order of the lines in core + reflects their nominal order. */ + +int +compare_prepared (line1, line2) + struct lineinfo *line1, *line2; +{ + int i; + int tem; + char *text1, *text2; + + /* Compare using the first keyfield, which has been found for us already */ + if (keyfields[0].positional) + { + if (line1->text - text_base > line2->text - text_base) + tem = 1; + else + tem = -1; + } + else if (keyfields[0].numeric) + tem = line1->key.number - line2->key.number; + else + tem = compare_field (keyfields, line1->key.keytext, line1->keylen, 0, + line2->key, line2->keylen, 0); + if (tem) + { + if (keyfields[0].reverse) + return - tem; + return tem; + } + + text1 = line1->text; + text2 = line2->text; + + /* Compare using the second keyfield; + if that does not distinguish the lines, try the third keyfield; and so + on. */ + + for (i = 1; i < num_keyfields; i++) + { + long length1, length2; + char *start1 = find_field (&keyfields[i], text1, &length1); + char *start2 = find_field (&keyfields[i], text2, &length2); + int tem = compare_field (&keyfields[i], + start1, length1, text1 - text_base, + start2, length2, text2 - text_base); + if (tem) + { + if (keyfields[i].reverse) + return - tem; + return tem; + } + } + + return 0; /* Lines match exactly */ +} + +/* Like compare_full but more general. + You can pass any strings, and you can say how many keyfields to use. + `pos1' and `pos2' should indicate the nominal positional ordering of + the two lines in the input. */ + +int +compare_general (str1, str2, pos1, pos2, use_keyfields) + char *str1, *str2; + long pos1, pos2; + int use_keyfields; +{ + int i; + + /* Compare using the first keyfield; + if that does not distinguish the lines, try the second keyfield; and so + on. */ + + for (i = 0; i < use_keyfields; i++) + { + long length1, length2; + char *start1 = find_field (&keyfields[i], str1, &length1); + char *start2 = find_field (&keyfields[i], str2, &length2); + int tem = compare_field (&keyfields[i], start1, length1, pos1, start2, + length2, pos2); + if (tem) + { + if (keyfields[i].reverse) + return - tem; + return tem; + } + } + + return 0; /* Lines match exactly */ +} + +/* Find the start and length of a field in `str' according to `keyfield'. + A pointer to the starting character is returned, and the length + is stored into the int that `lengthptr' points to. */ + +char * +find_field (keyfield, str, lengthptr) + struct keyfld *keyfield; + char *str; + long *lengthptr; +{ + char *start; + char *end; + char *(*fun) (); + + if (keyfield->braced) fun = find_braced_pos; + else fun = find_pos; + + start = ( *fun )(str, keyfield->startwords, keyfield->startchars, + keyfield->ignore_blanks); + if (keyfield->endwords < 0) + { + if (keyfield->braced) + end = find_braced_end (start); + else + { + end = start; + while (*end && *end != '\n') end++; + } + } + else + { + end = ( *fun )(str, keyfield->endwords, keyfield->endchars, 0); + if (end - str < start - str) end = start; + } + *lengthptr = end - start; + return start; +} + +/* Find a pointer to a specified place within `str', + skipping (from the beginning) `words' words and then `chars' chars. + If `ignore_blanks' is nonzero, we skip all blanks + after finding the specified word. */ + +char * +find_pos (str, words, chars, ignore_blanks) + char *str; + int words, chars; + int ignore_blanks; +{ + int i; + char *p = str; + + for (i = 0; i < words; i++) + { + char c; + /* Find next bunch of nonblanks and skip them. */ + while ((c = *p) == ' ' || c == '\t') p++; + while ((c = *p) && c != '\n' && !(c == ' ' || c == '\t')) p++; + if (!*p || *p == '\n') return p; + } + + while (*p == ' ' || *p == '\t') p++; + + for (i = 0; i < chars; i++) + { + if (!*p || *p == '\n') break; + p++; + } + return p; +} + +/* Like find_pos but assumes that each field is surrounded by braces + and that braces within fields are balanced. */ + +char * +find_braced_pos (str, words, chars, ignore_blanks) + char *str; + int words, chars; + int ignore_blanks; +{ + int i; + int bracelevel; + char *p = str; + char c; + + for (i = 0; i < words; i++) + { + bracelevel = 1; + while ((c = *p++) != '{' && c != '\n' && c); + if (c != '{') + return p - 1; + while (bracelevel) + { + c = *p++; + if (c == '{') bracelevel++; + if (c == '}') bracelevel--; + if (c == '\\') c = *p++; /* \ quotes braces and \ */ + if (c == 0 || c == '\n') return p-1; + } + } + + while ((c = *p++) != '{' && c != '\n' && c); + + if (c != '{') + return p-1; + + if (ignore_blanks) + while ((c = *p) == ' ' || c == '\t') p++; + + for (i = 0; i < chars; i++) + { + if (!*p || *p == '\n') break; + p++; + } + return p; +} + +/* Find the end of the balanced-brace field which starts at `str'. + The position returned is just before the closing brace. */ + +char * +find_braced_end (str) + char *str; +{ + int bracelevel; + char *p = str; + char c; + + bracelevel = 1; + while (bracelevel) + { + c = *p++; + if (c == '{') bracelevel++; + if (c == '}') bracelevel--; + if (c == '\\') c = *p++; + if (c == 0 || c == '\n') return p-1; + } + return p - 1; +} + +long +find_value (start, length) + char *start; + long length; +{ + while (length != 0L) { + if (isdigit(*start)) + return atol(start); + length--; + start++; + } + return 0l; +} + +/* Compare two fields (each specified as a start pointer and a character count) + according to `keyfield'. The sign of the value reports the relation between + the fields */ + +int +compare_field (keyfield, start1, length1, pos1, start2, length2, pos2) + struct keyfld *keyfield; + char *start1; + long length1; + long pos1; + char *start2; + long length2; + long pos2; +{ + if (keyfields[0].positional) + { + if (pos1 > pos2) + return 1; + else + return -1; + } + if (keyfield->numeric) + { + long value = find_value (start1, length1) - find_value (start2, length2); + if (value > 0) return 1; + if (value < 0) return -1; + return 0; + } + else + { + char *p1 = start1; + char *p2 = start2; + char *e1 = start1 + length1; + char *e2 = start2 + length2; + + int fold_case = keyfield->fold_case; + + while (1) + { + char c1, c2; + + if (p1 == e1) c1 = 0; + else c1 = *p1++; + if (p2 == e2) c2 = 0; + else c2 = *p2++; + + /* Ignore case of both if desired */ + + if (fold_case) + { + if (c1 >= 'A' && c1 <= 'Z') c1 = c1 + 040; + if (c2 >= 'A' && c2 <= 'Z') c2 = c2 + 040; + } + + /* Actually compare */ + + /* Anything but a letter or digit is less than any letter or digit */ + if ((isalnum (c1) == 0) != (isalnum (c2) == 0)) + return (isalnum (c1)) ? 1 : -1; + if (c1 != c2) return c1 - c2; + if (!c1) break; + } + return 0; + } +} + +/* A `struct linebuffer' is a structure which holds a line of text. + `readline' reads a line from a stream into a linebuffer + and works regardless of the length of the line. */ + +struct linebuffer + { + long size; + char *buffer; + }; + +/* Initialize a linebuffer for use */ + +void +initbuffer (linebuffer) + struct linebuffer *linebuffer; +{ + linebuffer->size = 200; + linebuffer->buffer = (char *) xmalloc (200); +} + +/* Read a line of text from `stream' into `linebuffer'. + Return the length of the line. */ + +long +readline (linebuffer, stream) + struct linebuffer *linebuffer; + FILE *stream; +{ + char *buffer = linebuffer->buffer; + char *p = linebuffer->buffer; + char *end = p + linebuffer->size; + + while (1) + { + int c = getc (stream); + if (p == end) + { + buffer = (char *) xrealloc (buffer, linebuffer->size *= 2); + p += buffer - linebuffer->buffer; + end += buffer - linebuffer->buffer; + linebuffer->buffer = buffer; + } + if (c < 0 || c == '\n') + { + *p = 0; + break; + } + *p++ = c; + } + + return p - buffer; +} + +/* Sort the input files together when they are too big to sort in core */ + +void +sort_offline (infile, nfiles, total, outfile) + char *infile; + long total; + char *outfile; +{ + int ntemps = 2 * (total + MAX_IN_CORE_SORT - 1) / MAX_IN_CORE_SORT; /* More + than enough */ + char **tempfiles = (char **) xmalloc (ntemps * sizeof (char *)); + FILE *istream = fopen (infile, "r"); + int i; + struct linebuffer lb; + long linelength; + + initbuffer (&lb); + + /* Read in one line of input data. */ + + linelength = readline (&lb, istream); + + /* Split up the input into `ntemps' temporary files, or maybe fewer, + and put the new files' names into `tempfiles' */ + + for (i = 0; i < ntemps; i++) + { + char *outname = maketempname (++tempcount); + FILE *ostream = fopen (outname, "w"); + long tempsize = 0; + + if (!ostream) pfatal_with_name (outname); + tempfiles[i] = outname; + + /* Copy lines into this temp file as long as it does not make file "too + big" or until there are no more lines. */ + + while (tempsize + linelength + 1 <= MAX_IN_CORE_SORT) + { + tempsize += linelength + 1; + fputs (lb.buffer, ostream); + putc ('\n', ostream); + + /* Read another line of input data. */ + + linelength = readline (&lb, istream); + if (!linelength && feof (istream)) break; + } + fclose (ostream); + if (feof (istream)) break; + } + + free (lb.buffer); + + /* Record number of temp files we actually needed. */ + + ntemps = i; + + /* Sort each tempfile into another tempfile. + Delete the first set of tempfiles and put the names of the second into + `tempfiles' */ + + for (i = 0; i < ntemps; i++) + { + char *newtemp = maketempname (++tempcount); + sort_in_core (&tempfiles[i], 1, MAX_IN_CORE_SORT, newtemp); + if (!keep_tempfiles) + unlink (tempfiles[i]); + tempfiles[i] = newtemp; + } + + /* Merge the tempfiles together and indexify */ + + merge_files (tempfiles, ntemps, outfile); +} + +/* Sort `infile', whose size is `total', + assuming that is small enough to be done in-core, + then indexify it and send the output to `outfile' (or to stdout). */ + +void +sort_in_core (infile, total, outfile) + char *infile; + long total; + char *outfile; +{ + char **nextline; + char *data = (char *) xmalloc (total + 1); + char *file_data; + long file_size; + FILE *ostream = stdout; + struct lineinfo *lineinfo; + + /* Read the contents of the file into the moby array `data' */ + + int desc = open (infile, 0, 0); + + if (desc < 0) + fatal ("failure reopening %s", infile); + file_size = READ (desc, data, total); + file_data = data; + data[file_size] = 0; + + close (desc); + + /* Sort routines want to know this address */ + + text_base = data; + + /* Create the array of pointers to lines, with a default size frequently + enough. */ + + lines = total / 50; + if (!lines) lines = 2; + linearray = (char **) xmalloc (lines * sizeof (char *)); + + /* `nextline' points to the next free slot in this array. + `lines' is the allocated size. */ + + nextline = linearray; + + /* Parse the input file's data, and make entries for the lines. */ + + nextline = parsefile (infile, nextline, file_data, file_size); + + /* Sort the lines */ + + /* If we have enough space, find the first keyfield of each line in advance. + Make a `struct lineinfo' for each line, which records the keyfield + as well as the line, and sort them. */ + + lineinfo = (struct lineinfo *) malloc ((nextline - linearray) * sizeof + (struct lineinfo)); + + if (lineinfo) + { + struct lineinfo *lp; + char **p; + + for (lp = lineinfo, p = linearray; p != nextline; lp++, p++) + { + lp->text = *p; + lp->key.keytext = find_field (keyfields, *p, &lp->keylen); + if (keyfields[0].numeric) + lp->key.number = find_value (lp->key.keytext, lp->keylen); + } + + qsort (lineinfo, nextline - linearray, sizeof (struct lineinfo), + compare_prepared); + + for (lp = lineinfo, p = linearray; p != nextline; lp++, p++) + *p = lp->text; + + free (lineinfo); + } + else + qsort (linearray, nextline - linearray, sizeof (char *), compare_full); + + /* Open the output file */ + + if (outfile) + { + ostream = fopen (outfile, "w"); + if (!ostream) + pfatal_with_name (outfile); + } + + writelines (linearray, nextline - linearray, ostream); + if (outfile) fclose (ostream); + + free (linearray); + free (data); +} + +/* Parse an input string in core into lines. + `data' is the input string, and `size' is its length. + Data goes in `linearray' starting at `nextline'. + The value returned is the first entry in `linearray' still unused. */ + +char ** +parsefile (filename, nextline, data, size) + char *filename; + char **nextline; + char *data; + long size; +{ + char *p, *end; + char **line = nextline; + + p = data; + end = p + size; + *end = 0; + + while (p != end) + { + *line = p; + while (*p && *p != '\n') p++; + if (p != end) p++; + + /* This feature will be installed later. */ + /* if (discard_empty_lines && p == *line + 1) continue; */ + + line++; + if (line == linearray + lines) + { + char **old = linearray; + linearray = (char **) xrealloc (linearray, sizeof (char *) * (lines + *= 4)); + line += linearray - old; + } + } + + return line; +} + +/* Indexification is a filter applied to the sorted lines + as they are being written to the output file. + Multiple entries for the same name, with different page numbers, + get combined into a single entry with multiple page numbers. + The first braced field, which is used for sorting, is discarded. + However, its first character is examined, folded to lower case, + and if it is different from that in the previous line fed to us + a \initial line is written with one argument, the new initial. + + If an entry has four braced fields, then the second and third + constitute primary and secondary names. + In this case, each change of primary name + generates a \primary line which contains only the primary name, + and in between these are \secondary lines which contain + just a secondary name and page numbers. +*/ + +/* The last primary name we wrote a \primary entry for. + If only one level of indexing is being done, this is the last name seen */ +char *lastprimary; +int lastprimarylength; /* Length of storage allocated for lastprimary */ + +/* Similar, for the secondary name. */ +char *lastsecondary; +int lastsecondarylength; + +/* Zero if we are not in the middle of writing an entry. + One if we have written the beginning of an entry but have not + yet written any page numbers into it. + Greater than one if we have written the beginning of an entry + plus at least one page number. */ +int pending; + +/* The initial (for sorting purposes) of the last primary entry written. + When this changes, a \initial {c} line is written */ + +char * lastinitial; + +int lastinitiallength; + +/* When we need a string of length 1 for the value of lastinitial, + store it here. */ + +char lastinitial1[2]; + +/* Initialize static storage for writing an index */ + +void +init_index () +{ + pending = 0; + lastinitial = lastinitial1; + lastinitial1[0] = 0; + lastinitial1[1] = 0; + lastinitiallength = 0; + lastprimarylength = 100; + lastprimary = (char *) xmalloc (lastprimarylength + 1); + bzero (lastprimary, lastprimarylength + 1); + lastsecondarylength = 100; + lastsecondary = (char *) xmalloc (lastsecondarylength + 1); + bzero (lastsecondary, lastsecondarylength + 1); +} + +static int pnr_begin = -1; /* current page number range */ +static int pnr_end = -1; + +/* Indexify. Merge entries for the same name, + insert headers for each initial character, etc. */ + +void +indexify (line, ostream) + char *line; + FILE *ostream; +{ + char *primary, *secondary, *pagenumber; + int number; + int primarylength, secondarylength, pagelength; + int nosecondary; + int initiallength; + char *initial; + char initial1[2]; + register char *p; + + /* First, analyze the parts of the entry fed to us this time */ + + p = find_braced_pos (line, 0, 0, 0); + if (*p == '{') + { + initial = p; + /* Get length of inner pair of braces starting at p, + including that inner pair of braces. */ + initiallength = find_braced_end (p + 1) + 1 - p; + } + else + { + initial = initial1; + initial1[0] = *p; + initial1[1] = 0; + initiallength = 1; + + if (initial1[0] >= 'a' && initial1[0] <= 'z') + initial1[0] -= 040; + } + + pagenumber = find_braced_pos (line, 1, 0, 0); + pagelength = find_braced_end (pagenumber) - pagenumber; + if (pagelength == 0) + abort (); + + primary = find_braced_pos (line, 2, 0, 0); + primarylength = find_braced_end (primary) - primary; + + secondary = find_braced_pos (line, 3, 0, 0); + nosecondary = !*secondary; + if (!nosecondary) + secondarylength = find_braced_end (secondary) - secondary; + + /* If the primary is different from before, make a new primary entry */ + if (strncmp (primary, lastprimary, primarylength)) + { + /* Close off current secondary entry first, if one is open */ + if (pending) + { + put_range(ostream); + fputs ("}\n", ostream); + pending = 0; + } + + /* If this primary has a different initial, include an entry for the + initial */ + if (initiallength != lastinitiallength || strcmp (initial, lastinitial)) + { + (void)fprintf (ostream, "\n\n\\initial {"); + if (strchr("^~\\",*initial) != (char*)NULL) + (void)fprintf(ostream,"\verb|%c|",*initial); + else + { + if (strchr("&$#%_{}",*initial) != (char*)NULL) + putc('\\',ostream); /* protect special characters */ + fwrite (initial, 1, initiallength, ostream); + } + (void)fprintf (ostream, "}\n", initial); + if (initial == initial1) + { + lastinitial = lastinitial1; + *lastinitial1 = *initial1; + } + else + { + lastinitial = initial; + } + lastinitiallength = initiallength; + } + + /* Make the entry for the primary. */ + if (nosecondary) + fputs ("\\entry {", ostream); + else + fputs ("\\primary {", ostream); + fwrite (primary, primarylength, 1, ostream); + if (nosecondary) + { + fputs ("}{", ostream); + pending = 1; + } + else + fputs ("}\n", ostream); + + /* Record name of most recent primary */ + if (lastprimarylength < primarylength) + { + lastprimarylength = primarylength + 100; + lastprimary = (char *) xrealloc (lastprimary, + 1 + lastprimarylength); + } + strncpy (lastprimary, primary, primarylength); + lastprimary[primarylength] = 0; + + /* There is no current secondary within this primary, now */ + lastsecondary[0] = 0; + } + + /* Should not have an entry with no subtopic following one with a subtopic */ + + if (nosecondary && *lastsecondary) + error ("entry %s follows an entry with a secondary name", line); + + /* Start a new secondary entry if necessary */ + if (!nosecondary && strncmp (secondary, lastsecondary, secondarylength)) + { + if (pending) + { + put_range(ostream); + fputs ("}\n", ostream); + pending = 0; + } + + /* Write the entry for the secondary. */ + fputs ("\\secondary {", ostream); + fwrite (secondary, secondarylength, 1, ostream); + fputs ("}{", ostream); + pending = 1; + + /* Record name of most recent secondary */ + if (lastsecondarylength < secondarylength) + { + lastsecondarylength = secondarylength + 100; + lastsecondary = (char *) xrealloc (lastsecondary, + 1 + lastsecondarylength); + } + strncpy (lastsecondary, secondary, secondarylength); + lastsecondary[secondarylength] = 0; + } + + /* Here to add one more page number to the current entry */ + if (isdigit(*pagenumber)) /* then non-negative arabic page + number */ + { + number = atoi(pagenumber); + if (pnr_begin < 0) /* start new range */ + { + pnr_begin = number; + pnr_end = number; + } + else if (number == (pnr_end + 1)) /* extend range */ + pnr_end = number; + else /* output current range and start new one */ + { + put_range(ostream); + pnr_begin = number; + pnr_end = number; + pending++; + } + } + else /* non-arabic page number (probably roman numerals) */ + { + if (pnr_begin >= 0) /* output current page range */ + { + put_range(ostream); + pending++; + } + if (pending > 1) + fputs (", ", ostream); /* Punctuate first, if this is not the first */ + pending++; + fwrite (pagenumber, pagelength, 1, ostream); + } +} + +void +put_range(ostream) /* output current page number range */ + FILE *ostream; +{ + if (pnr_begin > 0) /* output pending range */ + { + if (pending > 1) + fputs (", ", ostream); /* Punctuate first, this is not the first */ + if (pnr_end > pnr_begin) + (void)fprintf(ostream,"%d--%d",pnr_begin,pnr_end); + else + (void)fprintf(ostream,"%d",pnr_begin); + pnr_begin = -1; + pnr_end = -1; + } +} + + +/* Close out any unfinished output entry */ + +void +finish_index (ostream) + FILE *ostream; +{ + put_range(ostream); + if (pending) + fputs ("}\n", ostream); + free (lastprimary); + free (lastsecondary); +} + +/* Copy the lines in the sorted order. + Each line is copied out of the input file it was found in. */ + +void +writelines (linearray, nlines, ostream) + char **linearray; + int nlines; + FILE *ostream; +{ + char **stop_line = linearray + nlines; + char **next_line; + + init_index (); + + /* Output the text of the lines, and free the buffer space */ + + for (next_line = linearray; next_line != stop_line; next_line++) + { + /* If -u was specified, output the line only if distinct from previous + one. */ + if (next_line == linearray + /* Compare previous line with this one, using only the explicitly + specd keyfields */ + || compare_general (*(next_line - 1), *next_line, 0L, 0L, + num_keyfields)) + { + char *p = *next_line; + char c; + while ((c = *p++) && c != '\n'); + *(p-1) = 0; + indexify (*next_line, ostream); + } + } + + finish_index (ostream); +} + +/* Assume (and optionally verify) that each input file is sorted; + merge them and output the result. + Returns nonzero if any input file fails to be sorted. + + This is the high-level interface that can handle an unlimited number of + files. */ + +#define MAX_DIRECT_MERGE 10 + +int +merge_files (infiles, nfiles, outfile) + char **infiles; + int nfiles; + char *outfile; +{ + char **tempfiles; + int ntemps; + int i; + int value = 0; + int start_tempcount = tempcount; + + if (nfiles <= MAX_DIRECT_MERGE) + return merge_direct (infiles, nfiles, outfile); + + /* Merge groups of MAX_DIRECT_MERGE input files at a time, + making a temporary file to hold each group's result. */ + + ntemps = (nfiles + MAX_DIRECT_MERGE - 1) / MAX_DIRECT_MERGE; + tempfiles = (char **) xmalloc (ntemps * sizeof (char *)); + for (i = 0; i < ntemps; i++) + { + int nf = MAX_DIRECT_MERGE; + if (i + 1 == ntemps) + nf = nfiles - i * MAX_DIRECT_MERGE; + tempfiles[i] = maketempname (++tempcount); + value |= merge_direct (&infiles[i * MAX_DIRECT_MERGE], nf, tempfiles[i]); + } + + /* All temporary files that existed before are no longer needed + since their contents have been merged into our new tempfiles. + So delete them. */ + flush_tempfiles (start_tempcount); + + /* Now merge the temporary files we created. */ + + merge_files (tempfiles, ntemps, outfile); + + free (tempfiles); + + return value; +} + +/* Assume (and optionally verify) that each input file is sorted; + merge them and output the result. + Returns nonzero if any input file fails to be sorted. + + This version of merging will not work if the number of + input files gets too high. Higher level functions + use it only with a bounded number of input files. */ + +int +merge_direct (infiles, nfiles, outfile) + char **infiles; + int nfiles; + char *outfile; +{ + struct linebuffer *lb1, *lb2; + struct linebuffer **thisline, **prevline; + FILE **streams; + int i; + int nleft; + int lossage = 0; + int *file_lossage; + struct linebuffer *prev_out = 0; + FILE *ostream = stdout; + + if (outfile) + ostream = fopen (outfile, "w"); + if (!ostream) pfatal_with_name (outfile); + + init_index (); + + if (nfiles == 0) + { + if (outfile) + fclose (ostream); + return 0; + } + + /* For each file, make two line buffers. + Also, for each file, there is an element of `thisline' + which points at any time to one of the file's two buffers, + and an element of `prevline' which points to the other buffer. + `thisline' is supposed to point to the next available line from the file, + while `prevline' holds the last file line used, + which is remembered so that we can verify that the file is properly + sorted. */ + + /* lb1 and lb2 contain one buffer each per file */ + lb1 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer)); + lb2 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer)); + + /* thisline[i] points to the linebuffer holding the next available line in + file i, or is zero if there are no lines left in that file. */ + thisline = (struct linebuffer **) xmalloc (nfiles * sizeof (struct + linebuffer *)); + /* prevline[i] points to the linebuffer holding the last used line from file + i. This is just for verifying that file i is properly sorted. */ + prevline = (struct linebuffer **) xmalloc (nfiles * sizeof (struct + linebuffer *)); + /* streams[i] holds the input stream for file i. */ + streams = (FILE **) xmalloc (nfiles * sizeof (FILE *)); + /* file_lossage[i] is nonzero if we already know file i is not properly + sorted. */ + file_lossage = (int *) xmalloc (nfiles * sizeof (int)); + + /* Allocate and initialize all that storage */ + + for (i = 0; i < nfiles; i++) + { + initbuffer (&lb1[i]); + initbuffer (&lb2[i]); + thisline[i] = &lb1[i]; + prevline[i] = &lb2[i]; + file_lossage[i] = 0; + streams[i] = fopen (infiles[i], "r"); + if (!streams[i]) + pfatal_with_name (infiles[i]); + + (void)readline (thisline[i], streams[i]); + } + + /* Keep count of number of files not at eof */ + nleft = nfiles; + + while (nleft) + { + struct linebuffer *best = 0; + struct linebuffer *exch; + int bestfile = -1; + int i; + + /* Look at the next avail line of each file; choose the least one. */ + + for (i = 0; i < nfiles; i++) + { + if (thisline[i] && + (!best || + 0 < compare_general (best->buffer, thisline[i]->buffer, + (long) bestfile, (long) i, num_keyfields))) + { + best = thisline[i]; + bestfile = i; + } + } + + /* Output that line, unless it matches the previous one and we don't + want duplicates */ + + if (!(prev_out && + !compare_general (prev_out->buffer, best->buffer, 0L, 1L, + num_keyfields))) + indexify (best->buffer, ostream); + prev_out = best; + + /* Now make the line the previous of its file, and fetch a new line from + that file */ + + exch = prevline[bestfile]; + prevline[bestfile] = thisline[bestfile]; + thisline[bestfile] = exch; + + while (1) + { + /* If the file has no more, mark it empty */ + + if (feof (streams[bestfile])) + { + thisline[bestfile] = 0; + nleft--; /* Update the number of files still not empty */ + break; + } + (void)readline (thisline[bestfile], streams[bestfile]); + if (thisline[bestfile]->buffer[0] || !feof (streams[bestfile])) break; + } + } + + finish_index (ostream); + + /* Free all storage and close all input streams */ + + for (i = 0; i < nfiles; i++) + { + fclose (streams[i]); + free (lb1[i].buffer); + free (lb2[i].buffer); + } + free (file_lossage); + free (lb1); + free (lb2); + free (thisline); + free (prevline); + free (streams); + + if (outfile) + fclose (ostream); + + return lossage; +} + +/* Print error message and exit. */ + +void +fatal (s1, s2) + char *s1, *s2; +{ + error (s1, s2); + + EXIT (1); +} + +/* Print error message. `s1' is printf control string, `s2' is arg for it. */ + +void +error (s1, s2) + char *s1, *s2; +{ + (void)printf ("texi: "); + (void)printf (s1, s2); + (void)printf ("\n"); +} + +void +pfatal_with_name (name) + char *name; +{ + +#ifdef OS_VAXVMS + extern noshare int errno; + extern noshare int sys_nerr; + extern noshare char *sys_errlist[]; +#else + extern int errno, sys_nerr; + extern char *sys_errlist[]; +#endif + + char *s; + + if (errno < sys_nerr) + s = concat ("", sys_errlist[errno], " for %s"); + else + s = "cannot open %s"; + fatal (s, name); +} + +/* Return a newly-allocated string whose contents concatenate those of s1, s2, + s3. */ + +char * +concat (s1, s2, s3) + char *s1, *s2, *s3; +{ + int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); + char *result = (char *) xmalloc (len1 + len2 + len3 + 1); + + strcpy (result, s1); + strcpy (result + len1, s2); + strcpy (result + len1 + len2, s3); + *(result + len1 + len2 + len3) = 0; + + return result; +} + +/* Like malloc but get fatal error if memory is exhausted. */ + +char* +xmalloc (size) + int size; +{ + char* result = (char *)malloc (size); + if (!result) + fatal ("virtual memory exhausted", 0); + return result; +} + + +char* +xrealloc (ptr, size) + char *ptr; + int size; +{ + char* result = (char *)realloc (ptr, size); + if (!result) + fatal ("virtual memory exhausted", 0); + return result; +} + +#include "strchr.h" diff --git a/dviware/beebe/utils/texidx.hlp b/dviware/beebe/utils/texidx.hlp new file mode 100644 index 0000000000..4d95933cc5 --- /dev/null +++ b/dviware/beebe/utils/texidx.hlp @@ -0,0 +1,183 @@ + TeXIDX - TeX/LaTeX Index Filter + [07-Jan-88] + +TeXIDX (TeXINDEX on Unix systems) is a filter for converting the +index file output of TeX and LaTeX to a form suitable for later +input and generation of an index, with entries sorted by primary +text entries, and within these, sorted by secondary text entries, +and with duplicate page numbers eliminated. Elision of page +ranges is not yet supported. + +TeXIDX expects one or more files of index entries output by TeX +or LaTeX in the forms + +\entry{sort key}{page number}{primary entry} +\entry{sort key}{page number}{primary entry}{secondary entry} + +Several examples are given below. + +TeXIDX is run by + +@TeXIDX file1 file2 ... filen + +and produces output files with the same name, but the letter `s' +appended. Thus `foo.idx' is transformed to `foo.idxs'. + +The output of TeXIDX will contain lines like: + +\initial {c} % before the first topic whose + % initial is c +\entry {topic}{pagelist} % for a topic that is used + % without subtopics +\primary {topic} % for the beginning of a topic + % that is used with subtopics +\secondary {subtopic}{pagelist} % for each subtopic. + +All sorting is by the sort key field ONLY, with letter case +IGNORED. This means that if two primary/secondary fields have +the same leading text, a sort key must be given which includes +both the primary and secondary fields to preserve the correct +order, and this key must be distinguishable from another which +just happens to have a primary string equal to the concatenated +primary and secondary strings of the first. For example, + +\entry{text editing}{18}{text editing} +\entry{text}{20}{text} +\entry{text<TAB>editing}{32}{text}{editing} +\entry{text<TAB>buffering}{57}{text}{buffering} + +will produce correct index entries + + text, 20 + buffering, 57 + editing, 32 + text editing, 37 + +whereas simple juxtaposition of the primary and secondary fields +in the sort keys + +\entry{text editing}{18}{text editing} +\entry{text}{20}{text} +\entry{text editing}{32}{text}{editing} +\entry{text buffering}{57}{text}{buffering} + +will produce INCORRECT ordering: + + text, 20 + buffering, 57 + text editing, 18 + editing, 32 + +Any ASCII character which collates below space (dec. 32) will do +as a separator between the primary and secondary fields in the +sort key, but the only one that TeX will accept as input without +modification of character \catcode's is <TAB> (dec. 9). +Therefore, make sure that <TAB> characters are not used in the +primary or secondary text values themselves. + +In order for TeXIDX to be used, you must first provide TeX/LaTeX +with definitions of macros that create the output index file; +neither the TeX manmac macros (p. 423ff of the TeXbook) or the +LaTeX \index{} macros (p. 78, p. 189 of the LaTeX User's Guide +and Reference Manual) are suitable. Once TeXIDX has been run, +you must have definitions of \initial, \entry, \primary, and +\secondary so that the index file can be processed. + +Since these definitions only have to be done once, they have been +put in a LaTeX style file which can be automatically included in +the documentstyle option list: + +\documentstyle[gnuindex]{...} + +This will cause the file texinputs:gnuindex.sty to be read by +LaTeX at startup. This file defines \initial, \entry, \primary, +and \secondary, so that LaTeX can format your index, and provides +you with two macros to use to generate index entries. + +\INDEX{sortkey}{primary} +\SUBINDEX{sortkey}{primary}{secondary} + +For \SUBINDEX{}, the {secondary} field is automatically appended +to the sort key, but separated from it by an ASCII <TAB> +character; in most cases, this makes it possible to use the just +primary field as the sort key too, as long as the primary and +secondary fields do not have special characters, font changes, or +TeX control sequences embedded in them. + +To save some typing, and reduce the chances of error, you will +probably want to produce your own macros which reference these. +Here are two useful ones: + +\newcommand{\X}[1]{{#1}\INDEX{#1}{#1}} +\newcommand{\XX}[2]{{#1}\SUBINDEX{#1}{#1}{#2}} + +You can then type + + \X{gnats and gnus} + +to get the phrase `gnats and gnus' into the document text, as +well as into the index both as a sort key, and as a primary +field. Typing + + This chapter will discuss the cooking of + \XX{gnats and gnus}{cooking directions} ... + +will put the same phrase `gnats and gnus' into the document text, +but the index will get the sort key `gnats and gnus<TAB>cooking +directions', a primary field `gnats and gnus', and a secondary +field `cooking directions'. You would use \XX{} instead of \X{} +when you wanted to make the index entry more precise, but only +have the primary string in the running text. + +For those occasions when you need special fonts, or TeX control +sequences, in your index, you can still use \INDEX{} and +\SUBINDEX{} directly: + + \INDEX{LaTeX's gnus}{\string\LaTeX{}'s gnus} + \INDEX{gnats}{\string\sc GNATS} + +Note the use of `\string' in front of each control sequence--it +prevents the expansion of the following control sequence. That +way, your index file will contain the words `\LaTeX' and `\sc', +instead of the messy expansions of these. + +In summary, then, here is what your `foo.ltx' file might look like: + + \documentstyle[gnuindex]{...} + \makeindex + \begin{document} + ... + \begin{theindex} + \input{foo.idxs} % Change this to whatever your file is called + \end{theindex} + \end{document} + +To process it, you need to run LaTeX twice and TeXIDX once: + +@LaTeX foo.ltx +@TeXIDX foo.idx +@LaTeX foo.ltx + +TeXIDX was written by Richard Stallman as part of the GNU Project +at the Free Software Foundation in Cambridge, MA, and is in the +public domain (though subject to a liberal copyright contained in +the source file). It uses no proprietary software and should be +implementable with most C compilers on micros, minis, and +mainframes. In particular, all sorting is done with its own +code, rather than relying on system or library sorting routines. +The sorting is done in-core when possible, and otherwise, +automatically spills to scratch files which are individually +sorted, then merged. + +Nelson H.F. Beebe +Center for Scientific Computing +South Physics Building +University of Utah +Salt Lake City, UT 84112 + Tel: (801) 581-5254 + +Net mail: + BEEBE@SCIENCE.UTAH.EDU {preferred} + BEEBE@CS.UTAH.EDU + BEEBE@CTRSCI.UTAH.EDU + BEEBEN@RUAC.UTAH.EDU diff --git a/dviware/beebe/utils/unhd.c b/dviware/beebe/utils/unhd.c new file mode 100644 index 0000000000..456adec9f5 --- /dev/null +++ b/dviware/beebe/utils/unhd.c @@ -0,0 +1,55 @@ +/*********************************************************************** +Process a file output by hd back into an 8-bit binary file. Characters +out of the range 040..0176 are ignored. + +Usage: + unhd infile outfile + +The open mode flags passed to fopen() are likely to require modification +outside of TOPS-20. + +[15-Aug-87] +***********************************************************************/ + +#include <stdio.h> +#define COMMENT '!' /* marks start of comment to end-of-line */ + +void +main(argc,argv) +int argc; +char* argv[]; +{ + FILE* in; + FILE* out; + register int c; + + if (argc < 2) + { + (void)fprintf(stderr,"Usage: unhd infile outfile"); + exit(0); + } + if ((in = fopen(argv[1],"rb")) == (FILE*)NULL) + exit(1); + if ((out = fopen(argv[2],"wb8")) == (FILE*)NULL) + exit(2); + + while ((c = getc(in)) != EOF) + { + if (c == COMMENT) + { + while (((c = getc(in)) != EOF) && (c != '\n')) + /* flush comment */; + } + else if (c > 037) + { + if (c == '\\') + { + c = getc(in) - '0'; + c = (c << 3) + (getc(in) - '0'); + c = (c << 3) + (getc(in) - '0'); + } + putc(c,out); + } + } + exit(0); +} diff --git a/dviware/beebe/utils/vms/streamlf.fdl b/dviware/beebe/utils/vms/streamlf.fdl new file mode 100644 index 0000000000..be33609a40 --- /dev/null +++ b/dviware/beebe/utils/vms/streamlf.fdl @@ -0,0 +1,13 @@ +IDENT "17-APR-1987 15:13:54 VAX/VMS ANALYZE/RMS_FILE Utility" + +SYSTEM + SOURCE VAX/VMS + +FILE + ORGANIZATION sequential + +RECORD + BLOCK_SPAN yes + CARRIAGE_CONTROL carriage_return + FORMAT stream_lf + diff --git a/dviware/beebe/utils/vms/variable.fdl b/dviware/beebe/utils/vms/variable.fdl new file mode 100644 index 0000000000..3527be3444 --- /dev/null +++ b/dviware/beebe/utils/vms/variable.fdl @@ -0,0 +1,13 @@ +IDENT "17-APR-1987 17:20:30 VAX/VMS ANALYZE/RMS_FILE Utility" + +SYSTEM + SOURCE VAX/VMS + +FILE + ORGANIZATION sequential + +RECORD + BLOCK_SPAN yes + CARRIAGE_CONTROL carriage_return + FORMAT variable + diff --git a/dviware/beebe/utils/ws87.pas b/dviware/beebe/utils/ws87.pas new file mode 100644 index 0000000000..2bf88fa988 --- /dev/null +++ b/dviware/beebe/utils/ws87.pas @@ -0,0 +1,45 @@ +PROGRAM Ws87; + { + ********************************************************************** + Copy an 8-bit file to a 7-bit file, turning characters with bit 8 + set into 4-character octal escape sequences \nnn. This is useful in + analyzing WordStar microcomputer word processor files. + + Usage: + + @WS87 + Old 8-bit file: filespec + New 7-bit file: filespec + + [10-Oct-85] + ********************************************************************** + } +VAR + fp8,fp7 : PACKED FILE OF integer; +BEGIN +Rewrite(output,'tty:'); +Write('Old 8-bit file: '); +Reset(fp8,'':@,'/e/b:8'); +Write('New 7-bit file: '); +Rewrite(fp7,'':@,'/e/b:7'); +WHILE NOT Eof(fp8) DO + BEGIN + IF fp8^ > 127 THEN + BEGIN + fp7^ := ord('\'); + Put(fp7); + fp7^ := (fp8^ DIV 64) + ord('0'); + Put(fp7); + fp7^ := ((fp8^ DIV 8) MOD 8) + ord('0'); + Put(fp7); + fp7^ := (fp8^ MOD 8) + ord('0'); + Put(fp7) + END + ELSE + BEGIN + fp7^ := fp8^; + Put(fp7) + END; + Get(fp8) + END; +END. diff --git a/dviware/beebe/utils/wsltex.c b/dviware/beebe/utils/wsltex.c new file mode 100644 index 0000000000..ddfc5442e6 --- /dev/null +++ b/dviware/beebe/utils/wsltex.c @@ -0,0 +1,948 @@ +/* program Wsltex */ + + /* + ******************************************************************** + Copy an 8-bit file to a 7-bit file, turning characters with bit 8 + set into 4-character octal escape sequences \nnn. This is useful in + analyzing WordStar microcomputer word processor files. Many + sequences which can be recognized as doing something useful are + turned into LaTeX command sequences. Comments below describe the + sequences which are recognized and translated. + + Usage: + + @WSLTEX WordStar_inputfile >LaTeX_outputfile + + Remarks: + This program was converted automatically from Pascal to C by James + Peterson's Pascal-to-C translator from Carnegie-Mellon University. + Hand editing was required on all I/O references, which are not + converted satisfactorily (e.g. the Pascal file variable points to + the current input character returned by get(), while in C, one must + explicitly save the result of getc()). Comment and type declaration + formatting where also rearranged by hand. Defined constants were + changed to upper-case following the usual convenient C convention of + visible differences between variables and constants, and functions + and macros. + + The conversion of a test 188K Ph.D. thesis file produced identical + results with both versions. Pascal compilation was much faster than + the PCC compiler. The conversion time with the Pascal version was + 15.5 sec. In the C version using putc(), it was 25.1 sec; changing + putc() to use of write() with large buffers further reduced the time + to 21.2 sec. + + [21-Dec-85] conversion from Pascal + [11-Oct-85] original version + ******************************************************************** + */ + + +#include <stdio.h> +#include <file.h> /* for TOPS-20 open magic */ + +/* One of OS_UNIX or OS_TOPS20 should be defined at compile time. */ +/* Default is OS_UNIX */ + +#ifndef OS_TOPS20 +#define OS_TOPS20 0 +#define OS_UNIX 1 +#else +#define OS_UNIX 0 +#endif + +#if OS_UNIX +#define WRITELN(fp) putc('\n',fp) +#else +#define WRITELN(fp) {putc('\r',fp);putc('\n',fp);} +#endif + +#if OS_TOPS20 +#define EMPTY_BUFFER {if (the_next > 0) \ + _write(fileno(LaTeX_file),the_buffer,the_next);\ + the_next = 0;} +#else +#define EMPTY_BUFFER {if (the_next > 0) \ + write(fileno(LaTeX_file),the_buffer,the_next);\ + the_next = 0;} +#endif + +typedef int BOOLEAN; + +#define FALSE 0 + +#define TRUE 1 + +#define NUL '\0' + +#define BEL '\07' + +#define CR '\r' + +#define ESC '\033' + +#define FF '\f' + +#define HT '\t' + +#define LF '\n' + +#define MAXRING 256 /* limit for character ring */ + +#define MAXSPECIAL 100 /* limit for warning when special + strings (underline, bold, etc) exceed + this length */ + +#define MAXBUF 16384 /* large buffer for I/O efficiency */ + +#define UNSET 0x8000 /* use most-negative 16-bit integer */ + +FILE *WordStar_file; /* 8-bit input file */ +FILE *LaTeX_file; /* 7-bit or 8-bit output file */ + +char *the_buffer; /* the output buffer (malloc()'ed) */ +int the_next; /* index of next empty slot in + the_buffer[]*/ + +int ring_index; /* index into ring[] */ +char ring[MAXRING+1]; /* ring buffer for current output + context */ + +BOOLEAN hyphen_break; /* hyphen break flag */ +BOOLEAN eol; /* end-of-line flag */ +BOOLEAN is_underline; /* underline et al flags */ +BOOLEAN is_subscript; +BOOLEAN is_superscript; +BOOLEAN is_bold; +BOOLEAN is_alternate; + +int bi_eol; /* input byte offset at end-of-line */ +int bi_underline; +int bi_subscript; +int bi_superscript; +int bi_bold; +int bi_alternate; + +int bo_eol; /* output byte offset at end-of-line */ +int bo_underline; +int bo_subscript; +int bo_superscript; +int bo_bold; +int bo_alternate; + +int input_byte_offset; +int output_byte_offset; +int last_c; /* previous input character */ + +/* global functions */ + +#if OS_TOPS20 +#define Begin_alternate Beg_alternate /* unique to 6 characters */ +#define Begin_boldface Beg_boldface +#endif + +void Begin_alternate (); +void Begin_boldface (); +void End_alternate (); +void End_boldface (); +void Line_feed (); +void Superscript (); +void Subscript (); +void Underline (); +void Warning (); +void W_byte (); +void W_char (); +void W_octal (); +void W_string (); + +char *strchr(); + + +/**********************************************************************/ +/*-->main */ +main(argc,argv) /* Main -- WSLTEX */ +int argc; +char *argv[]; +{ + int fp; + register int c; /* current input character */ + register int c7; /* low-order 7 bits of c */ + + if (argc < 2) + { + (void)fprintf(stderr, + "%%Usage: %s WordStar_infile >LaTeX_outfile",argv[0]); + WRITELN(stderr); + exit(1); + } + + /* only 7-bit bytes required, so stdout is okay to use provided + it does not do CRLF <--> LF translation. On TOPS-20, this is + suppressed by loading this program with a special version of the I/O + library. */ + + LaTeX_file = stdout; + +#if OS_TOPS20 + /* Read file in bytesize 8 with binary flag set to prevent + CRLF <--> LF mapping; the "rb" or "wb" flag is not sufficient for + this because PCC-20 maintains two places internally + where the binary flag is set, and both are used! */ + + if ((fp = + open(argv[1], FATT_RDONLY | FATT_SETSIZE | FATT_BINARY,8)) >= 0) + WordStar_file = fdopen(fp,"rb"); + else + WordStar_file = (FILE *)NULL; +#else + WordStar_file = fopen(argv[1],"rb"); +#endif + + if (WordStar_file == (FILE *)NULL) + { + + (void)fprintf(stderr, + "?Open failure on WordStar input file [%s]",argv[1]); + WRITELN(stderr); + exit(1); + } + + /* Initializations -- in alphabetical order */ + + bi_alternate = -1; + bi_bold = -1; + bi_subscript = -1; + bi_superscript = -1; + bi_underline = -1; + bo_alternate = -1; + bo_bold = -1; + bo_subscript = -1; + bo_superscript = -1; + bo_underline = -1; + eol = TRUE; + hyphen_break = FALSE; + input_byte_offset = -1; + is_bold = FALSE; + is_subscript = FALSE; + is_superscript = FALSE; + is_underline = FALSE; + last_c = -1; + output_byte_offset = -1; + + for (ring_index=0; ring_index <= MAXRING; ring_index++) + ring[ring_index] = ' '; + ring_index = 0; + + if ((the_buffer = (char *)malloc(MAXBUF)) == (char *)NULL) + { + (void)fprintf(stderr, + "?Unable to allocate output buffer of size %d",MAXBUF); + WRITELN(stderr); + exit(1); + } + the_next = 0; + + /* + ===================================================================== + WordStar makes heavy use of the 8-th (high-order) bit of 8-bit ASCII + characters. In general, it turns on that bit for + -- any character (0..127) at end-of-word + -- any character (0..127) at end-of-line + -- "hard" line break on CTL-M + -- "hard" page break on CTL-L + + A discretionary hyphen (which can be removed on joining the lines) at + end-of-line is encoded as "-\215" (i.e. "-<\200|CTL-M>"). + + A required hyphen falling at end-of-line is encoded as "-\040\215" + (i.e. followed by a space). + + Comment lines and WordStar command lines begin with a dot. + + "Hard" line breaks are encoded as \215\015 (i.e. + "<\200|CTL-M><CTL-J>"); these occur between double-space lines. + + "Soft" line breaks are encoded as <CTL-M><CTL-J>; these occur at + paragraph ends. + + Centered text is stored centered without any special markings. + + Underlined text is bracketed by CTL-S. + + Boldface text is bracketed by CTL-E ..text.. CTL-R. + + Superscripts are bracketed by CTL-T. + + Subscripts are bracketed by CTL-V. + + Alternate typewheel strings appear as CTL-Q ..text.. CTL-W. Some of + these at least are mnemonic (e = epsilon, m = mu, . = centered dot). + + CTL-R also appears after all sub/superscript sequences, apparently + functioning as a "return to normal" state. + ===================================================================== + */ + + while ((c = getc(WordStar_file)) != EOF) + { + if (c < 32) /* ordinary control character */ + { + switch (c) + { + case 0: + case 1: + case 2: + case 3: + case 4: /* CTL-@ .. CTL-D */ + W_octal(c); + break; + + case 5: /* CTL-E */ + Begin_boldface(); + break; + + case 6: + case 7: + case 8: /* CTL-F .. CTL-H */ + W_octal(c); + break; + + case 9: /* CTL-I */ + W_byte(HT); + break; + + case 10: /* CTL-J */ + Line_feed(); + break; + + case 11: /* CTL-K */ + W_octal(c); + break; + + case 12: /* CTL-L */ + W_byte(FF); + break; + + case 13: /* CTL-M */ + if (last_c == (int)('-')) + hyphen_break = TRUE; + else if (!hyphen_break) + W_byte(CR); + break; + + case 14: + case 15: + case 16: /* CTL-N .. CTL-P */ + W_octal(c); + break; + + case 17: /* CTL-Q */ + Begin_alternate(); + break; + + case 18: /* CTL-R */ + if (is_bold) + End_boldface(); + /* ELSE discard character */ + break; + + case 19: /* CTL-S */ + Underline(); + break; + + case 20: /* CTL-T */ + Superscript(); + break; + + case 21: /* CTL-U */ + W_octal(c); + break; + + case 22: /* CTL-V */ + Subscript(); + break; + + case 23: /* CTL-W */ + End_alternate(); + break; + + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: /* CTL-X .. CTL-_ */ + W_octal(c); + break; + } + /* case */ + } + else if (strchr("#$%&~_^\\{}",c)) + /* LaTeX special characters must be quoted by backslash */ + { + W_char('\\'); + W_byte(c); + } + else if (c == (int)('.')) /* check for WordStar comment */ + { + if (eol) + W_string("%-WS-% "); + W_byte(c); + } + else if (c < 128) /* c in 32 .. 127 */ + W_byte(c); + else /* c > 127 */ + { + c7 = c & 0177; /* lop off 8-th bit */ + switch (c7) + { + case 0: /* CTL-@ */ + W_octal(c7); + break; + + case 1: /* CTL-A */ + W_octal(c7); + break; + + case 2: /* CTL-B */ + W_octal(c7); + break; + + case 3: /* CTL-C */ + W_octal(c7); + break; + + case 4: /* CTL-D */ + W_octal(c7); + break; + + case 5: /* CTL-E */ + Begin_boldface(); + break; + + case 6: /* CTL-F */ + W_octal(c7); + break; + + case 7: /* CTL-G */ + W_octal(c7); + break; + + case 8: /* CTL-H */ + W_octal(c7); + break; + + case 9: /* CTL-I */ + W_byte(HT); + break; + + case 10: /* CTL-J */ + Line_feed(); + break; + + case 11: /* CTL-K */ + W_octal(c7); + break; + + case 12: /* CTL-L */ + W_byte(FF); + break; + + case 13: /* CTL-M */ + if (last_c == (int)('-')) + hyphen_break = TRUE; + else if (!hyphen_break) + { + if (bo_eol < output_byte_offset) + W_byte(CR); + /* not double space */ + } + break; + + case 14: /* CTL-N */ + W_octal(c7); + break; + + case 15: /* CTL-O */ + W_octal(c7); + break; + + case 16: /* CTL-P */ + W_octal(c7); + break; + + case 17: /* CTL-Q */ + Begin_alternate(); + break; + + case 18: /* CTL-R */ + if (is_bold) + End_boldface(); + /* ELSE discard character */ + break; + + case 19: /* CTL-S */ + Underline(); + break; + + case 20: /* CTL-T */ + Superscript(); + break; + + case 21: /* CTL-U */ + W_octal(c7); + break; + + case 22: /* CTL-V */ + Subscript(); + break; + + case 23: /* CTL-W */ + End_alternate(); + break; + + case 24: /* CTL-X */ + W_octal(c7); + break; + + case 25: /* CTL-Y */ + W_octal(c7); + break; + + case 26: /* CTL-Z */ + W_octal(c7); + break; + + case 27: /* CTL-[ */ + W_octal(c7); + break; + + case 28: /* CTL-\ */ + W_octal(c7); + break; + + case 29: /* CTL-] */ + W_octal(c7); + break; + + case 30: /* CTL-^ */ + W_octal(c7); + break; + + case 31: /* CTL-_ */ + W_octal(c7); + break; + + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + W_byte(c7); + break; + + case 46: /* period */ + if (eol) + W_string("%-WS-% "); + W_byte(c7); + break; + + case 47: + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + case 58: + case 59: + case 60: + case 61: + case 62: + case 63: + case 64: + case 65: + case 66: + case 67: + case 68: + case 69: + case 70: + case 71: + case 72: + case 73: + case 74: + case 75: + case 76: + case 77: + case 78: + case 79: + case 80: + case 81: + case 82: + case 83: + case 84: + case 85: + case 86: + case 87: + case 88: + case 89: + case 90: + case 91: + case 92: + case 93: + case 94: + case 95: + case 96: + case 97: + case 98: + case 99: + case 100: + case 101: + case 102: + case 103: + case 104: + case 105: + case 106: + case 107: + case 108: + case 109: + case 110: + case 111: + case 112: + case 113: + case 114: + case 115: + case 116: + case 117: + case 118: + case 119: + case 120: + case 121: + case 122: + case 123: + case 124: + case 125: + case 126: + W_byte(c7); + break; + + case 127: + W_octal(c7); + break; + + default: + W_octal(c7); + break; + } /* CASE */ + } + last_c = c; + input_byte_offset++; + } + EMPTY_BUFFER; +} +/* Main -- WSLTEX */ + + +/**********************************************************************/ +/*-->Begin_alternate */ +void +Begin_alternate () +{ + if (is_alternate) + Warning("BEGIN ALTERNATE CHARACTER SET command encounted inside\ + alternate sequence", + bo_alternate,output_byte_offset); + bi_alternate = input_byte_offset; + bo_alternate = output_byte_offset; + is_alternate = TRUE; + W_string("{\\alt "); +} +/* Begin_alternate */ + + +/**********************************************************************/ +/*-->Begin_boldface */ +void +Begin_boldface () +{ + if (is_bold) + Warning("BEGIN BOLDFACE command encountered inside boldface", + bo_bold,output_byte_offset); + bi_bold = input_byte_offset; + bo_bold = output_byte_offset; + is_bold = TRUE; + W_string("{\\bf "); +} +/* Begin_boldface */ + +/**********************************************************************/ +/*-->End_alternate */ +void +End_alternate () +{ + if (is_alternate) + { + if ((bo_alternate + MAXSPECIAL) < output_byte_offset) + Warning("Long ALTERNATE CHARACTER SET sequence", + bo_alternate,output_byte_offset); + } + else + Warning("END ALTERNATE CHARACTER SET command encountered\ + outside alternate text",bo_alternate,output_byte_offset); + is_alternate = FALSE; + W_byte((int)('}')); +} +/* End_alternate */ + + +/**********************************************************************/ +/*-->End_boldface */ +void +End_boldface () +{ + if (is_bold) + { + if ((bo_bold + MAXSPECIAL) < output_byte_offset) + Warning("Long BOLDFACE sequence", + bo_bold,output_byte_offset); + } + else + Warning("END BOLDFACE command encountered outside boldface", + bo_bold,output_byte_offset); + is_bold = FALSE; + W_byte((int)('}')); +} +/* End_boldface */ + + +/**********************************************************************/ +/*-->Line_feed */ +void +Line_feed () +{ + if (hyphen_break) /* discard line break */ + hyphen_break = FALSE; + else + { + if (bo_eol < output_byte_offset) /* text on line */ + W_byte(LF); + else /* empty line */ + { + if (last_c != (0200 | CR)) + W_byte(LF); + } + } +} +/* Line_feed */ + + +/**********************************************************************/ +/*-->strchr() */ +char * +strchr(s,c) /* return pointer to c in s[], or (char*)NULL */ +char *s; +char c; +{ + while (*s && (*s != c)) + ++s; + if (*s == c) + return (s); + else + return ((char *)NULL); +} +/* strchr */ + + +/**********************************************************************/ +/*-->Superscript */ +void +Superscript () +{ + if (is_superscript) + /* ending old superscript */ + { + if ((bo_superscript + MAXSPECIAL) < output_byte_offset) + Warning("Long SUPERSCRIPT sequence", + bo_superscript,output_byte_offset); + W_byte((int)('}')); + } + else /* beginning new superscript */ + { + bi_superscript = input_byte_offset; + bo_superscript = output_byte_offset; + W_string("^{"); + } + is_superscript = !is_superscript; +} +/* Superscipt */ + + +/**********************************************************************/ +/*-->Subscript */ +void +Subscript () +{ + if (is_subscript) + /* ending old superscript */ + { + if ((bo_subscript + MAXSPECIAL) < output_byte_offset) + Warning("Long SUBSCRIPT sequence", + bo_subscript,output_byte_offset); + W_byte((int)('}')); + } + else /* beginning new superscript */ + { + bi_subscript = input_byte_offset; + bo_subscript = output_byte_offset; + W_string("_{"); + } + is_subscript = !is_subscript; +} +/* Subscript */ + + +/**********************************************************************/ +/*-->Underline */ +void +Underline () +{ + if (is_underline) + /* ending old underline */ + { + if ((bo_underline + MAXSPECIAL) < output_byte_offset) + Warning("Long UNDERLINE sequence", + bo_underline,output_byte_offset); + W_byte((int)('}')); + } + else /* beginning new underline */ + { + bi_underline = input_byte_offset; + bo_underline = output_byte_offset; + W_string("{\\em "); + } + /* underlined text is \emphasized in LaTeX */ + is_underline = !is_underline; +} +/* Underline */ + + +/**********************************************************************/ +/*-->Warning */ +void +Warning (s,b1,b2) +char s[]; +int b1, b2 /* output byte range, or UNSET,UNSET */; +{ + int k; + WRITELN(stderr); /* !!!! temporary for debugging !!!! */ + WRITELN(stderr); /* !!!! temporary for debugging !!!! */ + (void)fprintf(stderr, + "------------------------------------------------------------"); + WRITELN(stderr); + (void)fprintf(stderr,"%s",s); + WRITELN(stderr); + if (b1 != UNSET) + { + (void)fprintf(stderr,"\toutput byte range = %d .. %d",b1,b2); + WRITELN(stderr); + } + (void)fprintf(stderr,"\tinput byte offset = %d",input_byte_offset); + WRITELN(stderr); + (void)fprintf(stderr,"\toutput byte offset = %d",output_byte_offset); + WRITELN(stderr); + (void)fprintf(stderr,"\tcurrent context = ["); + WRITELN(stderr); + for (k=ring_index; k <= MAXRING; k++) + putc(ring[k],stderr); + for (k=0; k <= ((MAXRING + ring_index - 1) % MAXRING); k++) + putc(ring[k],stderr); + WRITELN(stderr); + (void)fprintf(stderr,"\t]"); + WRITELN(stderr); + (void)fprintf(stderr, + "------------------------------------------------------------"); + WRITELN(stderr); +} +/* Warning */ + + +/**********************************************************************/ +/*-->W_byte */ +void +W_byte (c) +int c; +{ + ring[ring_index] = (char)c; + ring_index = (ring_index++) % MAXRING; + + /* All output bytes go through this single piece of code, so + we optimize output by buffering it in large blocks. The use + of write() instead of fwrite() avoids CR LF <--> LF translation + on most machines, and on some is significantly more efficient. */ + + if (the_next >= MAXBUF) + EMPTY_BUFFER; + the_buffer[the_next++] = c; + + eol = (c == LF); + output_byte_offset++; + if (eol) + { + bi_eol = input_byte_offset; + bo_eol = output_byte_offset; + } +} +/* W_byte */ + + +/**********************************************************************/ +/*-->W_char */ +void +W_char (c) +char c; +{ + W_byte((int)(c)); +} +/* W_char */ + + +/**********************************************************************/ +/*-->W_octal */ +void +W_octal (c) +int c; +{ + c = c & 0377; + W_byte((int)('\\')); + W_byte((c >> 6) + (int)('0')); + W_byte(((c >> 3) & 07) + (int)('0')); + W_byte((c & 07) + (int)('0')); +} +/* W_octal */ + + +/**********************************************************************/ +/*-->W_string */ +void +W_string (s) +char *s; +{ + while (*s) + W_byte((int)(*s++)); +} +/* W_string */ diff --git a/dviware/beebe/utils/wsltex.let b/dviware/beebe/utils/wsltex.let new file mode 100644 index 0000000000..189afc4d56 --- /dev/null +++ b/dviware/beebe/utils/wsltex.let @@ -0,0 +1,72 @@ +12-Oct-85 17:47:22-MDT,00000003019;000000000001 +Date: 12 Oct 1985 1747-MDT +From: Beebe (Nelson H.F. Beebe) +Subject: [Beebe (Nelson H.F. Beebe): WordStar to LaTeX translation] +To: op.hendry, fh.harris +cc: BEEBE + +2 + --------------- + +Date: 11 Oct 1985 1804-MDT +From: Beebe (Nelson H.F. Beebe) +Subject: WordStar to LaTeX translation +To: C-GRISS, CH.JM.DOWNING, FH.HARRIS, MA.PETERSEN, OP.BOWMAN, OP.DUNCAN, +To: OP.HENDRY, OP.LICHTY, OP.WILLETT, VI.FULLERTON, GU.KILLIAN +cc: BEEBE, MA.HOPPENSTEADT, CH.JM.KLING, BI.PARKINSON, bi.kofOID, CH.MAYNE, +cc: vi.leaver, ma.othmer + +I completed today a pair of programs for assisting in the +conversion of files from WordStar (a popular microcomputer +word processor) to LaTeX. The subject manuscript was Pete +Conwell's Ph.D. thesis, which Ed Leaver is going to massage +further into a form that LaTeX will accept. + +WordStar file format makes extensive use of the high-order +bit of 8-bit ASCII characters to flag "hard" and "soft" line +breaks, underlining, subscripting, superscripting, +boldfacing, etc. The exact sequences to do this are +described in a document which the authors of WordStar market +for $500; needless to say, I did not buy it, but just +reverse engineered the job. + +The WordStar file was KERMITed to the DEC-20 from an IBM PC +by issuing SET FILE 8-BIT then SERVER to KERMIT-20, followed +by a normal KERMIT-PC SEND command. + +Both programs are in the directory APS:<BEEBE.UTILITY>. + +The first of them, WS87.PAS, can be used to copy any 8-bit +file to a 7-bit file, turning all characters in the range +128 .. 255 into printable \nnn octal escape sequences. This +allows examination of the WordStar file on the DEC-20, and +could be used for other 8-bit files as well. + +The second, WSLTEX, is a 535-line workhorse which identifies +all the WordStar magic sequences used in Pete's thesis and +turns them into appropriate LaTeX commands. It would be +straightforward to modify WSLTEX now for any other document +formatter, and if necessary, to recognize other WordStar +sequences not used in the thesis. + +Conversion time was 19 sec on the DEC-20 for 6000 lines of +WordStar input. + +WordStar is not a well-designed formatter, in that it does +not consistently identify document features. In particular, +double spacing actually appears verbatim (and is converted +to single spacing by WSLTEX, except at paragraph +boundaries), and centered text (as in chapter titles) is +just centered without any identification. Consequently, an +editing session is still necessary to take the output of +WSLTEX and convert it into true LaTeX input. The important +thing is that every special feature in the input WordStar +document is preserved, something which is not possible if +the 8-th bit is just lopped off. + +Help yourselves. Extensions, modifications, and bug reports +are welcome. It's all public domain, so don't sell it! +------- + ======== +------- + ======== diff --git a/dviware/beebe/utils/wsltex.pas b/dviware/beebe/utils/wsltex.pas new file mode 100644 index 0000000000..cc2119fef9 --- /dev/null +++ b/dviware/beebe/utils/wsltex.pas @@ -0,0 +1,537 @@ +PROGRAM Wsltex; + { + ********************************************************************** + Copy an 8-bit file to a 7-bit file, turning characters with bit 8 + set into 4-character octal escape sequences \nnn. This is useful in + analyzing WordStar microcomputer word processor files. Many + sequences which can be recognized as doing something useful are + turned into LaTeX command sequences. Comments below describe the + sequences which are recognized and translated. + + Usage: + + @WSLTEX + Old 8-bit file: filespec + New 7-bit file: filespec + + [11-Oct-85] + ********************************************************************** + } +{ ^L } +CONST + nul = 0; + + bel = 7; + + ht = 9; + lf = 10; + + ff = 12; + cr = 13; + + esc = 27; + + maxring = 256; { limit for character ring } + + maxspecial = 100; { limit for warning when special strings (underline, + bold, etc) exceed this length } + + unset = MAXINT; + +VAR + wordstar_file,latex_file : PACKED FILE OF integer; + ring_index : integer; + ring : PACKED ARRAY [0 .. maxring] OF integer; + hyphen_break : boolean; + eol,is_underline,is_subscript,is_superscript,is_bold, + is_alternate : boolean; + bi_eol,bi_underline,bi_subscript,bi_superscript,bi_bold, + bi_alternate : integer; + bo_eol,bo_underline,bo_subscript,bo_superscript,bo_bold, + bo_alternate : integer; + input_byte_offset,output_byte_offset : integer; + empty_count,last_c,c : integer; +{ ^L } +PROCEDURE Warning(s : PACKED ARRAY [k1 .. k2 : integer] OF char; + b1,b2 : integer { output byte range, or unset,unset } + ); + VAR k : integer; +BEGIN + Writeln(tty); { !!!! temporary for debugging !!!! } + Writeln(tty); { !!!! temporary for debugging !!!! } + Writeln(tty,'----------------------------------------------------------'); + Write(tty,'%'); + + FOR k := k1 TO k2 DO + Write(tty,s[k]); + Writeln(tty); + if b1 <> unset then + Writeln(tty,' output byte range = ',b1:0,' .. ',b2:0); + Writeln(tty,' input byte offset = ',input_byte_offset); + Writeln(tty,' output byte offset = ',output_byte_offset); + Writeln(tty,' current context = ['); + FOR k := ring_index TO maxring DO + Write(tty,Chr(ring[k])); + FOR k := 0 TO ((maxring + ring_index - 1) MOD maxring) DO + Write(tty,Chr(ring[k])); + Writeln(tty); + Writeln(tty,' ]'); + Writeln(tty,'----------------------------------------------------------'); + Writeln(tty) +END; { Warning } + +{ ^L } +PROCEDURE W_byte(c : integer); +BEGIN + ring[ring_index] := c; + ring_index := (ring_index + 1) MOD maxring; + latex_file^ := c; + eol := (c = lf); + Put(latex_file); + output_byte_offset := output_byte_offset + 1; + IF eol THEN + BEGIN + bi_eol := input_byte_offset; + bo_eol := output_byte_offset + END +END; { W_byte } + +PROCEDURE W_char(c : char); +BEGIN + W_byte(Ord(c)) +END; { W_char } +{ ^L } +PROCEDURE W_octal; +BEGIN + W_byte(Ord('\')); + W_byte((wordstar_file^ DIV 64) + Ord('0')); + W_byte(((wordstar_file^ DIV 8) MOD 8) + Ord('0')); + W_byte((wordstar_file^ MOD 8) + Ord('0')) +END; { W_octal } +{ ^L } +PROCEDURE W_string(s : PACKED ARRAY [k1 .. k2 : integer] OF char); + VAR k : integer; +BEGIN + FOR k := k1 TO k2 DO + W_byte(Ord(s[k])) +END; { W_string } +{ ^L } +PROCEDURE Begin_alternate; +BEGIN + IF is_alternate THEN + Warning( +'BEGIN ALTERNATE CHARACTER SET command encounted inside alternate sequence', + bo_alternate,output_byte_offset); + bi_alternate := input_byte_offset; + bo_alternate := output_byte_offset; + is_alternate := true; + W_string('{\alt ') +END; { Begin_alternate } +{ ^L } +PROCEDURE Begin_boldface; +BEGIN + IF is_bold THEN + Warning('BEGIN BOLDFACE command encountered inside boldface', + bo_bold,output_byte_offset); + bi_bold := input_byte_offset; + bo_bold := output_byte_offset; + is_bold := true; + W_string('{\bf ') +END; { Begin_boldface } +{ ^L } +PROCEDURE End_alternate; +BEGIN + IF is_alternate THEN + BEGIN + IF (bo_alternate + maxspecial) < output_byte_offset THEN + Warning('Long ALTERNATE CHARACTER SET sequence', + bo_alternate,output_byte_offset) + END + ELSE + Warning( +'END ALTERNATE CHARACTER SET command encountered outside alternate text', + bo_alternate,output_byte_offset); + is_alternate := false; + W_byte(Ord('}')) +END; { End_alternate } +{ ^L } +PROCEDURE End_boldface; +BEGIN + IF is_bold THEN + BEGIN + IF (bo_bold + maxspecial) < output_byte_offset THEN + Warning('Long BOLDFACE sequence',bo_bold,output_byte_offset) + END + ELSE + Warning('END BOLDFACE command encountered outside boldface', + bo_bold,output_byte_offset); + is_bold := false; + W_byte(Ord('}')) +END; { End_boldface } +{ ^L } +PROCEDURE Line_feed; +BEGIN { line_feed } + IF hyphen_break THEN { discard line break } + hyphen_break := false + ELSE + BEGIN + IF bo_eol < output_byte_offset THEN { text on line } + W_byte(lf) + ELSE { empty line } + BEGIN + IF last_c <> (128 + cr) THEN + W_byte(lf) + END + END +END; { Line_feed } +{ ^L } +PROCEDURE Superscript; +BEGIN + IF is_superscript THEN { ending old superscript } + BEGIN + IF (bo_superscript + maxspecial) < output_byte_offset THEN + Warning('Long SUPERSCRIPT sequence', + bo_superscript,output_byte_offset); + W_byte(Ord('}')) + END + ELSE { beginning new superscript } + BEGIN + bi_superscript := input_byte_offset; + bo_superscript := output_byte_offset; + W_string('^{') + END; + is_superscript := NOT is_superscript +END; { Superscipt } +{ ^L } +PROCEDURE Subscript; +BEGIN + IF is_subscript THEN { ending old superscript } + BEGIN + IF (bo_subscript + maxspecial) < output_byte_offset THEN + Warning('Long SUBSCRIPT sequence', + bo_subscript,output_byte_offset); + W_byte(Ord('}')) + END + ELSE { beginning new superscript } + BEGIN + bi_subscript := input_byte_offset; + bo_subscript := output_byte_offset; + W_string('_{'); + END; + is_subscript := NOT is_subscript +END; { Subscript } +{ ^L } +PROCEDURE Underline; +BEGIN + IF is_underline THEN { ending old underline } + BEGIN + IF (bo_underline + maxspecial) < output_byte_offset THEN + Warning('Long UNDERLINE sequence', + bo_underline,output_byte_offset); + W_byte(Ord('}')) + END + ELSE { beginning new underline } + BEGIN + bi_underline := input_byte_offset; + bo_underline := output_byte_offset; + W_string('{\em ') + END; + { underlined text is \emphasized in LaTeX } + is_underline := NOT is_underline +END; { Underline } +{ ^L } +BEGIN { Main -- WSLTEX } + +Rewrite(output,'tty:'); +Write('Input WordStar 8-bit file: '); +Reset(wordstar_file,'':@,'/e/b:8'); +Write('Output LaTeX 7-bit file: '); +Rewrite(latex_file,'':@,'/e/b:7'); + +{ Initializations -- in alphabetical order } +bi_alternate := -1; +bi_bold := -1; +bi_subscript := -1; +bi_superscript := -1; +bi_underline := -1; +bo_alternate := -1; +bo_bold := -1; +bo_subscript := -1; +bo_superscript := -1; +bo_underline := -1; +eol := true; +hyphen_break := false; +input_byte_offset := -1; +is_bold := false; +is_subscript := false; +is_superscript := false; +is_underline := false; +last_c := -1; +output_byte_offset := -1; + +for ring_index := 0 to maxring do + ring[ring_index] := ord(' '); +ring_index := 0; +{ +======================================================================== +WordStar makes heavy use of the 8-th (high-order) bit of 8-bit ASCII +characters. In general, it turns on that bit for +-- any character (0..127) at end-of-word +-- any character (0..127) at end-of-line +-- "hard" line break on CTL-M +-- "hard" page break on CTL-L + +A discretionary hyphen (which can be removed on joining the lines) at +end-of-line is encoded as "-\215" (i.e. "-<\200|CTL-M>"). + +A required hyphen falling at end-of-line is encoded as "-\040\215" (i.e. +followed by a space). + +Comment lines and WordStar command lines begin with a dot. + +"Hard" line breaks are encoded as \215\015 (i.e. "<\200|CTL-M><CTL-J>"); +these occur between double-space lines. + +"Soft" line breaks are encoded as <CTL-M><CTL-J>; these occur at +paragraph ends. + +Centered text is stored centered without any special markings. + +Underlined text is bracketed by CTL-S. + +Boldface text is bracketed by CTL-E ..text.. CTL-R. + +Superscripts are bracketed by CTL-T. + +Subscripts are bracketed by CTL-V. + +Alternate typewheel strings appear as CTL-Q ..text.. CTL-W. Some of +these at least are mnemonic (e = epsilon, m = mu, . = centered dot). + +CTL-R also appears after all sub/superscript sequences, apparently +functioning as a "return to normal" state. +======================================================================== +} + +c := wordstar_file^; +WHILE NOT Eof(wordstar_file) DO +BEGIN + IF c < 32 THEN { ordinary control character } + BEGIN + CASE c OF + 0,1,2,3,4 : { CTL-@ .. CTL-D } + W_octal; + + 5 : { CTL-E } + Begin_boldface; + + 6,7,8 : { CTL-F .. CTL-H } + W_octal; + + 9 : { CTL-I } + W_byte(ht); + + 10 : { CTL-J } + Line_feed; + + 11 : { CTL-K } + W_octal; + + 12 : { CTL-L } + W_byte(ff); + + 13 : { CTL-M } + IF last_c = Ord('-') THEN + hyphen_break := true + ELSE IF NOT hyphen_break THEN + W_byte(cr); + + 14,15,16 : { CTL-N .. CTL-P } + W_octal; + + 17 : { CTL-Q } + Begin_alternate; + + 18 : { CTL-R } + IF is_bold THEN + End_boldface; + { ELSE discard character } + + 19 : { CTL-S } + Underline; + + 20 : { CTL-T } + Superscript; + + 21 : { CTL-U } + W_octal; + + 22 : { CTL-V } + Subscript; + + 23 : { CTL-W } + End_alternate; + + 24,25,26,27,28,29,30,31 : { CTL-X .. CTL-_ } + W_octal + END { case } + END + ELSE IF chr(c) IN ['#','$','%','&','~','_','^','\','{','}'] + THEN { LaTeX special characters must be quoted by backslash } + BEGIN + W_char('\'); + W_byte(c) + END + ELSE IF c = Ord('.') THEN { check for WordStar comment } + BEGIN + IF eol THEN + W_string('%-WS-% '); + W_byte(c) + END + ELSE IF c < 128 THEN { c in 32 .. 127 } + W_byte(c) + ELSE { c > 127 } + BEGIN + c := c - 128; { lop off 8-th bit } + CASE c OF + 0 : { CTL-@ } + W_octal; + + 1 : { CTL-A } + W_octal; + + 2 : { CTL-B } + W_octal; + + 3 : { CTL-C } + W_octal; + + 4 : { CTL-D } + W_octal; + + 5 : { CTL-E } + Begin_boldface; + + 6 : { CTL-F } + W_octal; + + 7 : { CTL-G } + W_octal; + + 8 : { CTL-H } + W_octal; + + 9 : { CTL-I } + W_byte(ht); + + + 10 : { CTL-J } + Line_feed; + + 11 : { CTL-K } + W_octal; + + 12 : { CTL-L } + W_byte(ff); + + + 13 : { CTL-M } + IF last_c = Ord('-') THEN + hyphen_break := true + ELSE IF NOT hyphen_break THEN + BEGIN + IF bo_eol < output_byte_offset THEN { not double space} + W_byte(cr); + END; + + 14 : { CTL-N } + W_octal; + + 15 : { CTL-O } + W_octal; + + 16 : { CTL-P } + W_octal; + + 17 : { CTL-Q } + Begin_alternate; + + 18 : { CTL-R } + IF is_bold THEN + End_boldface; + { ELSE discard character } + + 19 : { CTL-S } + Underline; + + 20 : { CTL-T } + Superscript; + + 21 : { CTL-U } + W_octal; + + 22 : { CTL-V } + Subscript; + + 23 : { CTL-W } + End_alternate; + + 24 : { CTL-X } + W_octal; + + 25 : { CTL-Y } + W_octal; + + 26 : { CTL-Z } + W_octal; + + 27 : { CTL-[ } + W_octal; + + 28 : { CTL-\ } + W_octal; + + 29 : { CTL-] } + W_octal; + + 30 : { CTL-^ } + W_octal; + + 31 : { CTL-_ } + W_octal; + + 32,33,34,35,36,37,38,39,40,41,42,43,44,45 : + W_byte(c); + + 46 : { period } + BEGIN + IF eol THEN + W_string('%-WS-% '); + W_byte(c) + END; + + 47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63 : + W_byte(c); + + 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80, + 81,82,83,84,85,86,87,88,89,90,91,92,93,94,95 : + W_byte(c); + + 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110, + 111,112,113,114,115,116,117,118,119,120,121,122,123,124, + 125,126 : + W_byte(c); + + 127 : + W_octal; + + OTHERS : + W_octal; + END { CASE } + END; + last_c := wordstar_file^; + input_byte_offset := input_byte_offset + 1; + Get(wordstar_file); + c := wordstar_file^ +END; +END. { Main -- WSLTEX } diff --git a/dviware/beebe/utils/xref b/dviware/beebe/utils/xref new file mode 100644 index 0000000000..f45093cd3b --- /dev/null +++ b/dviware/beebe/utils/xref @@ -0,0 +1,25 @@ +#!/bin/csh +# Make a libref "references" and "referenced-by" pair of cross +# reference tables on stdout from a list of C sources files. +# +# Usage: +# xref filelist >foo.xref +# +# [09-Sep-87] + +set TEMPFILE = xref$$ + +# Make "name<tab>file" list in $TEMPFILE +cxref $* | awk -f xref1.awk | sort -u > $TEMPFILE + +# Make "references" libref-style map +echo Created `date` on `hostname` +echo xref $* +sort $TEMPFILE | awk -f xref2.awk + +# Make "referenced-by" libref-style map +echo "Created" `date` on `hostname` +echo xref $* +awk '{if ($2 != "") printf "%s\t%s\n",$2,$1;}' $TEMPFILE | sort | awk -f xref3.awk + +/bin/rm -f $TEMPFILE diff --git a/dviware/beebe/utils/xref1.awk b/dviware/beebe/utils/xref1.awk new file mode 100644 index 0000000000..556997b3b1 --- /dev/null +++ b/dviware/beebe/utils/xref1.awk @@ -0,0 +1,56 @@ +# Make a "nm"-style cross-reference table which can be later +# converted into neat tabular form. +# +# Usage: +# cxref filelist | awk -f xref1.awk | sort -u | >foo.nm +# +# Sun OS 3.3 cxref listings look like +# +#dvijep.c: +# +# SYMBOL FILE FUNCTION LINE +# +# #undef ./machdefs.h -- 382 404 406 413 427 432 436 441 446 466 +# ./main.h -- 17 45 67 78 +# ABS() +# ./fixpos.h -- 24 +# ./gendefs.h -- *16 +# ./movedown.h -- 27 +# ./moveover.h -- 30 +# ./option.h -- 123 +# dvijep.c -- 554 +# etc.. +# +# We want to extract from this a file with entries +# name<tab>xref +# +# We ignore lines with only one field (eliminating the filename lines), +# and reuse the previous name if the first field is empty. We +# eliminate leading "./" in filenames, and discard lines for which +# name == 'SYMBOL', or which have an absolute pathname in xref (we +# don't want to cross-reference names defined in /usr/include/*.h), +# or which have only digits or asterisks in xref (line numbers). +# [18-Jul-87] +BEGIN {name = "";} +{ + if (substr($0,1,1) != " ") + { + name = $1; + xref = $2; + } + else + xref = $1; + if ((name == "SYMBOL") && (xref == "FILE")) + next; + else if (substr(xref,1,1) == "/") + next; + else if (substr(name,1,1) == "#") + next; + else if (xref != "") + { + if (substr(xref,1,2) == "./") + xref = substr(xref,3) + if (xref !~ /[0-9*]/) + printf "%s\t%s\n",name,xref; + } +} diff --git a/dviware/beebe/utils/xref2.awk b/dviware/beebe/utils/xref2.awk new file mode 100644 index 0000000000..93eb37a6a5 --- /dev/null +++ b/dviware/beebe/utils/xref2.awk @@ -0,0 +1,74 @@ +# Convert a sorted file with entries +# name<tab>file +# to a libref-style "references" map on stdout (4 entries per line) +# [09-Sep-87] +BEGIN { + FS = "\t"; + nref = 0; + caller = ""; + print "*********************************************************************"; + print "* ..Name.. * ...Referenced in File... *"; + print "*********************************************************************"; + print "* * *"; +} + +{ + if (($1 != caller) && (caller != "")) + { + if (length(caller) > 20) + the_caller = substr(caller,1,20); + else + the_caller = caller; + printf "* %-20s<-",the_caller; + nref4 = 4*int((nref + 3)/4); + + for (k = nref; k < nref4; ++k) + refs[k] = " "; + nref = nref4; + for (k = 0; k < nref; ) + { + printf " %-10s",refs[k]; + ++k; + if ((k % 4) == 0) + { + printf "*\n"; + if (k < nref) + { + printf "* *"; + } + } + } + nref = 0; + print "* * *"; + } + caller = $1; + if (length($2) > 10) + $2 = substr($2,1,10); + refs[nref] = $2; + nref++; # awk treats refs[nref++] as refs[++nref], sigh... + +} + +END { + printf "* %-20s<-",caller; + nref4 = 4*int((nref + 3)/4); + for (k = nref; k < nref4; ++k) + refs[k] = " "; + nref = nref4; + for (k = 0; k < nref; ) + { + printf " %-10s",refs[k]; + ++k; + if ((k % 4) == 0) + { + printf "*\n"; + if (k < nref) + { + printf "* *"; + } + } + } + nref = 0; + print "* * *"; + print "*********************************************************************"; +} diff --git a/dviware/beebe/utils/xref3.awk b/dviware/beebe/utils/xref3.awk new file mode 100644 index 0000000000..935c310afa --- /dev/null +++ b/dviware/beebe/utils/xref3.awk @@ -0,0 +1,83 @@ +# Convert a sorted file with entries +# file<tab>name +# to a libref-style "referenced-by" map on stdout (4 entries per line) +# [09-Sep-87] +BEGIN { + FS = "\t"; + nref = 0; + callee = ""; + print "*********************************************************************"; + print "* ..File.. * ...Global Symbol... *"; + print "*********************************************************************"; + print "* * *"; +} + +{ + if (($1 != "") && ($1 != callee) && (callee != "")) + { + if (length(callee) > 20) + the_callee = substr(callee,1,20); + else + the_callee = callee; + printf "* %-20s->",the_callee; + nref4 = 4*int((nref + 3)/4); + + for (k = nref; k < nref4; ++k) + refby[k] = " "; + nref = nref4; + for (k = 0; k < nref; ) + { + printf " %-10s",refby[k]; + ++k; + if ((k % 4) == 0) + { + printf "*\n"; + if (k < nref) + { + printf "* *"; + } + } + } + nref = 0; + print "* * *"; + } + if ($1 != "") + callee = $1; # first type--initial entry for new callee + if ($2 == "") + $2 = $4; # second type--same callee, different caller + if ($2 != "") # not third type + { + if (length($2) > 10) + $2 = substr($2,1,10); + refby[nref] = $2; + nref++; # awk treats refby[nref++] as refby[++nref], sigh... + } +} + +END { + if (length(callee) > 20) + the_callee = substr(callee,1,20); + else + the_callee = callee; + printf "* %-20s->",the_callee; + nref4 = 4*int((nref + 3)/4); + for (k = nref; k < nref4; ++k) + refby[k] = " "; + nref = nref4; + for (k = 0; k < nref; ) + { + printf " %-10s",refby[k]; + ++k; + if ((k % 4) == 0) + { + printf "*\n"; + if (k < nref) + { + printf "* *"; + } + } + } + nref = 0; + print "* * *"; + print "*********************************************************************"; +} diff --git a/dviware/beebe/utils/xxu.c b/dviware/beebe/utils/xxu.c new file mode 100644 index 0000000000..8bdeada1d2 --- /dev/null +++ b/dviware/beebe/utils/xxu.c @@ -0,0 +1,172 @@ +/* /usr.MC68020/csc-sun/u/local/src/C/xxu.c, Sat Jun 27 13:53:01 1987, */ +/* Add special[] processing, strip trailing dots from names */ + +/* X X U -- 20-to-Unix filename converter */ + +/* + Change DEC-20 or VAX/VMS style filenames into normal Unix names. + Handy for use after ftp MGETs, when you find your directory full of + files with names like LIB:<KERMIT>CKUFIO.C.2 or FRED::[ETHEL]A.B;37 + when all you really wanted was ckufio.c and a.b. + + Usage: xxu file(s) + + Action: Renames argument files as follows: + strips Unix path name from front (up to rightmost '/') if present + strips DEC device:, node:: names from front (up to rightmost ':') if present + strips DEC-20 <directory> or VMS [directory] name if present + strips DEC-20 version number from end (everything after 2nd dot) if present + strips VMS generation number from end (everything after ';') if present + lowercases any uppercase letters + honors DEC-20 CTRL-V quote for special characters + discards unquoted unprintable characters + if result is null, file is renamed to xxfile-n, where n is a number. + if result would write over an existing file, file also renamed to xxfile-n. + + Recommended procedure: make a new directory, cd to it, then FTP files + from DEC-20 or VMS system, then do "xxu *". + + Author: F. da Cruz, CUCCA, July 85 + + Added directory handling: Brad Davis, UofU VCIS Group, Aug 85 +*/ +#include <stdio.h> +#include <ctype.h> +#include <sys/file.h> /* For access() */ +#ifdef DODIRS +#include <sys/types.h> +#include <sys/dir.h> +#endif +#include <errno.h> + +/* A few names will be preserved in upper case or mixed case */ +char* special[] = + { /* "old name", "new name" */ + "bugs", "BUGS", + "install", "INSTALL", + "makefile", "Makefile", + "note", "NOTE", + "readme", "README", + "todo", "TODO", + (char*)NULL, (char*)NULL + }; + +char name[500]; /* File name buffer */ +char *pp, *cp, *xp; /* Character pointers */ +char delim; /* Directory Delimiter */ +int dc = 0, n = 0; /* Counters */ +int quote = 0, indir = 0; done = 0; /* Flags */ +#ifdef DODIRS +DIR *dir; +struct direct *entry; +#endif + +main(argc, argv) +int argc; +char **argv; +{ + if (argc < 2) { /* Give message if no args */ +#ifdef DODIRS + (void)fprintf(stderr,"Usage: xxu directory(s)\n"); +#else + (void)fprintf(stderr,"Usage: xxu file(s)\n"); +#endif + exit(1); + } + n = 0; /* Unfixable filename counter */ + while (--argc > 0) { /* For all files on command line... */ + argv++; +#ifdef DODIRS + dir = opendir(*argv); + while ((entry = readdir(dir)) != (struct direct *)NULL) { + xp = entry->d_name; /* Copy pointer for simplicity */ + if (*xp == '.') continue; /* leave . and .. alone */ +#else + xp = *argv; /* Copy pointer for simplicity */ +#endif + (void)printf("%s ",xp); /* Echo name of this file */ + pp = name; /* Point to translation buffer */ + *name = '\0'; /* Initialize buffer */ + dc = 0; /* Filename dot counter */ + done = 0; /* Flag for early completion */ + for (cp = xp; (*cp != '\0') && !done; cp++) + { /* Loop thru chars... */ + if (quote) { /* If this char quoted, */ + *pp++ = *cp; /* include it literally. */ + quote = 0; + continue; + } /* */ + if (indir) { /* If in directory name, */ + if (*cp == delim) indir = 0; /* look for end delimiter. */ + continue; + } + switch (*cp) { + case '<': /* Discard DEC-20 directory name */ + indir = 1; + delim = '>'; + break; + case '[': /* Discard VMS directory name */ + indir = 1; + delim = ']'; + break; + case '/': /* Discard Unix path name */ + case ':': /* or DEC dev: or node:: name */ + pp = name; + break; + case '.': /* DEC -20 generation number */ + if (++dc == 1) /* Keep first dot */ + *pp++ = *cp; + else /* Discard everything starting */ + done = 1; /* with second dot. */ + break; + case ';': /* VMS generation or DEC-20 attrib */ + done = 1; /* Discard everything starting with */ + break; /* semicolon */ + case '\026': /* Control-V quote for special chars */ + quote = 1; /* Set flag for next time. */ + break; + default: + if (isupper(*cp)) /* Uppercase letter to lowercase */ + *pp++ = tolower(*cp); + else if (isprint(*cp)) /* Other printable, just keep */ + *pp++ = *cp; + } + } + *pp = '\0'; /* Done with name, terminate it */ + if (strcmp(name,xp) == 0) { /* If no renaming necessary, */ + (void)printf("(ok)\n"); /* just give message. */ + continue; + } + /* Strip trailing dot (so makefile. becomes makefile) + and then check for special Unix files with + mixed case */ + { + char **p; + if (*(pp-1) == '.') + *(pp-1) = '\0'; + for (p = special; (*p != (char*)NULL); p += 2) + { + if (strcmp(name,*p) == 0) + { + strcpy(name,*(p+1)); + break; + } + } + } + while (*name == '\0' || + (access(name,0) == 0) && (errno != ENOENT)) + { /* Find unique name */ + (void)sprintf(name,"xxfile-%d",n++); + } + (void)printf("=> %s ",name); /* Tell what new name will be */ + if ((strcmp(xp,name) == 0) || + (rename(xp,name) == 0)) /* Try to rename it */ + (void)printf("(ok)\n"); /* Say what happened */ + else + perror("failed"); + } +#ifdef DODIRS + } +#endif + exit(0); /* Done. */ +} |