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