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