/* -*-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 [ # # # # # ] # D (string) # # S can be reduced to [# # # # #]# 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 Subject: Re: Apple Laserwriter XON/XOFF problem To: 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"