diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/beebe/src/dvialw.c |
Initial commit
Diffstat (limited to 'dviware/beebe/src/dvialw.c')
-rw-r--r-- | dviware/beebe/src/dvialw.c | 1935 |
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" |