allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (10/01/89)
Posting-number: Volume 8, Issue 75 Submitted-by: howard@dahlbeck.ericsson.se (Howard Gayle) Archive-name: cz/part11 #! /bin/sh # This is a shell archive. Remove anything before this line, then feed it # into a shell via "sh file" or similar. To overwrite existing files, # type "sh file -c". # The tool that generated this appeared in the comp.sources.unix newsgroup; # send mail to comp-sources-unix@uunet.uu.net if you want that tool. # If this archive is complete, you will see the following message at the end: # "End of archive 11 (of 14)." # Contents: cz0.c # Wrapped by howard@dahlbeck on Mon Sep 25 07:15:24 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'cz0.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'cz0.c'\" else echo shar: Extracting \"'cz0.c'\" \(54952 characters\) sed "s/^X//" >'cz0.c' <<'END_OF_FILE' X/* X * cz0 - Convert text in any octet-based character set into PostScript. X */ X X#include <stdio.h> X#include <howard/port.h> X#include <howard/version.h> X#include <howard/usage.h> X XMAINVER ("@(#)$Header: cz0.c,v 2.25 89/08/21 10:54:56 howard Exp $"); XUSAGE ("[-o file] {-command argument}"); X X#include <ctype.h> X#include <string.h> X#include <time.h> X#include <howard/a2.h> X#include <howard/malf.h> X#include <howard/registers.i> X#include "FREEZE.i" X#include "cz.h" X#include "ps-abbrev.i" X#include "cz0.h" X#include "state0.i" X X/* a2ocol - convert string to output column number */ X XPRIVATE ushrtT a2ocol (s, n) XbStrT s; /* Input string.*/ XbStrT n; /* Field name.*/ X X/* Function: X * s is a string representation of an output column number, e.g. X * FoldFirst. It is either "Inf" for the maximum output column, X * or an integer numeric literal. X * Algorithm: X * X * Returns: X * X * Notes: X * X */ X{ Xreturn (bStrEQ (S("Inf"), s) ? MOCOL : ADA_US (s, n, 0, MOCOL)); X} X X/* addFnt - add a font to fonts[] if it's not already there */ X XPRIVATE void addFnt (f, s) XR2 bStrT f; /* Font name.*/ X boolT s; /* A symbol font.*/ X X/* Function: X * If font f is not already in the list of fonts used, add it. X * If it *is* already in the list, make sure its stored symbol font X * status is the same as s. X * Algorithm: X * Linear search. X * Returns: X * X * Notes: X * 1) It's necessary to distinguish symbol fonts from non-symbol X * fonts because symbol fonts must not be reencoded. X */ X{ XR1 fontT *fp; /* Steps through fonts[].*/ X Xfor (fp = fonts; (fp != fontP) && !bStrEQ (f, fp->fntName); ++fp) X ; Xif (fp == fontP) X { X if (fp == &fonts[MFONTS]) malf1 (eMFonts, MFONTS); X fp->fntName = f; X fp->fntSymb = s; X ++fontP; X } Xelse if (fp->fntSymb != s) X malf1 (eSymFnt, f); X} X X/* addso - add one state-octet pair to state table */ X XPRIVATE void addso (sos, pss) XR4 bStrT sos; /* State-octet pair as a string.*/ XR5 bStrT pss; /* Corresponding PostScript string.*/ X X/* Function: X * sos is a string representing a state-octet pair. X * pss is a string containing the text to emit for that pair, X * and optionally a new state at the end. addso() enters X * this into the state table, building new parts if necessary. X * Algorithm: X * Convert state and octet to numbers. Check pss for bad escapes. X * If there is no entry in state table for s, make one. X * If there is a next state at the end of pss, convert it to a number. X * Store pss and next state for this pair. X * Returns: X * X * Notes: X * 1) Should probably convert pss to nextc() output format here. X */ X{ XR6 unsigned ns = 0; /* Next state.*/ XR7 unsigned o; /* Octet.*/ XR1 bStrT p1; /* General purpose.*/ XR8 unsigned s; /* State.*/ XR2 soT *sop1; /* Current soT.*/ XR3 soT *sop2; /* End of new stateT.*/ XR9 stateT *sp; /* Points to current stateT.*/ X Xp1 = bStrChr (sos, SOSEP); Xif (NULBSTR == p1) malf1 (eSOSep, SOSEP, sos, pss); Xs = mra2u (sos, p1, FALSE, S("State"), (unsigned) 0, (unsigned) MSTATE, X (bStrT *) NULL); Xo = mra2u (1 + p1, NULBSTR, FALSE, S("Octet"), (unsigned) 0, (unsigned) 255, X (bStrT *) NULL); Xfor (p1 = pss; NULBSTR != (p1 = bStrChr (p1, E_ESC)); ++p1) X { X ++p1; X if (T_RES == ncMap[B(*p1)]) malf1 (eEsc, E_ESC, B(*p1), sos, pss); X } Xsp = states[s]; Xif (((stateT *) NULL) == sp) X { X sp = (stateT *) mcalloc (1, sizeof (stateT), "State table"); X sop1 = (soT *) sp; X sop2 = sop1 + 256; X for (; sop1 != sop2; ++sop1) X sop1->so_ps = NULBSTR; X states[s] = sp; X } Xp1 = bStrRChr (pss, E_ESC); Xif ((NULBSTR != p1) && (E_NEXTS == B(p1[1]))) X { X ns = mra2u (2 + p1, NULBSTR, FALSE, S("Next state"), (unsigned) 0, X (unsigned) MSTATE, (bStrT *) NULL); X *p1 = EOS; X } Xif (strlen (pss) > MPSSTR) malf1 (eBigPS, sos, MPSSTR, pss); Xsop1 = ((soT *) sp) + o; Xsop1->so_nxt = ns; Xsop1->so_ps = mcpstr (pss); Xif (DB(D_OCT)) X FPRINTF (stderr, "State %u Octet %c 8#%o# (%s%c%c%u)\n", X s, o, o, sop1->so_ps, E_ESC, E_NEXTS, sop1->so_nxt); X} X X/* cmd - execute one command */ X XPRIVATE void cmd (cp, ap, fn, ln) XR1 bStrT cp; /* Command.*/ X bStrT ap; /* Argument.*/ X cStrT fn; /* File name.*/ X unsigned ln; /* Line number in file.*/ X X/* Function: X * Execute the given command with the given argument. On error, X * write an error message, using the file name and line number. X * Algorithm: X * Linear search for command name. X * Notes: X * 1) Should use perfect hashing. X */ X{ XR2 bStrT p; /* General putpose.*/ X Xif (DB(D_CMD)) FPRINTF (stderr, "%s: %u: %s %s\n", fn, ln, cp, ap); Xif (NULBSTR != (p = prefix (S("AutoColumn"), cp))) X param0.AutoCol[ADA_US (p, "Number of columns", 1, MPAGCOL)] = X a2ocol (ap, S("Maximum number of output columns")); Xelse if (bStrEQ (S("AutoFile"), cp)) X param0.AutoFil = ms2bool (ap, cp); Xelse if (bStrEQ (S("AutoLandscape"), cp)) X param0.AutoLnd = a2ocol (ap, cp); Xelse if (bStrEQ (S("BodySize"), cp)) X param0.BodySiz = mra2bp (ap, cp, 1.0, 1000.0); Xelse if (bStrEQ (S("BottomMarginLandscape"), cp)) X param0.BMargL = mra2bp (ap, cp, 0.0, MM(100.0)); Xelse if (bStrEQ (S("BottomMarginPortrait"), cp)) X param0.BMargP = mra2bp (ap, cp, 0.0, MM(100.0)); Xelse if (bStrEQ (S("BottomSkip"), cp)) X param0.BSkip = mra2bp (ap, cp, 0.0, MM(100.0)); Xelse if (bStrEQ (S("CommandFile"), cp)) X { X if (bStrEQ (ap, S("-"))) readrc (stdin, sStdin); else readpth (ap); X } Xelse if (bStrEQ (S("Columns"), cp)) X param0.Columns = ADA_US (ap, cp, 1, MPAGCOL); Xelse if (bStrEQ (S("ColumnSeparation"), cp)) X param0.ColSep = mra2bp (ap, cp, 0.0, MM(100.0)); Xelse if (bStrEQ (S("Debug"), cp)) X Debug = ADA_INT (ap, cp, 0, 9); Xelse if (bStrEQ (S("EndControlD"), cp)) X EndCtlD = ms2bool (ap, cp); Xelse if (bStrEQ (S("FixedWidthBodyFont"), cp)) X param0.FWFont = mcpstr (ap); Xelse if (bStrEQ (S("File"), cp)) X { X if (filp == &fil[MFILES + 1]) malf1 (eMFiles, MFILES); X filp->filName = mcpstr (ap); X filp->filPara = param0; X ++filp; X } Xelse if (bStrEQ (S("FixedWidth"), cp)) X param0.FixWid = ms2bool (ap, cp); Xelse if (bStrEQ (S("FoldFirst"), cp)) X param0.FoldFst = a2ocol (ap, cp); Xelse if (bStrEQ (S("FoldIndent"), cp)) X param0.FoldInd = mra2bp (ap, cp, 0.0, MM(100.0)); Xelse if (bStrEQ (S("FoldRest"), cp)) X param0.FoldRst = a2ocol (ap, cp); Xelse if (bStrEQ (S("FooterFont"), cp)) X param0.FootFnt = mcpstr (ap); Xelse if (bStrEQ (S("FooterHeight"), cp)) X param0.FootHt = mra2bp (ap, cp, 0.0, 72.0); Xelse if (bStrEQ (S("Header"), cp)) X filp->filHdr = mcpstr (ap); Xelse if (bStrEQ (S("HeaderFont"), cp)) X param0.HeadFnt = mcpstr (ap); Xelse if (bStrEQ (S("HeaderHeight"), cp)) X param0.HeadHt = mra2bp (ap, cp, 0.0, 1000.0); Xelse if (bStrEQ (S("LandscapeRotation"), cp)) X { X param0.LandRot = ADA_INT (ap, cp, -90, 90); X if ((-90 != param0.LandRot) && (90 != param0.LandRot)) malf1 (eRot); X } Xelse if (bStrEQ (S("LeftMarginLandscape"), cp)) X param0.LMargL = mra2bp (ap, cp, 0.0, MM(100.0)); Xelse if (bStrEQ (S("LeftMarginPortrait"), cp)) X param0.LMargP = mra2bp (ap, cp, 0.0, MM(100.0)); Xelse if (bStrEQ (S("LineNumberFont"), cp)) X param0.LNFnt = mcpstr (ap); Xelse if (bStrEQ (S("LineNumberHeight"), cp)) X param0.LNHt = mra2bp (ap, cp, 0.0, 72.0); Xelse if (bStrEQ (S("LineNumberMultiple"), cp)) X param0.LNMult = ADA_US (ap, cp, 0, 1000); Xelse if (bStrEQ (S("LineNumberWidth"), cp)) X param0.LNWid = mra2bp (ap, cp, 0.0, MM(100.0)); Xelse if (NULBSTR != (p = prefix (S("Octet"), cp))) X addso (p, ap); Xelse if (bStrEQ (S("PageHeight"), cp)) X param0.PageHt = mra2bp (ap, cp, MM(100.0), MM(1000.0)); Xelse if (bStrEQ (S("PageWidth"), cp)) X param0.PageWid = mra2bp (ap, cp, MM(100.0), MM(1000.0)); Xelse if (bStrEQ (S("PostScript"), cp)) X FPRINTF (psos, "%s\n", ap); Xelse if (bStrEQ (S("Reverse"), cp)) X Reverse = ms2bool (ap, cp); Xelse if (bStrEQ (S("RightMarginLandscape"), cp)) X param0.RMargL = mra2bp (ap, cp, 0.0, MM(100.0)); Xelse if (bStrEQ (S("RightMarginPortrait"), cp)) X param0.RMargP = mra2bp (ap, cp, 0.0, MM(100.0)); Xelse if (bStrEQ (S("Spacing"), cp)) X param0.Spacing = mra2d (ap, NULBSTR, TRUE, cp, 0.5, 10.0, (bStrT *) NULL); Xelse if (bStrEQ (S("SymbolFont"), cp)) X param0.SymbFnt = mcpstr (ap); Xelse if (bStrEQ (S("TabWidth"), cp)) X param0.TabWid = ADA_US (ap, cp, 1, 80); Xelse if (bStrEQ (S("TextVertical"), cp)) X param0.TxtVert = ms2bool (ap, cp); Xelse if (bStrEQ (S("TopMarginLandscape"), cp)) X param0.TMargL = mra2bp (ap, cp, 0.0, MM(100.0)); Xelse if (bStrEQ (S("TopMarginPortrait"), cp)) X param0.TMargP = mra2bp (ap, cp, 0.0, MM(100.0)); Xelse if (bStrEQ (S("TopSkip"), cp)) X param0.TSkip = mra2bp (ap, cp, 0.0, MM(100.0)); Xelse if (NULBSTR != (p = prefix (S("Undefine"), cp))) X undef (p, ap); Xelse if (bStrEQ (S("VariableWidthBodyFont"), cp)) X param0.VWFont = mcpstr (ap); Xelse if (bStrEQ (S("XAdjust"), cp)) X param0.XAdjust = mra2bp (ap, cp, MM(-50.0), MM(50.0)); Xelse if (bStrEQ (S("YAdjust"), cp)) X param0.YAdjust = mra2bp (ap, cp, MM(-50.0), MM(50.0)); Xelse malf1 (eCmd, fn, ln, cp, ap); X} X X/* cpStdin - copy standard input to temporary file */ X XPRIVATE void cpStdin (fp) XR1 filT *fp; /* Points to data for file.*/ X X/* Function: X * This is the result of a "File -" command. The standard input X * must be copied to a temporary file because cz needs to read it X * twice. If there was no Header command, make the header X * "Standard Input." X * Algorithm: X * Make temporary file. Open it for append. Call mfcopy(). X * Close files. X * Returns: X * X * Notes: X * 1) Don't exit on a read error, just write a warning. X */ X{ XR2 streamT tos; /* Temporary file output stream.*/ Xstatic char tfnb2[] = "/tmp/czsXXXXXX"; /* Temporary file name buffer.*/ X Xif (NULBSTR == fp->filHdr) fp->filHdr = sStdin; Xfp->filName = (bStrT) mktemp (tfnb2); Xtos = mfopen (fp->filName, "w+"); Xfp->filTmp = TRUE; Xmfcopy (stdin, 0, sStdin, tos, 1, fp->filName); Xif (fclose (stdin)) malf0 (eClose, sStdin); Xmfclose (tos, fp->filName); Xif (DB(D_FILE)) FPRINTF (stderr, "stdin -> %s\n", fp->filName); X} X X/* cvcol - try to output one page column */ X XPRIVATE int cvcol (fp, pc, clm, moc) XR6 filT *fp; /* Points to data for file to convert.*/ XR7 unsigned pc; /* Page column number.*/ XR9 unsigned clm; /* Max number of output lines in column.*/ X unsigned moc; /* Max output column.*/ X X/* Function: X * Attempt to emit one output column. The output goes to a temporary X * file, so if it fails, because of line overflow, the caller can X * fseek back to the beginning of the failed attempt. X * Algorithm: X * Loop until failure or until a complete column is output. X * Call cvline() to attempt to convert each line, and switch X * on the return code. On success, end of column, end of page, X * end of file in middle of line, or success (folded line), X * print the line, using the appropriate PostScript functions X * at the beginning and end of the line. One end of file at the X * beginning of a line or line overflow, don't print anything, just X * return the appropriate code. X * Returns: X * SUCCESS or R_* code. X * Notes: X * 1) Variable s is used for for loop control (when negative) and X * as return code (when non-negative). This is a common trick. X * 2) linNum is incremented at the *end* of an input line, so eln X * is 1 + linNum for folded lines. X */ X{ XR8 unsigned cl = 1; /* Output line number within column.*/ XR5 unsigned eln; /* Effective line number.*/ XR4 boolT p; /* Print this output line.*/ XR2 bStrT pnb; /* PostScript procedure for beginning of line.*/ XR3 bStrT pne; /* PostScript procedure for end of line.*/ XR1 int s = -1; /* Return code.*/ X char lns[20]; /* Line number string.*/ X XFPRINTF (psts, "(%u)%u %s\n", pc, pc, PCOLB); Xfor (; s < 0; ++cl) X { X outBufP = outBuf; X p = FALSE; X psLinL = 0; X switch (s = cvline (fp, moc)) X { X case SUCCESS: X case R_COLE: X case R_PAGEE: X case R_EOFM: X if (linCont) X { X pnb = PLLB; X pne = PLLE; X linCont = FALSE; X } X else X { X pnb = PSLB; X pne = PSLE; X } X if ((SUCCESS == s) && (cl != clm)) s = -1; X p = TRUE; X break; X case R_CONT: X if (linCont) X { X pnb = PMLB; X pne = PMLE; X } X else X { X pnb = PFLB; X pne = PFLE; X linCont = TRUE; X } X s = ((cl == clm) ? SUCCESS : -1); X p = TRUE; X break; X case R_EOFB: X if (1 != cl) s = R_EOFM; X break; X case R_OVFL: X break; X default: X malf1 (eIntern, "cvcol", __LINE__); X break; X } X if (p) X { X eln = linNum; X if (linCont) ++eln; X PSPUTC (EOS); X if ((0 != fp->filPara.LNMult) && X ((0 == (eln % fp->filPara.LNMult)) || (eln==lines))) X SPRINTF (lns, "(%u)", eln); X else X STRCPY (lns, "()"); X FPRINTF (psts, "%s%u %s\n%s%s%u %s\n", lns, eln, pnb, X outBuf, lns, eln, pne); X } X } XFPRINTF (psts, "(%u)%u %s\n", pc, pc, PCOLE); Xif (DB(D_COL)) FPRINTF (stderr, "cvcol (%u, %u, %u) = %d\n", pc, clm, moc, s); Xreturn (s); X} X X/* cvfile - convert one file into PostScript */ X XPRIVATE void cvfile (fp) XR2 filT *fp; /* Points to data for file to convert.*/ X X/* Function: X * Convert the file to PostScript. X * Algorithm: X * If the file is standard input, copy it to a temporary file. X * Call doTop() to generate the output that is the same for every page. X * Open the file and call preScan() to compute the starting number X * of page columns for each page (pc0), and starting orientation (por0). X * preScan also counts input lines. Open a temporary output file. X * The outer (mf) loop is executed once for each page. X * The inner (mp) loop is executed once for each page attempt. X * Start with pc0 and por0. Compute the maximum allowed output X * columns for this page attempt (moc) from pc, por, and the X * AutoFile, AutoLandscape, and AutoColumn data. Call cvpage() X * to make the try. On overflow, first try decreasing pc. If pc X * is 1, try going to landscape. Seek back to the beginning of the X * page and try again. At the end of the outer loop, step through X * each page and call putPage() to write it for real. X * Notes: X * X */ X{ XR9 streamT f; /* Input stream.*/ XR10 long isp; /* Offset in input stream.*/ XR8 boolT mf; /* More of file to read.*/ XR3 unsigned moc; /* Max number of output columns to try.*/ XR1 boolT mp; /* More of page to convert.*/ X ncStatT ncs; /* Save nc state at beginning of page.*/ XR11 long osp; /* Offset in output stream.*/ XR14 unsigned pages; /* Pages of output for this file.*/ XR5 unsigned pc; /* Current number of page columns.*/ X unsigned pc0; /* Initial number of page columns.*/ XR4 boolT por; /* Current page in portrait mode.*/ X boolT por0; /* Initially portrait mode.*/ XR7 unsigned pn; /* Page number.*/ XR6 int s; /* Return code.*/ XR12 unsigned sln; /* Save line number.*/ X pageT pageBy[MPAGES + 2]; /* Offset in psts of each page.*/ XR13 pageT *pp; /* Steps through pageBy[].*/ Xstatic char tfnb1[] = "/tmp/czpXXXXXX"; /* Temporary file name buffer.*/ X Xif (DB(D_FILE)) FPRINTF (stderr, "cvfile %s\n", fp->filName); Xif (bStrEQ (S("-"), fp->filName)) cpStdin (fp); Xif (!doTop (fp)) return; Xf = fopen (fp->filName, "r"); Xif (NULSTRM == f) X { X malf0 (eOpen, fp->filName); X return; X } XpreScan (fp, f, &pc0, &por0); Xif (0 == pc0) X { X malf0 (eEmpty, fp->filName); X if (fclose (f)) malf0 (eClose, fp->filName); X if (fp->filTmp) X { X if (unlink (fp->filName)) malf0 (eUnlink, fp->filName); X } X return; X } Xif (NULCSTR == pstfn) pstfn = mktemp (tfnb1); Xpsts = mfopen (pstfn, "w+"); Xnc = nc0; Xnc.ncIStrm = f; XlinNum = 0; Xpn = 0; Xpp = &pageBy[1]; Xfor (mf = TRUE; mf;) X { X ++pn; X pc = pc0; X por = por0; X isp = ftell (f); X ncs = nc; X osp = ftell (psts); X sln = linNum; X for (mp = TRUE; mp;) X { X if (fp->filPara.AutoFil) X moc = MOCOL; X else if (por && (1 == pc)) X moc = fp->filPara.AutoLnd; X else if (1 != pc) X moc = fp->filPara.AutoCol[pc]; X else X moc = MOCOL; X s = cvpage (fp, pc, por, moc); X switch (s) X { X case R_EOFB: X --pn; X /* Falls through.*/ X case R_EOFM: X mf = FALSE; X /* Falls through.*/ X case SUCCESS: X case R_PAGEE: X mp = FALSE; X break; X case R_OVFL: X if (por && (1 == pc)) X por = FALSE; X else if (1 != pc) X --pc; X else X malf1 (eIntern, "cvfile", __LINE__); X mfseek (f, isp, 0, fp->filName); X mfflush (psts, pstfn); X mfseek (psts, osp, 0, pstfn); X linNum = sln; X nc = ncs; X break; X default: X malf1 (eIntern, "cvfile", __LINE__); X break; X } X } X if (pn > MPAGES) malf1 (eMPages, fp->filName, MPAGES); X if (R_EOFB != s) X { X mfflush (psts, pstfn); X pp->pgPos = osp; X pp->pgCols = pc; X pp->pgPor = por; X ++pp; X if (DB(D_PAGE)) X FPRINTF (stderr, "page %u: %u cols %s\n", pn, X pc, por ? "portrait" : "landscape"); X } X } Xif (ferror (f)) malf0 (eReadL, fp->filName, linNum); Xif (fclose (f)) malf0 (eClose, fp->filName); Xif (fp->filTmp) X { X if (unlink (fp->filName)) malf0 (eUnlink, fp->filName); X } Xpages = pn; Xif (Reverse) X { X pp->pgPos = ftell (psts); X for (--pp; pp != pageBy; --pp) X putPage (fp, pp, pn--, pages, pp[1].pgPos - pp->pgPos); X } Xelse X { X pn = 1; X pp->pgPos = ftell (psts); X for (pp = &pageBy[1]; pn <= pages; ++pp) X putPage (fp, pp, pn++, pages, pp[1].pgPos - pp->pgPos); X } Xif (fclose (psts)) malf0 (eClose, pstfn); XtotPag += pages; X} X X/* cvline - Try to convert one output line to PostScript */ X XPRIVATE int cvline (fp, moc) XR9 filT *fp; /* Points to data for file to convert.*/ XR8 unsigned moc; /* Max output column.*/ X X/* Function: X * Attempt to convert one output line. The output goes into a buffer; X * it is not written onto the temporary file here. This is because X * the output must be preceded by a call to the appropriate PostScript X * procedure, but which one is appropriate depends on whether the line X * is folded. X * Algorithm: X * Loop. Call nextc() to get next input character and convert it X * to nextc() output form, which is an array of unsigned shorts. X * Elements less than 256 are literal bytes to be output; other X * elements are from the T_* codes, with a bias of 256. X * (T_END + 256) marks the end of the array. X * X * Set endF if this character ends the line in some way. X * Set tabF is this character is a tab. Compute the number of X * spaces. (The -1 is because nextc() has already incremented X * nc.ncICol and oCol.) Check for output column overflow and folding. X * Step through each element in the array. Put literal bytes into X * the buffer and switch on the T_* codes. If a PostScript line X * could become longer than MPSLINE characters, force the end of a X * string. X * Returns: X * Return code. X * Notes: X * 1) The ENDSTR macro assumes that PSPUTC is one character. X * 2) Warning messages for undefined characters have already X * been printed in the preScan() pass. X */ X{ X/* If outputting a PostScript string, end it:*/ X#define ENDSTR {if(ins){PSPUTC(')');PSPUTC(*PSHOW);PSPUTC('\n');ins=FALSE;}} XR2 ushrtT *pp; /* Returned by nextc().*/ XR1 ushrtT *pp2; /* Steps through pp[].*/ XR3 boolT endF; /* T_{LINE,COLE,PAGEE,EOF} in pp[].*/ XR4 boolT tabF; /* T_TAB in pp[].*/ XR5 boolT ins = FALSE; /* Flag set when PS string being output.*/ XR6 int s = -1; /* Loop control and return code.*/ XR7 unsigned spcs; /* Tab expands into this many spaces.*/ XR10 int i; /* Count octets.*/ X XoCol = 0; Xwhile (s < 0) X { X pp = nextc(); X endF = FALSE; X tabF = FALSE; X for (pp2 = pp; (T_END + 256) != *pp2; ++pp2) X { X if (((T_LINEE + 256) == *pp2) || ((T_COLE + 256) == *pp2) || X ((T_PAGEE + 256) == *pp2) || ((T_EOF + 256) == *pp2)) X endF = TRUE; X else if ((T_TAB + 256) == *pp2) X tabF = TRUE; X } X if (!tabF) X spcs = 1; X else X { X spcs = fp->filPara.TabWid - ((nc.ncICol - 1) % fp->filPara.TabWid); X nc.ncICol += spcs - 1; X oCol += spcs - 1; X } X if (!endF) X { X if (oCol >= moc) X s = R_OVFL; X else if (oCol >= (linCont ? fp->filPara.FoldRst : fp->filPara.FoldFst)) X { X if (nc.ncUn) malf1 (eIntern, "cvline", __LINE__); X nc.ncUn = TRUE; X nc.ncICol -= spcs; X s = R_CONT; X } X } X if (s < 0) X { X do X { X if (*pp <= 256) X PSPUTC (*pp); X else X { X switch (*pp - 256) X { X case T_UNDEF: X ENDSTR; X PSPUTC ('('); X if (fp->filPara.FixWid) X SPRINTF (outBufP, "%02X", nc.ncOb[nc.ncN - 1]); X else X { X SPRINTF (outBufP, "%o", nc.ncOb[0]); X for (i = 1; i != nc.ncN; ++i) X { X outBufP = strend (outBufP); X SPRINTF (outBufP, " %o", nc.ncOb[i]); X } X } X outBufP = strend (outBufP); X SPRINTF (outBufP, ")%s", PUNDEF); X outBufP = strend (outBufP); X PSPUTC ('\n'); X break; X case T_TAB: X if (!ins) X { X PSPUTC ('('); X ins = TRUE; X } X while (spcs--) X PSPUTC (' '); X break; X case T_STRB: X if (!ins) X { X PSPUTC ('('); X ins = TRUE; X } X break; X case T_STRE: X ENDSTR; X break; X case T_LINEE: X ++linNum; X nc.ncICol = 0; X s = SUCCESS; X break; X case T_COLE: X s = R_COLE; X break; X case T_PAGEE: X s = R_PAGEE; X break; X case T_EOF: X s = ((0 == oCol) ? R_EOFB : R_EOFM); X break; X } X } X } X while ((T_END + 256) != *++pp); X } X if (!ins) X PSPUTC ('\n'); X else if (psLinL > (MPSLINE - MMULOCT * MPSSTR - 1)) X ENDSTR; X } XENDSTR; Xif (DB(D_LINE)) FPRINTF (stderr, "cvline %u = %d\n", linNum, s); Xreturn (s); X} X X/* cvpage - try to convert one page to PostScript */ X XPRIVATE int cvpage (fp, pc, por, moc) XR4 filT *fp; /* Points to data for file to convert.*/ XR3 unsigned pc; /* Page columns to try.*/ X boolT por; /* Portrait mode.*/ XR6 unsigned moc; /* Max input column.*/ X X/* Function: X * Try to convert one page. X * Algorithm: X * Compute clm, the maximum number of output lines that will fit X * in one output column. This has to be recomputed for each page X * attempt because pc and por can be different. Loop over the X * page columns. Call cvcol() to try to convert one column, and X * switch on the return code. X * Returns: X * Return code. X * Notes: X * X */ X{ X double bodHt; /* Body height.*/ XR2 unsigned c = 1; /* Current page column.*/ XR5 unsigned clm; /* Max number of output lines in a page column.*/ XR7 paramT *p = &fp->filPara; X double leading = p->BodySiz * p->Spacing; /* Space between lines.*/ XR1 int s; /* Return code.*/ X double yHead; /* Y coordinate of header baseline.*/ X Xif (por) X { X yHead = p->PageHt - p->TMargP - p->HeadHt; X if (yHead <= 0.0) malf1 (eBigHd, p->TMargP + p->HeadHt, p->PageHt); X bodHt = yHead - p->TSkip - p->BSkip - p->FootHt - p->BMargL; X } Xelse X { X yHead = p->PageWid - p->TMargL - p->HeadHt; X if (yHead <= 0.0) malf1 (eBigHd, p->TMargL + p->HeadHt, p->PageWid); X bodHt = yHead - p->TSkip - p->BSkip - p->FootHt - p->BMargP; X } Xif (bodHt < leading) malf1 (eNoBod, bodHt, leading); Xclm = (unsigned)(bodHt / leading); Xfor (s = -1; s < 0; ++c) X { X switch (s = cvcol (fp, c, clm, moc)) X { X case SUCCESS: X case R_COLE: X s = ((c == pc) ? SUCCESS : -1); X break; X case R_EOFM: X case R_PAGEE: X case R_OVFL: X break; X case R_EOFB: X if (1 != c) s = R_EOFM; X break; X default: X malf1 (eIntern, "cvpage", __LINE__); X break; X } X } Xif (DB(D_PAGEA)) X FPRINTF (stderr, "cvpage (%u, %s, %u) = %d\n", pc, X por ? "portrait" : "landscape", moc, s); Xreturn (s); X} X X/* docFnts - output %%DocumentFonts: comment */ X XPRIVATE void docFnts() X X/* Function: X * Write the DocumentFonts structure comment that lists all fonts X * used. Get as many font names on a line as possible, without X * exceeding MPSLINE. Use the %%+ line continuation convention X * if necessary. X * Algorithm: X * Step through fonts[], write each font name, and keep track of X * the output column. X * Returns: X * X * Notes: X * X */ X{ XR2 unsigned c; /* Output column.*/ XR1 fontT *fp; /* Steps through fonts[].*/ XR3 unsigned l; /* Length of font name and leading space.*/ Xstatic char df[] = "%%DocumentFonts:"; X Xc = strlen (df); XFPUTS (df, psos); Xfor (fp = fonts; fp != fontP; ++fp) X { X l = 1 + strlen (fp->fntName); X if ((c + l) >= MPSLINE) X { X FPUTS ("\n%%+", psos); X c = 0; X } X PUTC (' ', psos); X FPUTS (fp->fntName, psos); X c += l; X } XPUTC ('\n', psos); X} X X/* doTop - set up topBuf[] for a new file */ X XPRIVATE boolT doTop (fp) XR3 filT *fp; /* Points to data for file to convert.*/ X X/* Function: X * There is some repetitive stuff at the beginning of every page X * that is the same for every file. It's repeated so that every X * PostScript page is independent of every other page. This X * allows page reversal, page selection, and parallel page interpretation. X * This function generates the constant top-of-page stuff, and X * places it in the topBuf[] buffer. X * Algorithm: X * Store the constant defs. Call cvline() to store the header. X * Returns: X * TRUE of success; FALSE on error. X * Notes: X * X */ X{ XR2 paramT *p = &fp->filPara; XR1 bStrT tp; /* Steps through topBuf[].*/ X Xtp = topBuf; XSPRINTF (tp, "%s\n", PSAVE); Xtp = strend (tp); XSPRINTF (tp, "/%s /%sE %s\n", PFONT, p->FixWid ? p->FWFont : p->VWFont, X PDEF); Xtp = strend (tp); XSPRINTF (tp, "/%s /%sE %s\n", FOOTFNT, p->FootFnt, PDEF); Xtp = strend (tp); XSPRINTF (tp, "/%s /%sE %s\n", HEADFNT, p->HeadFnt, PDEF); Xtp = strend (tp); XSPRINTF (tp, "/%s /%sE %s\n", PLNFNT, p->LNFnt, PDEF); Xtp = strend (tp); XSPRINTF (tp, "/%s /%s %s\n", SYMBFNT, p->SymbFnt, PDEF); Xtp = strend (tp); XSPRINTF (tp, "/%s %s %s\n", PFIXWID, p->FixWid ? "true" : "false", PDEF); XoutBufP = strend (tp); XoutBufE = &topBuf[MTOPBUF]; XputDimO (BODYSIZ, p->BodySiz); XputDimO (PFOOTHT, p->FootHt); XputDimO (PHEADHT, p->HeadHt); XputDimO (LEADING, p->BodySiz * p->Spacing); XputDimO (PLNHT, p->LNHt); XputDimO (PLNWID, p->LNWid); XputDimO (XADJUST, p->XAdjust); XputDimO (YADJUST, p->YAdjust); XSPRINTF (outBufP, "/%s", PHEADER); XoutBufP = strend (outBufP); XPSPUTC ('\n'); XPSPUTC ('{'); XPSPUTC ('\n'); Xnc = nc0; Xnc.ncFP = fp; Xif (NULBSTR == fp->filHdr) fp->filHdr = fp->filName; Xnc.ncStr = fp->filHdr; Xswitch (cvline (fp, MOCOL)) X { X case R_EOFB: X case R_EOFM: X break; X case SUCCESS: X malf0 (eHdrEnd, "line", fp->filName, fp->filHdr); X return (FALSE); X case R_COLE: X malf0 (eHdrEnd, "column", fp->filName, fp->filHdr); X return (FALSE); X case R_PAGEE: X malf0 (eHdrEnd, "page", fp->filName, fp->filHdr); X return (FALSE); X default: X malf1 (eIntern, "cvfile", __LINE__); X break; X } XPSPUTC ('}'); XSTRCPY (outBufP, PDEF); XoutBufP = strend (outBufP); XPSPUTC ('\n'); XPSPUTC (EOS); Xnc = nc0; Xreturn (TRUE); X} X X/* headCom - output PostScript structure header comments */ X XPRIVATE void headCom() X X/* Function: X * Output the structure comments at the beginning of the PostScript X * output. X * Algorithm: X * X * Returns: X * X * Notes: X * 1) The %%For: line is entirely optional. If your system X * has any trouble with the code to generate it, you can X * safely comment it out. X */ X{ XR1 struct tm *tmp; /* Returned by localtime().*/ X long ut; /* Current system time.*/ X byteT fnb[1024]; /* Store user's full name here.*/ Xextern long time(); /* (3C).*/ X XFPUTS ("%!PS-Adobe-2.1\n", psos); XFPRINTF (psos, "%%%%Creator: cz%d.%d\n", FRZ_MAJ, FRZ_MIN); Xut = time ((long *) NULL); Xtmp = localtime (&ut); XFPRINTF (psos, "%%%%CreationDate: %d-%02d-%02d %02d:%02d:%02d\n", X 1900 + tmp->tm_year, 1 + tmp->tm_mon, tmp->tm_mday, X tmp->tm_hour, tmp->tm_min, tmp->tm_sec); Xif (NULBSTR != userfn (fnb)) FPRINTF (psos, "%%%%For: %s\n", fnb); XFPUTS ("%%Pages: (atend)\n", psos); XFPUTS ("%%DocumentFonts: (atend)\n", psos); X} X X/* init - initialize at start of execution */ X XPRIVATE void init() X X/* Function: X * Initialize some things. X * Algorithm: X * X * Returns: X * X * Notes: X * 1) The umask setting will make the temporary files unreadable by X * others than the creator, for security. X */ X{ XR1 bStrT bp1; /* Steps through ncMap[].*/ XR2 bStrT bp2; /* End of ncMap[].*/ XR5 int i; /* Loop counter.*/ XR3 ushrtT *up1; /* Steps through AutoCol[].*/ XR4 ushrtT *up2; /* End of AutoCol[].*/ Xextern int umask(); /* (2).*/ X X(void) umask (0077); Xnc0.ncStr = NULBSTR; Xbp1 = ncMap; Xbp2 = &ncMap[256]; Xwhile (bp1 != bp2) X *bp1++ = T_RES; XncMap[E_STRB] = T_STRB; XncMap[E_STRE] = T_STRE; XncMap[E_COM] = T_COM; XncMap[E_EESC] = T_EESC; XncMap[E_COLE] = T_COLE; XncMap[E_LINEE] = T_LINEE; XncMap[E_PAGEE] = T_PAGEE; XncMap[E_TAB] = T_TAB; Xup1 = param0.AutoCol; Xup2 = up1 + MPAGCOL + 1; Xwhile (up1 != up2) X *up1++ = MOCOL; Xparam0.AutoLnd = MOCOL; Xfor (i = 1; MSTATE != i; ++i) X states[i] = (stateT *) NULL; X#include "cz0-init.h" X} X X/* mpsputc - handle output buffer overflow */ X XPRIVATE void mpsputc () X X/* Function: X * The buffer in which PSPUTC stores bytes has overflowed. X Write an error message. X * Algorithm: X * Figure out which buffer and call malf1(). X * Returns: X * No return. X * Notes: X * X */ X{ Xif (&outBuf[MOUTBUF] == outBufE) X malf1 (ePSPutC, "outBuf", MOUTBUF); Xelse if (&topBuf[MTOPBUF] == outBufE) X malf1 (ePSPutC, "topBuf", MTOPBUF); Xelse X malf1 (eIntern, "mpsputc", __LINE__); X} X X/* mra2bp - convert string to typographical units and check for errors */ X XPRIVATE double mra2bp (s, n, l, h) XR3 bStrT s; /* Input string.*/ X bStrT n; /* Name of field, for error messages.*/ X double l; /* Lower bound.*/ X double h; /* Upper bound.*/ X X/* Function: X * String s is supposed to be a real numeric literal followed by a X * two-letter units abbreviation. Convert it to big points. X * Algorithm: X * Linear search on units, then call mra2d(). X * Returns: X * PostScript internal units. X * Notes: X * 1) Maybe I should use perfect hashing on the units? X * 2) For now, loose syntax is allowed, e.g. 0bp. But this is not X * documented, so I can tighten up whenever I want. X */ X{ X double sf; /* Scaling factor.*/ XR2 int ls; /* Length of input string.*/ XR1 bStrT p; /* Should point to units.*/ X Xif (DB(D_PSC)) FPRINTF (stderr, "mra2bp (%s, %s, %G, %G)\n", s, n, l, h); Xls = strlen (s); Xif (ls < 3) malf1 ("%s [%s]: Bad format", n, s); Xp = &s[ls - 2]; Xif (bStrEQ (S("bp"), p)) sf = 1.0; Xelse if (bStrEQ (S("cc"), p)) sf = CF_CC; Xelse if (bStrEQ (S("cm"), p)) sf = CF_CM; Xelse if (bStrEQ (S("dd"), p)) sf = CF_DD; Xelse if (bStrEQ (S("in"), p)) sf = CF_IN; Xelse if (bStrEQ (S("mm"), p)) sf = CF_MM; Xelse if (bStrEQ (S("pc"), p)) sf = CF_PC; Xelse if (bStrEQ (S("pt"), p)) sf = CF_PT; Xelse malf1 (eUnits, n, s, p); Xreturn (sf * mra2d (s, p, TRUE, n, l, h, (bStrT *) NULL)); X} X X/* ms2bool - convert string to Boolean and handle errors */ X XPRIVATE boolT ms2bool (s, fn) XR1 bStrT s; /* Input string.*/ X bStrT fn; /* Field name.*/ X X/* Function: X * Convert string representations of Booleans to internal representation. X * Algorithm: X * Linear search. X * Returns: X * TRUE or FALSE. No return on error. X * Notes: X * 1) Case is significant. X */ X{ Xif (bStrEQ (S("false"), s)) return (FALSE); Xelse if (bStrEQ (S("true"), s)) return (TRUE); Xelse malf1 ("%s [%s] neither false nor true", s, fn); X/*NOTREACHED*/ X} X X/* nextc - get next input character */ X XPRIVATE ushrtT *nextc() X X/* Function: X * Convert one input character to output format. The input character X * can come from a stream or a string (for headers). A character X * can be up to MMULOCT bytes. Output format is an array of unsigned X * shorts. Elements in the range [0, 255] are bytes to be output literally. X * Higher elements are one of the T_* codes biased by 256. X * (T_END + 256) marks the end of the array. X * Algorithm: X * If previous result was pushed back by line folding, unpush it and return. X * Otherwise, start in state 0 and loop. Get one byte from the string X * or stream. Handle end of string/file. Get the state-octet entry. X * Step through the PostScript. Copy ordinary characters to the return X * buffer, but switch on escapes. X * Returns: X * A pointer to the array. X * Notes: X * X */ X{ XR7 stateT *sp; /* Points to current stateT.*/ XR4 soT *sop; /* Points to current state-octet pair.*/ XR6 boolT m; /* More to do.*/ XR5 unsigned st; /* State.*/ XR3 ushrtT *rbp; /* Steps through return buffer.*/ XR9 bStrT obp; /* Steps through octet buffer.*/ XR8 rcharT o; /* Current input octet.*/ XR1 unsigned p; /* Current result byte.*/ XR2 bStrT psp; /* Steps through PostScript for each state-octet pair.*/ X Xif (nc.ncUn) X { X nc.ncUn = FALSE; X return (nc.ncRb); X } Xst = 0; Xobp = nc.ncOb; Xrbp = nc.ncRb; Xfor (m = TRUE; m;) X { X if (NULBSTR != nc.ncStr) X { X o = B(*nc.ncStr); X ++nc.ncStr; X if (EOS == o) X { X if (0 != st) X { X malf0 (eEOSSt, st, nc.ncFP->filHdr); X st = 0; X } X o = EOF; X } X } X else X { X o = getc (nc.ncIStrm); X if (EOF == o) X { X if (ferror (nc.ncIStrm)) malf0 (eRead, nc.ncFP->filName); X if (0 != st) X { X malf0 (eEOFSt, nc.ncFP->filName, st); X st = 0; X } X } X } X if (EOF == o) X { X *rbp++ = T_EOF + 256; X m = FALSE; X } X else X { X if ((o < 0) || (o > 255)) malf1 (eIntern, "nextc", __LINE__); X *obp++ = o; X if (0 == st) X { X ++nc.ncICol; X ++oCol; X } X p = 0; X sp = states[st]; X if (((stateT *) NULL) == sp) X { X if (DB(D_OCT)) FPRINTF (stderr, "State %u undefined\n", st); X p = T_UNDEF + 256; X } X else X { X sop = ((soT *) sp) + o; X psp = sop->so_ps; X if (DB(D_OCT)) X FPRINTF (stderr, "State %u Octet %c 8#%o# (%s%c%c%u)\n", X st, o, o, psp, E_ESC, E_NEXTS, sop->so_nxt); X if (NULBSTR == psp) p = T_UNDEF + 256; X } X if ((T_UNDEF + 256) == p) X { X rbp = nc.ncRb; X *rbp++ = p; X st = 0; X } X else X { X for (; EOS != (p = B(*psp)); ++psp) X { X if (E_ESC != p) X *rbp++ = p; X else X { X ++psp; X p = ncMap[B(*psp)]; X switch (p) X { X case T_RES: /* Can't happen.*/ X malf1 (eMap, E_ESC, *psp, *psp, st, o, o); X break; X case T_COM: X *rbp++ = COMMENT; X break; X case T_EESC: X *rbp++ = E_ESC; X break; X default: X *rbp++ = p + 256; X break; X } X } X } X st = sop -> so_nxt; X } X } X if (0 == st) m = FALSE; X } X*rbp = T_END + 256; Xnc.ncN = obp - nc.ncOb; Xif (DB(D_PSC)) X { X for (rbp = nc.ncRb; (T_END + 256) != *rbp; ++rbp) X { X if (*rbp < 256) X PUTC (*rbp, stderr); X else X { X switch (*rbp - 256) X { X case T_UNDEF: X FPRINTF (stderr, "%cU", E_ESC); X break; X case T_STRB: X FPRINTF (stderr, "%c%c", E_ESC, E_STRB); X break; X case T_STRE: X FPRINTF (stderr, "%c%c", E_ESC, E_STRE); X break; X case T_TAB: X FPRINTF (stderr, "%c%c(%u)", E_ESC, E_TAB, nc.ncICol); X break; X case T_COLE: X FPRINTF (stderr, "%c%c", E_ESC, E_COLE); X break; X case T_LINEE: X FPRINTF (stderr, "%c%c", E_ESC, E_LINEE); X break; X case T_PAGEE: X FPRINTF (stderr, "%c%c", E_ESC, E_PAGEE); X break; X case T_EOF: X FPRINTF (stderr, "%cE", E_ESC); X break; X default: X malf1 (eIntern, "nextc", __LINE__); X break; X } X } X } X PUTC ('\n', stderr); X } Xreturn (nc.ncRb); X} X X/* preScan - find widest line in input file, and count lines */ X XPRIVATE void preScan (fp, f, pcp, porp) X filT *fp; /* Points to data for file to convert.*/ XR8 streamT f; /* Input stream.*/ X unsigned *pcp; /* Store initial number of page columns here.*/ X boolT *porp; /* Store initial orientation here.*/ X X/* Function: X * If AutoColumn or AutoLandscape are being done on a whole-file X * basis (AutoFile true), then we need to know the widest line in X * the file. Also, we need to know the number of lines in the file X * so we can always output the line number of the last one. X * This function reads through the entire file and then rewinds it X * for the conversion pass. X * Algorithm: X * Loop through each input character. Switch on T_* codes. X * Expand tabs. On end of line set mc = max (mc, oCol). X * At the end of the loop, compute pc0 and por0. X * Returns: X * Stores pc0 in *pcp and por0 in *porp. pc0 is 0 for an empty file. X * Notes: X * 1) This pass could be avoided if AutoFile is false and line numbers X * are not being printed. X */ X{ XR4 boolT nl = TRUE; /* Start of new line.*/ XR5 unsigned mc = 0; /* Max input columns in file.*/ XR6 unsigned mcl = 0; /* Line number of (first) widest line in file.*/ XR2 paramT *p = &fp->filPara; XR7 unsigned pc; /* Initial page columns.*/ XR1 ushrtT *pp; /* Returned by nextc().*/ XR3 unsigned spcs; /* Tab expands into this many spaces.*/ X XlinNum = 0; XoCol = 0; Xnc.ncIStrm = f; Xpp = nextc(); Xdo X { X if ((T_END + 256) == *pp) pp = nextc(); X if (*pp <= 256) X nl = FALSE; X else X { X switch (*pp - 256) X { X case T_TAB: X spcs = p->TabWid - ((nc.ncICol - 1) % p->TabWid) - 1; X nc.ncICol += spcs; X oCol += spcs; X nl = FALSE; X break; X case T_UNDEF: X malf0 (eUndef, fp->filName, linNum + 1); X /* Falls through.*/ X case T_STRB: X case T_STRE: X nl = FALSE; X break; X case T_LINEE: X ++linNum; X nc.ncICol = 0; X if (oCol > mc) X { X mcl = linNum; X mc = oCol; X } X nl = TRUE; X oCol = 0; X break; X case T_COLE: X case T_PAGEE: X if (oCol > mc) X { X mcl = linNum + 1; X mc = oCol; X } X oCol = 0; X break; X case T_EOF: X if (!nl) malf0 (eEOF, fp->filName, linNum + 1); X if (oCol > mc) X { X mcl = linNum + 1; X mc = oCol; X } X break; X default: X malf1 (eIntern, "cvfile", __LINE__); X break; X } X } X } Xwhile ((T_EOF + 256) != *pp++); Xif (0 == mc) X { /* Empty file.*/ X *pcp = 0; X return; X } Xlines = linNum; X--mc; Xif (p->AutoFil) X { X for (pc = p->Columns; (1 != pc) && (mc > p->AutoCol[pc]); --pc) X ; X *porp = (mc <= p->AutoLnd); X } Xelse X { X pc = p->Columns; X *porp = (0 != p->AutoLnd); X } X*pcp = pc; Xrewind (f); XlinCont = FALSE; XoutBufE = &outBuf[MOUTBUF]; Xif (DB(D_FILE)) X FPRINTF (stderr, X "preScan: widest line: %u (%u cols)\n\ttotal lines: %u\n\tinitial page columns: %u %s\n", X mcl, mc, linNum, pc, *porp ? "portrait" : "landscape"); X} X X/* psputc - append one byte to output buffer */ X XPRIVATE void psputc (c) XR1 rcharT c; /* Byte to append.*/ X X/* Function: X * Store c in the output buffer. Handle long lines and buffer overflow. X * Algorithm: X * psLinL is the current number of bytes already output on the current X * output line. Just ignore a newline after another newline. X * Returns: X * X * Notes: X * 1) This is inefficient. We shouldn't be copying so many bytes around. X * We should use pointers instead. X */ X{ Xif ('\n' == c) X { X if (0 != psLinL) X { X *outBufP++ = c; X psLinL = 0; X } X } Xelse X { X *outBufP++ = c; X ++psLinL; X } Xif (outBufP >= outBufE) mpsputc(); X} X X/* putDim - write a dimension to output buffer */ X XPRIVATE void putDim (a, v) XcStrT a; /* Abbreviation string for dimension.*/ Xdouble v; /* Value of dimension.*/ X X/* Function: X * Write a def directly to the output stream. X * Algorithm: X * X * Returns: X * X * Notes: X * 1) Two decimal places are enough precision for printers with up X * to 7200 dots per inch resolution. X */ X{ XFPRINTF (psos, "/%s %.2f %s\n", a, v, PDEF); X} X X/* putDimO - write a dimension to output buffer */ X XPRIVATE void putDimO (a, v) XcStrT a; /* Abbreviation string for dimension.*/ Xdouble v; /* Value of dimension.*/ X X/* Function: X * Store a def in the output buffer. X * Algorithm: X * The first call to PSPUTC makes psLinL nonzero for the second call. X * Otherwise the second call would be ignored. The second call X * checks for output buffer overflow. X * Returns: X * X * Notes: X * X */ X{ XPSPUTC ('/'); XSPRINTF (outBufP, "%s %.2f %s", a, v, PDEF); XoutBufP = strend (outBufP); XPSPUTC ('\n'); X} X X/* putFnts - write definition for each font used */ X XPRIVATE void putFnts() X X/* Function: X * Create the list of all fonts used by all files in the job. X * Output reencode commands for all fonts used except symbol fonts. X * Algorithm: X * Loop through each file. Call addFnt() for each font. X * Then loop through each font. X * Returns: X * X * Notes: X * X */ X{ XR1 filT *fp; /* Steps through fil[].*/ XR2 fontT *fnp; /* Steps through fonts[].*/ XR3 paramT *p; /* &fp->filPara.*/ X Xfor (fp = &fil[1]; fp != filp; ++fp) X { X p = &fp->filPara; X addFnt (p->FixWid ? p->FWFont : p->VWFont, FALSE); X addFnt (p->FootFnt, FALSE); X addFnt (p->HeadFnt, FALSE); X addFnt (p->LNFnt, FALSE); X addFnt (p->SymbFnt, TRUE); X } Xfor (fnp = fonts; fnp != fontP; ++fnp) X { X if (!fnp->fntSymb) X FPRINTF (psos, "/%sE /%s %s\n", fnp->fntName, fnp->fntName, REENCOD); X } X} X X/* putPage - Write one page to psos */ XPRIVATE void putPage (fp, pp, pn, tp, nb) XR4 filT *fp; /* Points to file data.*/ XR7 pageT *pp; /* Points to data for page.*/ XR5 unsigned pn; /* Page number.*/ XR6 unsigned tp; /* Total number of pages in file.*/ XR2 long nb; /* Number of bytes to copy from temporary file.*/ X X/* Function: X * X * Algorithm: X * The width available for one column is the (effective) page width X * less the left and right margins and column separation gutters, X * all divided by the number of columns. X * The maximum number of lines per column is the (effective) page X * height less the top and bottom margins and header and footer, X * divided by the distance between lines, then rounded down. X * X * Output all the dimensions, then copy bytes. X * Returns: X * X * Notes: X * 1) I have no idea if the TxtVert code is the right thing to do. X * The theory is that landscaped vertical text should be like X * portrait horizontal text, and vice versa. X * 2) It would be faster to copy the bytes in big chunks, not X * one at a time. X */ X{ XR1 rcharT c; /* Current byte from temp file.*/ XR3 paramT *p = &fp->filPara; X double cw; /* Page column width.*/ X double ePageHt; /* Effective page height.*/ X double ePageWid; /* Effective page width.*/ X double eLMarg; /* Effective left margin.*/ X double eRMarg; /* Effective right margin.*/ X double eTMarg; /* Effective top margin.*/ X double eBMarg; /* Effective bottom margin.*/ X Xmfseek (psts, pp->pgPos, 0, pstfn); XFPRINTF (psos, "%%%%Page: %s-%u %u\n", fp->filName, pn, pn + totPag); XFPUTS (topBuf, psos); Xif (pp->pgPor != p->TxtVert) X { X ePageHt = p->PageHt; X ePageWid = p->PageWid; X eLMarg = p->LMargP; X eRMarg = p->RMargP; X eTMarg = p->TMargP; X eBMarg = p->BMargP; X FPRINTF (psos, "/%s{}%s\n", PROTATE, PDEF); X } Xelse X { X ePageHt = p->PageWid; X ePageWid = p->PageHt; X eLMarg = p->LMargL; X eRMarg = p->RMargL; X eTMarg = p->TMargL; X eBMarg = p->BMargL; X FPRINTF (psos, "/%s/%s %s %s\n", X PROTATE, (90 == p->LandRot) ? PROTPOS : PROTNEG, PLOAD, PDEF); X } Xif (eTMarg + p->HeadHt > ePageHt) X malf1 (eBigHd, p->TMargP + p->HeadHt, p->PageHt); Xcw = (ePageWid - eLMarg - eRMarg - (pp->pgCols - 1) * p->ColSep) / pp->pgCols; Xif (cw <= 0.0) malf1 (eColWid, cw); XputDim (LMARGIN, eLMarg); XputDim (RMARGIN, eRMarg); XputDim (BMARGIN, eBMarg); XputDim (TMARGIN, eTMarg); XputDim (PPAGEWD, ePageWid); XputDim (PPAGEHT, ePageHt); XFPRINTF (psos, "/%s %u %s\n", PPAGEN, pn, PDEF); XFPRINTF (psos, "/%s(- %u / %u -)%s\n", PPAGES, pn, tp, PDEF); XputDim (FOLDIND, p->FoldInd); XputDim (TOPSKIP, p->TSkip); XputDim (PDX, cw + p->ColSep); XFPRINTF (psos, "%s\n", PPAGEB); Xwhile (nb--) X { X c = getc (psts); X if (EOF == c) X { X if (ferror (psts)) malf1 (eRead, pstfn); X malf1 (eUEOF, pstfn); X } X PUTC (c, psos); X } XFPRINTF (psos, "%s\n%%%%PageTrailer\n", PPAGEE); X} X X/* readenv - process environment variables */ X XPRIVATE void readenv() X X/* Function: X * Execute any commands in the environment. X * Algorithm: X * Linear search through the environment variables for any matches. X * Call cmd() on a match. X * Notes: X * 1) Ignore CZPATH. It's handled elsewhere. X */ X{ Xextern cStrT *environ; /* (5V).*/ XR4 bStrT *ep; /* Steps through environment variables.*/ XR3 bStrT cp; /* General purpose.*/ XR2 bStrT cp2; /* General purpose.*/ XR1 bStrT cp3; /* General purpose.*/ X byteT cbuf[MLINE + 1]; /* Command buffer.*/ X Xfor (ep = (bStrT *) environ; NULBSTR != (cp = *ep++);) X { X if ((NULBSTR != (cp3 = prefix (S(ENVPRE), cp))) && X (NULBSTR == prefix (S(CZPATH), cp))) X { X cp2 = cbuf; X for (; (EOS != B(*cp3)) && ('=' != B(*cp3)); ++cp3) X { X if (cp2 == &cbuf[MLINE]) malf1 (eMLine, ep[-1], MLINE); X *cp2++ = B(*cp3); X } X if (('=' == B(*cp3)) && (EOS != B(cp3[1]))) X { X ++cp3; X *cp2 = EOS; X cmd (cbuf, cp3, "Environment", 0); X } X } X } X} X X/* readpth - read every command file on the path */ X XPRIVATE void readpth (cfn) XR7 bStrT cfn; /* Command file name.*/ X X/* Function: X * Read and execute every cz.rc file on the search path. X * Copy every cz.ps file to output. X * Algorithm: X * Starting at the beginning of the path, X * and working toward the end, copy each segment into X * fnbuf[], append the command file name, and try to open the X * file. If the file can be opened, call readrc() on it, then X * close it and proceed to the next segment. X */ X{ XR1 bStrT p1; /* Step through path.*/ XR2 bStrT p2; /* Step through path.*/ XR3 streamT f; /* Command file.*/ XR4 int i; /* Path length.*/ XR5 int l; /* Length of command file name.*/ XR6 int m; /* Max path length.*/ Xextern cStrT getenv(); /* (3).*/ X byteT fnbuf[MFILE]; /* Buffer for current file name.*/ X Xl = strlen ((cStrT) cfn); Xm = MFILE - 1 - l - MAX (strlen (CZSUF), strlen (PSSUF)); Xp1 = path; Xif (DB(D_CMD)) FPRINTF (stderr, "readpth %s\n", cfn); Xdo X { X p2 = bStrChr (p1, PATHSEP); X i = ((NULBSTR == p2) ? strlen (p1) : p2 - p1); X if ((0 == i) || (i > m)) malf1 (eMPath, m, p1); X (void) strncpy ((cStrT) fnbuf, (cStrT) p1, i); X p1 = &fnbuf[i]; X if ('/' != B(p1[-1])) *p1++ = '/'; X STRCPY ((cStrT) p1, (cStrT) cfn); X p1 += l; X STRCPY ((cStrT) p1, CZSUF); X f = fopen ((cStrT) fnbuf, "r"); X if (NULSTRM == f) X { X if (DB(D_CMD)) FPRINTF (stderr, "trying %s...failed\n", fnbuf); X } X else X { X if (DB(D_CMD)) FPRINTF (stderr, "trying %s...ok\n", fnbuf); X readrc (f, fnbuf); X if (fclose (f)) malf0 (eClose, fnbuf); X } X STRCPY ((cStrT) p1, PSSUF); X f = fopen ((cStrT) fnbuf, "r"); X if (NULSTRM == f) X { X if (DB(D_CMD)) FPRINTF (stderr, "trying %s...failed\n", fnbuf); X } X else X { X if (DB(D_CMD)) FPRINTF (stderr, "trying %s...ok\n", fnbuf); X FPRINTF (psos, "%%%%BeginFile: %s\n", fnbuf); X mfcopy (f, 0, fnbuf, psos, 1, Out); X if (fclose (f)) malf0 (eClose, fnbuf); X FPUTS ("%%EndFile\n", psos); X } X if (NULBSTR != p2) p1 = p2 + 1; X } Xwhile (NULBSTR != p2); X} X X/* readrc - read one command file */ X XPRIVATE void readrc (f, fn) XR4 streamT f; /* File.*/ XR3 bStrT fn; /* File name.*/ X X/* Function: X * Read through one command file and execute each command. X * Algorithm: X * Read each line. Strip comments and trailing white space. X * Skip leading white X * space. Find command. Put NUL at end of it. Skip white X * space. Find value. Call cmd(). X * Notes: X * X */ X{ XR1 bStrT cp; /* General purpose.*/ XR2 bStrT cmdp; /* Points to command.*/ X unsigned ln = 0; /* Current line number.*/ X byteT lb[MLINE]; /* Input line buffer.*/ X Xwhile (NULBSTR != getlic (lb, MLINE, f, fn, &ln, 1, COMMENT)) X { X for (cp = lb; ' ' == B(*cp); ++cp) X ; X cmdp = cp++; X for (; (EOS != B(*cp)) && (' ' != B(*cp)); ++cp) X ; X if (EOS != B(*cp)) X { X *cp++ = EOS; X for (; ' ' == B(*cp); ++cp) X ; X if (EOS != B(*cp)) cmd (cmdp, cp, fn, ln); X else malf0 (eNoArgL, fn, ln, lb); X } X } X} X X/* undef - undefine one state-octet pair or one whole state */ X XPRIVATE void undef (ss, os) X bStrT ss; /* State as a string.*/ XR1 bStrT os; /* Octet as a string.*/ X X/* Function: X * cz0 starts out configured for ISO 8859/1. For other character X * sets, it's sometimes necessary to undefine state-octet pairs. X * Algorithm: X * Convert state to number. If "octet" is All, zap the whole state. X * Otherwise, convert octet to number and zap that entry. X * Returns: X * X * Notes: X * 1) Dynamic memory is not freed. X */ X{ XR2 unsigned o; /* Octet.*/ XR3 unsigned s; /* State.*/ XR4 soT *sop1; /* Current soT.*/ XR5 stateT *sp; /* Points to current stateT.*/ X Xs = mra2u (ss, NULBSTR, FALSE, S("State"), (unsigned) 0, (unsigned) MSTATE, X (bStrT *) NULL); Xif (bStrEQ (S("All"), os)) X states[s] = (stateT *) NULL; Xelse X { X o = mra2u (os, NULBSTR, FALSE, "Octet", (unsigned) 0, (unsigned) 255, X (bStrT *) NULL); X sp = states[s]; X if (((stateT *) NULL) != sp) X { X sop1 = ((soT *) sp) + o; X sop1->so_ps = NULBSTR; X } X } X} X X/* main - main function */ X XPUBLIC void main (argc, argv) X int argc; /* Number of arguments.*/ XR2 bStrT *argv; /* Points to array of argument strings.*/ X X/* Function: X * Main function. X * Algorithm: X * If there's a -o option, open the output stream. X * Call init(), etc. X * Step through command line arguments and call cmd() on them. X * Step through files and call cvfile() on each. X * Notes: X * X */ X X{ XR1 bStrT cp; /* Used in argument decoding.*/ XR3 filT *fp; /* Steps through fil[].*/ X X++argv; Xcp = *argv++; Xif ((argc >= 3) && (bStrEQ (S("-o"), cp))) X { X cp = *argv++; X if (PIPECHR != B(*cp)) X psos = fopen ((cStrT) cp, "w"); X else if (EOS == B(cp[1])) X malf1 (eNoPipe, PIPECHR); X else X psos = popen ((cStrT) &cp[1], "w"); X if (NULSTRM == psos) malf1 (eOpen, cp); X Out = cp; X cp = *argv++; X } Xinit(); XheadCom(); Xipath(); Xreadpth ("header"); XFPUTS ("%%EndComments\n", psos); XFPRINTF (psos, "/%s/load load def\n/%s/def %s def\n/Version(cz%d.%d)%s\n", X PLOAD, PDEF, PLOAD, FRZ_MAJ, FRZ_MIN, PDEF); Xreadpth ("prolog-beg"); Xreadenv(); Xwhile ((NULBSTR != cp) && ('-' == B(*cp))) X { X ++cp; X if (NULBSTR == *argv) malf1 (eNoArg, cp); X else cmd (cp, *argv++, sCLine, 0); X cp = *argv++; X } Xif (NULBSTR != cp) usage(); Xif (filp == &fil[1]) malf1 (eNoFile); Xif (DB(D_JOB)) FPRINTF (stderr, "%d file(s)\n", filp - fil - 1); XputFnts(); Xreadpth ("prolog-end"); XFPUTS ("%%EndProlog\n", psos); Xif (Reverse) X { X for (fp = filp - 1; fp != fil;) X cvfile (fp--); X } Xelse X { X for (fp = &fil[1]; fp != filp;) X cvfile (fp++); X } XFPRINTF (psos, "%%%%Trailer\n%%%%Pages: %u\n", totPag); XdocFnts(); Xif (EndCtlD) PUTC (4, psos); Xmfflush (psos, Out); Xif ((PIPECHR == B(*Out)) ? pclose (psos) : fclose (psos)) malf0 (eClose, Out); Xif ((NULCSTR != pstfn) && unlink (pstfn)) malf0 (eUnlink, pstfn); Xexit (0); X} END_OF_FILE if test 54952 -ne `wc -c <'cz0.c'`; then echo shar: \"'cz0.c'\" unpacked with wrong size! fi # end of 'cz0.c' fi echo shar: End of archive 11 \(of 14\). cp /dev/null ark11isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 14 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0