1 /*
2  *   These routines do most of the communicating with the printer.
3  *
4  *   LINELENGTH tells the maximum line length to send out.  It's been
5  *   reduced to 72 because sometimes PostScript files are included in
6  *   mail messages and many mailers mutilate longer lines.
7  */
8 #define LINELENGTH (72)
9 #include "dvips.h" /* The copyright notice in that file is included too! */
10 #include <ctype.h>
11 #include <stdlib.h>
12 
13 #ifdef OS2
14 #ifdef _MSC_VER
15 #define popen(pcmd, pmode)  _popen(pcmd, pmode)
16 #define pclose(pstream) _pclose(pstream)
17 #endif
18 #endif
19 #if defined(WIN32) && defined(KPATHSEA)
20 #undef fopen
21 #undef popen
22 #undef pclose
23 #define fopen(file, fmode)  fsyscp_fopen(file, fmode)
24 #define popen(pcmd, pmode)  fsyscp_popen(pcmd, pmode)
25 #define pclose(pstream) _pclose(pstream)
26 #endif
27 
28 #ifdef __DJGPP__
29 #include <unistd.h>	/* for `isatty' */
30 #endif
31 
32 /* UCS -> UTF-8 */
33 #define UCStoUTF8B1(x)  (0xc0 + (((x) >>  6) & 0x1f))
34 #define UCStoUTF8B2(x)  (0x80 + (((x)      ) & 0x3f))
35 
36 #define UCStoUTF8C1(x)  (0xe0 + (((x) >> 12) & 0x0f))
37 #define UCStoUTF8C2(x)  (0x80 + (((x) >>  6) & 0x3f))
38 #define UCStoUTF8C3(x)  (0x80 + (((x)      ) & 0x3f))
39 
40 #define UCStoUTF8D1(x)  (0xf0 + (((x) >> 18) & 0x07))
41 #define UCStoUTF8D2(x)  (0x80 + (((x) >> 12) & 0x3f))
42 #define UCStoUTF8D3(x)  (0x80 + (((x) >>  6) & 0x3f))
43 #define UCStoUTF8D4(x)  (0x80 + (((x)      ) & 0x3f))
44 
45 /* UTF-32 over U+FFFF -> UTF-16 surrogate pair */
46 #define UTF32toUTF16HS(x)  (0xd800 + (((x-0x10000) >> 10) & 0x3ff))
47 #define UTF32toUTF16LS(x)  (0xdc00 + (  x                 & 0x3ff))
48 
49 /*
50  *   The external declarations:
51  */
52 #include "protos.h"
53 
54 char preamblecomment[256]; /* usually "TeX output ..." */
55 integer rdir = 0, fdir = 0;
56 /*
57  *   We need a few statics to take care of things.
58  */
59 static void chrcmd(char c);
60 static void tell_needed_fonts(void);
61 static void print_composefont(void);
62 static void setdir(int d);
63 static int JIStoSJIS(int c);
64 
65 static Boolean any_dir = 0; /* did we output any direction commands? */
66 static Boolean jflag = 0;
67 static integer rhh, rvv;
68 static int instring;
69 static Boolean lastspecial = 1;
70 static shalfword d;
71 static Boolean popened = 0;
72 static int lastfont;
73 static char strbuffer[LINELENGTH + 20], *strbp = strbuffer;
74 static struct papsiz *finpapsiz;
75 static struct papsiz defpapsiz = {
76    0, 40258437L, 52099154L, "letter", ""
77 };
78 #ifdef CREATIONDATE
79 #if (!defined(VMS) && !defined(MSDOS) && !(defined(OS2) && defined(_MSC_VER)) && !defined(ATARIST))
80  /* VAXC/MSDOS don't like/need this !! */
81 #include <sys/types.h>
82 #ifndef WIN32
83 #include <sys/time.h> /* time(), at least on BSD Unix */
84 #endif
85 #endif
86 #include <time.h> /* asctime() and localtime(), at least on BSD Unix */
87 static time_t jobtime;
88 #endif
89 /*
90  *   This routine copies a file down the pipe.  Search path uses the
91  *   header path.
92  *
93  *   We add code to handle the case of MS-DOS font files.
94  *
95  *   Format:  80 {01,02} four byte length in littleendian order data
96  *   repeated possibly multiple times.
97  */
98 static const char *hxdata = "0123456789ABCDEF";
99 static int infigure;
100 static char possibleDSCLine[81],
101        *dscLinePointer = possibleDSCLine, *dscLineEnd = possibleDSCLine + 80;
102 void
copyfile_general(const char * s,struct header_list * cur_header)103 copyfile_general(const char *s, struct header_list *cur_header)
104 {
105    FILE *f = NULL;
106    int c, prevc = '\n';
107    long len;
108    /* begin DOS EPS code */
109    int doseps = 0;
110    unsigned long dosepsbegin, dosepsend = 0;
111    int removingBytes = 0;
112    const char *scanForEnd = 0;
113    int scanningFont = 0;
114 
115    /* end DOS EPS code */
116 #if defined(VMCMS) || defined (MVSXA)
117    register char *lastdirsep;
118    register char *trunc_s;
119    trunc_s = s;
120 #endif
121    dscLinePointer = possibleDSCLine;
122 
123    switch (infigure) {
124    case 1:
125 /*
126  *   Look in headerpath too, just in case.  This allows common header
127  *   or figure files to be installed in the .../ps directory.
128  */
129       f = search(figpath, s, READBIN);
130       if (f == 0)
131          f = search(headerpath, s, READBIN);
132 #if defined(VMCMS) || defined (MVSXA)
133       lastdirsep = strrchr(s, '/');
134       if ( NULL != lastdirsep ) trunc_s = lastdirsep + 1;
135 #ifdef VMCMS
136       sprintf(errbuf,
137    "Couldn't find figure file %s with CMS name %s; continuing.", s, trunc_s);
138       if (secure == 2) {
139          strcat(errbuf, "\nNote that an absolute path or a relative path with .. are denied in -R2 mode.");
140       }
141 #else /* VMCMS */
142       sprintf(errbuf,
143     "Couldn't find figure file %s with MVS name %s; continuing.", s, trunc_s);
144       if (secure == 2) {
145          strcat(errbuf, "\nNote that an absolute path or a relative path with .. are denied in -R2 mode.");
146       }
147 #endif /* VMCMS */
148 #else /* VMCMS || MVSXA */
149       sprintf(errbuf, "Could not find figure file %s; continuing.", s);
150       if (secure == 2) {
151          strcat(errbuf, "\nNote that an absolute path or a relative path with .. are denied in -R2 mode.");
152       }
153 #endif /* VMCMS || MVSXA */
154       break;
155 #ifndef VMCMS
156 #ifndef MVSXA
157 #ifndef VMS
158 #if !defined(MSDOS) || defined(__DJGPP__)
159 #ifndef ATARIST
160 #ifndef __THINK__
161    case 2:
162 #ifdef SECURE
163       sprintf(errbuf, "<%s>: Tick filename execution disabled", s);
164 #else
165 #ifdef OS2
166       if (_osmode == OS2_MODE) {
167 #endif
168       if (secure == 0) {
169          sprintf(errbuf, "Execution of  <%s> failed ", s);
170          f = popen(s, "r");
171          if (f != 0)
172             SET_BINARY(fileno(f));
173 	}
174 	else {
175       sprintf(errbuf,"Secure mode is %d so execute <%s> will not run", secure,s);
176 	}
177 #ifdef OS2
178       }
179 #endif
180 #endif
181       break;
182 #endif
183 #endif
184 #endif
185 #endif
186 #endif
187 #endif
188    default:
189       f = search(headerpath, s, READBIN);
190       if(cur_header && (cur_header->precode || cur_header->postcode)) {
191 	 if(f==NULL)
192 	    f = search(figpath, s, READBIN);
193       }
194       sprintf(errbuf, "! Could not find header file %s.", s);
195       if (secure == 2) {
196          strcat(errbuf, "\nNote that an absolute path or a relative path with .. are denied in -R2 mode.");
197       }
198       break;
199    }
200    if (f==NULL)
201       error(errbuf);
202    else {
203       if (! quiet) {
204 #if defined(VMCMS) || defined (MVSXA)
205          if (strlen(s) + prettycolumn > STDOUTSIZE) {
206 #else
207          if (strlen(realnameoffile) + prettycolumn > STDOUTSIZE) {
208 #endif
209             fprintf(stderr, "\n");
210             prettycolumn = 0;
211          }
212 #if defined(VMCMS) || defined (MVSXA)
213          fprintf(stderr, "<%s>", trunc_s);
214 #else
215          fprintf(stderr, "<%s>", realnameoffile);
216 #endif
217          fflush(stderr);
218 #if defined(VMCMS) || defined (MVSXA)
219          prettycolumn += 2 + strlen(s);
220 #else
221          prettycolumn += 2 + strlen(realnameoffile);
222 #endif
223       }
224       if (linepos != 0)
225          putc('\n', bitfile);
226 /*
227  *   Suggested by Andrew Trevorrow; don't ever BeginFont a file ending in .enc
228  */
229       if (infont && strstr(s,".enc"))
230          infont = 0;
231       if (! disablecomments) {
232          if (infigure)
233             fprintf(bitfile, "%%%%BeginDocument: %s\n", s);
234          else if (infont)
235             fprintf(bitfile, "%%%%BeginFont: %s\n", infont);
236 #ifdef HPS
237          else if (noprocset) {}
238 #endif
239          else
240             fprintf(bitfile, "%%%%BeginProcSet: %s 0 0\n", s);
241       }
242       if (cur_header && cur_header->precode) {
243          fprintf(bitfile, "%s\n", cur_header->precode);
244          free(cur_header->precode);
245       }
246       c = getc(f);
247       if (c == 0x80) {
248          while (1) {
249             c = getc(f);
250             switch(c) {
251 case 1:
252 case 2:
253                len = getc(f);
254                len += getc(f) * 256L;
255                len += getc(f) * 65536L;
256                len += getc(f) * 256L * 65536;
257                if (c == 1) {
258                   while (len > 0) {
259                      c = getc(f);
260                      if (c == EOF) {
261                         error("premature EOF in MS-DOS font file");
262                         len = 0;
263                      } else {
264 		        if (c == '\r') { /* Mac- or DOS-style text file */
265                            putc('\n', bitfile);
266 			   if ((c = getc(f)) == '\n') /* DOS-style text */
267 			      len--; /* consume, but don't generate NL */
268 			   else
269 			      ungetc(c, f);
270 			}
271                         else
272                            putc(c, bitfile);
273                         len--;
274                      }
275                   }
276                } else {
277                   putc('\n', bitfile);
278                   prevc = 0;
279                   while (len > 0) {
280                      c = getc(f);
281                      if (c == EOF) {
282                         error("premature EOF in MS-DOS font file");
283                         len = 0;
284                      } else {
285                         putc(hxdata[c >> 4], bitfile);
286                         putc(hxdata[c & 15], bitfile);
287                         len--;
288                         prevc += 2;
289                         if (prevc >= 76) {
290                            putc('\n', bitfile);
291                            prevc = 0;
292                         }
293                      }
294                   }
295                }
296                break;
297 case 3:
298                goto msdosdone;
299 default:
300                error("saw type other than 1, 2, or 3 in MS-DOS font file");
301                break;
302             }
303             c = getc(f);
304             if (c == EOF)
305                break;
306             if (c != 0x80) {
307                error("saw non-MSDOS header in MSDOS font file");
308                break;
309             }
310          }
311 msdosdone:
312          prevc = 0;
313       } else {
314 /* begin DOS EPS code */
315          if (c == 'E'+0x80) {
316             if ((getc(f)=='P'+0x80) && (getc(f)=='S'+0x80)
317 	                            && (getc(f)=='F'+0x80)) {
318                doseps = 1;
319                dosepsbegin = getc(f);
320                dosepsbegin += getc(f) * 256L;
321                dosepsbegin += getc(f) * 65536L;
322                dosepsbegin += getc(f) * 256L * 65536;
323                dosepsend = getc(f);
324                dosepsend += getc(f) * 256L;
325                dosepsend += getc(f) * 65536L;
326                dosepsend += getc(f) * 256L * 65536;
327                fseek(f, dosepsbegin, 0);
328                c = getc(f);
329                dosepsend--;
330             }
331             else {
332                rewind(f);
333                c = getc(f);
334             }
335          }
336 /* end DOS EPS code */
337          if (c != EOF) {
338             while (1) {
339                if (c == '\n') { /* end or beginning of line; check DSC */
340                   *dscLinePointer = 0; /* make sure we terminate!
341                                          * might be a new empty line! */
342                   if (strncmp(possibleDSCLine, "%%BeginBinary:", 14) == 0 ||
343                       strncmp(possibleDSCLine, "%%BeginData:", 12) == 0 ||
344                       strncmp(possibleDSCLine, "%%BeginFont:", 12) == 0) {
345                      integer size = 0;
346                      char *p = possibleDSCLine;
347                      *dscLinePointer = 0;
348                      *dscLineEnd = 0;
349                      if (scanForEnd == 0 && removecomments) {
350                         fputs(possibleDSCLine, bitfile);
351                         putc('\n', bitfile);
352                      }
353 
354                      if (strncmp(possibleDSCLine, "%%BeginFont:", 12) == 0) {
355 
356                        /* Theoretically, we could wait until we see
357                           the "currentfile eexec" and possibly even
358                           check that the following data really looks
359                           like binary before we begin verbatim
360                           copying, but that would complicate the code
361                           beyond our present needs.  If we were going
362                           to do that much work, this entire chunk of
363                           code should probably be
364                           rewritten. [dmj@ams.org, 2007/08/20] */
365 
366                        scanForEnd = "%%EndFont";
367                        scanningFont = 1;
368                      } else {
369                        scanningFont = 0;
370 
371                      scanForEnd = 0;
372                      while (*p != ':')
373                         p++;
374                      p++;
375                      while (*p && *p <= ' ')
376                         p++;
377                      if ('0' > *p || *p > '9') {
378                         /*
379                          *   No byte count!  We need to scan for end binary
380                          *   or end data, and hope we get it right.  Really
381                          *   the file is malformed.
382                          */
383                         scanForEnd = "Yes";
384                      }
385                      while ('0' <= *p && *p <= '9') {
386                         size = size * 10 + *p - '0';
387                         p++;
388                      }
389                      while (*p && *p <= ' ')
390                         p++;
391                      if (*p == 'h' || *p == 'H')
392                         /*
393                          *   Illustrator 8 and 9 have bogus byte counts
394                          *   for hex data.  But if it is hex, we assume
395                          *   that it is safe to use ASCII scanning, so
396                          *   we do so.
397                          */
398                         scanForEnd = "Yes";
399                      while (*p > ' ') /* ignore Hex/Binary/ASCII */
400                         p++;
401                      while (*p && *p <= ' ')
402                         p++;
403                      putc(c, bitfile);
404                      if (c == '\r') { /* maybe we have a DOS-style text file */
405                         c = getc(f);
406                         if (c == '\n') {
407                            putc(c, bitfile);
408                            dosepsend--;
409                         } else
410                            ungetc(c, f);
411                      }
412                      if (scanForEnd != 0) {
413                         if (strncmp(possibleDSCLine, "%%BeginBinary", 13) == 0)
414                            scanForEnd = "%%EndBinary";
415                         else
416                            scanForEnd = "%%EndData";
417                      }
418                      }
419                      if (scanForEnd == 0) {
420                         if (strncmp(p, "lines", 5) != 0 &&
421                             strncmp(p, "Lines", 5) != 0) {
422                            for (; size>0; size--) {
423                               c = getc(f);
424                               dosepsend--;
425                               if (c == EOF)
426                                  error(
427                                  "! premature end of file in binary section");
428                               putc(c, bitfile);
429                            }
430                         } else {
431                            /*
432                             *  Count both newlines and returns, and when either
433                             *  goes over the count, we are done.
434                             */
435                            int newlines=0, returns=0;
436                            while (newlines < size && returns < size) {
437                               c = getc(f);
438                               dosepsend--;
439                               if (c == EOF)
440                                  error(
441                                     "! premature end of file in binary section");
442                               putc(c, bitfile);
443                               if (c == '\n')
444                                  newlines++;
445                               else if (c == '\r')
446                                  returns++;
447                            }
448                            /*
449                             *   If we've seen precisely one too few newlines,
450                             *   and the next char is a newline, include it too.
451                             */
452                            if (returns == newlines + 1) {
453                               if ((c = getc(f)) == '\n') {
454                                  putc(c, bitfile);
455                                  dosepsend--;
456                               } else {
457                                  ungetc(c, f);
458                               }
459                            }
460                         }
461                         c = getc(f);
462                         dosepsend--;
463                         if (c == '\n' || c == '\r') {
464                            putc(c, bitfile);
465 			   if (c == '\r') { /* DOS-style text file? */
466 			      c = getc(f);
467                               dosepsend--;
468 			      if (c == '\n') {
469 			         putc(c, bitfile);
470 			         c = getc(f);
471                                  dosepsend--;
472 			      }
473 			   } else {
474 			      c = getc(f);
475                               dosepsend--;
476                            }
477                         }
478                         if (c != '%') {
479                            /*   try to find %%EndBinary or %%EndData anywhere
480                                 in the rest of the file, and pretend it
481                                 worked; this works around various Illustrator
482                                 bugs.   -tgr, 14 June 2003                  */
483                            const char *m1 = "%%EndData";
484                            const char *m2 = "%%EndBinary";
485                            const char *p1 = m1;
486                            const char *p2 = m2;
487                            error(
488                " expected to see %%EndBinary at end of data; struggling on");
489                            while (1) {
490                               putc(c, bitfile);
491                               if (c == '\r' || c == '\n') {
492 			         if (c == '\r') { /* DOS-style text file? */
493 			            c = getc(f);
494 			            if (c != '\n')
495 				       ungetc(c, f);
496                                     else
497                                        dosepsend--;
498 			         }
499                                  break;
500 			      }
501                               c = getc(f);
502                               dosepsend--;
503                               if (c == EOF)
504                                  error(
505                                  "! premature end of file in binary section");
506  /*
507   *   By the way, this code can be fooled by things like %%%EndBinary
508   *   or even %%EndBi%%EndBinary, but this isn't valid DSC anyway.
509   *   This comment is mainly here to prevent anyone else from emulating
510   *   this code when doing stream-based substring matching.
511   */
512                               if (c == *p1) {
513                                  p1++;
514                                  if (*p1 == 0)
515                                     break;
516                               } else {
517                                  p1 = m1;
518                               }
519                               if (c == *p2) {
520                                  p2++;
521                                  if (*p2 == 0)
522                                     break;
523                               } else {
524                                  p2 = m2;
525                               }
526                            }
527                         }
528                         while (1) {
529                            putc(c, bitfile);
530                            if (c == '\r' || c == '\n') {
531 			      if (c == '\r') { /* DOS-style text file? */
532 			         c = getc(f);
533 			         if (c != '\n')
534 				    ungetc(c, f);
535                                  else {
536                                     putc(c, bitfile);
537                                     dosepsend--;
538                                  }
539 			      }
540                               break;
541 			   }
542                            c = getc(f);
543                            removingBytes = 0;
544                            dosepsend--;
545                            if (c == EOF)
546                               error(
547                                  "! premature end of file in binary section");
548                         }
549                         c = getc(f);
550                         dosepsend--;
551                      }
552                   } else if (scanForEnd && strncmp(possibleDSCLine, scanForEnd,
553                                                    strlen(scanForEnd))==0) {
554                      scanForEnd = 0;
555                      scanningFont = 0;
556                   }
557                   dscLinePointer = possibleDSCLine;
558                } else if (dscLinePointer < dscLineEnd) {
559                   *dscLinePointer++ = c;
560                   if (removecomments && scanForEnd == 0 &&
561                       c == '%' && dscLinePointer == possibleDSCLine + 1) {
562                      /* % is first char */
563                      c = getc(f);
564                      if (c == '%' || c == '!')
565                         removingBytes = 1;
566                      if (c != EOF)
567                         ungetc(c, f);
568                      c = '%';
569                   }
570                }
571 #if defined(VMCMS) || defined (MVSXA)
572                if (c != 0x37  || scanningFont) {
573 #else
574                if (c != 4 || scanningFont) {
575 #endif
576                   if (!removingBytes)
577                      putc(c, bitfile);
578                }
579                prevc = c;
580 /* begin DOS EPS code */
581                if (doseps && (dosepsend <= 0))
582                   break;      /* stop at end of DOS EPS PostScript section */
583 /* end DOS EPS code */
584                c = getc(f);
585                dosepsend--;
586                if (c == EOF)
587                   break;
588                else if (c == '\r' && ! scanningFont) {
589 		  c = getc(f);
590 		  if (c == '\n') { /* DOS-style text file? */
591 		     if (!removingBytes) putc('\r', bitfile);
592                      dosepsend--;
593 		  } else
594 		     ungetc(c, f);
595                   c = '\n';
596 	       }
597                if (prevc == '\n')
598                   removingBytes = 0;
599             }
600          }
601       }
602       if (prevc != '\n')
603          putc('\n', bitfile);
604       linepos = 0;
605 #ifndef VMCMS
606 #ifndef MVSXA
607 #ifndef VMS
608 #if !defined(MSDOS) || defined(__DJGPP__)
609 #ifndef ATARIST
610 #ifndef __THINK__
611       if (infigure == 2)
612 #ifdef OS2
613          {
614             if (_osmode == OS2_MODE)
615                pclose(f);
616          }
617 #else
618          pclose(f);
619 #endif
620       else
621 #endif
622 #endif
623 #endif
624 #endif
625 #endif
626 #endif
627          fclose(f);
628       if (cur_header && cur_header->postcode) {
629          fprintf(bitfile, "\n%s", cur_header->postcode);
630          free(cur_header->postcode);
631       }
632       if (!disablecomments) {
633          if (infigure)
634             fprintf(bitfile, "\n%%%%EndDocument\n");
635          else if (infont)
636             fprintf(bitfile, "\n%%%%EndFont\n");
637 #ifdef HPS
638          else if (noprocset) {}
639 #endif
640          else
641             fprintf(bitfile, "\n%%%%EndProcSet\n");
642       }
643    }
644 }
645 
646 void
647 copyfile(const char *s)
648 {
649    copyfile_general(s, NULL);
650 }
651 
652 /*
653  *   For included PostScript graphics, we use the above routine, but
654  *   with no fatal error message.
655  */
656 void
657 figcopyfile(char *s, int systemtype)
658 {
659    infigure = systemtype ? 2 : 1;
660    copyfile(s);
661    infigure = 0;
662 }
663 /*
664  *   This next routine writes out a `special' character.  In this case,
665  *   we simply put it out, since any special character terminates the
666  *   preceding token.
667  */
668 void
669 specialout(char c)
670 {
671    if (linepos >= LINELENGTH) {
672       putc('\n', bitfile);
673       linepos = 0;
674    }
675    putc(c, bitfile);
676    linepos++;
677    lastspecial = 1;
678 }
679 
680 void
681 stringend(void)
682 {
683    if (linepos + instring >= LINELENGTH - 2) {
684       putc('\n', bitfile);
685       linepos = 0;
686    }
687    putc('(', bitfile);
688    *strbp = 0;
689    fputs(strbuffer, bitfile);
690    putc(')', bitfile);
691    linepos += instring + 2;
692    lastspecial = 1;
693    instring = 0;
694    strbp = strbuffer;
695 }
696 
697 #ifdef SHIFTLOWCHARS
698 /*
699  *   moving chars 0-32 and 127 to higher positions
700  *   is desirable when using some fonts
701  */
702 int
703 T1Char(int c)
704 {
705   int tmpchr = c;
706   if (shiftlowchars && curfnt->resfont) {
707     if ((tmpchr <= 0x20)&&(tmpchr>=0)) {
708       if (tmpchr < 0x0A) {
709         tmpchr += 0xA1;
710       }
711       else {
712         tmpchr += 0xA3;
713       }
714     }
715     else if (tmpchr == 0x7F) {
716       tmpchr = 0xC4;
717     }
718   }
719   if (curfnt->chardesc[tmpchr].flags2 & EXISTS)
720     tmpchr = c;
721   return tmpchr;
722 }
723 #endif
724 
725 void
726 scout(unsigned char c)   /* string character out */
727 {
728 /*
729  *   Is there room in the buffer?  LINELENGTH-6 is used because we
730  *   need room for (, ), and a possible four-byte string \000, for
731  *   instance.  If it is too long, we send out the string.
732  */
733    jflag = 0;
734    if (instring > LINELENGTH-6) {
735       stringend();
736       chrcmd('p');
737    }
738 #ifdef SHIFTLOWCHARS
739    c=T1Char(c);
740 #endif
741 /*  changed next line to hex representation for VMCMS port
742    if (c<' ' || c > 126 || c=='%' ) {
743 */
744    if ( c<0x20 || c>= 0x7F || c==0x25 ) {
745       *strbp++ = '\\';
746       *strbp++ = '0' + ((c >> 6) & 3);
747       *strbp++ = '0' + ((c >> 3) & 7);
748       *strbp++ = '0' + (c & 7);
749       instring += 4;
750    } else {
751 #if defined(VMCMS) || defined (MVSXA)
752      c = ascii2ebcdic[c];
753 #endif
754      if (c == '(' || c == ')' || c == '\\') {
755        *strbp++ = '\\';
756        *strbp++ = c;
757        instring += 2;
758      } else {
759        *strbp++ = c;
760        instring++;
761      }
762    }
763 }
764 
765 static void
766 scout2(int c)
767 {
768    char s[64];
769 
770    sprintf(s, "<%04x>p", c);
771    cmdout(s);
772 }
773 
774 static void
775 jscout(int c, char *fs)   /* string character out */
776 {
777    char s[64];
778 
779    if (!dir) {
780       numout(hh);
781       numout(vv);
782    } else {
783       numout(vv);
784       numout(-hh);
785    }
786    if (strstr(fs,"-UTF32-")!=NULL) {
787       snprintf(s, sizeof(s), "a<%08x>p", c);
788    } else if (strstr(fs,"-UTF8-")!=NULL) {
789       if (c<0x80) {
790          snprintf(s, sizeof(s), "a<%02x>p", c);
791       } else if (c<0x800) {
792 	 snprintf(s, sizeof(s), "a<%02x%02x>p", UCStoUTF8B1(c), UCStoUTF8B2(c));
793       } else if (c<0x10000) {
794 	 snprintf(s, sizeof(s), "a<%02x%02x%02x>p", UCStoUTF8C1(c),
795                  UCStoUTF8C2(c), UCStoUTF8C3(c));
796       } else if (c<0x110000) {
797 	 snprintf(s, sizeof(s), "a<%02x%02x%02x%02x>p", UCStoUTF8D1(c),
798 		 UCStoUTF8D2(c), UCStoUTF8D3(c), UCStoUTF8D4(c));
799       } else {
800          error("warning: Illegal code value.");
801       }
802    } else if (c>0xffff && strstr(fs,"-UTF16-")!=NULL) {
803       snprintf(s, sizeof(s), "a<%04x%04x>p",
804 	       UTF32toUTF16HS(c), UTF32toUTF16LS(c));
805    } else {
806       if ((strstr(fs,"-RKSJ-")!=NULL)) c = JIStoSJIS(c);
807       snprintf(s, sizeof(s), "a<%04x>p", c);
808    }
809    cmdout(s);
810    instring = 0;
811    jflag = 1;
812    strbuffer[0] = '\0';
813 }
814 
815 void
816 cmdout(const char *s)
817 {
818    int l;
819 
820    /* hack added by dorab */
821    if (instring && !jflag) {
822         stringend();
823         chrcmd('p');
824    }
825    l = strlen(s);
826    if ((! lastspecial && linepos >= LINELENGTH - 20) ||
827            linepos + l >= LINELENGTH) {
828       putc('\n', bitfile);
829       linepos = 0;
830    } else if (! lastspecial) {
831       putc(' ', bitfile);
832       linepos++;
833    }
834    fputs(s, bitfile);
835    linepos += l;
836    lastspecial = 0;
837 }
838 
839 
840 static void
841 chrcmd(char c)
842 {
843    if ((! lastspecial && linepos >= LINELENGTH - 20) ||
844        linepos + 2 > LINELENGTH) {
845       putc('\n', bitfile);
846       linepos = 0;
847    } else if (! lastspecial) {
848       putc(' ', bitfile);
849       linepos++;
850    }
851    putc(c, bitfile);
852    linepos++;
853    lastspecial = 0;
854 }
855 
856 void
857 floatout(float n)
858 {
859    char buf[50];
860 
861    snprintf(buf, sizeof(buf), "%.2f", n);
862    cmdout(buf);
863 }
864 
865 void
866 doubleout(double n)
867 {
868    char buf[50];
869 
870    snprintf(buf, sizeof(buf), "%g", n);
871    cmdout(buf);
872 }
873 
874 void
875 numout(integer n)
876 {
877    char buf[50];
878 
879 #ifdef SHORTINT
880    snprintf(buf, sizeof(buf), "%ld", n);
881 #else
882    snprintf(buf, sizeof(buf), "%d", n);
883 #endif
884    cmdout(buf);
885 }
886 
887 void
888 mhexout(register unsigned char *p,
889         register long len)
890 {
891    register const char *hexchar = hxdata;
892    register int n, k;
893 
894    while (len > 0) {
895       if (linepos > LINELENGTH - 2) {
896          putc('\n', bitfile);
897          linepos = 0;
898       }
899       k = (LINELENGTH - linepos) >> 1;
900       if (k > len)
901          k = len;
902       len -= k;
903       linepos += (k << 1);
904       while (k--) {
905          n = *p++;
906          putc(hexchar[n >> 4], bitfile);
907          putc(hexchar[n & 15], bitfile);
908       }
909    }
910 }
911 
912 static void
913 fontout(halfword n)
914 {
915    char buf[6];
916 
917    if (instring && !jflag) {
918       stringend();
919       chrcmd('p');
920    }
921    makepsname(buf, n);
922    cmdout(buf);
923 
924    lastfont = curfnt->psname;
925 }
926 
927 void
928 hvpos(void)
929 {
930    if (!dir) {
931       if (rvv != vv || jflag) {
932          if (instring) {
933             stringend();
934             numout(hh);
935             numout(vv);
936             chrcmd('y');
937          } else if (rhh != hh || jflag) {
938             numout(hh);
939             numout(vv);
940             chrcmd('a') ;
941          } else { /* hard to get this case, but it's there when you need it! */
942             numout(vv - rvv);
943             chrcmd('x');
944          }
945          rvv = vv;
946       } else if (rhh != hh || jflag) {
947          if (instring) {
948             stringend();
949             if (hh - rhh < 5 && rhh - hh < 5) {
950 #if defined(VMCMS) || defined (MVSXA) /*  should replace 'p' in non-VMCMS, non-MVSXA line as well */
951                chrcmd(ascii2ebcdic[(char)(112 + hh - rhh)]);
952 #else
953                chrcmd((char)('p' + hh - rhh));
954 #endif
955             } else if (hh - rhh < d + 5 && rhh - hh < 5 - d) {
956 #if defined(VMCMS) || defined (MVSXA) /* should replace 'g' in non-VMCMS, non-MVSXA line as well  */
957                chrcmd(ascii2ebcdic[(char)(103 + hh - rhh - d)]);
958 #else
959                chrcmd((char)('g' + hh - rhh - d));
960 #endif
961                d = hh - rhh;
962             } else {
963                numout(hh - rhh);
964                chrcmd('b');
965                d = hh - rhh;
966             }
967          } else {
968             numout(hh - rhh);
969             chrcmd('w');
970          }
971       }
972       rhh = hh;
973    } else {
974       if (rhh != hh || jflag) {
975          if (instring) {
976             stringend();
977             numout(vv);
978             numout(-hh);
979             chrcmd('y');
980          } else if (rvv != vv || jflag) {
981             numout(vv);
982             numout(-hh);
983             chrcmd('a');
984          } else { /* hard to get this case, but it's there when you need it! */
985             numout(rhh - hh);
986             chrcmd('x');
987          }
988          rhh = hh;
989       } else if (rvv != vv || jflag) {
990          if (instring) {
991             stringend();
992             if (vv - rvv < 5 && rvv - vv < 5) {
993 #if defined(VMCMS) || defined (MVSXA) /*  should replace 'p' in non-VMCMS, non-MVSXA line as well */
994                chrcmd(ascii2ebcdic[(char)(112 + vv - rvv)]);
995 #else
996                chrcmd((char)('p' + vv - rvv));
997 #endif
998             } else if (vv - rvv < d + 5 && rvv - vv < 5 - d) {
999 #if defined(VMCMS) || defined (MVSXA) /* should replace 'g' in non-VMCMS, non-MVSXA line as well  */
1000                chrcmd(ascii2ebcdic[(char)(103 + vv - rvv - d)]);
1001 #else
1002                chrcmd((char)('g' + vv - rvv - d));
1003 #endif
1004                d = vv - rvv;
1005             } else {
1006                numout(vv - rvv);
1007                chrcmd('b');
1008                d = vv - rvv;
1009             }
1010          } else {
1011             numout(vv - rvv);
1012             chrcmd('w');
1013          }
1014       }
1015       rvv = vv;
1016    }
1017 }
1018 
1019 /*
1020  *   initprinter opens the bitfile and writes the initialization sequence
1021  *   to it.
1022  */
1023 void
1024 newline(void)
1025 {
1026    if (linepos != 0) {
1027       fprintf(bitfile, "\n");
1028       linepos = 0;
1029    }
1030    lastspecial = 1;
1031 }
1032 
1033 void
1034 nlcmdout(const char *s)
1035 {
1036    newline();
1037    cmdout(s);
1038    newline();
1039 }
1040 /*
1041  *   Is the dimension close enough for a match?  We use 5bp
1042  *   as a match; this is 65536*72.27*5/72 or 328909 scaled points.
1043  */
1044 static int
1045 indelta(integer i)
1046 {
1047    if (i < 0)
1048       i = -i;
1049    return (i <= 328909);
1050 }
1051 /*
1052  *   A case-irrelevant string compare.
1053  */
1054 static int
1055 mlower(int c)
1056 {
1057    if ('A' <= c && c <= 'Z')
1058       return c - 'A' + 'a';
1059    else
1060       return c;
1061 }
1062 static int
1063 ncstrcmp(const char *a, const char *b)
1064 {
1065    while (*a && (*a == *b ||
1066                        mlower(*a) == mlower(*b)))
1067       a++, b++;
1068    if (*a == 0 && *b == 0)
1069       return 0;
1070    else
1071       return 1;
1072 }
1073 /*
1074  *   Find the paper size.
1075  */
1076 static void
1077 findpapersize(void) {
1078    if (finpapsiz == 0) {
1079       struct papsiz *ps;
1080       struct papsiz *fps = 0;
1081       int    ih, iv, it;
1082       int    mindiff = 0x7fffffff;
1083 
1084       if (tryepsf && !landscape) {
1085          finpapsiz = &defpapsiz;
1086          hpapersize = defpapsiz.xsize;
1087          vpapersize = defpapsiz.ysize;
1088          return;
1089       }
1090       if (cropmarks) {
1091 /*
1092  *   If user wanted crop marks, we increase the size of the page by
1093  *   a half inch all around.
1094  */
1095          if (hpapersize == 0 || vpapersize == 0) {
1096             error(
1097  "warning: -k crop marks wanted, but no paper size specified; using default");
1098             if (landscape) {
1099                hpapersize = defpapsiz.ysize;
1100                vpapersize = defpapsiz.xsize;
1101             } else {
1102                hpapersize = defpapsiz.xsize;
1103                vpapersize = defpapsiz.ysize;
1104             }
1105          }
1106          hpapersize += 2368143L;
1107          vpapersize += 2368143L;
1108          add_header(CROPHEADER);
1109       }
1110       if (paperfmt && *paperfmt) {
1111          for (ps = papsizes; ps; ps = ps->next)
1112             if (ncstrcmp(paperfmt, ps->name)==0)
1113                finpapsiz = ps;
1114          if (finpapsiz == 0)
1115             error("no match for papersize");
1116       }
1117       if (finpapsiz == 0 && hpapersize > 0 && vpapersize > 0) {
1118          for (ps=papsizes; ps; ps = ps->next) {
1119             ih = ps->xsize-hpapersize;
1120             iv = ps->ysize-vpapersize;
1121             if (ih < 0) ih = -ih;
1122             if (iv < 0) iv = -iv;
1123             it = ih;
1124             if (it < iv) it = iv;
1125             if (it < mindiff) {
1126                mindiff = it;
1127                fps = ps;
1128             }
1129          }
1130          if (indelta(mindiff))
1131             landscape = 0;
1132          else
1133             fps = 0;
1134          mindiff = 0x7fffffff;
1135          if (fps == 0) {
1136             for (ps=papsizes; ps; ps = ps->next) {
1137                iv = ps->ysize-hpapersize;
1138                ih = ps->xsize-vpapersize;
1139                if (ih < 0) ih = -ih;
1140                if (iv < 0) iv = -iv;
1141                it = ih;
1142                if (it < iv) it = iv;
1143                if (it < mindiff) {
1144                   mindiff = it;
1145                   fps = ps;
1146                }
1147             }
1148             if (indelta(mindiff))
1149                landscape = 1;
1150             else
1151                fps = 0;
1152             if (fps == 0) {
1153                for (ps=papsizes; ps; ps = ps->next) {
1154                   if (ps->ysize == 0 && ps->xsize == 0) {
1155                      fps = ps;
1156                      break;
1157                   }
1158                }
1159                if (fps == 0) {
1160                   landscape = (hpapersize > vpapersize);
1161                   error(
1162                     "no match for special paper size found; using default");
1163                }
1164             }
1165          }
1166          finpapsiz = fps;
1167       }
1168       if (finpapsiz == 0) {
1169          if (papsizes)
1170             finpapsiz = papsizes;
1171          else
1172             finpapsiz = &defpapsiz;
1173 /*
1174  *   But change xsize/ysize to match so bounding box works.
1175  */
1176          if (hpapersize && vpapersize) {
1177             if (landscape) {
1178                finpapsiz->ysize = hpapersize;
1179                finpapsiz->xsize = vpapersize;
1180             } else {
1181                finpapsiz->xsize = hpapersize;
1182                finpapsiz->ysize = vpapersize;
1183             }
1184          }
1185       }
1186 /*
1187  *   Here, there was no papersize special.  We set the paper size from
1188  *   the selected paper format.  If the selected paper format has no
1189  *   sizes, we use the defaults.
1190  */
1191       if (hpapersize == 0 || vpapersize == 0) {
1192          if (finpapsiz->xsize == 0 || finpapsiz->ysize == 0) {
1193             finpapsiz->xsize = defpapsiz.xsize;
1194             finpapsiz->ysize = defpapsiz.ysize;
1195          }
1196          if (landscape) {
1197             vpapersize = finpapsiz->xsize;
1198             hpapersize = finpapsiz->ysize;
1199          } else {
1200             hpapersize = finpapsiz->xsize;
1201             vpapersize = finpapsiz->ysize;
1202          }
1203 /*
1204  *   Here, there was a papersize special, but the selected paper
1205  *   format has 0 0 for sizes.  We set the sizes here so that the
1206  *   bounding box works.
1207  */
1208       } else if (finpapsiz->xsize == 0 || finpapsiz->ysize == 0) {
1209          finpapsiz->xsize = hpapersize;
1210          finpapsiz->ysize = vpapersize;
1211 /*
1212  *   Here, the user specified a size with -t, and there was a
1213  *   papersize special, and its sizes were greater than zero.
1214  *   We make sure the sizes are okay.  Note that the user must have
1215  *   specified landscape if this is desired.
1216  */
1217       } else if (paperfmt && *paperfmt) {
1218          if (landscape) {
1219             if (!indelta(vpapersize - finpapsiz->xsize) ||
1220                 !indelta(hpapersize - finpapsiz->ysize)) {
1221                if (vpapersize > finpapsiz->xsize ||
1222                    hpapersize > finpapsiz->ysize)
1223                   error("warning: -t selected paper may be too small");
1224                else
1225                   error("note: -t selected paper may be too large");
1226             }
1227          } else {
1228             if (!indelta(hpapersize - finpapsiz->xsize) ||
1229                 !indelta(vpapersize - finpapsiz->ysize)) {
1230                if (hpapersize > finpapsiz->xsize ||
1231                    vpapersize > finpapsiz->ysize)
1232                   error("warning: -t selected paper may be too small");
1233                else
1234                   error("note: -t selected paper may be too large");
1235             }
1236          }
1237       }
1238    }
1239 }
1240 /*
1241  *   Convert scaled points to PostScript points.  This is the same
1242  *   as return (i * 72 / (65536 * 72.27)), which is the same as
1243  *   dividing by 65781.76, but we want to round up.
1244  */
1245 static int
1246 topoints(integer i)
1247 {
1248    i += 65780L;
1249    return (i / 6578176L)*100 + (i % 6578176) * 100 / 6578176;
1250 }
1251 /*
1252  *   Send out the special paper stuff.  If `hed' is non-zero, only
1253  *   send out lines starting with `!' else send all other lines out.
1254  */
1255 static void
1256 paperspec(const char *s, int hed)
1257 {
1258    int sendit;
1259 
1260    while (*s) {
1261       s++;
1262       if (*s == '\0')
1263          return;
1264       if (*s == '!') {
1265          s++;
1266          while (*s == ' ') s++;
1267          sendit = hed;
1268       } else
1269          sendit = ! hed;
1270       if (sendit) {
1271          while (*s && *s != '\n')
1272             putc(*s++, bitfile);
1273          putc('\n', bitfile);
1274       } else {
1275          while (*s && *s != '\n')
1276             s++;
1277       }
1278    }
1279 }
1280 static char *
1281 epsftest(integer bop)
1282 {
1283    if (tryepsf && paperfmt == 0 && *iname) {
1284       findbb(bop+44);
1285       return nextstring;
1286    }
1287    return 0;
1288 }
1289 static char *isepsf = 0;
1290 static int endprologsent;
1291 void
1292 open_output(void) {
1293    FILE * pf = NULL;
1294    if (*oname != 0) {
1295 /*
1296  *   We check to see if the first character is a exclamation
1297  *   point, and popen if so.
1298  */
1299       if (*oname == '!' || *oname == '|') {
1300 #if defined(MSDOS) && !defined(__DJGPP__) || defined(VMS) || defined(VMCMS) || defined(MVSXA) || defined(__THINK__) || defined(ATARIST)
1301             error("! can't open output pipe");
1302 #else
1303 #ifdef OS2
1304          if (_osmode != OS2_MODE) {
1305             error("! can't open output pipe");
1306          } else {
1307 #endif
1308 #ifdef __DJGPP__
1309         /* Feature: if they pipe to "lpr" and there's no executable by
1310            that name anywhere in sight, write to local printer instead.
1311 
1312            We do this up front, before even trying to popen, because on
1313            MS-DOS popen always succeeds for writing (it only opens a
1314            temporary file), and by the time we get to actually run the
1315            (possibly nonexistent) program in pclose, it's too late to
1316            fall back.
1317 
1318            We don't use kpathsea functions here because they don't
1319            know about DOS-specific executable extensions, while we
1320            want to be able to find "lpr.exe", "lpr.com", "lpr.bat" etc.  */
1321         extern char *__dosexec_find_on_path(const char *,
1322                                             char **, char *);
1323         extern char **environ;
1324         char *p = oname + 1;
1325         char found[FILENAME_MAX];
1326 
1327         while (ISSPACE(*p))
1328           p++;
1329         if (strncmp(p, "lpr", 3) == 0 && (ISSPACE(p[3]) || p[3] == '\0')
1330             && !__dosexec_find_on_path(oname+1, (char **)0, found)
1331             && !__dosexec_find_on_path(oname+1, environ, found))
1332            pf = fopen("PRN", "w");
1333 #endif
1334 	 if (pf == NULL && (pf = popen(oname+1, "w")) != NULL) {
1335 	    popened = 1;
1336 	    SET_BINARY(fileno(pf));
1337 	 }
1338          if (pf == NULL)
1339             error("! couldn't open output pipe");
1340 	 bitfile = pf;
1341 #ifdef OS2
1342          }
1343 #endif
1344 #endif /* MSDOS && !__DJGPP__ || VMS || ... */
1345       } else {
1346          if ((bitfile=fopen(oname,"w"))==NULL)
1347             error("! couldn't open PostScript file");
1348          SET_BINARY(fileno(bitfile));
1349       }
1350    } else {
1351       bitfile = stdout;
1352    }
1353 
1354    /* Even PostScript output may include binary characters, so switch
1355       bitfile to binary mode.  */
1356    if (O_BINARY && !isatty(fileno(bitfile)))
1357       SET_BINARY(fileno(bitfile));
1358 }
1359 void
1360 initprinter(sectiontype *sect)
1361 {
1362    int n = sect->numpages * pagecopies * collatedcopies;
1363 #ifdef HPS
1364    if (!HPS_FLAG)
1365 #endif
1366       open_output();
1367 
1368    findpapersize();
1369    if (disablecomments) {
1370       fprintf(bitfile,
1371              "%%!PS (but not EPSF; comments have been disabled)\n");
1372       fprintf(stderr, "Warning:  no %%%%Page comments generated.\n");
1373    } else {
1374       if (multiplesects) {
1375          fprintf(bitfile,
1376              "%%!PS (but not EPSF because of memory limits)\n");
1377          fprintf(stderr, "Warning:  no %%%%Page comments generated.\n");
1378       } else {
1379          isepsf = epsftest(sect->bos);
1380          if (isepsf)
1381             fprintf(bitfile, "%%!PS-Adobe-2.0 EPSF-2.0\n");
1382          else
1383             fprintf(bitfile, "%%!PS-Adobe-2.0\n");
1384       }
1385       if (tryepsf && isepsf == 0)
1386          error("We tried, but couldn't make it EPSF.");
1387       fprintf(bitfile, "%%%%Creator: %s\n", banner + 8);
1388       if (*iname)
1389          fprintf(bitfile, "%%%%Title: %s\n", iname);
1390 #ifdef CREATIONDATE
1391       jobtime=time(0);
1392       fprintf(bitfile, "%%%%CreationDate: %s",
1393                                  asctime(localtime(&jobtime)));
1394 #endif
1395       if (! isepsf) {
1396 /*
1397  *   Normally, we wouldn't want to add that second field
1398  *   indicating that the page order is reversed, as per page
1399  *   644 of the Red book.  But we have to, for many existing
1400  *   spoolers.
1401  */
1402         fprintf(bitfile, "%%%%Pages: %d%s\n", (sepfiles ? n : totalpages),
1403                                                     (reverse?" -1":""));
1404         fprintf(bitfile, "%%%%PageOrder: %sscend\n", reverse?"De":"A");
1405       }
1406       if (landscape) {
1407          fprintf(bitfile, "%%%%Orientation: Landscape\n");
1408          fprintf(bitfile, "%%%%BoundingBox: 0 0 %d %d\n",
1409               topoints(finpapsiz->xsize), topoints(finpapsiz->ysize));
1410       } else if (isepsf)
1411          fprintf(bitfile, "%%%%BoundingBox: %s\n", isepsf);
1412       else
1413          fprintf(bitfile, "%%%%BoundingBox: 0 0 %d %d\n",
1414               topoints(finpapsiz->xsize), topoints(finpapsiz->ysize));
1415       tell_needed_fonts();
1416       paperspec(finpapsiz->specdat, 1);
1417       fprintf(bitfile, "%%%%EndComments\n");
1418    }
1419    {
1420       int i, len;
1421       char *p;
1422 
1423 /*
1424  *   Here, too, we have to be careful not to exceed the line length
1425  *   limitation, if possible.
1426  */
1427       fprintf(bitfile, "%%DVIPSWebPage: %s\n", banner2);
1428       fprintf(bitfile, "%%DVIPSCommandLine:");
1429       len = 18;
1430       for (i=0; i<gargc; i++) {
1431          p = gargv[i];
1432          while (*p > ' ')
1433             p++;
1434          if (*p)
1435             len += 2;
1436          len += strlen(gargv[i]) + 1;
1437          if (len > LINELENGTH) {
1438             fprintf(bitfile, "\n%%+");
1439             len = strlen(gargv[i]) + 3;
1440             if (*p)
1441                len += 2;
1442          }
1443          fprintf(bitfile, (*p ? " \"%s\"" : " %s"), gargv[i]);
1444       }
1445       fprintf(bitfile, "\n%%DVIPSParameters: dpi=%d", actualdpi);
1446       if (actualdpi != vactualdpi)
1447          fprintf(bitfile, "x%d", vactualdpi);
1448       if (compressed)
1449          fprintf(bitfile, ", compressed");
1450       if (removecomments)
1451          fprintf(bitfile, ", comments removed");
1452       fputc('\n', bitfile);
1453    }
1454 #if defined(VMCMS) || defined (MVSXA)  /* convert preamblecomment to ebcdic so we can read it */
1455    {
1456       int i;
1457       for ( i=0; preamblecomment[i]; i++ )
1458           preamblecomment[i] = ascii2ebcdic[preamblecomment[i]];
1459    }
1460 #endif
1461    fprintf(bitfile, "%%DVIPSSource: %s\n", preamblecomment);
1462    linepos = 0;
1463    endprologsent = 0;
1464    if (safetyenclose)
1465       fprintf(bitfile, "/SafetyEnclosure save def\n");
1466    print_composefont();
1467    if (! headers_off)
1468       send_headers();
1469 }
1470 void
1471 setup(void) {
1472    newline();
1473    if (endprologsent == 0 && !disablecomments) {
1474       fprintf(bitfile, "%%%%EndProlog\n");
1475       fprintf(bitfile, "%%%%BeginSetup\n");
1476       if (vactualdpi == actualdpi)
1477          fprintf(bitfile, "%%%%Feature: *Resolution %ddpi\n",
1478                                            actualdpi);
1479       else
1480          fprintf(bitfile, "%%%%Feature: *Resolution %dx%ddpi\n",
1481                                            actualdpi, vactualdpi);
1482       if (multiplesects && *(finpapsiz->specdat)) {
1483          fprintf(bitfile, "TeXDict begin\n");
1484          paperspec(finpapsiz->specdat, 0);
1485          fprintf(bitfile, "end\n");
1486       }
1487       if (manualfeed)
1488          fprintf(bitfile, "%%%%Feature: *ManualFeed True\n");
1489 #ifdef HPS
1490       if (!HPS_FLAG)
1491 #endif
1492       if (multiplesects)
1493          fprintf(bitfile, "%%%%EndSetup\n");
1494    }
1495    if (multiplesects && ! disablecomments)
1496       fprintf(bitfile, "%%DVIPSBeginSection\n");
1497    cmdout("TeXDict");
1498    cmdout("begin");
1499    if (endprologsent || disablecomments || multiplesects == 0) {
1500       fprintf(bitfile, "\n");
1501       paperspec(finpapsiz->specdat, 0);
1502    }
1503    if (manualfeed) cmdout("@manualfeed");
1504    if (landscape) cmdout("@landscape");
1505    if (numcopies != 1) {
1506       numout((integer)numcopies);
1507       cmdout("@copies");
1508    }
1509    cmdout("end");
1510    if (endprologsent == 0 && !disablecomments) {
1511       newline();
1512       endprologsent = 1;
1513 #ifdef HPS
1514       if (!HPS_FLAG)
1515 #endif
1516          if (! multiplesects)
1517             fprintf(bitfile, "%%%%EndSetup\n");
1518    }
1519 #ifdef HPS
1520   if (HPS_FLAG) {
1521     fclose(bitfile);
1522     set_bitfile("body.tmp",0);
1523   }
1524 #endif
1525 }
1526 /*
1527  *   cleanprinter is the antithesis of the above routine.
1528  */
1529 void
1530 cleanprinter(void)
1531 {
1532    fprintf(bitfile, "\n");
1533    fprintf(bitfile, "userdict /end-hook known{end-hook}if\n");
1534    if (safetyenclose)
1535       fprintf(bitfile, "SafetyEnclosure restore\n");
1536    if (!disablecomments)
1537       fprintf(bitfile, "%%%%EOF\n");
1538    if (sendcontrolD)
1539       putc(4, bitfile);
1540    if (ferror(bitfile))
1541       error("Problems with file writing; probably disk full.");
1542 #if !defined(MSDOS) || defined(__DJGPP__)
1543 #ifndef VMS
1544 #ifndef MVSXA
1545 #ifndef VMCMS
1546 #ifndef __THINK__
1547 #ifndef ATARIST
1548 #ifdef OS2
1549    if (_osmode == OS2_MODE)
1550 #endif
1551       if (popened)
1552          pclose(bitfile);
1553 #endif
1554 #endif
1555 #endif
1556 #endif
1557 #endif
1558 #endif
1559    if (popened == 0)
1560       fclose(bitfile);
1561    bitfile = NULL;
1562 }
1563 
1564 /* this tells dvips that it has no clue where it is. */
1565 static int thispage = 0;
1566 static integer rulex, ruley;
1567 void
1568 psflush(void) {
1569    rulex = ruley = rhh = rvv = -314159265;
1570    lastfont = -1;
1571 }
1572 /*
1573  *   pageinit initializes the output variables.
1574  */
1575 void
1576 pageinit(void)
1577 {
1578    psflush();
1579    newline();
1580    thispage++;
1581    if (!disablecomments) {
1582       if (multiplesects)
1583 #ifdef SHORTINT
1584          fprintf(bitfile, "%%DVIPSSectionPage: %ld\n", pagenum);
1585       else if (! isepsf)
1586          fprintf(bitfile, "%%%%Page: %ld %d\n", pagenum, thispage);
1587 #else
1588          fprintf(bitfile, "%%DVIPSSectionPage: %d\n", pagenum);
1589       else if (! isepsf)
1590          fprintf(bitfile, "%%%%Page: %d %d\n", pagenum, thispage);
1591 #endif
1592    }
1593    linepos = 0;
1594    cmdout("TeXDict");
1595    cmdout("begin");
1596 #ifdef HPS
1597    if (HPS_FLAG) {
1598       cmdout("HPSdict");
1599       cmdout("begin");
1600    }
1601 #endif
1602    if (landscape) cmdout("@landscape");
1603    numout((integer)pagenum);
1604    numout((integer)thispage-1);
1605    cmdout("bop");
1606    d = 0;
1607 }
1608 
1609 
1610 
1611 /*
1612  *   This routine ends a page.
1613  */
1614 void
1615 pageend(void)
1616 {
1617    if (instring) {
1618       stringend();
1619       chrcmd('p');
1620    }
1621    if (dir)
1622       cmdout("-90 rotate");
1623    if (any_dir)
1624       cmdout("dyy");
1625    cmdout("eop");
1626    cmdout("end");
1627 #ifdef HPS
1628    if (HPS_FLAG)
1629       cmdout("end");
1630 #endif
1631 }
1632 
1633 /*
1634  *   drawrule draws a rule at the specified position.
1635  *   It does nothing to save/restore the current position,
1636  *   or even draw the current string.  (Rules are normally
1637  *   set below the baseline anyway, so this saves us on
1638  *   output size almost always.)
1639  */
1640 void
1641 drawrule(integer rw, integer rh)
1642 {
1643    if (!dir) {
1644      numout((integer)hh);
1645      numout((integer)vv);
1646    } else {
1647      numout((integer)vv);
1648      numout((integer)-hh);
1649    }
1650    if (rw == rulex && rh == ruley)
1651       chrcmd('V');
1652    else {
1653       numout((integer)rw);
1654       numout((integer)rh);
1655       chrcmd('v');
1656       rulex = rw;
1657       ruley = rh;
1658    }
1659 }
1660 
1661 /*
1662  *   drawchar draws a character at the specified position.
1663  */
1664 void
1665 drawchar(chardesctype *c, int cc)
1666 {
1667    if (rdir != dir || fdir != curfnt->dir) {
1668       if (curfnt->dir == 9)
1669          setdir(dir+2);
1670       else
1671          setdir(dir);
1672       rdir = dir;
1673       fdir = curfnt->dir;
1674    }
1675 
1676    if (curfnt->iswide == 0 && curfnt->codewidth == 2) {
1677       Boolean savejflag = jflag;
1678       jflag = 1;
1679       hvpos();
1680       jflag = savejflag;
1681       if (lastfont != curfnt->psname)
1682          fontout(curfnt->psname);
1683       scout2(cc);
1684    }
1685    else if (curfnt->iswide) {
1686       if (lastfont != curfnt->psname)
1687          fontout(curfnt->psname);
1688       jscout(cc, curfnt->resfont->PSname);
1689    }
1690    else {
1691       if (jflag) {
1692          if (!dir){
1693             numout(hh);
1694             numout(vv);
1695          }
1696          else {
1697             numout(vv);
1698             numout(-hh);
1699          }
1700          chrcmd('a');
1701          rhh = hh;
1702          rvv = vv;
1703       }
1704       else hvpos();
1705       if (lastfont != curfnt->psname)
1706          fontout(curfnt->psname);
1707       scout((unsigned char)cc);
1708    }
1709    if (!dir)
1710       rhh = hh + c->pixelwidth; /* rvv = rv */
1711    else
1712       rvv = vv + c->pixelwidth; /* rhh = rh */
1713 }
1714 /*
1715  *   This routine sends out the document fonts comment.
1716  */
1717 static void
1718 tell_needed_fonts(void) {
1719    struct header_list *hl = ps_fonts_used;
1720    char *q;
1721    int roomleft = -1;
1722 
1723    if (hl == 0)
1724       return;
1725    while (0 != (q=get_name(&hl))) {
1726       if ((int)strlen(q) >= roomleft) {
1727          if (roomleft != -1) {
1728             fprintf(bitfile, "\n%%%%+");
1729             roomleft = LINELENGTH - 3;
1730          } else {
1731             fprintf(bitfile, "%%%%DocumentFonts:");
1732             roomleft = LINELENGTH - 16;
1733          }
1734       }
1735       fprintf(bitfile, " %s", q);
1736       roomleft -= strlen(q) + 1;
1737    }
1738    fprintf(bitfile, "\n");
1739 }
1740 
1741 static void print_composefont(void)
1742 {
1743    struct header_list *hl = ps_fonts_used;
1744    int  len;
1745    char *q, *p;
1746 
1747    if (hl == 0)
1748       return;
1749    while (0 != (q=get_name(&hl))) {
1750      len = strlen(q);
1751      if(len > 11 && (!strncmp(q+len-10, "Identity-H", 10) ||
1752              !strncmp(q+len-10, "Identity-V", 10))) {
1753        fprintf(bitfile, "%%%%BeginFont: %s\n", q);
1754        fprintf(bitfile, "/%s ", q);
1755        fprintf(bitfile, "/%s ", q+len-10);
1756        fprintf(bitfile, "[/");
1757        for(p=q; p <= q+len-12; p++)
1758           fprintf(bitfile, "%c", *p);
1759        fprintf(bitfile, "] composefont pop\n");
1760        fprintf(bitfile, "%%%%EndFont\n");
1761      }
1762    }
1763 }
1764 
1765 static void setdir(int d)
1766 {
1767    if (instring) {
1768       stringend();
1769       chrcmd('p');
1770    }
1771    switch(d) {
1772    case 1 :
1773       cmdout("dyt");
1774       break;
1775    case 2 :
1776       cmdout("dty");
1777       break;
1778    case 3 :
1779       cmdout("dtt");
1780       break;
1781    default :
1782       cmdout("dyy");
1783       break;
1784    }
1785    linepos += 4;
1786    any_dir = 1;
1787 }
1788 
1789 void cmddir(void)
1790 {
1791    if (dir != rdir) {
1792       if (dir)
1793          cmdout("90 rotate");
1794       else
1795          cmdout("-90 rotate");
1796       rdir = dir;
1797    }
1798 }
1799 
1800 static int JIStoSJIS(int c)
1801 {
1802     int high, low;
1803     int nh,nl;
1804 
1805     high = (c>>8) & 0xff;
1806     low = c & 0xff;
1807     nh = ((high-0x21)>>1) + 0x81;
1808     if (nh>0x9f)
1809     nh += 0x40;
1810     if (high & 1) {
1811         nl = low + 0x1f;
1812         if (low>0x5f)
1813         nl++;
1814     }
1815     else
1816         nl = low + 0x7e;
1817     if (((nh >= 0x81 && nh <= 0x9f) || (nh >= 0xe0 && nh <= 0xfc)) &&
1818         (nl >= 0x40 && nl <= 0xfc && nl != 0x7f))
1819         return((nh<<8) | nl);
1820     else
1821         return(0x813f);
1822 }
1823