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