summaryrefslogtreecommitdiff
path: root/dviware/beebe/src/dvialw.c
diff options
context:
space:
mode:
Diffstat (limited to 'dviware/beebe/src/dvialw.c')
-rw-r--r--dviware/beebe/src/dvialw.c1935
1 files changed, 1935 insertions, 0 deletions
diff --git a/dviware/beebe/src/dvialw.c b/dviware/beebe/src/dvialw.c
new file mode 100644
index 0000000000..729a94da5f
--- /dev/null
+++ b/dviware/beebe/src/dvialw.c
@@ -0,0 +1,1935 @@
+/* -*-C-*- dvialw.c */
+/*-->dvialw*/
+/**********************************************************************/
+/******************************* dvialw *******************************/
+/**********************************************************************/
+
+#include "dvihead.h"
+
+/***********************************************************************
+[23-Oct-87] Modify output so that on each page, fonts appear first,
+ followed by "save ...text... restore" sequences.
+ Current PostScript implementations on commercial
+ printers lack garbage collection, and strings consume
+ memory even after printing. The Apple LaserWriter and
+ LaserWriter Plus have only about 100Kb free for each
+ job, which at current memory prices is grossly
+ inadequate. Other PostScript printer vendors are
+ offering substantially more memory.
+
+ This feature is implemented not by time-consuming double
+ passes through the DVI file, but rather by having
+ setchar() and setstr() buffer their output, which is
+ dumped (with bracketing save/restore commands) either
+ when the buffer fills up, or when end-of-page is
+ reached. A buffer of 8Kb is adequate for this purpose
+ (based on a 100-page document (dvidriver.ltx) producing
+ a .dvi-alw file of 830Kb, of which 163Kb was font
+ definitions, giving an average text requirement of
+ 6.7Kb/page). These statistics were determined on Unix
+ by
+
+ awk '/^\[/,/^>/' foo.dvi-alw >foo.tmp
+ ls -l foo.*
+
+ Awk extracts the font definitions into the file foo.tmp,
+ and ls tells how big the files are. A similar test on
+ pages from the TeXBook found some pages needing up to
+ 11Kb of text.
+
+ Several new routines (putfontname(), text*()) and macros
+ (OUT_*) are introduced to support these changes. Some
+ care is needed when introducing new output sections to
+ call OUT_IMMEDIATE or OUT_DEFERRED, as appropropriate.
+ If this is not done, output will be in an incorrect
+ order.
+
+ Now that almost all output flows through a single
+ routine, textchr(), it is possible to monitor the output
+ to ensure that lines do not exceed PS_WIDTH. Text
+ output for the \special{} command is an exception to
+ this rule; it is transmitted exactly as found. Long
+ comments are continued with a trailing "-" followed by
+ "%-" on the next line. When textflush() empties the
+ text buffer, newlines preceding "(" (the commonest case)
+ are squeezed out, as long as this does not exceed the
+ line width limit. Font changes are shortened to F#
+ sequences, where # is the sequential number of the font
+ (1,2,...) in the dvi file. F0 is reserved for a
+ temporary font created inside a save/restore pair for a
+ large character.
+
+ Perhaps at some later date, we could sort the buffered
+ text by font type, and minimize font changing.
+
+[10-Dec-86] Fix off-by-one error in value of y-offset output in
+ character definition in loadchar(); this affects only
+ the combination of rules with characters, such as LaTeX
+ arrowheads. No other DVI drivers are affected by this.
+
+ Fix off-by-one error in size of rule; this involves no
+ code change here, only a change in dvialw.ps.
+ Examination of output rules under high power magnifier
+ shows that to draw a rule of width N dots, the bounding
+ box should have a width of N-1 dots; the boundary counts
+ toward the fill; this is not clear from the PostScript
+ manual.
+
+[13-Jun-86] Fix special()--a short plot file could result in
+ infinite loop in search for %%BoundingBox. Fixed
+ openfont() to output requested magnification as well as
+ substituted magnification.
+
+[19-Apr-86] Fix infinite loop in setstr(); BIGCHAR() forced exit
+ from character collection loop on first iteration, and
+ the current input character was stuffed back into the
+ input buffer. A big character should just suppress
+ downloading in the first loop.
+
+[12-Mar-86] Version 2.03 -- Major overhaul of PostScript output.
+ Removed most explicit PostScript commands to header file
+ dvialw.ps (in current directory), or if unavailable, the
+ system file texinputs:dvialw.ps (defined by symbols
+ PSDEF_PATH and PSDEF_FILE) which is copied to the output
+ file by new procedure cppsfile(), stripped of comments
+ and excess whitespace. References to these macros are
+ output instead. This makes parameter twiddling and
+ local customization much easier, and will allow users to
+ obtain a variety of page formats and orientations by
+ simple changes to personal copies of the header file.
+ The header file is heavily commented and should be
+ referred to for macro descriptions and an outline of the
+ general PostScript document format produced by DVIALW.
+
+ Removed variable-length argument lists to fatal() and
+ warning() for portability. Changed all preprocessor
+ #ifdef's and #ifndef's to #if's for portability; all
+ symbols for devices, operating systems, and
+ implementations are now explicitly defined to be 0 or 1.
+
+ Added procedures fontfile() and fontsub() to encapsulate
+ construction of system-dependent font file names and
+ provide for user-specifiable font substitutions for
+ unavailable font files.
+
+ Fonts and character definitions are now encapsulated in
+ compact macros. With help of Neal Holtz's DVI2PS and
+ TEX.PS, figured out how to define fonts with origin
+ along baseline, allowing output of several characters in
+ a single command (except where roundoff would make TeX
+ and PostScript positions disagree). New procedure
+ setstr() handles this. Font scaling is now 1 for normal
+ output, but can be changed to any other value if
+ PostScript is to rescale the bitmaps (slow). Tests show
+ a reduction of about 20% in total output file size.
+ When PS_SHORTLINES is defined, character bitmaps are
+ output one scan line per line, making them somewhat
+ readable, and avoiding long lines. Leaving them as one
+ long line could reduce the file size even further.
+ Added support for LaTeX invisible fonts; if you send a
+ bitmap of size 0 by 0 to the LaserWriter, all further
+ fonts are printed as blanks until you cycle the power.
+ No character definitions are loaded for such fonts.
+
+ Made reloading of fonts for each page an option "-v"; it
+ should now rarely be necessary. With large manuscripts,
+ avoiding reloading cuts the space by 60% or more, and
+ seems to be more successful at printing, averaging 30
+ sec/page and 700-780 char/sec (close to limit of 960
+ char/sec from 9600 baud serial line).
+
+ Removed old #ifdef FOOBAR ... #endif code sections in
+ several procedures which were completely obsolete.
+ Added header comment line to every file; it contains the
+ EMACS "-*-C-*-" mode string and the exact (case-sensive)
+ filename, since many functions have been defined with
+ names in mixed case for readability (probably should
+ have used underscore instead, but none do), and on Unix,
+ the letter case matters.
+
+ Replaced index() and rindex(), which have different
+ definitions in different C implementations, by 4.2BSD
+ (and coming ANSI C standard) functions strchr() and
+ strrchr(), for which .h files are provided.
+
+ To further reduce the PostScript output size, PostScript
+ interactive mode experiments determined that spaces are
+ not required around parentheses, brackets, or braces,
+ but ARE necessary between numbers and names. Thus the
+ sequences
+
+ [ <hexstring> # # # # # ] # D
+ (string) # # S
+
+ can be reduced to
+
+ [<hexstring># # # # #]# D
+ (string)# # S
+
+ saving 4 and 1 characters respectively for each use of
+ these commands. The PostScript file copy utility, LW78,
+ already reduces CR LF pairs to LF, so in the interests
+ of editability, we retain the former. Heavily-used
+ macros have also been redefined with single letter
+ names.
+
+[18-Jan-86] Version 2.02 -- Added macros to define new fonts (NF),
+ set fonts (SF), and define characters (CH) in main.h,
+ and use them in readfont.h and setchar(). Changed
+ setchar() to skip character loading when character is
+ not on page. Added setstr() to output several
+ characters at a time, instead of using setchar() for
+ each of them. These reduce the output file size
+ considerably. Moved character bitmap output code into
+ loadchar() where it should have been in the first place.
+ Added test for output errors (usually because disk
+ storage is exhausted) in main.h and prtpage.h.
+
+[20-Dec-85] Following recommendation of Allan Hetzel on LASER-LOVERS
+ ARPA BBOARD, added "() pop" at top of every page. This
+ selected by the switch PS_XONXOFFBUG:
+
+ --------------------------------------------------------
+ From: Allan Hetzel <SYSAL%UKCC.BITNET@WISCVM.ARPA>
+ Subject: Re: Apple Laserwriter XON/XOFF problem
+ To: <LASER-LOVERS@WASHINGTON.ARPA>
+
+ The note posted to Laser-Lovers on Oct 28 by Joseph
+ Goldstone of Symbolics Cambridge Research Center was
+ helpful but I didn't try his suggested fix correctly and
+ so I called Adobe. They were very helpful (much more so
+ than Apple) and explained the problem and how to bypass
+ it.
+
+ My apologies to Adobe if this not an accurate
+ description of the problem. The problem apparently is
+ due to the PostScript interpreter getting confused by
+ what it thinks is an excess of white space characters.
+
+ The bypass is to place a special character (parenthesis,
+ bracket, brace, slash, etc.) to the right of some token,
+ but without an intervening white space character. As the
+ PostScript scanner reads the token it also reads the
+ special character which acts as a delimiter. The scanner
+ then has to back up one character so that it can
+ reprocess the special character after it has processed
+ the preceding token. During this backing up process a
+ number of internal values are recalculated, including
+ some pointer into the input buffer. This causes the
+ XON/XOFF protocol to work properly. Doing this once per
+ page seems to keep everybody happy.
+
+ Each page in the PostScript file built by our word
+ processing program is surrounded by a "save restore"
+ sequence. We changed the beginning save sequence
+ "/saveobj save def" to read "/saveobj save def() pop".
+ The "() pop" is effectively a no-op and we are assured
+ that the necessary recalculations are done on each page.
+ This seems to have corrected the problem completely.
+
+ Allan Hetzel (sysal@ukcc.bitnet)
+ --------------------------------------------------------
+***********************************************************************/
+
+/**********************************************************************/
+/************************ Device Definitions ************************/
+/**********************************************************************/
+
+/* All output-device-specific definitions go here. This section must
+be changed when modifying a dvi driver for use on a new device */
+
+#undef POSTSCRIPT
+#define POSTSCRIPT 1 /* conditional compilation flag */
+
+#define PS_SIZELIMIT 150 /* characters larger than this */
+ /* many dots high get loaded with */
+ /* surrounding save/restore to */
+ /* get around PostScript bugs */
+
+#undef PS_XONXOFFBUG
+#define PS_XONXOFFBUG 1 /* Allen Hetzel's XON/XOFF bug fix */
+
+#ifndef PS_SHORTLINES
+#define PS_SHORTLINES 0 /* run with long output lines */
+#endif
+
+#define VERSION_NO "2.10" /* DVI driver version number */
+
+#if PS_XONXOFFBUG
+#undef VERSION_NO
+#define VERSION_NO "2.10b" /* DVI driver version number */
+#endif
+
+
+#define DEVICE_ID "PostScript [Apple LaserWriter laser printer]"
+ /* this string is printed at runtime */
+
+#define OUTFILE_EXT "alw"
+
+#define MAXPSLINE 80 /* longest line in PSDEF_FILE */
+
+#define PSDEF_PATH subpath /* pathname of system header file */
+#define PSDEF_FILE "dvialw.ps" /* name of header file */
+
+#define BYTE_SIZE 7 /* output file byte size */
+
+#undef STDRES
+#define STDRES 1 /* to get standard font resolution */
+
+#undef MAXOPEN
+#define MAXOPEN 12 /* limit on number of open files */
+
+#define MAXLINE 4096 /* maximum input file line size */
+ /* it is needed only in special() */
+
+#define XDPI 300 /* horizontal dots/inch */
+#define XPSIZE 14 /* horizontal paper size in inches */
+ /* (allow for landscape paper) */
+#define XSIZE (((XDPI*XPSIZE+2*HOST_WORD_SIZE-1)/\
+ (2*HOST_WORD_SIZE))*(2*HOST_WORD_SIZE))
+ /* number of horizontal dots; */
+ /* MUST BE multiple of */
+ /* 2*HOST_WORD_SIZE */
+
+#define YDPI 300 /* vertical dots/inch */
+#define YPSIZE 11 /* vertical paper size in inches */
+#define YSIZE (YDPI*YPSIZE) /* number of vertical dots */
+
+
+#if PS_SHORTLINES
+
+#ifndef PS_MAXWIDTH
+#define PS_MAXWIDTH 72 /* output never exceeds this width */
+#endif
+
+INT16 out_width; /* current line width */
+
+#endif /* PS_SHORTLINES */
+
+/***********************************************************************
+The following variables and macros implement the buffering of PostScript
+output so that output size can be reduced by removing unneeded
+separators, and so that a maximum line width can be enforced, except for
+code from special{}, which must be output verbatim.
+
+All PostScript output filters through textchr() at the lowest level, and
+on the basis of the `deferred' flag setting, it either defers output of
+its argument character by buffering it in textbuf[], or it outputs it
+immediately with putc().
+
+Because PostScript line breaking conventions are context sensitive,
+textchr() maintains static variables to keep track of the output state
+(comment, text, or string). It also handles all end-of-line
+translations, so \n can be used for end-of-line everywhere else.
+
+All output calls outside the text*() routines are done through macros
+OUT_*, and to shorten coding, OUT_NUM provides a trailing delimiting
+space.
+
+textbuf[] is allocated dynamically on the first call to devinit() so as
+not to consume space in the executable program disk file.
+
+textflush() is called by textchr() when textbuf[] fills up, and by
+eopact() at end-of-page.
+
+***********************************************************************/
+
+#define MAXTEXT 16384 /* size of textbuf[] buffer */
+
+static char* textbuf = (char*)NULL; /* buffer for setchar() and setstr() */
+static char* ptext; /* next position in textbuf[] */
+static BOOLEAN deferred; /* deferred output status flag */
+static UNSIGN16 last_font_number; /* set by loadchar() */
+
+#if PS_SHORTLINES
+static BOOLEAN is_comment = FALSE;
+static BOOLEAN is_text = FALSE;
+static BOOLEAN is_string = FALSE;
+#endif /* PS_SHORTLINES */
+
+#define OUT_CHR(c) textchr((char)c)
+
+#define OUT_DEFERRED {deferred = TRUE;}
+
+#define OUT_FLT(fmt,flt) {\
+ char s[25];\
+ (void)sprintf(s,fmt,flt);\
+ OUT_STR(s);}
+
+#define OUT_FONTNAME {\
+ char s[11];\
+ (void)sprintf(s,"F%d",fontptr->font_number);\
+ OUT_STR(s);}
+
+#define OUT_IMMEDIATE {deferred = FALSE;}
+
+#define OUT_NL OUT_CHR('\n')
+
+#define OUT_NUM(n) textnum((long)(n))
+
+#define OUT_STR(s) textstr(s)
+
+#define OUT_XCHR(c) emitchar(c)
+
+#include "main.h"
+#include "abortrun.h"
+#include "actfact.h"
+#include "alldone.h"
+
+/*-->bopact*/
+/**********************************************************************/
+/******************************* bopact *******************************/
+/**********************************************************************/
+
+void
+bopact() /* beginning of page action */
+{
+ INT16 page_number; /* TeX's \count0 parameter */
+
+ page_number = (INT16)tex_counter[0];
+
+ if (cur_page_number <= MAXPAGE)
+ {
+ (void)fflush(plotfp);
+ page_loc[cur_page_number] = (long)FTELL(plotfp);
+ page_tex[cur_page_number] = (INT32)page_number;
+ }
+ OUT_IMMEDIATE;
+ OUT_STR("%%Page: ");
+ OUT_NUM(page_number);
+ OUT_NUM(cur_page_number);
+ OUT_NL;
+ if (ps_vmbug)
+ OUT_STR("/SaveImage save def() pop\n");
+ OUT_STR("BOP\n");
+
+ rule_height = -1; /* reset last rule parameters */
+ rule_width = -1;
+ str_ycp = -1; /* last string ycp */
+}
+
+#include "chargf.h"
+#include "charpk.h"
+#include "charpxl.h"
+#include "clrrow.h"
+
+/*-->cppsfile*/
+/**********************************************************************/
+/****************************** cppsfile ******************************/
+/**********************************************************************/
+
+void
+cppsfile() /* Copy PostScript header file to output */
+{ /* discarding comments and collapsing whitespace */
+ register int c; /* input character */
+ register int k; /* index in line[] */
+ FILE *psfp; /* PostScript macro definition file */
+ char fname[MAXFNAME];
+ char line[MAXPSLINE+1]; /* extra space for NUL */
+
+ /* Try private version of header file first, and if that fails, use */
+ /* system version. Tell the user when a private version is selected. */
+
+ OUT_IMMEDIATE;
+ (void)strcpy(fname,PSDEF_FILE);
+ psfp = fopen(fname,"r");
+ DEBUG_OPEN(psfp,fname,"r");
+ if (psfp == (FILE *)NULL)
+ {
+ (void)strcpy(fname,PSDEF_PATH);
+ (void)strcat(fname,PSDEF_FILE);
+ psfp = fopen(fname,"r");
+ DEBUG_OPEN(psfp,fname,"r");
+ if (psfp == (FILE *)NULL)
+ {
+ (void)sprintf(message,
+ "cppsfile(): Cannot open PostScript definition file [%s]",
+ fname);
+ (void)fatal(message);
+ }
+ }
+ else if (!quiet)
+ {
+ (void)fprintf(stderr,"[Using private PostScript definition file [%s]]",
+ fname);
+ NEWLINE(stderr);
+ }
+
+ k = 0;
+ while ((c = getc(psfp)) != EOF)
+ {
+ if (c == '%') /* flush comments to (but not including) end-of-line */
+ {
+ while (((c = getc(psfp)) != EOF) && (c != '\n'))
+ ; /* flush to end-of-line or end-of-file */
+ c = '\n'; /* to force line output */
+ line[k++] = '\n';
+ }
+ else if ((c == ' ') || (c == '\t') || (c == '\f'))
+ { /* have whitespace */
+ if (k) /* then not at beginning of line */
+ line[k++] = ' '; /* so save only one blank */
+ while (((c == ' ') || (c == '\t') || (c == '\f')) && (c != EOF))
+ c = getc(psfp); /* discard following whitespace */
+ ungetc(c,psfp); /* put back lookahead */
+ }
+ else if (c != '\r') /* save all but CR */
+ line[k++] = (char)c;
+
+ if ((c == '\n') || (c == EOF) || (k >= MAXPSLINE))
+ {
+ if (c == '\n') /* discard LF */
+ k--;
+ while ((k > 0) && (line[k-1] == ' ')) /* and trailing blanks */
+ k--;
+ line[k] = '\0';
+ if (k > 0) /* non-empty line */
+ {
+ OUT_STR(line);
+ OUT_NL;
+ }
+ k = 0;
+ }
+ }
+
+ while ((k > 0) && (line[k-1] == ' ')) /* discard trailing blanks */
+ k--;
+ line[k] = '\0';
+ if (k > 0) /* non-empty line */
+ {
+ OUT_STR(line);
+ OUT_NL;
+ }
+
+ (void)fclose(psfp);
+}
+
+#include "dbgopen.h"
+
+/*-->devinit*/
+/**********************************************************************/
+/****************************** devinit *******************************/
+/**********************************************************************/
+
+void
+devinit(argc,argv) /* initialize device */
+int argc;
+char *argv[];
+{
+ register INT16 k; /* loop index */
+ char timestring[26]; /* "wkd mon dd hh:mm:ss 19yy\n" */
+ long timeval; /* clock value from time() for ctime() */
+
+ if (textbuf == (char*)NULL)
+ { /* allocate textbuf[] only once */
+ textbuf = (char*)MALLOC((unsigned)(MAXTEXT+1));
+ if (textbuf == (char*)NULL)
+ (void)fatal("Cannot allocate memory for textbuf[]");
+ }
+
+ ptext = textbuf;
+
+ OUT_IMMEDIATE; /* need immediate output here */
+ OUT_STR("%!\n"); /* magical file header */
+ OUT_STR("%%Dimensions: 0 0 612 792\n"); /* 8.5 x 11 inch page size */
+
+ OUT_STR("%%Title: ");
+ OUT_STR(argv[0]); /* start of our command line */
+ for (k = 1; k < (INT16)argc; ++k)
+ {
+ OUT_CHR(' ');
+ OUT_STR(argv[k]);
+ }
+ OUT_NL; /* end of %%Title line */
+
+ timeval = time((long*)NULL);
+ (void)strcpy(timestring,ctime(&timeval));
+ timestring[24] = '\0'; /* kill stupid \n from ctime() */
+
+ OUT_STR("%%CreationDate: ");
+ OUT_STR(timestring);
+ OUT_NL;
+ OUT_STR("%%Creator: ");
+ OUT_STR((cuserid((char*)NULL) == (char*)NULL) ? "" : cuserid((char*)NULL));
+ OUT_STR(" and [TeX82 DVI Translator Version ");
+ OUT_STR(VERSION_NO);
+ OUT_STR(" for ");
+ OUT_STR(DEVICE_ID);
+ OUT_NL;
+
+ OUT_STR("%%Pages: (atend)\n");
+
+ if (ps_vmbug)
+ {
+ OUT_STR("%%BugHistory: Incorporates save/restore and font");
+ OUT_STR(" reloading for each page as PS Version 23.0");
+ OUT_STR(" \"VM error\" bug workaround\n");
+ }
+
+#if PS_XONXOFFBUG
+ OUT_STR("%%BugHistory: Incorporates Allan Hetzel\'s 31-Oct-85");
+ OUT_STR(" DARPA LASER-LOVERS PS Version 23.0 X-on/X-off");
+ OUT_STR(" bug workaround\n");
+#endif /* PS_XONXOFFBUG */
+
+ OUT_STR("%%EndComments\n");
+ OUT_STR("%%EndProlog\n");
+ font_switched = TRUE;
+
+ (void)cppsfile(); /* copy standard PostScript definitions */
+
+ OUT_STR("TeXdict begin\n");
+ OUT_STR("BOJ\n");
+
+ /* TB and TE (Text Begin and Text End) are save/restore sequences;
+ they are used when textflush() has to empty its current buffer. */
+
+ OUT_STR("/TB {save} bdf\n");
+ OUT_STR("/TE {restore} bdf\n");
+
+#if 0
+ OUT_STR("/TE {currentpoint 3 -1 roll restore moveto} bdf\n");
+#endif
+
+ /* BB and BE (Big character Begin and End) are save/restore
+ sequences that create a temporary font and set a character
+ inside a save/restore pair. */
+ OUT_STR("/BB {save /F0 NF 1 /F0 SF} bdf\n");
+ OUT_STR("/BE {restore} bdf\n");
+
+ font_count = 0; /* no font numbers are assigned yet */
+}
+
+/*-->devterm*/
+/**********************************************************************/
+/****************************** devterm *******************************/
+/**********************************************************************/
+
+void
+devterm() /* terminate device */
+{
+ register INT16 k; /* loop index */
+
+ OUT_IMMEDIATE;
+ OUT_STR("EOJ\n");
+ OUT_STR("%%Trailer\n");
+ OUT_STR("%%Pages: ");
+ OUT_NUM(page_count);
+ OUT_NL;
+ OUT_STR("%%PageTable: ");
+
+ for (k = 1; k <= MIN(MAXPAGE,cur_page_number); ++k)
+ {
+ OUT_NUM(page_tex[k]);
+ OUT_NUM(k);
+ OUT_NUM(page_loc[k]);
+ }
+
+ OUT_NL;
+ OUT_CHR('\004'); /* PostScript end-of-job signal */
+}
+
+#include "dvifile.h"
+#include "dviinit.h"
+#include "dviterm.h"
+
+/*-->emitchar*/
+/**********************************************************************/
+/****************************** emitchar ******************************/
+/**********************************************************************/
+
+void
+emitchar(c) /* output string character with */
+register BYTE c; /* escapes and octal as necessary */
+{
+
+ /* we do our own octal formatting for speed */
+ static char octalchars[] = "01234567";
+
+#define OCTAL(b) octalchars[((b) & 07)]
+
+#if PS_SHORTLINES
+ if (!deferred && ((out_width + 4) >= (PS_MAXWIDTH-1)))
+ {
+ OUT_CHR('\\'); /* PostScript ignores */
+ OUT_NL; /* backslash-newline sequences */
+ }
+#endif /* PS_SHORTLINES */
+
+ if (isprint(c) &&
+ /* [textchr() requires the following restrictions] */
+ !((c == ' ' ) || (c == '%') || (c == '(') || (c == ')') ||
+ (c == '<') || (c == '>'))) /* character is printable */
+ {
+ if (c == '\\') /* double backslashes */
+ OUT_CHR('\\');
+ OUT_CHR(c);
+ }
+ else /* use octal form */
+ {
+ OUT_CHR('\\');
+ OUT_CHR(OCTAL(c >> 6));
+ OUT_CHR(OCTAL(c >> 3));
+ OUT_CHR(OCTAL(c));
+ }
+}
+
+/*-->eopact*/
+/**********************************************************************/
+/******************************* eopact *******************************/
+/**********************************************************************/
+
+void
+eopact() /* end of page action */
+{
+ register INT32 k; /* loop index */
+
+ textflush(); /* output accumulated text */
+ OUT_IMMEDIATE;
+ OUT_NUM(copies);
+ OUT_STR("EOP\n");
+
+ if (ps_vmbug)
+ {
+ OUT_STR("SaveImage restore() pop\n");
+ font_switched = TRUE;
+ fontptr = hfontptr;
+ while (fontptr != (struct font_entry *)NULL)
+ {
+ for (k = 0; k < NPXLCHARS; ++k)
+ fontptr->ch[k].isloaded = FALSE;
+ fontptr = fontptr->next;
+ }
+ }
+
+ for (k = (INT32)copies; k; --k)
+ OUTC('\f'); /* FF's for simple page accounting */
+}
+
+#include "f20open.h"
+#include "fatal.h"
+
+/*-->fillrect*/
+/**********************************************************************/
+/****************************** fillrect ******************************/
+/**********************************************************************/
+
+void
+fillrect(x,y,width,height)
+COORDINATE x,y,width,height; /* lower left corner, size */
+
+/***********************************************************************
+With the page origin (0,0) at the lower-left corner, draw a filled
+rectangle at (x,y).
+
+For most TeX uses, rules are uncommon, and little optimization is
+possible. However, for the LaTeX Bezier option, curves are simulated by
+many small rules (typically 2 x 2) separated by positioning commands.
+By remembering the size of the last rule set, we can test for the
+occurrence of repeated rules of the same size, and reduce the output by
+omitting the rule sizes. The last rule parameters are reset by the
+begin-page action in prtpage(), so they do not carry across pages.
+
+It is not possible to use relative, instead of absolute, moves in these
+sequences, without stacking rules for the whole page, because each rule
+is separated in the DVI file by push, pop, and positioning commands,
+making for an uncertain correspondence between internal (xcp,ycp)
+pixel page coordinates and external device coordinates.
+***********************************************************************/
+
+{
+ str_ycp = -1; /* invalidate string y coordinate */
+
+ OUT_IMMEDIATE; /* because Q uses width and height saved */
+ OUT_NUM(x); /* by B, we cannot use deferred output; */
+ OUT_NUM(y); /* otherwise a TB B TE TB Q TE would fail */
+ if ((height != rule_height) || (width != rule_width))
+ {
+ OUT_CHR('M');
+ OUT_CHR(' ');
+ OUT_NUM(width);
+ OUT_NUM(height);
+ OUT_CHR('B');
+ OUT_CHR(' ');
+ rule_width = width; /* save current rule parameters */
+ rule_height = height;
+ }
+ else
+ {
+ OUT_CHR('Q');
+ OUT_CHR(' ');
+ }
+}
+
+#include "findpost.h"
+#include "fixpos.h"
+#include "fontfile.h"
+#include "fontsub.h"
+#include "getbytes.h"
+#include "getfntdf.h"
+#include "getpgtab.h"
+#include "inch.h"
+#include "initglob.h"
+
+/*-->loadchar*/
+/**********************************************************************/
+/****************************** loadchar ******************************/
+/**********************************************************************/
+
+void
+loadchar(c)
+register BYTE c;
+{
+ void (*charyy)(); /* subterfuge to get around PCC-20 bug */
+ register struct char_entry *tcharptr; /* temporary char_entry pointer */
+
+ if ((c < FIRSTPXLCHAR) || (LASTPXLCHAR < c)) /* check character range */
+ return;
+
+ tcharptr = &(fontptr->ch[c]);
+
+ if (!VISIBLE(tcharptr))
+ return; /* do nothing for invisible fonts */
+
+ if (fontptr != pfontptr)
+ openfont(fontptr->n);
+
+ if (fontfp == (FILE *)NULL) /* do nothing if no font file */
+ return;
+
+ tcharptr->isloaded = TRUE;
+
+ clearerr(plotfp); /* VMS sets the error flag unexpectedly */
+
+ OUT_IMMEDIATE;
+ OUT_STR("[<");
+
+ /* Bug workaround: PCC-20 otherwise jumps to charxx instead of *charxx */
+ charyy = fontptr->charxx;
+ (void)(*charyy)(c,outrow); /* output rasters */
+
+ OUT_CHR('>');
+ OUT_NUM(tcharptr->xoffp);
+ OUT_NUM((tcharptr->yoffp)+1);
+ OUT_NUM(tcharptr->wp);
+ OUT_NUM(tcharptr->hp);
+ OUT_FLT("%.7f]",(float)(tcharptr->tfmw)*conv)
+ OUT_NUM(c);
+ OUT_CHR('D');
+
+#if PS_SHORTLINES
+ OUT_CHR(' ');
+#else
+ OUT_NL;
+#endif /* PS_SHORTLINES */
+
+ /* Because of the deferred output feature, we now need to remember
+ the last font used, so on the next call, we know whether to
+ issue another OUT_FONTNAME or not. font_switched is no longer
+ sufficient.
+ */
+ last_font_number = fontptr->font_number;
+
+ if (DISKFULL(plotfp))
+ (void)fatal("loadchar(): Output error -- disk storage probably full");
+}
+
+
+#include "movedown.h"
+#include "moveover.h"
+#include "moveto.h"
+
+/*-->newfont*/
+/**********************************************************************/
+/****************************** newfont *******************************/
+/**********************************************************************/
+
+void
+newfont()
+{
+ register UNSIGN16 the_char; /* loop index */
+ char s[MAXSTR];
+
+ for (the_char = FIRSTPXLCHAR; the_char <= LASTPXLCHAR; the_char++)
+ fontptr->ch[the_char].isloaded = FALSE;
+
+ font_count++;
+ fontptr->font_number = font_count;
+
+ OUT_IMMEDIATE;
+
+ (void)sprintf(s,"/%s NF %% %s\n",putfontname(fontptr),
+ fontptr->name);
+ OUT_STR(s); /* declare new font for PostScript */
+
+ (void)sprintf(s,"/F%d {1 /%s SF} bdf\n",
+ fontptr->font_number,putfontname(fontptr));
+ OUT_STR(s); /* compact shorthand for font changes */
+}
+
+#include "nosignex.h"
+#include "openfont.h"
+#include "option.h"
+
+/*-->outrow*/
+/**********************************************************************/
+/******************************* outrow *******************************/
+/**********************************************************************/
+
+void
+outrow(c,yoff) /* output img_row[] to device */
+BYTE c; /* current character value */
+UNSIGN16 yoff; /* offset from top row (0,1,...,hp-1) (UNUSED here) */
+{
+ UNSIGN16 bytes_per_row; /* number of raster bytes to copy */
+ register UNSIGN16 k; /* loop index */
+ register UNSIGN32 *p; /* pointer into img_row[] */
+ struct char_entry *tcharptr;/* temporary char_entry pointer */
+ register BYTE the_byte; /* unpacked raster byte */
+
+ /* we do our own hexadecimal formatting for speed */
+ static char hexchars[] = "0123456789ABCDEF";
+
+#define NIBBLE(b) hexchars[(b) & 0x0f]
+
+ tcharptr = &(fontptr->ch[c]); /* assume check for valid c has been done */
+ bytes_per_row = (UNSIGN16)((tcharptr->wp) + 7) >> 3; /* wp div 8 */
+ p = img_row; /* we step pointer p along img_row[] */
+
+ for (k = bytes_per_row; k > 0; ++p)
+ {
+
+ the_byte = (BYTE)((*p) >> 24);
+ OUT_CHR(NIBBLE(the_byte>>4));
+ OUT_CHR(NIBBLE(the_byte));
+ if ((--k) <= 0)
+ break;
+
+ the_byte = (BYTE)((*p) >> 16);
+ OUT_CHR(NIBBLE(the_byte>>4));
+ OUT_CHR(NIBBLE(the_byte));
+ if ((--k) <= 0)
+ break;
+
+ the_byte = (BYTE)((*p) >> 8);
+ OUT_CHR(NIBBLE(the_byte>>4));
+ OUT_CHR(NIBBLE(the_byte));
+ if ((--k) <= 0)
+ break;
+
+ the_byte = (BYTE)(*p);
+ OUT_CHR(NIBBLE(the_byte>>4));
+ OUT_CHR(NIBBLE(the_byte));
+ if ((--k) <= 0)
+ break;
+ }
+
+#if PS_SHORTLINES
+ /* line breaking handled by textchr() */
+#else
+ k = 40 / MAX(1,bytes_per_row); /* rows per 80-character line */
+ /* break after last row, or whenever an 80-character line has
+ been filled up */
+ if (((yoff+1) == tcharptr->hp) || (((yoff+1) % k) == 0))
+ OUT_NL;
+#endif /* PS_SHORTLINES */
+
+}
+
+#include "prtpage.h"
+
+/*-->putfontname*/
+/**********************************************************************/
+/**************************** putfontname *****************************/
+/**********************************************************************/
+
+char*
+putfontname(font_ptr)
+register struct font_entry *font_ptr;
+/* Output TeX font name and magnification in form "cmr10_1500" as a
+unique PostScript font identifier */
+{
+ register char* nameptr;
+ register char* p;
+ static char namebuf[MAXSTR];
+
+ nameptr = &(font_ptr->n[0]);
+ p = namebuf;
+
+ while (*nameptr) /* make name with non-alphanumerics */
+ { /* changed to underscore for PostScript */
+ *p++ = isalnum(*nameptr) ? *nameptr : '_';
+ nameptr++;
+ }
+
+ (void)sprintf(p,"_%d",(int)font_ptr->magnification);
+
+ return (&namebuf[0]);
+}
+
+#include "readfont.h"
+#include "readgf.h"
+#include "readpk.h"
+#include "readpost.h"
+#include "readpxl.h"
+#include "reldfont.h"
+#include "rulepxl.h"
+
+/*-->setchar*/
+/**********************************************************************/
+/****************************** setchar *******************************/
+/**********************************************************************/
+
+void
+setchar(c, update_h)
+register BYTE c;
+register BOOLEAN update_h;
+{
+ register struct char_entry *tcharptr; /* temporary char_entry pointer */
+
+ /* BIGCHAR() and ONPAGE() are used here and in setstr() */
+
+#define BIGCHAR(t) ((t->wp > (COORDINATE)size_limit) ||\
+ (t->hp > (COORDINATE)size_limit))
+
+#define ONPAGE(t) (((hh - t->xoffp + t->pxlw) <= XSIZE) \
+ && (hh >= 0)\
+ && (vv <= YSIZE)\
+ && (vv >= 0))
+
+ if (DBGOPT(DBG_SET_TEXT))
+ {
+ (void)fprintf(stderr,"setchar('");
+ if (isprint(c))
+ (void)putc(c,stderr);
+ else
+ (void)fprintf(stderr,"\\%03o",(int)c);
+ (void)fprintf(stderr,"'<%d>) (hh,vv) = (%ld,%ld) font name <%s>",
+ (int)c, (long)hh, (long)vv, fontptr->n);
+ NEWLINE(stderr);
+ }
+
+ tcharptr = &(fontptr->ch[c]);
+
+ moveto(hh,YSIZE-vv);
+ if (ONPAGE(tcharptr))
+ { /* character fits entirely on page */
+ if (VISIBLE(tcharptr))
+ {
+ if (BIGCHAR(tcharptr))
+ {
+ /* always need absolute coordinates (save/restore causes */
+ /* loss of updated position) */
+ OUT_IMMEDIATE;
+
+#if PS_SHORTLINES
+ /* line breaking handled by textchar() */
+#else
+ OUT_NL;
+#endif /* PS_SHORTLINES */
+
+ OUT_STR("BB");
+
+#if PS_SHORTLINES
+ OUT_CHR(' ');
+#else
+ OUT_NL;
+#endif /* PS_SHORTLINES */
+
+ loadchar(c);
+ OUT_CHR('(');
+ OUT_XCHR(c);
+ OUT_CHR(')');
+ OUT_NUM(xcp);
+ OUT_NUM(ycp);
+ OUT_CHR('S');
+
+#if PS_SHORTLINES
+ OUT_CHR(' ');
+#else
+ OUT_NL;
+#endif /* PS_SHORTLINES */
+
+ OUT_STR("BE");
+
+#if PS_SHORTLINES
+ /* line breaking handled by textchar() */
+#else
+ OUT_NL;
+#endif /* PS_SHORTLINES */
+
+ tcharptr->isloaded = FALSE; /* 'unload' character */
+ }
+ else
+ {
+ if (!tcharptr->isloaded)
+ {
+ if ((font_switched) ||
+ (fontptr->font_number != last_font_number))
+ {
+ OUT_IMMEDIATE;
+ OUT_FONTNAME;
+ }
+ loadchar(c);
+ }
+ OUT_DEFERRED;
+ if (font_switched)
+ {
+ OUT_FONTNAME;
+ font_switched = FALSE;
+ }
+ OUT_CHR('(');
+ OUT_XCHR(c);
+ OUT_CHR(')');
+ if (ycp != str_ycp)
+ {
+ OUT_NUM(xcp);
+ OUT_NUM(ycp);
+ OUT_STR("S\n");
+ str_ycp = ycp;
+ }
+ else
+ {
+ OUT_NUM(xcp);
+ OUT_STR("T\n");
+ }
+ }
+
+ }
+ }
+ else if (DBGOPT(DBG_OFF_PAGE) && !quiet)
+ { /* character is off page -- discard it */
+ (void)fprintf(stderr,
+ "setchar(): Char %c [10#%3d 8#%03o 16#%02x] off page.",
+ isprint(c) ? c : '?',c,c,c);
+ NEWLINE(stderr);
+ }
+
+ if (update_h)
+ {
+ h += (INT32)tcharptr->tfmw;
+ hh += (COORDINATE)tcharptr->pxlw;
+ hh = fixpos(hh-lmargin,h,conv) + lmargin;
+ }
+}
+
+#include "setfntnm.h"
+#include "setrule.h"
+
+/*-->setstr*/
+/**********************************************************************/
+/******************************* setstr *******************************/
+/**********************************************************************/
+
+void
+setstr(c)
+register BYTE c;
+{
+ register struct char_entry *tcharptr; /* temporary char_entry pointer */
+ register BOOLEAN inside;
+ COORDINATE xcp_start,ycp_start; /* starting coordinates of string */
+ INT32 h0,v0; /* (h,v) at entry */
+ COORDINATE hh0,vv0; /* (hh,vv) at entry */
+ register UNSIGN16 k; /* loop index */
+ UNSIGN16 maxstr; /* loop limit */
+ UNSIGN16 nstr; /* number of characters in str[] */
+ BOOLEAN save_font_switched; /* for saving font_switched value */
+ BYTE str[MAXSTR+1]; /* string accumulator */
+ BOOLEAN truncated; /* off-page string truncation flag */
+
+ /*******************************************************************
+ Set a sequence of characters in SETC_000 .. SETC_127 with a minimal
+ number of PostScript print-string commands. These sequences tend to
+ occur in long clumps in a DVI file, and setting them together
+ whenever possible substantially decreases the PostScript overhead
+ and the size of the output file. A sequence can be set as a single
+ string if
+
+ * TeX and PostScript coordinates of each character agree (always
+ true since PostScript has high-precision character widths
+ available; for non-PostScript devices, violation of this
+ requirement can be detected if fixpos() changes hh, or if ycp
+ != ycp_start), AND
+
+ * each character is in the same font (this will always be true
+ in a sequence from a DVI file), AND
+
+ * each character fits within the page boundaries, AND
+
+ * each character definition is already loaded, AND
+
+ * each character is from a visible font, AND
+
+ * each character bitmap extent is smaller than the size_limit
+ (which is used to enable discarding large characters after
+ each use in order to conserve virtual memory storage on the
+ output device).
+
+ Whenever any of these conditions does not hold, any string already
+ output is terminated, and a new one begun. In order to avoid output
+ of empty string requests, a flag "inside" is set when a string
+ opener "(" is output, and unset when the string terminator ") x y S"
+ or ") P" is output.
+
+ Two output optimizations are implemented here. First, up to MAXSTR
+ (in practice more than enough) characters are collected in str[],
+ and any that require downloading are handled. Then the entire
+ string is set at once, subject to the above limitations. Second, by
+ recording the vertical page coordinate, ycp, in the global variable
+ str_ycp (reset in prtpage() at begin-page processing), it is
+ possible to avoid outputting y coordinates unnecessarily, since a
+ single line of text will generally result in many calls to this
+ function.
+ *******************************************************************/
+
+#define BEGINSTRING {inside = TRUE;\
+ xcp_start = xcp;\
+ ycp_start = ycp;\
+ OUT_CHR('(');}
+
+#define ENDSTRING {inside = FALSE;\
+ OUT_CHR(')');\
+ if (ycp == str_ycp)\
+ {\
+ OUT_NUM(xcp_start);\
+ OUT_STR("T\n");\
+ }\
+ else\
+ {\
+ OUT_NUM(xcp_start);\
+ OUT_NUM(ycp_start);\
+ OUT_STR("S\n");\
+ str_ycp = ycp;\
+ }}
+
+#define OFF_PAGE (-32767) /* off-page coordinate value */
+
+ inside = FALSE;
+ truncated = FALSE;
+ OUT_IMMEDIATE;
+
+ hh0 = hh;
+ vv0 = vv;
+ h0 = h;
+ v0 = v;
+ save_font_switched = font_switched;
+ nstr = 0;
+
+#if PS_SHORTLINES
+ /* With deferred output, textflush() cannot do any output parsing,
+ so to avoid long lines, we allow at most a string
+ "(...)nnnnn nnnnn S" on one line. */
+ maxstr = MIN(PS_MAXWIDTH-15,MAXSTR);
+#else
+ maxstr = MAXSTR;
+#endif /* PS_SHORTLINES */
+
+ while ((SETC_000 <= c) && (c <= SETC_127) && (nstr < maxstr))
+ { /* collect character sequence and download needed fonts */
+ tcharptr = &(fontptr->ch[c]);
+
+ moveto(hh,YSIZE-vv);
+
+ if (ONPAGE(tcharptr) && VISIBLE(tcharptr))
+ { /* character fits entirely on page and is visible */
+ if ((!tcharptr->isloaded) && (!BIGCHAR(tcharptr)))
+ {
+ if (font_switched ||
+ (fontptr->font_number != last_font_number))
+ {
+ OUT_FONTNAME;
+ font_switched = FALSE;
+ }
+ loadchar(c);
+ }
+ }
+ /* update horizontal positions in TFM and pixel units */
+ h += (INT32)tcharptr->tfmw;
+ hh += (COORDINATE)tcharptr->pxlw;
+ hh = fixpos(hh-lmargin,h,conv) + lmargin;
+
+ str[nstr++] = c; /* save string character */
+
+ c = (BYTE)nosignex(dvifp,(BYTE)1);
+ }
+
+ /* put back character which terminated the loop */
+ (void)UNGETC((int)(c),dvifp);
+
+ hh = hh0; /* restore coordinates at entry */
+ vv = vv0;
+ h = h0;
+ v = v0;
+
+ if (DBGOPT(DBG_SET_TEXT))
+ {
+ (void)fprintf(stderr,"setstr(\"");
+ for (k = 0; k < nstr; ++k)
+ {
+ c = str[k];
+ if (isprint(c))
+ (void)putc(c,stderr);
+ else
+ (void)fprintf(stderr,"\\%03o",(int)c);
+ }
+ (void)fprintf(stderr,"\") (hh,vv) = (%ld,%ld) font name <%s>",
+ (long)hh, (long)vv, fontptr->n);
+ NEWLINE(stderr);
+ }
+
+ OUT_DEFERRED;
+ font_switched = save_font_switched;
+ if (font_switched)
+ {
+ OUT_FONTNAME;
+ OUT_NL; /* string might not be visible */
+ font_switched = FALSE;
+ }
+
+ for (k = 0; k < nstr; ++k)
+ { /* now set the collected characters */
+ c = str[k];
+ tcharptr = &(fontptr->ch[c]);
+ moveto(hh,YSIZE-vv);
+
+ if (ONPAGE(tcharptr) && VISIBLE(tcharptr))
+ { /* character fits entirely on page and is visible */
+ if (tcharptr->isloaded) /* character already downloaded */
+ {
+ if (!inside)
+ BEGINSTRING;
+ OUT_XCHR(c);
+ }
+ else /* must be big character (others are already downloaded) */
+ {
+ if (inside)
+ ENDSTRING; /* finish any open string */
+ if (BIGCHAR(tcharptr))
+ { /* Large character to be discarded. */
+ /* Inside save/restore, updated current point */
+ /* is lost, so we must force absolute positioning */
+ /* by resetting str_ycp before and after setting */
+ /* the character. */
+ str_ycp = OFF_PAGE;
+ OUT_IMMEDIATE;
+
+#if PS_SHORTLINES
+ /* line breaking handled by textchar() */
+#else
+ OUT_NL;
+#endif /* PS_SHORTLINES */
+
+ OUT_STR("BB");
+
+#if PS_SHORTLINES
+ OUT_CHR(' ');
+#else
+ OUT_NL;
+#endif /* PS_SHORTLINES */
+
+ loadchar(c);
+ BEGINSTRING;
+ OUT_XCHR(c);
+ ENDSTRING;
+ OUT_STR("BE");
+
+#if PS_SHORTLINES
+ OUT_CHR(' ');
+#else
+ OUT_NL;
+#endif /* PS_SHORTLINES */
+
+ OUT_CHR(' ');
+ OUT_DEFERRED;
+ tcharptr->isloaded = FALSE; /* 'unload' character */
+ str_ycp = OFF_PAGE;
+ }
+ }
+ }
+ else /* character does not fit on page -- output */
+ { /* current string and discard the character */
+ truncated = TRUE;
+ if (inside)
+ ENDSTRING;
+ }
+ /* update horizontal positions in TFM and pixel units */
+ h += (INT32)tcharptr->tfmw;
+ hh += (COORDINATE)tcharptr->pxlw;
+ hh = fixpos(hh-lmargin,h,conv) + lmargin;
+ }
+ if (truncated && DBGOPT(DBG_OFF_PAGE) && !quiet)
+ {
+ (void)fprintf(stderr,"setstr(): Text [");
+ for (k = 0; k < nstr; ++k)
+ (void)fprintf(stderr,isprint(str[k]) ? "%c" : "\\%03o",str[k]);
+ (void)fprintf(stderr,"] truncated at page boundaries.");
+ NEWLINE(stderr);
+ }
+
+ if (inside) /* finish last string */
+ ENDSTRING;
+}
+
+#include "signex.h"
+#include "skgfspec.h"
+#include "skipfont.h"
+#include "skpkspec.h"
+
+/*-->special*/
+/**********************************************************************/
+/****************************** special *******************************/
+/**********************************************************************/
+
+void
+special(s) /* process TeX \special{} string in s[] */
+register char *s;
+{
+ char line[MAXLINE+2];
+ FILE *specfile;
+ BOOLEAN abspos;
+ INT16 k;
+ int llx,lly,urx,ury; /* must be int for sscanf() */
+ struct stat statbuf; /* so fstat() can get file size */
+
+/***********************************************************************
+The TeX \special{} command is expected to look like
+
+ \special{overlay filename} % absolute positioning
+ or
+ \special{include filename} % relative positioning
+ or
+ \special{insert filename} % relative positioning
+
+In the first case, the PostScript file to be included will be mapped
+onto the page at precisely the coordinates it specifies. In the other
+two cases, the upper-left corner of the bounding box will be placed at
+the current point. The PostScript file must then contain (usually near
+the start) a comment of the form
+
+%%BoundingBox: llx lly urx ury
+
+specifying the bounding box lower-left and upper-right coordinates in
+standard PostScript units (1/72 inch). Alternatively, if the comment
+
+%%BoundingBox: (atend)
+
+is found in the file, the last 1000 characters of the file will be
+searched to find a comment of the form:
+
+%%BoundingBox: llx lly urx ury
+
+If the PostScript file cannot be opened, or the \special{} command
+string cannot be recognized, or for relative positioning, the bounding
+box cannot be determined, a warning message is issued and the \special
+command is ignored.
+
+Otherwise, the section of the PostScript file between the comment lines
+
+%begin(plot)
+%end(plot)
+
+is copied to the output file surrounded by
+
+save
+300 72 div 300 72 div scale % revert to standard 1/72 inch units
+(xcp(in 1/72in)-llx) (ycp(in 1/72in)-ury) translate % if relative positioning
+...PostScript file contents...
+restore
+
+***********************************************************************/
+
+ clearerr(plotfp); /* VMS sets the error flag unexpectedly */
+
+ if (strncmp("overlay ",s,8) == 0)
+ {
+ k = 8;
+ abspos = TRUE;
+ }
+ else if (strncmp("include ",s,8) == 0)
+ {
+ k = 8;
+ abspos = FALSE;
+ }
+ else if (strncmp("insert ",s,7) == 0)
+ {
+ k = 7;
+ abspos = FALSE;
+ }
+ else
+ {
+ NEWLINE(stderr);
+ (void)fprintf(stderr,
+ "[TeX \\special{%s} command not understood]",s);
+ NEWLINE(stderr);
+ (void)fprintf(stderr,"Expected one of:");
+ NEWLINE(stderr);
+ (void)fprintf(stderr,
+ "\t\\special{overlay filename} [relative to page origin in ");
+ (void)fprintf(stderr,
+ "lower-left corner]");
+ NEWLINE(stderr);
+ (void)fprintf(stderr,"or");
+ NEWLINE(stderr);
+ (void)fprintf(stderr,
+ "\t\\special{insert filename} [relative to current position]");
+ NEWLINE(stderr);
+ (void)fprintf(stderr,"or");
+ NEWLINE(stderr);
+ (void)fprintf(stderr,
+ "\t\\special{include filename} [relative to current position]");
+ NEWLINE(stderr);
+ (void)fprintf(stderr,"\\special{%s} request ignored",s);
+ NEWLINE(stderr);
+ (void)fprintf(stderr,"Current TeX page counters: [%s]",tctos());
+ NEWLINE(stderr);
+ return;
+ }
+ specfile = fopen(&s[k],"r");
+ DEBUG_OPEN(specfile,&s[k],"r");
+ if (specfile == (FILE *)NULL)
+ {
+ NEWLINE(stderr);
+ (void)fprintf(stderr,
+ "Open failure on \\special file [%s]",&s[k]);
+ NEWLINE(stderr);
+ (void)fprintf(stderr,"\\special{%s} request ignored",s);
+ NEWLINE(stderr);
+ (void)fprintf(stderr,"Current TeX page counters: [%s]",tctos());
+ NEWLINE(stderr);
+ return;
+ }
+ if (abspos)
+ {
+ llx = lly = 0;
+ urx = (72*17)/2;
+ ury = 72*11;
+ }
+ else
+ {
+ llx = lly = urx = ury = -1;
+ while (fgets(line,MAXLINE,specfile) != (char *)NULL)
+ {
+ llx = lly = urx = ury = -1;
+ if (strncmp(line,"%%BoundingBox: (atend)",22) == 0)
+ { /* reposition to up to 1000 chars from end of file */
+ (void)fstat(fileno(specfile),&statbuf);
+ k = MIN(1000,(INT16)((long)statbuf.st_size-ftell(specfile)));
+ if (k > 0)
+ (void)fseek(specfile,(long)(-k),2);
+ }
+ else if (strncmp(line,"%%BoundingBox:",14) == 0)
+ {
+ k = (INT16)sscanf(line,
+ "%%%%BoundingBox: %d %d %d %d",&llx,&lly,&urx,&ury);
+ if (k == 4)
+ break; /* got %%BoundingBox */
+ }
+ }
+ }
+ if (ury == (-1))
+ {
+ NEWLINE(stderr);
+ (void)fprintf(stderr,
+ "Could not find PostScript %%%%BoundingBox command ");
+ (void)fprintf(stderr,"needed to position plot on page");
+ NEWLINE(stderr);
+ (void)fprintf(stderr,"\\special{%s} request ignored",s);
+ NEWLINE(stderr);
+ (void)fprintf(stderr,"Current TeX page counters: [%s]",tctos());
+ NEWLINE(stderr);
+ return;
+ }
+ NEWLINE(stderr);
+ (void)fprintf(stderr,"\t[\\special{%s}] ",s);
+ NEWLINE(stderr);
+
+ OUT_IMMEDIATE;
+ OUT_STR("save\n"); /* save current state */
+
+ OUT_STR("300 72 div 300 72 div scale\n"); /* revert to standard units */
+
+ if (!abspos) /* move origin for include/insert */
+ {
+ moveto(hh,YSIZE-vv); /* update current point */
+ OUT_NUM((72*xcp)/300-llx);
+ OUT_NUM((72*ycp)/300-ury);
+ OUT_STR("translate\n");
+ }
+ (void)REWIND(specfile); /* rewind file */
+
+ while (fgets(line,MAXLINE,specfile) != (char *)NULL)
+ { /* search for %begin(plot) ... %end(plot) */
+ if (strncmp(line,"%begin(plot)",12) == 0)
+ { /* copy until %end(plot) */
+ while (fgets(line,MAXLINE,specfile) != (char *)NULL)
+ {
+ if (strncmp(line,"%end(plot)",10) == 0)
+ break;
+ OUTS(line);
+ }
+ break;
+ }
+ }
+ OUT_STR("restore\n");
+ (void)fclose(specfile);
+ if (!quiet)
+ {
+ (void)fprintf(stderr," [OK]");
+ NEWLINE(stderr);
+ }
+ if (DISKFULL(plotfp))
+ (void)fatal("special(): Output error -- disk storage probably full");
+}
+
+#include "strchr.h"
+#include "strcm2.h"
+#include "strid2.h"
+#include "strrchr.h"
+#include "tctos.h"
+
+/*-->textchr*/
+/**********************************************************************/
+/****************************** textchr *******************************/
+/**********************************************************************/
+
+void
+textchr(c) /* output character c */
+register char c;
+{
+ char* psave;
+
+ if (deferred) /* deferred output */
+ {
+ *ptext++ = c;
+ if (ptext >= (textbuf + MAXTEXT))
+ {
+ /* textbuf[] is full. Backup to the last newline, output
+ textbuf[] to that point, move the remainder to the
+ start of textbf[], and resume character collection. */
+ *ptext = '\0'; /* mark the end */
+ psave = strrchr(textbuf,'\n'); /* find last line break */
+ ptext = psave; /* shorten buffer */
+ *ptext = '\0'; /* mark the new end */
+ textflush(); /* output the buffer */
+ ++psave; /* where we want to pick up remainder */
+ OUT_FONTNAME; /* make sure current font starts buffer */
+ OUT_NL;
+ OUT_NUM(xcp); /* make sure current point is set too */
+ OUT_NUM(ycp);
+ OUT_STR("M\n");
+
+ /* Since the above initial sequence requires at most 25
+ characters, we should be safe here, since psave should
+ be pointing near the end of textbuf[]. Nevertheless, we
+ should watch for this time bomb, because someday someone
+ might make MAXTEXT ridiculously small. */
+ if (ptext > psave)
+ fatal("textchr(): internal error--textbuf[] too small");
+
+ (void)strcpy(ptext,psave); /* move remainder to start */
+ ptext = strchr(textbuf,'\0'); /* find the new end again */
+ }
+ }
+ else /* immediate output */
+ {
+
+#if PS_SHORTLINES
+ /***************************************************************
+ Unfortunately, PostScript does allows only text bracketed by ()
+ to be broken across lines by a \newline sequence. We must
+ therefore continue comments manually and break <...> strings by
+ a newline. emitchar() ensures that % in () and non-bracketing
+ () <> are encoded in octal, so as not to confuse us here.
+ ***************************************************************/
+
+ switch (c) /* set flags for exiting environments */
+ {
+ case '\n':
+ is_comment = FALSE;
+ break;
+
+ /* '<' editor balance */
+ case '>':
+ if (!is_comment)
+ is_string = FALSE;
+ break;
+
+ /* '(' editor balance */
+ case ')':
+ if (!is_comment)
+ is_text = FALSE;
+ break;
+ }
+
+ if (out_width < (PS_MAXWIDTH-2)) /* 3 or more slots left on line */
+ {
+ switch (c)
+ {
+ case '\n':
+ NEWLINE(plotfp);
+ out_width = 0;
+ break;
+
+ default:
+ OUTC(c);
+ out_width++;
+ break;
+ }
+ }
+ else if (out_width == (PS_MAXWIDTH-2)) /* 2 slots left on line */
+ {
+ if (is_comment)
+ {
+ OUTC(c);
+ out_width++;
+ }
+ else /* not comment */
+ {
+ switch (c)
+ {
+ case '(': /* special \newline inside (...text...) */
+ OUTC(c);
+ OUTC('\\');
+ NEWLINE(plotfp);
+ out_width = 0;
+ break;
+
+ case '\n': /* ordinary newline */
+ NEWLINE(plotfp);
+ out_width = 0;
+ break;
+
+ default: /* else just output the character */
+ OUTC(c);
+ out_width++;
+ break;
+ } /* end switch */
+ } /* end if (is_comment) */
+ }
+ else /* at most 1 slot left */
+ {
+ if (is_comment)
+ { /* make special continued comment */
+ OUTC('-');
+ NEWLINE(plotfp);
+ OUTS("%-");
+ OUTC(c);
+ out_width = 3;
+ }
+ else /* not comment */
+ {
+ switch (c)
+ {
+ case '%': /* start newline for comment or (...text...) */
+ case '(':
+ NEWLINE(plotfp);
+ OUTC(c);
+ out_width = 1;
+ break;
+
+ case ')': /* follow (...text...) with newline */
+ case '<': /* newline inside <...text...> okay */
+ case '>': /* follow <...text...> with newline */
+ OUTC(c);
+ NEWLINE(plotfp);
+ out_width = 0;
+ break;
+
+ case ' ': /* change trailing space to newline */
+ case '\n': /* newline */
+ NEWLINE(plotfp);
+ out_width = 0;
+ break;
+
+ default:
+ if (is_text) /* \newline continuation in (...text...) */
+ {
+ OUTC('\\');
+ NEWLINE(plotfp);
+ OUTC(c);
+ out_width = 1;
+ }
+ else if (is_string) /* newline inside <...text...> okay */
+ {
+ OUTC(c);
+ NEWLINE(plotfp);
+ out_width = 0;
+ }
+ else /* cannot break at this point, sigh... */
+ {
+ OUTC(c);
+ out_width++;
+ }
+ break;
+ } /* end switch */
+ } /* end if (is_comment) */
+ }
+
+ switch (c) /* set flags for entering environments */
+ {
+ case '%':
+ is_comment = TRUE;
+ break;
+
+ case '<':
+ if (!is_comment)
+ is_string = TRUE;
+ break;
+
+ case '(':
+ if (!is_comment)
+ is_text = TRUE;
+ break;
+ }
+#else /* NOT PS_SHORTLINES */
+ OUTC(c);
+#endif /* PS_SHORTLINES */
+
+ } /* endif deferred/immediate */
+}
+
+/*-->textflush*/
+/**********************************************************************/
+/***************************** textflush ******************************/
+/**********************************************************************/
+
+void
+textflush() /* flush current textbuf[] to output */
+{
+
+#if PS_SHORTLINES
+ register char* pbreak; /* point to character before */
+ /* which we can insert a line break */
+ char linebuf[PS_MAXWIDTH+1]; /* buffer for output line */
+ register INT16 k; /* index in linebuf[] */
+ register INT16 kbreak; /* break index in linebuf[] */
+ /* corresponding to pbreak */
+#endif /* PS_SHORTLINES */
+
+ /* Wrap the current textbuf[] contents with save/restore, but
+ preserve the current point and font. */
+ if (ptext > textbuf) /* make sure textbuf[] is not empty */
+ {
+
+#if PS_SHORTLINES
+ if (out_width > 0) /* want TB ... TE on separate lines */
+ NEWLINE(plotfp);
+#endif /* PS_SHORTLINES */
+
+ OUTS("TB");
+ NEWLINE(plotfp);
+
+ *ptext = '\0'; /* terminate current textbuf[] */
+
+#if PS_SHORTLINES
+ ptext = textbuf;
+ pbreak = ptext;
+ k = 0;
+ kbreak = 0;
+ while (*ptext)
+ {
+ if (k >= PS_MAXWIDTH)
+ {
+ if (kbreak > 0)
+ {
+ k = kbreak;
+ ptext = pbreak;
+ }
+ while ((k > 0) && (linebuf[k-1] == ' '))
+ k--; /* trim trailing space */
+ linebuf[k] = '\0';
+ OUTS(linebuf);
+ k = 0;
+ if ((kbreak > 0) || (*(ptext+1) == '\0'))
+ NEWLINE(plotfp);
+ }
+ if ((*ptext == '\n') && (*(ptext+1) == '('))
+ ptext++; /* squeeze out useless newline */
+ if (*ptext == '\n')
+ *ptext = ' '; /* change newline to blank */
+ if ((k == 0) && (*ptext == ' '))
+ /* NO-OP */; /* don't save leading space */
+ else
+ linebuf[k++] = *ptext;
+ if ((*ptext == ' ') || (*ptext == '('))
+ {
+ kbreak = k - 1;
+ pbreak = ptext;
+ }
+ else if (*ptext == ')')
+ {
+ kbreak = k;
+ pbreak = ptext + 1;
+ }
+ ptext++;
+ }
+ if (k > 0)
+ {
+ while ((k > 0) && (linebuf[k-1] == ' '))
+ k--; /* trim trailing space */
+ linebuf[k] = '\0';
+ OUTS(linebuf);
+ NEWLINE(plotfp);
+ }
+ out_width = 0;
+#else /* NOT PS_SHORTLINES */
+ OUTS(textbuf);
+ NEWLINE(plotfp);
+#endif /* PS_SHORTLINES */
+
+ OUTS("TE");
+ NEWLINE(plotfp);
+
+ ptext = textbuf;
+ }
+}
+
+/*-->textnum*/
+/**********************************************************************/
+/****************************** textnum *******************************/
+/**********************************************************************/
+
+void
+textnum(n) /* output number with one trailing space */
+long n; /* the number */
+{
+ char digits[11];
+
+ (void)sprintf(digits,"%ld",n);
+ textstr(digits);
+
+#if PS_SHORTLINES
+ if (!deferred && !is_comment && (out_width == 0))
+ /* NO-OP */; /* omit space at beginning of line */
+ else
+ textchr(' ');
+
+#else /* NOT PS_SHORTLINES */
+ textchr(' ');
+#endif /* PS_SHORTLINES */
+
+}
+
+
+
+/*-->textstr*/
+/**********************************************************************/
+/****************************** textstr *******************************/
+/**********************************************************************/
+
+void
+textstr(s) /* output string s[] */
+register char* s;
+{
+
+#if PS_SHORTLINES
+ if (!deferred && !is_comment && ((out_width + strlen(s)) > PS_MAXWIDTH))
+ OUT_NL;
+#endif /* PS_SHORTLINES */
+
+ for (; *s; ++s)
+ textchr(*s);
+}
+
+#include "usage.h"
+#include "warning.h"