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