v08i075: cz text to PostScript system, part 11 of 14
Brandon S. Allbery - comp.sources.misc
allbery at uunet.UU.NET
Mon Oct 2 00:40:29 AEST 1989
Posting-number: Volume 8, Issue 75
Submitted-by: howard at 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 at 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 at 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
More information about the Comp.sources.misc
mailing list