]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/textcommon.c
Merge CUPS 1.4svn-r8052 (tentative 1.4b1)
[thirdparty/cups.git] / filter / textcommon.c
1 /*
2 * "$Id: textcommon.c 6649 2007-07-11 21:46:42Z mike $"
3 *
4 * Common text filter routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2008 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 *
17 * Contents:
18 *
19 * TextMain() - Standard main entry for text filters.
20 * compare_keywords() - Compare two C/C++ keywords.
21 * getutf8() - Get a UTF-8 encoded wide character...
22 */
23
24 /*
25 * Include necessary headers...
26 */
27
28 #include "textcommon.h"
29 #include <cups/i18n.h>
30
31
32 /*
33 * Globals...
34 */
35
36 int WrapLines = 1, /* Wrap text in lines */
37 SizeLines = 60, /* Number of lines on a page */
38 SizeColumns = 80, /* Number of columns on a line */
39 PageColumns = 1, /* Number of columns on a page */
40 ColumnGutter = 0, /* Number of characters between text columns */
41 ColumnWidth = 80, /* Width of each column */
42 PrettyPrint = 0, /* Do pretty code formatting */
43 Copies = 1; /* Number of copies */
44 lchar_t **Page = NULL; /* Page characters */
45 int NumPages = 0; /* Number of pages in document */
46 float CharsPerInch = 10; /* Number of character columns per inch */
47 float LinesPerInch = 6; /* Number of lines per inch */
48 int UTF8 = 0; /* Use UTF-8 encoding? */
49 int NumKeywords = 0; /* Number of known keywords */
50 char **Keywords = NULL; /* List of known keywords */
51
52
53 /*
54 * Local globals...
55 */
56
57 static char *code_keywords[] = /* List of known C/C++ keywords... */
58 {
59 "and",
60 "and_eq",
61 "asm",
62 "auto",
63 "bitand",
64 "bitor",
65 "bool",
66 "break",
67 "case",
68 "catch",
69 "char",
70 "class",
71 "compl",
72 "const",
73 "const_cast",
74 "continue",
75 "default",
76 "delete",
77 "do",
78 "double",
79 "dynamic_cast",
80 "else",
81 "enum",
82 "explicit",
83 "extern",
84 "false",
85 "float",
86 "for",
87 "friend",
88 "goto",
89 "if",
90 "inline",
91 "int",
92 "long",
93 "mutable",
94 "namespace",
95 "new",
96 "not",
97 "not_eq",
98 "operator",
99 "or",
100 "or_eq",
101 "private",
102 "protected",
103 "public",
104 "register",
105 "reinterpret_cast",
106 "return",
107 "short",
108 "signed",
109 "sizeof",
110 "static",
111 "static_cast",
112 "struct",
113 "switch",
114 "template",
115 "this",
116 "throw",
117 "true",
118 "try",
119 "typedef",
120 "typename",
121 "union",
122 "unsigned",
123 "virtual",
124 "void",
125 "volatile",
126 "while",
127 "xor",
128 "xor_eq"
129 },
130 *sh_keywords[] = /* List of known Boure/Korn/zsh/bash keywords... */
131 {
132 "alias",
133 "bg",
134 "break",
135 "case",
136 "cd",
137 "command",
138 "continue",
139 "do",
140 "done",
141 "echo",
142 "elif",
143 "else",
144 "esac",
145 "eval",
146 "exec",
147 "exit",
148 "export",
149 "fc",
150 "fg",
151 "fi",
152 "for",
153 "function",
154 "getopts",
155 "if",
156 "in",
157 "jobs",
158 "kill",
159 "let",
160 "limit",
161 "newgrp",
162 "print",
163 "pwd",
164 "read",
165 "readonly",
166 "return",
167 "select",
168 "set",
169 "shift",
170 "test",
171 "then",
172 "time",
173 "times",
174 "trap",
175 "typeset",
176 "ulimit",
177 "umask",
178 "unalias",
179 "unlimit",
180 "unset",
181 "until",
182 "wait",
183 "whence"
184 "while",
185 },
186 *csh_keywords[] = /* List of known csh/tcsh keywords... */
187 {
188 "alias",
189 "aliases",
190 "bg",
191 "bindkey",
192 "break",
193 "breaksw",
194 "builtins",
195 "case",
196 "cd",
197 "chdir",
198 "complete",
199 "continue",
200 "default",
201 "dirs",
202 "echo",
203 "echotc",
204 "else",
205 "end",
206 "endif",
207 "eval",
208 "exec",
209 "exit",
210 "fg",
211 "foreach",
212 "glob",
213 "goto",
214 "history",
215 "if",
216 "jobs",
217 "kill",
218 "limit",
219 "login",
220 "logout",
221 "ls",
222 "nice",
223 "nohup",
224 "notify",
225 "onintr",
226 "popd",
227 "pushd",
228 "pwd",
229 "rehash",
230 "repeat",
231 "set",
232 "setenv",
233 "settc",
234 "shift",
235 "source",
236 "stop",
237 "suspend",
238 "switch",
239 "telltc",
240 "then",
241 "time",
242 "umask",
243 "unalias",
244 "unbindkey",
245 "unhash",
246 "unlimit",
247 "unset",
248 "unsetenv",
249 "wait",
250 "where",
251 "which",
252 "while"
253 },
254 *perl_keywords[] = /* List of known perl keywords... */
255 {
256 "abs",
257 "accept",
258 "alarm",
259 "and",
260 "atan2",
261 "bind",
262 "binmode",
263 "bless",
264 "caller",
265 "chdir",
266 "chmod",
267 "chomp",
268 "chop",
269 "chown",
270 "chr",
271 "chroot",
272 "closdir",
273 "close",
274 "connect",
275 "continue",
276 "cos",
277 "crypt",
278 "dbmclose",
279 "dbmopen",
280 "defined",
281 "delete",
282 "die",
283 "do",
284 "dump",
285 "each",
286 "else",
287 "elsif",
288 "endgrent",
289 "endhostent",
290 "endnetent",
291 "endprotoent",
292 "endpwent",
293 "endservent",
294 "eof",
295 "eval",
296 "exec",
297 "exists",
298 "exit",
299 "exp",
300 "fcntl",
301 "fileno",
302 "flock",
303 "for",
304 "foreach",
305 "fork",
306 "format",
307 "formline",
308 "getc",
309 "getgrent",
310 "getgrgid",
311 "getgrnam",
312 "gethostbyaddr",
313 "gethostbyname",
314 "gethostent",
315 "getlogin",
316 "getnetbyaddr",
317 "getnetbyname",
318 "getnetent",
319 "getpeername",
320 "getpgrp",
321 "getppid",
322 "getpriority",
323 "getprotobyname",
324 "getprotobynumber",
325 "getprotoent",
326 "getpwent",
327 "getpwnam",
328 "getpwuid",
329 "getservbyname",
330 "getservbyport",
331 "getservent",
332 "getsockname",
333 "getsockopt",
334 "glob",
335 "gmtime",
336 "goto",
337 "grep",
338 "hex",
339 "if",
340 "import",
341 "index",
342 "int",
343 "ioctl",
344 "join",
345 "keys",
346 "kill",
347 "last",
348 "lc",
349 "lcfirst",
350 "length",
351 "link",
352 "listen",
353 "local",
354 "localtime",
355 "log",
356 "lstat",
357 "map",
358 "mkdir",
359 "msgctl",
360 "msgget",
361 "msgrcv",
362 "msgsend",
363 "my",
364 "next",
365 "no",
366 "not",
367 "oct",
368 "open",
369 "opendir",
370 "or",
371 "ord",
372 "pack",
373 "package",
374 "pipe",
375 "pop",
376 "pos",
377 "print",
378 "printf",
379 "push",
380 "quotemeta",
381 "rand",
382 "read",
383 "readdir",
384 "readlink",
385 "recv",
386 "redo",
387 "ref",
388 "rename",
389 "require",
390 "reset",
391 "return",
392 "reverse",
393 "rewinddir",
394 "rindex",
395 "rmdir",
396 "scalar",
397 "seek",
398 "seekdir",
399 "select",
400 "semctl",
401 "semget",
402 "semop",
403 "send",
404 "setgrent",
405 "sethostent",
406 "setnetent",
407 "setpgrp",
408 "setpriority",
409 "setprotoent",
410 "setpwent",
411 "setservent",
412 "setsockopt",
413 "shift",
414 "shmctl",
415 "shmget",
416 "shmread",
417 "shmwrite",
418 "shutdown",
419 "sin",
420 "sleep",
421 "socket",
422 "socketpair",
423 "sort",
424 "splice",
425 "split",
426 "sprintf",
427 "sqrt",
428 "srand",
429 "stat",
430 "study",
431 "sub",
432 "substr",
433 "symlink",
434 "syscall",
435 "sysread",
436 "sysseek",
437 "system",
438 "syswrite",
439 "tell",
440 "telldir",
441 "tie",
442 "tied",
443 "time",
444 "times"
445 "times",
446 "truncate",
447 "uc",
448 "ucfirst",
449 "umask",
450 "undef",
451 "unless",
452 "unlink",
453 "unpack",
454 "unshift",
455 "untie",
456 "until",
457 "use",
458 "utime",
459 "values",
460 "vec",
461 "wait",
462 "waitpid",
463 "wantarray",
464 "warn",
465 "while",
466 "write"
467 };
468
469
470 /*
471 * Local functions...
472 */
473
474 static int compare_keywords(const void *, const void *);
475 static int getutf8(FILE *fp);
476
477
478 /*
479 * 'TextMain()' - Standard main entry for text filters.
480 */
481
482 int /* O - Exit status */
483 TextMain(const char *name, /* I - Name of filter */
484 int argc, /* I - Number of command-line arguments */
485 char *argv[]) /* I - Command-line arguments */
486 {
487 FILE *fp; /* Print file */
488 ppd_file_t *ppd; /* PPD file */
489 int i, /* Looping var */
490 ch, /* Current char from file */
491 lastch, /* Previous char from file */
492 attr, /* Current attribute */
493 line, /* Current line */
494 column, /* Current column */
495 page_column; /* Current page column */
496 int num_options; /* Number of print options */
497 cups_option_t *options; /* Print options */
498 const char *val; /* Option value */
499 char keyword[64], /* Keyword string */
500 *keyptr; /* Pointer into string */
501 int keycol; /* Column where keyword starts */
502 int ccomment; /* Inside a C-style comment? */
503 int cstring; /* Inside a C string */
504
505
506 /*
507 * Make sure status messages are not buffered...
508 */
509
510 setbuf(stderr, NULL);
511
512 /*
513 * Check command-line...
514 */
515
516 if (argc < 6 || argc > 7)
517 {
518 _cupsLangPrintf(stderr,
519 _("Usage: %s job-id user title copies options [file]\n"),
520 name);
521 return (1);
522 }
523
524 /*
525 * If we have 7 arguments, print the file named on the command-line.
526 * Otherwise, send stdin instead...
527 */
528
529 if (argc == 6)
530 fp = stdin;
531 else
532 {
533 /*
534 * Try to open the print file...
535 */
536
537 if ((fp = fopen(argv[6], "rb")) == NULL)
538 {
539 perror("DEBUG: unable to open print file - ");
540 return (1);
541 }
542 }
543
544 /*
545 * Process command-line options and write the prolog...
546 */
547
548 options = NULL;
549 num_options = cupsParseOptions(argv[5], 0, &options);
550
551 if ((val = cupsGetOption("prettyprint", num_options, options)) != NULL &&
552 strcasecmp(val, "no") && strcasecmp(val, "off") &&
553 strcasecmp(val, "false"))
554 {
555 PageLeft = 72.0f;
556 PageRight = PageWidth - 36.0f;
557 PageBottom = PageBottom > 36.0f ? PageBottom : 36.0f;
558 PageTop = PageLength - 36.0f;
559 CharsPerInch = 12;
560 LinesPerInch = 8;
561
562 if ((val = getenv("CONTENT_TYPE")) == NULL)
563 {
564 PrettyPrint = PRETTY_PLAIN;
565 NumKeywords = 0;
566 Keywords = NULL;
567 }
568 else if (strcasecmp(val, "application/x-cshell") == 0)
569 {
570 PrettyPrint = PRETTY_SHELL;
571 NumKeywords = sizeof(csh_keywords) / sizeof(csh_keywords[0]);
572 Keywords = csh_keywords;
573 }
574 else if (strcasecmp(val, "application/x-csource") == 0)
575 {
576 PrettyPrint = PRETTY_CODE;
577 NumKeywords = sizeof(code_keywords) / sizeof(code_keywords[0]);
578 Keywords = code_keywords;
579 }
580 else if (strcasecmp(val, "application/x-perl") == 0)
581 {
582 PrettyPrint = PRETTY_PERL;
583 NumKeywords = sizeof(perl_keywords) / sizeof(perl_keywords[0]);
584 Keywords = perl_keywords;
585 }
586 else if (strcasecmp(val, "application/x-shell") == 0)
587 {
588 PrettyPrint = PRETTY_SHELL;
589 NumKeywords = sizeof(sh_keywords) / sizeof(sh_keywords[0]);
590 Keywords = sh_keywords;
591 }
592 else
593 {
594 PrettyPrint = PRETTY_PLAIN;
595 NumKeywords = 0;
596 Keywords = NULL;
597 }
598 }
599
600 ppd = SetCommonOptions(num_options, options, 1);
601
602 if ((val = cupsGetOption("wrap", num_options, options)) == NULL)
603 WrapLines = 1;
604 else
605 WrapLines = !strcasecmp(val, "true") || !strcasecmp(val, "on") ||
606 !strcasecmp(val, "yes");
607
608 if ((val = cupsGetOption("columns", num_options, options)) != NULL)
609 {
610 PageColumns = atoi(val);
611
612 if (PageColumns < 1)
613 {
614 _cupsLangPrintf(stderr, _("ERROR: Bad columns value %d!\n"), PageColumns);
615 return (1);
616 }
617 }
618
619 if ((val = cupsGetOption("cpi", num_options, options)) != NULL)
620 {
621 CharsPerInch = atof(val);
622
623 if (CharsPerInch <= 0.0)
624 {
625 _cupsLangPrintf(stderr, _("ERROR: Bad cpi value %f!\n"), CharsPerInch);
626 return (1);
627 }
628 }
629
630 if ((val = cupsGetOption("lpi", num_options, options)) != NULL)
631 {
632 LinesPerInch = atof(val);
633
634 if (LinesPerInch <= 0.0)
635 {
636 _cupsLangPrintf(stderr, _("ERROR: Bad lpi value %f!\n"), LinesPerInch);
637 return (1);
638 }
639 }
640
641 if (PrettyPrint)
642 PageTop -= 216.0f / LinesPerInch;
643
644 Copies = atoi(argv[4]);
645
646 WriteProlog(argv[3], argv[2], getenv("CLASSIFICATION"),
647 cupsGetOption("page-label", num_options, options), ppd);
648
649 /*
650 * Read text from the specified source and print it...
651 */
652
653 lastch = 0;
654 column = 0;
655 line = 0;
656 page_column = 0;
657 attr = 0;
658 keyptr = keyword;
659 keycol = 0;
660 ccomment = 0;
661 cstring = 0;
662
663 while ((ch = getutf8(fp)) >= 0)
664 {
665 /*
666 * Control codes:
667 *
668 * BS Backspace (0x08)
669 * HT Horizontal tab; next 8th column (0x09)
670 * LF Line feed; forward full line (0x0a)
671 * VT Vertical tab; reverse full line (0x0b)
672 * FF Form feed (0x0c)
673 * CR Carriage return (0x0d)
674 * ESC 7 Reverse full line (0x1b 0x37)
675 * ESC 8 Reverse half line (0x1b 0x38)
676 * ESC 9 Forward half line (0x1b 0x39)
677 */
678
679 switch (ch)
680 {
681 case 0x08 : /* BS - backspace for boldface & underline */
682 if (column > 0)
683 column --;
684
685 keyptr = keyword;
686 keycol = column;
687 break;
688
689 case 0x09 : /* HT - tab to next 8th column */
690 if (PrettyPrint && keyptr > keyword)
691 {
692 *keyptr = '\0';
693 keyptr = keyword;
694
695 if (bsearch(&keyptr, Keywords, NumKeywords, sizeof(char *),
696 compare_keywords))
697 {
698 /*
699 * Put keywords in boldface...
700 */
701
702 i = page_column * (ColumnWidth + ColumnGutter);
703
704 while (keycol < column)
705 {
706 Page[line][keycol + i].attr |= ATTR_BOLD;
707 keycol ++;
708 }
709 }
710 }
711
712 column = (column + 8) & ~7;
713
714 if (column >= ColumnWidth && WrapLines)
715 { /* Wrap text to margins */
716 line ++;
717 column = 0;
718
719 if (line >= SizeLines)
720 {
721 page_column ++;
722 line = 0;
723
724 if (page_column >= PageColumns)
725 {
726 WritePage();
727 page_column = 0;
728 }
729 }
730 }
731
732 keycol = column;
733
734 attr &= ~ATTR_BOLD;
735 break;
736
737 case 0x0d : /* CR */
738 #ifndef __APPLE__
739 /*
740 * All but MacOS/Darwin treat CR as was intended by ANSI
741 * folks, namely to move to column 0/1. Some programs still
742 * use this to do boldfacing and underlining...
743 */
744
745 column = 0;
746 break;
747 #else
748 /*
749 * MacOS/Darwin still need to treat CR as a line ending.
750 */
751
752 {
753 int nextch;
754 if ((nextch = getc(fp)) != 0x0a)
755 ungetc(nextch, fp);
756 else
757 ch = nextch;
758 }
759 #endif /* !__APPLE__ */
760
761 case 0x0a : /* LF - output current line */
762 if (PrettyPrint && keyptr > keyword)
763 {
764 *keyptr = '\0';
765 keyptr = keyword;
766
767 if (bsearch(&keyptr, Keywords, NumKeywords, sizeof(char *),
768 compare_keywords))
769 {
770 /*
771 * Put keywords in boldface...
772 */
773
774 i = page_column * (ColumnWidth + ColumnGutter);
775
776 while (keycol < column)
777 {
778 Page[line][keycol + i].attr |= ATTR_BOLD;
779 keycol ++;
780 }
781 }
782 }
783
784 line ++;
785 column = 0;
786 keycol = 0;
787
788 if (!ccomment && !cstring)
789 attr &= ~(ATTR_ITALIC | ATTR_BOLD | ATTR_RED | ATTR_GREEN | ATTR_BLUE);
790
791 if (line >= SizeLines)
792 {
793 page_column ++;
794 line = 0;
795
796 if (page_column >= PageColumns)
797 {
798 WritePage();
799 page_column = 0;
800 }
801 }
802 break;
803
804 case 0x0b : /* VT - move up 1 line */
805 if (line > 0)
806 line --;
807
808 keyptr = keyword;
809 keycol = column;
810
811 if (!ccomment && !cstring)
812 attr &= ~(ATTR_ITALIC | ATTR_BOLD | ATTR_RED | ATTR_GREEN | ATTR_BLUE);
813 break;
814
815 case 0x0c : /* FF - eject current page... */
816 if (PrettyPrint && keyptr > keyword)
817 {
818 *keyptr = '\0';
819 keyptr = keyword;
820
821 if (bsearch(&keyptr, Keywords, NumKeywords, sizeof(char *),
822 compare_keywords))
823 {
824 /*
825 * Put keywords in boldface...
826 */
827
828 i = page_column * (ColumnWidth + ColumnGutter);
829
830 while (keycol < column)
831 {
832 Page[line][keycol + i].attr |= ATTR_BOLD;
833 keycol ++;
834 }
835 }
836 }
837
838 page_column ++;
839 column = 0;
840 keycol = 0;
841 line = 0;
842
843 if (!ccomment && !cstring)
844 attr &= ~(ATTR_ITALIC | ATTR_BOLD | ATTR_RED | ATTR_GREEN | ATTR_BLUE);
845
846 if (page_column >= PageColumns)
847 {
848 WritePage();
849 page_column = 0;
850 }
851 break;
852
853 case 0x1b : /* Escape sequence */
854 ch = getutf8(fp);
855 if (ch == '7')
856 {
857 /*
858 * ESC 7 Reverse full line (0x1b 0x37)
859 */
860
861 if (line > 0)
862 line --;
863 }
864 else if (ch == '8')
865 {
866 /*
867 * ESC 8 Reverse half line (0x1b 0x38)
868 */
869
870 if ((attr & ATTR_RAISED) && line > 0)
871 {
872 attr &= ~ATTR_RAISED;
873 line --;
874 }
875 else if (attr & ATTR_LOWERED)
876 attr &= ~ATTR_LOWERED;
877 else
878 attr |= ATTR_RAISED;
879 }
880 else if (ch == '9')
881 {
882 /*
883 * ESC 9 Forward half line (0x1b 0x39)
884 */
885
886 if ((attr & ATTR_LOWERED) && line < (SizeLines - 1))
887 {
888 attr &= ~ATTR_LOWERED;
889 line ++;
890 }
891 else if (attr & ATTR_RAISED)
892 attr &= ~ATTR_RAISED;
893 else
894 attr |= ATTR_LOWERED;
895 }
896 break;
897
898 default : /* All others... */
899 if (ch < ' ')
900 break; /* Ignore other control chars */
901
902 if (PrettyPrint > PRETTY_PLAIN)
903 {
904 /*
905 * Do highlighting of C/C++ keywords, preprocessor commands,
906 * and comments...
907 */
908
909 if (ch == ' ' && (attr & ATTR_BOLD))
910 {
911 /*
912 * Stop bolding preprocessor command...
913 */
914
915 attr &= ~ATTR_BOLD;
916 }
917 else if (!(isalnum(ch & 255) || ch == '_') && keyptr > keyword)
918 {
919 /*
920 * Look for a keyword...
921 */
922
923 *keyptr = '\0';
924 keyptr = keyword;
925
926 if (!(attr & ATTR_ITALIC) &&
927 bsearch(&keyptr, Keywords, NumKeywords, sizeof(char *),
928 compare_keywords))
929 {
930 /*
931 * Put keywords in boldface...
932 */
933
934 i = page_column * (ColumnWidth + ColumnGutter);
935
936 while (keycol < column)
937 {
938 Page[line][keycol + i].attr |= ATTR_BOLD;
939 keycol ++;
940 }
941 }
942 }
943 else if ((isalnum(ch & 255) || ch == '_') && !ccomment && !cstring)
944 {
945 /*
946 * Add characters to the current keyword (if they'll fit).
947 */
948
949 if (keyptr == keyword)
950 keycol = column;
951
952 if (keyptr < (keyword + sizeof(keyword) - 1))
953 *keyptr++ = ch;
954 }
955 else if (ch == '\"' && lastch != '\\' && !ccomment && !cstring)
956 {
957 /*
958 * Start a C string constant...
959 */
960
961 cstring = -1;
962 attr = ATTR_BLUE;
963 }
964 else if (ch == '*' && lastch == '/' && !cstring &&
965 PrettyPrint != PRETTY_SHELL)
966 {
967 /*
968 * Start a C-style comment...
969 */
970
971 ccomment = 1;
972 attr = ATTR_ITALIC | ATTR_GREEN;
973 }
974 else if (ch == '/' && lastch == '/' && !cstring &&
975 PrettyPrint == PRETTY_CODE)
976 {
977 /*
978 * Start a C++-style comment...
979 */
980
981 attr = ATTR_ITALIC | ATTR_GREEN;
982 }
983 else if (ch == '#' && !cstring && PrettyPrint != PRETTY_CODE)
984 {
985 /*
986 * Start a shell-style comment...
987 */
988
989 attr = ATTR_ITALIC | ATTR_GREEN;
990 }
991 else if (ch == '#' && column == 0 && !ccomment && !cstring &&
992 PrettyPrint == PRETTY_CODE)
993 {
994 /*
995 * Start a preprocessor command...
996 */
997
998 attr = ATTR_BOLD | ATTR_RED;
999 }
1000 }
1001
1002 if (column >= ColumnWidth && WrapLines)
1003 { /* Wrap text to margins */
1004 column = 0;
1005 line ++;
1006
1007 if (line >= SizeLines)
1008 {
1009 page_column ++;
1010 line = 0;
1011
1012 if (page_column >= PageColumns)
1013 {
1014 WritePage();
1015 page_column = 0;
1016 }
1017 }
1018 }
1019
1020 /*
1021 * Add text to the current column & line...
1022 */
1023
1024 if (column < ColumnWidth)
1025 {
1026 i = column + page_column * (ColumnWidth + ColumnGutter);
1027
1028 if (PrettyPrint)
1029 Page[line][i].attr = attr;
1030 else if (ch == ' ' && Page[line][i].ch)
1031 ch = Page[line][i].ch;
1032 else if (ch == Page[line][i].ch)
1033 Page[line][i].attr |= ATTR_BOLD;
1034 else if (Page[line][i].ch == '_')
1035 Page[line][i].attr |= ATTR_UNDERLINE;
1036 else if (ch == '_')
1037 {
1038 Page[line][i].attr |= ATTR_UNDERLINE;
1039
1040 if (Page[line][i].ch)
1041 ch = Page[line][i].ch;
1042 }
1043 else
1044 Page[line][i].attr = attr;
1045
1046 Page[line][i].ch = ch;
1047 }
1048
1049 if (PrettyPrint)
1050 {
1051 if ((ch == '{' || ch == '}') && !ccomment && !cstring &&
1052 column < ColumnWidth)
1053 {
1054 /*
1055 * Highlight curley braces...
1056 */
1057
1058 Page[line][column].attr |= ATTR_BOLD;
1059 }
1060 else if ((ch == '/' || ch == '*') && lastch == '/' &&
1061 column < ColumnWidth && PrettyPrint != PRETTY_SHELL)
1062 {
1063 /*
1064 * Highlight first comment character...
1065 */
1066
1067 Page[line][column - 1].attr = attr;
1068 }
1069 else if (ch == '\"' && lastch != '\\' && !ccomment && cstring > 0)
1070 {
1071 /*
1072 * End a C string constant...
1073 */
1074
1075 cstring = 0;
1076 attr &= ~ATTR_BLUE;
1077 }
1078 else if (ch == '/' && lastch == '*' && ccomment)
1079 {
1080 /*
1081 * End a C-style comment...
1082 */
1083
1084 ccomment = 0;
1085 attr &= ~(ATTR_ITALIC | ATTR_GREEN);
1086 }
1087
1088 if (cstring < 0)
1089 cstring = 1;
1090 }
1091
1092 column ++;
1093 break;
1094 }
1095
1096 /*
1097 * Save this character for the next cycle.
1098 */
1099
1100 lastch = ch;
1101 }
1102
1103 /*
1104 * Write any remaining page data...
1105 */
1106
1107 if (line > 0 || page_column > 0 || column > 0)
1108 WritePage();
1109
1110 /*
1111 * Write the epilog and return...
1112 */
1113
1114 WriteEpilogue();
1115
1116 if (ppd != NULL)
1117 ppdClose(ppd);
1118
1119 return (0);
1120 }
1121
1122
1123 /*
1124 * 'compare_keywords()' - Compare two C/C++ keywords.
1125 */
1126
1127 static int /* O - Result of strcmp */
1128 compare_keywords(const void *k1, /* I - First keyword */
1129 const void *k2) /* I - Second keyword */
1130 {
1131 return (strcmp(*((const char **)k1), *((const char **)k2)));
1132 }
1133
1134
1135 /*
1136 * 'getutf8()' - Get a UTF-8 encoded wide character...
1137 */
1138
1139 static int /* O - Character or -1 on error */
1140 getutf8(FILE *fp) /* I - File to read from */
1141 {
1142 int ch; /* Current character value */
1143 int next; /* Next character from file */
1144
1145
1146 /*
1147 * Read the first character and process things accordingly...
1148 *
1149 * UTF-8 maps 16-bit characters to:
1150 *
1151 * 0 to 127 = 0xxxxxxx
1152 * 128 to 2047 = 110xxxxx 10yyyyyy (xxxxxyyyyyy)
1153 * 2048 to 65535 = 1110xxxx 10yyyyyy 10zzzzzz (xxxxyyyyyyzzzzzz)
1154 *
1155 * We also accept:
1156 *
1157 * 128 to 191 = 10xxxxxx
1158 *
1159 * since this range of values is otherwise undefined unless you are
1160 * in the middle of a multi-byte character...
1161 *
1162 * This code currently does not support anything beyond 16-bit
1163 * characters, in part because PostScript doesn't support more than
1164 * 16-bit characters...
1165 */
1166
1167 if ((ch = getc(fp)) == EOF)
1168 return (EOF);
1169
1170 if (ch < 0xc0 || !UTF8) /* One byte character? */
1171 return (ch);
1172 else if ((ch & 0xe0) == 0xc0)
1173 {
1174 /*
1175 * Two byte character...
1176 */
1177
1178 if ((next = getc(fp)) == EOF)
1179 return (EOF);
1180 else
1181 return (((ch & 0x1f) << 6) | (next & 0x3f));
1182 }
1183 else if ((ch & 0xf0) == 0xe0)
1184 {
1185 /*
1186 * Three byte character...
1187 */
1188
1189 if ((next = getc(fp)) == EOF)
1190 return (EOF);
1191
1192 ch = ((ch & 0x0f) << 6) | (next & 0x3f);
1193
1194 if ((next = getc(fp)) == EOF)
1195 return (EOF);
1196 else
1197 return ((ch << 6) | (next & 0x3f));
1198 }
1199 else
1200 {
1201 /*
1202 * More than three bytes... We don't support that...
1203 */
1204
1205 return (EOF);
1206 }
1207 }
1208
1209
1210 /*
1211 * End of "$Id: textcommon.c 6649 2007-07-11 21:46:42Z mike $".
1212 */