]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/bannertops.c
Merge changes from CUPS 1.4svn-r7994.
[thirdparty/cups.git] / filter / bannertops.c
1 /*
2 * "$Id$"
3 *
4 * Banner to PostScript filter for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2008 by Apple Inc.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Apple Inc. and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
11 * which should have been included with this file. If this file is
12 * file is missing or damaged, see the license at "http://www.cups.org/".
13 *
14 * This file is subject to the Apple OS-Developed Software exception.
15 *
16 * Contents:
17 *
18 */
19
20 /*
21 * Include necessary headers...
22 */
23
24 #include "common.h"
25 #include "image.h"
26 #include <cups/i18n.h>
27
28
29 /*
30 * Globals...
31 */
32
33 char *Glyphs[65536]; /* PostScript glyphs for Unicode */
34 int NumFonts; /* Number of fonts to use */
35 char *Fonts[256][4]; /* Fonts to use */
36 unsigned short Chars[65536]; /* 0xffcc (ff = font, cc = char) */
37 unsigned short Codes[65536]; /* Unicode glyph mapping to fonts */
38 int Widths[256]; /* Widths of each font */
39 int Directions[256];/* Text directions for each font */
40
41
42 /*
43 * Local functions...
44 */
45
46 static void write_line(int row, lchar_t *line);
47 static void write_string(int col, int row, int len, lchar_t *s);
48 static void write_text(const char *s);
49
50
51 /*
52 * 'main()' - Generate PostScript cover pages.
53 */
54
55 int /* O - Exit status */
56 main(int argc, /* I - Number of command-line arguments */
57 char *argv[]) /* I - Command-line arguments */
58 {
59 }
60
61
62 /*
63 * 'WriteEpilogue()' - Write the PostScript file epilogue.
64 */
65
66 void
67 WriteEpilogue(void)
68 {
69 puts("%%Trailer");
70 printf("%%%%Pages: %d\n", NumPages);
71 puts("%%EOF");
72
73 free(Page[0]);
74 free(Page);
75 }
76
77
78 /*
79 * 'WritePage()' - Write a page of text.
80 */
81
82 void
83 WritePage(void)
84 {
85 int line; /* Current line */
86
87
88 NumPages ++;
89 printf("%%%%Page: %d %d\n", NumPages, NumPages);
90
91 puts("gsave");
92
93 if (PrettyPrint)
94 printf("%d H\n", NumPages);
95
96 for (line = 0; line < SizeLines; line ++)
97 write_line(line, Page[line]);
98
99 puts("grestore");
100 puts("showpage");
101
102 memset(Page[0], 0, sizeof(lchar_t) * SizeColumns * SizeLines);
103 }
104
105
106 /*
107 * 'WriteProlog()' - Write the PostScript file prolog with options.
108 */
109
110 void
111 WriteProlog(const char *title, /* I - Title of job */
112 const char *user, /* I - Username */
113 const char *classification, /* I - Classification */
114 const char *label, /* I - Page label */
115 ppd_file_t *ppd) /* I - PPD file info */
116 {
117 int i, j, k; /* Looping vars */
118 char *charset; /* Character set string */
119 char filename[1024]; /* Glyph filenames */
120 FILE *fp; /* Glyph files */
121 const char *datadir; /* CUPS_DATADIR environment variable */
122 char line[1024], /* Line from file */
123 *lineptr, /* Pointer into line */
124 *valptr; /* Pointer to value in line */
125 int ch, unicode; /* Character values */
126 int start, end; /* Start and end values for range */
127 char glyph[64]; /* Glyph name */
128 time_t curtime; /* Current time */
129 struct tm *curtm; /* Current date */
130 char curdate[255]; /* Current date (text format) */
131 int num_fonts; /* Number of unique fonts */
132 char *fonts[1024]; /* Unique fonts */
133 static char *names[] = /* Font names */
134 {
135 "cupsNormal",
136 "cupsBold",
137 "cupsItalic"
138 };
139
140
141 /*
142 * Get the data directory...
143 */
144
145 if ((datadir = getenv("CUPS_DATADIR")) == NULL)
146 datadir = CUPS_DATADIR;
147
148 /*
149 * Adjust margins as necessary...
150 */
151
152 if (classification || label)
153 {
154 /*
155 * Leave room for labels...
156 */
157
158 PageBottom += 36;
159 PageTop -= 36;
160 }
161
162 /*
163 * Allocate memory for the page...
164 */
165
166 SizeColumns = (PageRight - PageLeft) / 72.0 * CharsPerInch;
167 SizeLines = (PageTop - PageBottom) / 72.0 * LinesPerInch;
168
169 Page = calloc(sizeof(lchar_t *), SizeLines);
170 Page[0] = calloc(sizeof(lchar_t), SizeColumns * SizeLines);
171 for (i = 1; i < SizeLines; i ++)
172 Page[i] = Page[0] + i * SizeColumns;
173
174 if (PageColumns > 1)
175 {
176 ColumnGutter = CharsPerInch / 2;
177 ColumnWidth = (SizeColumns - ColumnGutter * (PageColumns - 1)) /
178 PageColumns;
179 }
180 else
181 ColumnWidth = SizeColumns;
182
183 /*
184 * Output the DSC header...
185 */
186
187 curtime = time(NULL);
188 curtm = localtime(&curtime);
189 strftime(curdate, sizeof(curdate), "%c", curtm);
190
191 puts("%!PS-Adobe-3.0");
192 printf("%%%%BoundingBox: 0 0 %.0f %.0f\n", PageWidth, PageLength);
193 printf("%%cupsRotation: %d\n", (Orientation & 3) * 90);
194 puts("%%Creator: texttops/" CUPS_SVERSION);
195 printf("%%%%CreationDate: %s\n", curdate);
196 WriteTextComment("Title", title);
197 WriteTextComment("For", user);
198 puts("%%Pages: (atend)");
199
200 /*
201 * Initialize globals...
202 */
203
204 NumFonts = 0;
205 memset(Fonts, 0, sizeof(Fonts));
206 memset(Glyphs, 0, sizeof(Glyphs));
207 memset(Chars, 0, sizeof(Chars));
208 memset(Codes, 0, sizeof(Codes));
209
210 /*
211 * Load the PostScript glyph names and the corresponding character
212 * set definition...
213 */
214
215 snprintf(filename, sizeof(filename), "%s/data/psglyphs", datadir);
216
217 if ((fp = fopen(filename, "r")) != NULL)
218 {
219 while (fscanf(fp, "%x%63s", &unicode, glyph) == 2)
220 Glyphs[unicode] = strdup(glyph);
221
222 fclose(fp);
223 }
224 else
225 {
226 fprintf(stderr, _("ERROR: Unable to open \"%s\" - %s\n"), filename,
227 strerror(errno));
228 exit(1);
229 }
230
231 /*
232 * Get the output character set...
233 */
234
235 charset = getenv("CHARSET");
236 if (charset != NULL && strcmp(charset, "us-ascii") != 0)
237 {
238 snprintf(filename, sizeof(filename), "%s/charsets/%s", datadir, charset);
239
240 if ((fp = fopen(filename, "r")) == NULL)
241 {
242 /*
243 * Can't open charset file!
244 */
245
246 fprintf(stderr, _("ERROR: Unable to open %s: %s\n"), filename,
247 strerror(errno));
248 exit(1);
249 }
250
251 /*
252 * Opened charset file; now see if this is really a charset file...
253 */
254
255 if (fgets(line, sizeof(line), fp) == NULL)
256 {
257 /*
258 * Bad/empty charset file!
259 */
260
261 fclose(fp);
262 fprintf(stderr, _("ERROR: Bad charset file %s\n"), filename);
263 exit(1);
264 }
265
266 if (strncmp(line, "charset", 7) != 0)
267 {
268 /*
269 * Bad format/not a charset file!
270 */
271
272 fclose(fp);
273 fprintf(stderr, _("ERROR: Bad charset file %s\n"), filename);
274 exit(1);
275 }
276
277 /*
278 * See if this is an 8-bit or UTF-8 character set file...
279 */
280
281 line[strlen(line) - 1] = '\0'; /* Drop \n */
282 for (lineptr = line + 7; isspace(*lineptr & 255); lineptr ++); /* Skip whitespace */
283
284 if (strcmp(lineptr, "8bit") == 0)
285 {
286 /*
287 * 8-bit text...
288 */
289
290 UTF8 = 0;
291 NumFonts = 0;
292
293 /*
294 * Read the font description(s)...
295 */
296
297 while (fgets(line, sizeof(line), fp) != NULL)
298 {
299 /*
300 * Skip comment and blank lines...
301 */
302
303 if (line[0] == '#' || line[0] == '\n')
304 continue;
305
306 /*
307 * Read the font descriptions that should look like:
308 *
309 * first last direction width normal [bold italic bold-italic]
310 */
311
312 lineptr = line;
313
314 start = strtol(lineptr, &lineptr, 16);
315 end = strtol(lineptr, &lineptr, 16);
316
317 while (isspace(*lineptr & 255))
318 lineptr ++;
319
320 if (!*lineptr)
321 break; /* Must be a font mapping */
322
323 valptr = lineptr;
324
325 while (!isspace(*lineptr & 255) && *lineptr)
326 lineptr ++;
327
328 if (!*lineptr)
329 {
330 /*
331 * Can't have a font without all required values...
332 */
333
334 fprintf(stderr, _("ERROR: Bad font description line: %s\n"), valptr);
335 fclose(fp);
336 exit(1);
337 }
338
339 *lineptr++ = '\0';
340
341 if (strcmp(valptr, "ltor") == 0)
342 Directions[NumFonts] = 1;
343 else if (strcmp(valptr, "rtol") == 0)
344 Directions[NumFonts] = -1;
345 else
346 {
347 fprintf(stderr, _("ERROR: Bad text direction %s\n"), valptr);
348 fclose(fp);
349 exit(1);
350 }
351
352 /*
353 * Got the direction, now get the width...
354 */
355
356 while (isspace(*lineptr & 255))
357 lineptr ++;
358
359 valptr = lineptr;
360
361 while (!isspace(*lineptr & 255) && *lineptr)
362 lineptr ++;
363
364 if (!*lineptr)
365 {
366 /*
367 * Can't have a font without all required values...
368 */
369
370 fprintf(stderr, _("ERROR: Bad font description line: %s\n"), valptr);
371 fclose(fp);
372 exit(1);
373 }
374
375 *lineptr++ = '\0';
376
377 if (strcmp(valptr, "single") == 0)
378 Widths[NumFonts] = 1;
379 else if (strcmp(valptr, "double") == 0)
380 Widths[NumFonts] = 2;
381 else
382 {
383 fprintf(stderr, _("ERROR: Bad text width %s\n"), valptr);
384 fclose(fp);
385 exit(1);
386 }
387
388 /*
389 * Get the fonts...
390 */
391
392 for (i = 0; *lineptr && i < 4; i ++)
393 {
394 while (isspace(*lineptr & 255))
395 lineptr ++;
396
397 valptr = lineptr;
398
399 while (!isspace(*lineptr & 255) && *lineptr)
400 lineptr ++;
401
402 if (*lineptr)
403 *lineptr++ = '\0';
404
405 if (lineptr > valptr)
406 Fonts[NumFonts][i] = strdup(valptr);
407 }
408
409 /*
410 * Fill in remaining fonts as needed...
411 */
412
413 for (j = i; j < 4; j ++)
414 Fonts[NumFonts][j] = strdup(Fonts[NumFonts][0]);
415
416 /*
417 * Define the character mappings...
418 */
419
420 for (i = start, j = NumFonts * 256; i <= end; i ++, j ++)
421 Chars[i] = j;
422
423 NumFonts ++;
424 }
425
426 /*
427 * Read encoding lines...
428 */
429
430 do
431 {
432 /*
433 * Skip comment and blank lines...
434 */
435
436 if (line[0] == '#' || line[0] == '\n')
437 continue;
438
439 /*
440 * Grab the character and unicode glyph number.
441 */
442
443 if (sscanf(line, "%x%x", &ch, &unicode) == 2 && ch < 256)
444 Codes[Chars[ch]] = unicode;
445 }
446 while (fgets(line, sizeof(line), fp) != NULL);
447
448 fclose(fp);
449 }
450 else if (strcmp(lineptr, "utf8") == 0)
451 {
452 /*
453 * UTF-8 (Unicode) text...
454 */
455
456 UTF8 = 1;
457
458 /*
459 * Read the font descriptions...
460 */
461
462 NumFonts = 0;
463
464 while (fgets(line, sizeof(line), fp) != NULL)
465 {
466 /*
467 * Skip comment and blank lines...
468 */
469
470 if (line[0] == '#' || line[0] == '\n')
471 continue;
472
473 /*
474 * Read the font descriptions that should look like:
475 *
476 * start end direction width normal [bold italic bold-italic]
477 */
478
479 lineptr = line;
480
481 start = strtol(lineptr, &lineptr, 16);
482 end = strtol(lineptr, &lineptr, 16);
483
484 while (isspace(*lineptr & 255))
485 lineptr ++;
486
487 valptr = lineptr;
488
489 while (!isspace(*lineptr & 255) && *lineptr)
490 lineptr ++;
491
492 if (!*lineptr)
493 {
494 /*
495 * Can't have a font without all required values...
496 */
497
498 fprintf(stderr, _("ERROR: Bad font description line: %s\n"), valptr);
499 fclose(fp);
500 exit(1);
501 }
502
503 *lineptr++ = '\0';
504
505 if (strcmp(valptr, "ltor") == 0)
506 Directions[NumFonts] = 1;
507 else if (strcmp(valptr, "rtol") == 0)
508 Directions[NumFonts] = -1;
509 else
510 {
511 fprintf(stderr, _("ERROR: Bad text direction %s\n"), valptr);
512 fclose(fp);
513 exit(1);
514 }
515
516 /*
517 * Got the direction, now get the width...
518 */
519
520 while (isspace(*lineptr & 255))
521 lineptr ++;
522
523 valptr = lineptr;
524
525 while (!isspace(*lineptr & 255) && *lineptr)
526 lineptr ++;
527
528 if (!*lineptr)
529 {
530 /*
531 * Can't have a font without all required values...
532 */
533
534 fprintf(stderr, _("ERROR: Bad font description line: %s\n"), valptr);
535 fclose(fp);
536 exit(1);
537 }
538
539 *lineptr++ = '\0';
540
541 if (strcmp(valptr, "single") == 0)
542 Widths[NumFonts] = 1;
543 else if (strcmp(valptr, "double") == 0)
544 Widths[NumFonts] = 2;
545 else
546 {
547 fprintf(stderr, _("ERROR: Bad text width %s\n"), valptr);
548 fclose(fp);
549 exit(1);
550 }
551
552 /*
553 * Get the fonts...
554 */
555
556 for (i = 0; *lineptr && i < 4; i ++)
557 {
558 while (isspace(*lineptr & 255))
559 lineptr ++;
560
561 valptr = lineptr;
562
563 while (!isspace(*lineptr & 255) && *lineptr)
564 lineptr ++;
565
566 if (*lineptr)
567 *lineptr++ = '\0';
568
569 if (lineptr > valptr)
570 Fonts[NumFonts][i] = strdup(valptr);
571 }
572
573 /*
574 * Fill in remaining fonts as needed...
575 */
576
577 for (j = i; j < 4; j ++)
578 Fonts[NumFonts][j] = strdup(Fonts[NumFonts][0]);
579
580 /*
581 * Define the character mappings...
582 */
583
584 for (i = start, j = NumFonts * 256; i <= end; i ++, j ++)
585 {
586 Chars[i] = j;
587 Codes[j] = i;
588 }
589
590 /*
591 * Move to the next font, stopping if needed...
592 */
593
594 NumFonts ++;
595 if (NumFonts >= 256)
596 break;
597 }
598
599 fclose(fp);
600 }
601 else
602 {
603 fprintf(stderr, _("ERROR: Bad charset type %s\n"), lineptr);
604 fclose(fp);
605 exit(1);
606 }
607 }
608 else
609 {
610 /*
611 * Standard ASCII output just uses Courier, Courier-Bold, and
612 * possibly Courier-Oblique.
613 */
614
615 NumFonts = 1;
616
617 Fonts[0][ATTR_NORMAL] = strdup("Courier");
618 Fonts[0][ATTR_BOLD] = strdup("Courier-Bold");
619 Fonts[0][ATTR_ITALIC] = strdup("Courier-Oblique");
620 Fonts[0][ATTR_BOLDITALIC] = strdup("Courier-BoldOblique");
621
622 Widths[0] = 1;
623 Directions[0] = 1;
624
625 /*
626 * Define US-ASCII characters...
627 */
628
629 for (i = 32; i < 127; i ++)
630 {
631 Chars[i] = i;
632 Codes[i] = i;
633 }
634 }
635
636 /*
637 * Generate a list of unique fonts to use...
638 */
639
640 for (i = 0, num_fonts = 0; i < NumFonts; i ++)
641 for (j = PrettyPrint ? 2 : 1; j >= 0; j --)
642 {
643 for (k = 0; k < num_fonts; k ++)
644 if (strcmp(Fonts[i][j], fonts[k]) == 0)
645 break;
646
647 if (k >= num_fonts)
648 {
649 /*
650 * Add new font...
651 */
652
653 fonts[num_fonts] = Fonts[i][j];
654 num_fonts ++;
655 }
656 }
657
658 /*
659 * List the fonts that will be used...
660 */
661
662 for (i = 0; i < num_fonts; i ++)
663 if (i == 0)
664 printf("%%%%DocumentNeededResources: font %s\n", fonts[i]);
665 else
666 printf("%%%%+ font %s\n", fonts[i]);
667
668 puts("%%DocumentSuppliedResources: procset texttops 1.1 0");
669
670 for (i = 0; i < num_fonts; i ++)
671 {
672 if (ppd != NULL)
673 {
674 fprintf(stderr, "DEBUG: ppd->num_fonts = %d\n", ppd->num_fonts);
675
676 for (j = 0; j < ppd->num_fonts; j ++)
677 {
678 fprintf(stderr, "DEBUG: ppd->fonts[%d] = %s\n", j, ppd->fonts[j]);
679
680 if (strcmp(fonts[i], ppd->fonts[j]) == 0)
681 break;
682 }
683 }
684 else
685 j = 0;
686
687 if ((ppd != NULL && j >= ppd->num_fonts) ||
688 strncmp(fonts[i], "Courier", 7) == 0 ||
689 strcmp(fonts[i], "Symbol") == 0)
690 {
691 /*
692 * Need to embed this font...
693 */
694
695 printf("%%%%+ font %s\n", fonts[i]);
696 }
697 }
698
699 puts("%%EndComments");
700
701 puts("%%BeginProlog");
702
703 /*
704 * Download any missing fonts...
705 */
706
707 for (i = 0; i < num_fonts; i ++)
708 {
709 if (ppd != NULL)
710 {
711 for (j = 0; j < ppd->num_fonts; j ++)
712 if (strcmp(fonts[i], ppd->fonts[j]) == 0)
713 break;
714 }
715 else
716 j = 0;
717
718 if ((ppd != NULL && j >= ppd->num_fonts) ||
719 strncmp(fonts[i], "Courier", 7) == 0 ||
720 strcmp(fonts[i], "Symbol") == 0)
721 {
722 /*
723 * Need to embed this font...
724 */
725
726 printf("%%%%BeginResource: font %s\n", fonts[i]);
727
728 /**** MRS: Need to use CUPS_FONTPATH env var! ****/
729 /**** Also look for Fontmap file or name.pfa, name.pfb... ****/
730 snprintf(filename, sizeof(filename), "%s/fonts/%s", datadir, fonts[i]);
731 if ((fp = fopen(filename, "rb")) != NULL)
732 {
733 while ((j = fread(line, 1, sizeof(line), fp)) > 0)
734 fwrite(line, 1, j, stdout);
735
736 fclose(fp);
737 }
738
739 puts("\n%%EndResource");
740 }
741 }
742
743 /*
744 * Write the encoding array(s)...
745 */
746
747 puts("% character encoding(s)");
748
749 for (i = 0; i < NumFonts; i ++)
750 {
751 printf("/cupsEncoding%02x [\n", i);
752
753 for (ch = 0; ch < 256; ch ++)
754 {
755 if (Glyphs[Codes[i * 256 + ch]])
756 printf("/%s", Glyphs[Codes[i * 256 + ch]]);
757 else if (Codes[i * 256 + ch] > 255)
758 printf("/uni%04X", Codes[i * 256 + ch]);
759 else
760 printf("/.notdef");
761
762 if ((ch & 7) == 7)
763 putchar('\n');
764 }
765
766 puts("] def");
767 }
768
769 /*
770 * Create the fonts...
771 */
772
773 if (NumFonts == 1)
774 {
775 /*
776 * Just reencode the named fonts...
777 */
778
779 puts("% Reencode fonts");
780
781 for (i = PrettyPrint ? 2 : 1; i >= 0; i --)
782 {
783 printf("/%s findfont\n", Fonts[0][i]);
784 puts("dup length 1 add dict begin\n"
785 " { 1 index /FID ne { def } { pop pop } ifelse } forall\n"
786 " /Encoding cupsEncoding00 def\n"
787 " currentdict\n"
788 "end");
789 printf("/%s exch definefont pop\n", names[i]);
790 }
791 }
792 else
793 {
794 /*
795 * Construct composite fonts... Start by reencoding the base fonts...
796 */
797
798 puts("% Reencode base fonts");
799
800 for (i = PrettyPrint ? 2 : 1; i >= 0; i --)
801 for (j = 0; j < NumFonts; j ++)
802 {
803 printf("/%s findfont\n", Fonts[j][i]);
804 printf("dup length 1 add dict begin\n"
805 " { 1 index /FID ne { def } { pop pop } ifelse } forall\n"
806 " /Encoding cupsEncoding%02x def\n"
807 " currentdict\n"
808 "end\n", j);
809 printf("/%s%02x exch definefont /%s%02x exch def\n", names[i], j,
810 names[i], j);
811 }
812
813 /*
814 * Then merge them into composite fonts...
815 */
816
817 puts("% Create composite fonts...");
818
819 for (i = PrettyPrint ? 2 : 1; i >= 0; i --)
820 {
821 puts("8 dict begin");
822 puts("/FontType 0 def/FontMatrix[1.0 0 0 1.0 0 0]def/FMapType 2 def/Encoding[");
823 for (j = 0; j < NumFonts; j ++)
824 if (j == (NumFonts - 1))
825 printf("%d", j);
826 else if ((j & 15) == 15)
827 printf("%d\n", j);
828 else
829 printf("%d ", j);
830 puts("]def/FDepVector[");
831 for (j = 0; j < NumFonts; j ++)
832 if (j == (NumFonts - 1))
833 printf("%s%02x", names[i], j);
834 else if ((j & 3) == 3)
835 printf("%s%02x\n", names[i], j);
836 else
837 printf("%s%02x ", names[i], j);
838 puts("]def currentdict end");
839 printf("/%s exch definefont pop\n", names[i]);
840 }
841 }
842
843 /*
844 * Output the texttops procset...
845 */
846
847 puts("%%BeginResource: procset texttops 1.1 0");
848
849 puts("% Define fonts");
850
851 printf("/FN /cupsNormal findfont [%.3f 0 0 %.3f 0 0] makefont def\n",
852 120.0 / CharsPerInch, 68.0 / LinesPerInch);
853 printf("/FB /cupsBold findfont [%.3f 0 0 %.3f 0 0] makefont def\n",
854 120.0 / CharsPerInch, 68.0 / LinesPerInch);
855 if (PrettyPrint)
856 printf("/FI /cupsItalic findfont [%.3f 0 0 %.3f 0 0] makefont def\n",
857 120.0 / CharsPerInch, 68.0 / LinesPerInch);
858
859 puts("% Common procedures");
860
861 puts("/N { FN setfont moveto } bind def");
862 puts("/B { FB setfont moveto } bind def");
863 printf("/U { gsave 0.5 setlinewidth 0 %.3f rmoveto "
864 "0 rlineto stroke grestore } bind def\n", -6.8 / LinesPerInch);
865
866 if (PrettyPrint)
867 {
868 if (ColorDevice)
869 {
870 puts("/S { 0.0 setgray show } bind def");
871 puts("/r { 0.5 0.0 0.0 setrgbcolor show } bind def");
872 puts("/g { 0.0 0.5 0.0 setrgbcolor show } bind def");
873 puts("/b { 0.0 0.0 0.5 setrgbcolor show } bind def");
874 }
875 else
876 {
877 puts("/S { 0.0 setgray show } bind def");
878 puts("/r { 0.2 setgray show } bind def");
879 puts("/g { 0.2 setgray show } bind def");
880 puts("/b { 0.2 setgray show } bind def");
881 }
882
883 puts("/I { FI setfont moveto } bind def");
884
885 puts("/n {");
886 puts("\t20 string cvs % convert page number to string");
887 if (NumFonts > 1)
888 {
889 /*
890 * Convert a number to double-byte chars...
891 */
892
893 puts("\tdup length % get length");
894 puts("\tdup 2 mul string /P exch def % P = string twice as long");
895 puts("\t0 1 2 index 1 sub { % loop through each character in the page number");
896 puts("\t\tdup 3 index exch get % get character N from the page number");
897 puts("\t\texch 2 mul dup % compute offset in P");
898 puts("\t\tP exch 0 put % font 0");
899 puts("\t\t1 add P exch 2 index put % character");
900 puts("\t\tpop % discard character");
901 puts("\t} for % do for loop");
902 puts("\tpop pop % discard string and length");
903 puts("\tP % put string on stack");
904 }
905 puts("} bind def");
906
907 printf("/T");
908 write_text(title);
909 puts("def");
910
911 printf("/D");
912 write_text(curdate);
913 puts("def");
914
915 puts("/H {");
916 puts("\tgsave");
917 puts("\t0.9 setgray");
918
919 if (Duplex)
920 {
921 puts("\tdup 2 mod 0 eq {");
922 printf("\t\t%.3f %.3f translate } {\n",
923 PageWidth - PageRight, PageTop + 72.0f / LinesPerInch);
924 printf("\t\t%.3f %.3f translate } ifelse\n",
925 PageLeft, PageTop + 72.0f / LinesPerInch);
926 }
927 else
928 printf("\t%.3f %.3f translate\n",
929 PageLeft, PageTop + 72.0f / LinesPerInch);
930
931 printf("\t0 0 %.3f %.3f rectfill\n", PageRight - PageLeft,
932 144.0f / LinesPerInch);
933
934 puts("\tFB setfont");
935 puts("\t0 setgray");
936
937 if (Duplex)
938 {
939 puts("\tdup 2 mod 0 eq {");
940 printf("\t\tT stringwidth pop neg %.3f add %.3f } {\n",
941 PageRight - PageLeft - 36.0f / LinesPerInch,
942 (0.5f + 0.157f) * 72.0f / LinesPerInch);
943 printf("\t\t%.3f %.3f } ifelse\n", 36.0f / LinesPerInch,
944 (0.5f + 0.157f) * 72.0f / LinesPerInch);
945 }
946 else
947 printf("\t%.3f %.3f\n", 36.0f / LinesPerInch,
948 (0.5f + 0.157f) * 72.0f / LinesPerInch);
949
950 puts("\tmoveto T show");
951
952 printf("\tD dup stringwidth pop neg 2 div %.3f add %.3f\n",
953 (PageRight - PageLeft) * 0.5,
954 (0.5f + 0.157f) * 72.0f / LinesPerInch);
955 puts("\tmoveto show");
956
957 if (Duplex)
958 {
959 puts("\tdup n exch 2 mod 0 eq {");
960 printf("\t\t%.3f %.3f } {\n", 36.0f / LinesPerInch,
961 (0.5f + 0.157f) * 72.0f / LinesPerInch);
962 printf("\t\tdup stringwidth pop neg %.3f add %.3f } ifelse\n",
963 PageRight - PageLeft - 36.0f / LinesPerInch,
964 (0.5f + 0.157f) * 72.0f / LinesPerInch);
965 }
966 else
967 printf("\tn dup stringwidth pop neg %.3f add %.3f\n",
968 PageRight - PageLeft - 36.0f / LinesPerInch,
969 (0.5f + 0.157f) * 72.0f / LinesPerInch);
970
971 puts("\tmoveto show");
972 puts("\tgrestore");
973 puts("} bind def");
974 }
975 else
976 puts("/S { show } bind def");
977
978 puts("%%EndResource");
979
980 puts("%%EndProlog");
981 }
982
983
984 /*
985 * 'write_line()' - Write a row of text.
986 */
987
988 static void
989 write_line(int row, /* I - Row number (0 to N) */
990 lchar_t *line) /* I - Line to print */
991 {
992 int i; /* Looping var */
993 int col; /* Current column */
994 int attr; /* Current attribute */
995 int font, /* Font to use */
996 lastfont, /* Last font */
997 mono; /* Monospaced? */
998 lchar_t *start; /* First character in sequence */
999
1000
1001 for (col = 0; col < SizeColumns;)
1002 {
1003 while (col < SizeColumns && (line->ch == ' ' || line->ch == 0))
1004 {
1005 col ++;
1006 line ++;
1007 }
1008
1009 if (col >= SizeColumns)
1010 break;
1011
1012 if (NumFonts == 1)
1013 {
1014 /*
1015 * All characters in a single font - assume monospaced...
1016 */
1017
1018 attr = line->attr;
1019 start = line;
1020
1021 while (col < SizeColumns && line->ch != 0 && attr == line->attr)
1022 {
1023 col ++;
1024 line ++;
1025 }
1026
1027 write_string(col - (line - start), row, line - start, start);
1028 }
1029 else
1030 {
1031 /*
1032 * Multiple fonts; break up based on the font...
1033 */
1034
1035 attr = line->attr;
1036 start = line;
1037 lastfont = Chars[line->ch] / 256;
1038 mono = strncmp(Fonts[lastfont][0], "Courier", 7) == 0;
1039 col ++;
1040 line ++;
1041
1042 if (mono)
1043 {
1044 while (col < SizeColumns && line->ch != 0 && attr == line->attr)
1045 {
1046 font = Chars[line->ch] / 256;
1047 if (strncmp(Fonts[font][0], "Courier", 7) != 0 ||
1048 font != lastfont)
1049 break;
1050
1051 col ++;
1052 line ++;
1053 }
1054 }
1055
1056 if (Directions[lastfont] > 0)
1057 write_string(col - (line - start), row, line - start, start);
1058 else
1059 {
1060 /*
1061 * Do right-to-left text...
1062 */
1063
1064 while (col < SizeColumns && line->ch != 0 && attr == line->attr)
1065 {
1066 if (Directions[Chars[line->ch] / 256] > 0 &&
1067 !ispunct(line->ch & 255) && !isspace(line->ch & 255))
1068 break;
1069
1070 col ++;
1071 line ++;
1072 }
1073
1074 for (i = 1; start < line; i ++, start ++)
1075 if (!isspace(start->ch & 255))
1076 write_string(col - i, row, 1, start);
1077 }
1078 }
1079 }
1080 }
1081
1082
1083 /*
1084 * 'write_string()' - Write a string of text.
1085 */
1086
1087 static void
1088 write_string(int col, /* I - Start column */
1089 int row, /* I - Row */
1090 int len, /* I - Number of characters */
1091 lchar_t *s) /* I - String to print */
1092 {
1093 int ch; /* Current character */
1094 float x, y; /* Position of text */
1095 unsigned attr; /* Character attributes */
1096
1097
1098 /*
1099 * Position the text and set the font...
1100 */
1101
1102 if (Duplex && (NumPages & 1) == 0)
1103 {
1104 x = PageWidth - PageRight;
1105 y = PageTop;
1106 }
1107 else
1108 {
1109 x = PageLeft;
1110 y = PageTop;
1111 }
1112
1113 x += (float)col * 72.0f / (float)CharsPerInch;
1114 y -= (float)(row + 0.843) * 72.0f / (float)LinesPerInch;
1115
1116 attr = s->attr;
1117
1118 if (attr & ATTR_RAISED)
1119 y += 36.0 / (float)LinesPerInch;
1120 else if (attr & ATTR_LOWERED)
1121 y -= 36.0 / (float)LinesPerInch;
1122
1123 if (x == (int)x)
1124 printf("%.0f ", x);
1125 else
1126 printf("%.3f ", x);
1127
1128 if (y == (int)y)
1129 printf("%.0f ", y);
1130 else
1131 printf("%.3f ", y);
1132
1133 if (attr & ATTR_BOLD)
1134 putchar('B');
1135 else if (attr & ATTR_ITALIC)
1136 putchar('I');
1137 else
1138 putchar('N');
1139
1140 if (attr & ATTR_UNDERLINE)
1141 printf(" %.3f U", (float)len * 72.0 / (float)CharsPerInch);
1142
1143 if (NumFonts > 1)
1144 {
1145 /*
1146 * Write a hex string...
1147 */
1148
1149 putchar('<');
1150
1151 while (len > 0)
1152 {
1153 printf("%04x", Chars[s->ch]);
1154
1155 len --;
1156 s ++;
1157 }
1158
1159 putchar('>');
1160 }
1161 else
1162 {
1163 /*
1164 * Write a quoted string...
1165 */
1166
1167 putchar('(');
1168
1169 while (len > 0)
1170 {
1171 ch = Chars[s->ch];
1172
1173 if (ch < 32 || ch > 126)
1174 {
1175 /*
1176 * Quote 8-bit and control characters...
1177 */
1178
1179 printf("\\%03o", ch);
1180 }
1181 else
1182 {
1183 /*
1184 * Quote the parenthesis and backslash as needed...
1185 */
1186
1187 if (ch == '(' || ch == ')' || ch == '\\')
1188 putchar('\\');
1189
1190 putchar(ch);
1191 }
1192
1193 len --;
1194 s ++;
1195 }
1196
1197 putchar(')');
1198 }
1199
1200 if (PrettyPrint)
1201 {
1202 if (attr & ATTR_RED)
1203 puts("r");
1204 else if (attr & ATTR_GREEN)
1205 puts("g");
1206 else if (attr & ATTR_BLUE)
1207 puts("b");
1208 else
1209 puts("S");
1210 }
1211 else
1212 puts("S");
1213 }
1214
1215
1216 /*
1217 * 'write_text()' - Write a text string, quoting/encoding as needed.
1218 */
1219
1220 static void
1221 write_text(const char *s) /* I - String to write */
1222 {
1223 int ch; /* Actual character value (UTF8) */
1224 const unsigned char *utf8; /* UTF8 text */
1225
1226
1227 if (NumFonts > 1)
1228 {
1229 /*
1230 * 8/8 encoding...
1231 */
1232
1233 putchar('<');
1234
1235 utf8 = (const unsigned char *)s;
1236
1237 while (*utf8)
1238 {
1239 if (*utf8 < 0xc0 || !UTF8)
1240 ch = *utf8 ++;
1241 else if ((*utf8 & 0xe0) == 0xc0)
1242 {
1243 /*
1244 * Two byte character...
1245 */
1246
1247 ch = ((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f);
1248 utf8 += 2;
1249 }
1250 else
1251 {
1252 /*
1253 * Three byte character...
1254 */
1255
1256 ch = ((((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f)) << 6) |
1257 (utf8[2] & 0x3f);
1258 utf8 += 3;
1259 }
1260
1261 printf("%04x", Chars[ch]);
1262 }
1263
1264 putchar('>');
1265 }
1266 else
1267 {
1268 /*
1269 * Standard 8-bit encoding...
1270 */
1271
1272 putchar('(');
1273
1274 while (*s)
1275 {
1276 if (*s < 32 || *s > 126)
1277 printf("\\%03o", *s);
1278 else
1279 {
1280 if (*s == '(' || *s == ')' || *s == '\\')
1281 putchar('\\');
1282
1283 putchar(*s);
1284 }
1285
1286 s ++;
1287 }
1288
1289 putchar(')');
1290 }
1291 }
1292
1293
1294 /*
1295 * End of "$Id$".
1296 */