]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/textcommon.c
Mirror 1.1.x changes.
[thirdparty/cups.git] / filter / textcommon.c
1 /*
2 * "$Id: textcommon.c,v 1.16.2.14 2004/02/25 20:01:37 mike Exp $"
3 *
4 * Common text filter routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2003 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") && strcasecmp(val, "off") &&
559 strcasecmp(val, "false"))
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 = 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 PageColumns = atoi(val);
610
611 if ((val = cupsGetOption("cpi", num_options, options)) != NULL)
612 CharsPerInch = atof(val);
613
614 if ((val = cupsGetOption("lpi", num_options, options)) != NULL)
615 LinesPerInch = atof(val);
616
617 if (PrettyPrint)
618 PageTop -= 216.0f / LinesPerInch;
619
620 Copies = atoi(argv[4]);
621
622 WriteProlog(argv[3], argv[2], getenv("CLASSIFICATION"),
623 cupsGetOption("page-label", num_options, options), ppd);
624
625 /*
626 * Read text from the specified source and print it...
627 */
628
629 lastch = 0;
630 column = 0;
631 line = 0;
632 page_column = 0;
633 attr = 0;
634 keyptr = keyword;
635 keycol = 0;
636 ccomment = 0;
637 cstring = 0;
638
639 while ((ch = getutf8(fp)) >= 0)
640 {
641 /*
642 * Control codes:
643 *
644 * BS Backspace (0x08)
645 * HT Horizontal tab; next 8th column (0x09)
646 * LF Line feed; forward full line (0x0a)
647 * VT Vertical tab; reverse full line (0x0b)
648 * FF Form feed (0x0c)
649 * CR Carriage return (0x0d)
650 * ESC 7 Reverse full line (0x1b 0x37)
651 * ESC 8 Reverse half line (0x1b 0x38)
652 * ESC 9 Forward half line (0x1b 0x39)
653 */
654
655 switch (ch)
656 {
657 case 0x08 : /* BS - backspace for boldface & underline */
658 if (column > 0)
659 column --;
660
661 keyptr = keyword;
662 keycol = column;
663 break;
664
665 case 0x09 : /* HT - tab to next 8th column */
666 if (PrettyPrint && keyptr > keyword)
667 {
668 *keyptr = '\0';
669 keyptr = keyword;
670
671 if (bsearch(&keyptr, Keywords, NumKeywords, sizeof(char *),
672 compare_keywords))
673 {
674 /*
675 * Put keywords in boldface...
676 */
677
678 i = page_column * (ColumnWidth + ColumnGutter);
679
680 while (keycol < column)
681 {
682 Page[line][keycol + i].attr |= ATTR_BOLD;
683 keycol ++;
684 }
685 }
686 }
687
688 column = (column + 8) & ~7;
689
690 if (column >= ColumnWidth && WrapLines)
691 { /* Wrap text to margins */
692 line ++;
693 column = 0;
694
695 if (line >= SizeLines)
696 {
697 page_column ++;
698 line = 0;
699
700 if (page_column >= PageColumns)
701 {
702 WritePage();
703 page_column = 0;
704 }
705 }
706 }
707
708 keycol = column;
709 break;
710
711 case 0x0d : /* CR */
712 #ifndef __APPLE__
713 /*
714 * All but MacOS/Darwin treat CR as was intended by ANSI
715 * folks, namely to move to column 0/1. Some programs still
716 * use this to do boldfacing and underlining...
717 */
718
719 column = 0;
720 break;
721 #else
722 /*
723 * MacOS/Darwin still need to treat CR as a line ending.
724 */
725
726 {
727 int nextch;
728 if ((nextch = getc(fp)) != 0x0a)
729 ungetc(nextch, fp);
730 else
731 ch = nextch;
732 }
733 #endif /* !__APPLE__ */
734
735 case 0x0a : /* LF - output current line */
736 if (PrettyPrint && keyptr > keyword)
737 {
738 *keyptr = '\0';
739 keyptr = keyword;
740
741 if (bsearch(&keyptr, Keywords, NumKeywords, sizeof(char *),
742 compare_keywords))
743 {
744 /*
745 * Put keywords in boldface...
746 */
747
748 i = page_column * (ColumnWidth + ColumnGutter);
749
750 while (keycol < column)
751 {
752 Page[line][keycol + i].attr |= ATTR_BOLD;
753 keycol ++;
754 }
755 }
756 }
757
758 line ++;
759 column = 0;
760 keycol = 0;
761
762 if (!ccomment && !cstring)
763 attr &= ~(ATTR_ITALIC | ATTR_BOLD | ATTR_RED | ATTR_GREEN | ATTR_BLUE);
764
765 if (line >= SizeLines)
766 {
767 page_column ++;
768 line = 0;
769
770 if (page_column >= PageColumns)
771 {
772 WritePage();
773 page_column = 0;
774 }
775 }
776 break;
777
778 case 0x0b : /* VT - move up 1 line */
779 if (line > 0)
780 line --;
781
782 keyptr = keyword;
783 keycol = column;
784
785 if (!ccomment && !cstring)
786 attr &= ~(ATTR_ITALIC | ATTR_BOLD | ATTR_RED | ATTR_GREEN | ATTR_BLUE);
787 break;
788
789 case 0x0c : /* FF - eject current page... */
790 if (PrettyPrint && keyptr > keyword)
791 {
792 *keyptr = '\0';
793 keyptr = keyword;
794
795 if (bsearch(&keyptr, Keywords, NumKeywords, sizeof(char *),
796 compare_keywords))
797 {
798 /*
799 * Put keywords in boldface...
800 */
801
802 i = page_column * (ColumnWidth + ColumnGutter);
803
804 while (keycol < column)
805 {
806 Page[line][keycol + i].attr |= ATTR_BOLD;
807 keycol ++;
808 }
809 }
810 }
811
812 page_column ++;
813 column = 0;
814 keycol = 0;
815 line = 0;
816
817 if (!ccomment && !cstring)
818 attr &= ~(ATTR_ITALIC | ATTR_BOLD | ATTR_RED | ATTR_GREEN | ATTR_BLUE);
819
820 if (page_column >= PageColumns)
821 {
822 WritePage();
823 page_column = 0;
824 }
825 break;
826
827 case 0x1b : /* Escape sequence */
828 ch = getutf8(fp);
829 if (ch == '7')
830 {
831 /*
832 * ESC 7 Reverse full line (0x1b 0x37)
833 */
834
835 if (line > 0)
836 line --;
837 }
838 else if (ch == '8')
839 {
840 /*
841 * ESC 8 Reverse half line (0x1b 0x38)
842 */
843
844 if ((attr & ATTR_RAISED) && line > 0)
845 {
846 attr &= ~ATTR_RAISED;
847 line --;
848 }
849 else if (attr & ATTR_LOWERED)
850 attr &= ~ATTR_LOWERED;
851 else
852 attr |= ATTR_RAISED;
853 }
854 else if (ch == '9')
855 {
856 /*
857 * ESC 9 Forward half line (0x1b 0x39)
858 */
859
860 if ((attr & ATTR_LOWERED) && line < (SizeLines - 1))
861 {
862 attr &= ~ATTR_LOWERED;
863 line ++;
864 }
865 else if (attr & ATTR_RAISED)
866 attr &= ~ATTR_RAISED;
867 else
868 attr |= ATTR_LOWERED;
869 }
870 break;
871
872 default : /* All others... */
873 if (ch < ' ')
874 break; /* Ignore other control chars */
875
876 if (PrettyPrint)
877 {
878 /*
879 * Do highlighting of C/C++ keywords, preprocessor commands,
880 * and comments...
881 */
882
883 if ((ch == ' ' || ch == '\t') && (attr & ATTR_BOLD))
884 {
885 /*
886 * Stop bolding preprocessor command...
887 */
888
889 attr &= ~ATTR_BOLD;
890 }
891 else if (!(isalnum(ch & 255) || ch == '_') && keyptr > keyword)
892 {
893 /*
894 * Look for a keyword...
895 */
896
897 *keyptr = '\0';
898 keyptr = keyword;
899
900 if (!(attr & ATTR_ITALIC) &&
901 bsearch(&keyptr, Keywords, NumKeywords, sizeof(char *),
902 compare_keywords))
903 {
904 /*
905 * Put keywords in boldface...
906 */
907
908 i = page_column * (ColumnWidth + ColumnGutter);
909
910 while (keycol < column)
911 {
912 Page[line][keycol + i].attr |= ATTR_BOLD;
913 keycol ++;
914 }
915 }
916 }
917 else if ((isalnum(ch & 255) || ch == '_') && !ccomment && !cstring)
918 {
919 /*
920 * Add characters to the current keyword (if they'll fit).
921 */
922
923 if (keyptr == keyword)
924 keycol = column;
925
926 if (keyptr < (keyword + sizeof(keyword) - 1))
927 *keyptr++ = ch;
928 }
929 else if (ch == '\"' && lastch != '\\' && !ccomment && !cstring)
930 {
931 /*
932 * Start a C string constant...
933 */
934
935 cstring = -1;
936 attr |= ATTR_BLUE;
937 }
938 else if (ch == '*' && lastch == '/' && !cstring &&
939 PrettyPrint != PRETTY_SHELL)
940 {
941 /*
942 * Start a C-style comment...
943 */
944
945 ccomment = 1;
946 attr |= ATTR_ITALIC | ATTR_GREEN;
947 }
948 else if (ch == '/' && lastch == '/' && !cstring &&
949 PrettyPrint == PRETTY_CODE)
950 {
951 /*
952 * Start a C++-style comment...
953 */
954
955 attr |= ATTR_ITALIC | ATTR_GREEN;
956 }
957 else if (ch == '#' && !cstring && PrettyPrint != PRETTY_CODE)
958 {
959 /*
960 * Start a shell-style comment...
961 */
962
963 attr |= ATTR_ITALIC | ATTR_GREEN;
964 }
965 else if (ch == '#' && column == 0 && !ccomment && !cstring &&
966 PrettyPrint == PRETTY_CODE)
967 {
968 /*
969 * Start a preprocessor command...
970 */
971
972 attr |= ATTR_BOLD | ATTR_RED;
973 }
974 }
975
976 if (column >= ColumnWidth && WrapLines)
977 { /* Wrap text to margins */
978 column = 0;
979 line ++;
980
981 if (line >= SizeLines)
982 {
983 page_column ++;
984 line = 0;
985
986 if (page_column >= PageColumns)
987 {
988 WritePage();
989 page_column = 0;
990 }
991 }
992 }
993
994 /*
995 * Add text to the current column & line...
996 */
997
998 if (column < ColumnWidth)
999 {
1000 i = column + page_column * (ColumnWidth + ColumnGutter);
1001
1002 if (PrettyPrint)
1003 Page[line][i].attr = attr;
1004 else if (ch == ' ' && Page[line][i].ch)
1005 ch = Page[line][i].ch;
1006 else if (ch == Page[line][i].ch)
1007 Page[line][i].attr |= ATTR_BOLD;
1008 else if (Page[line][i].ch == '_')
1009 Page[line][i].attr |= ATTR_UNDERLINE;
1010 else if (ch == '_')
1011 {
1012 Page[line][i].attr |= ATTR_UNDERLINE;
1013
1014 if (Page[line][i].ch)
1015 ch = Page[line][i].ch;
1016 }
1017 else
1018 Page[line][i].attr = attr;
1019
1020 Page[line][i].ch = ch;
1021 }
1022
1023 if (PrettyPrint)
1024 {
1025 if ((ch == '{' || ch == '}') && !ccomment && !cstring &&
1026 column < ColumnWidth)
1027 {
1028 /*
1029 * Highlight curley braces...
1030 */
1031
1032 Page[line][column].attr |= ATTR_BOLD;
1033 }
1034 else if ((ch == '/' || ch == '*') && lastch == '/' &&
1035 column < ColumnWidth && PrettyPrint != PRETTY_SHELL)
1036 {
1037 /*
1038 * Highlight first comment character...
1039 */
1040
1041 Page[line][column - 1].attr = attr;
1042 }
1043 else if (ch == '\"' && lastch != '\\' && !ccomment && cstring > 0)
1044 {
1045 /*
1046 * End a C string constant...
1047 */
1048
1049 cstring = 0;
1050 attr &= ~ATTR_BLUE;
1051 }
1052 else if (ch == '/' && lastch == '*' && ccomment)
1053 {
1054 /*
1055 * End a C-style comment...
1056 */
1057
1058 ccomment = 0;
1059 attr &= ~(ATTR_ITALIC | ATTR_GREEN);
1060 }
1061
1062 if (cstring < 0)
1063 cstring = 1;
1064 }
1065
1066 column ++;
1067 break;
1068 }
1069
1070 /*
1071 * Save this character for the next cycle.
1072 */
1073
1074 lastch = ch;
1075 }
1076
1077 /*
1078 * Write any remaining page data...
1079 */
1080
1081 if (line > 0 || page_column > 0 || column > 0)
1082 WritePage();
1083
1084 /*
1085 * Write the epilog and return...
1086 */
1087
1088 WriteEpilogue();
1089
1090 if (ppd != NULL)
1091 ppdClose(ppd);
1092
1093 return (0);
1094 }
1095
1096
1097 /*
1098 * 'compare_keywords()' - Compare two C/C++ keywords.
1099 */
1100
1101 static int /* O - Result of strcmp */
1102 compare_keywords(const void *k1, /* I - First keyword */
1103 const void *k2) /* I - Second keyword */
1104 {
1105 return (strcmp(*((const char **)k1), *((const char **)k2)));
1106 }
1107
1108
1109 /*
1110 * 'getutf8()' - Get a UTF-8 encoded wide character...
1111 */
1112
1113 static int /* O - Character or -1 on error */
1114 getutf8(FILE *fp) /* I - File to read from */
1115 {
1116 int ch; /* Current character value */
1117 int next; /* Next character from file */
1118
1119
1120 /*
1121 * Read the first character and process things accordingly...
1122 *
1123 * UTF-8 maps 16-bit characters to:
1124 *
1125 * 0 to 127 = 0xxxxxxx
1126 * 128 to 2047 = 110xxxxx 10yyyyyy (xxxxxyyyyyy)
1127 * 2048 to 65535 = 1110xxxx 10yyyyyy 10zzzzzz (xxxxyyyyyyzzzzzz)
1128 *
1129 * We also accept:
1130 *
1131 * 128 to 191 = 10xxxxxx
1132 *
1133 * since this range of values is otherwise undefined unless you are
1134 * in the middle of a multi-byte character...
1135 *
1136 * This code currently does not support anything beyond 16-bit
1137 * characters, in part because PostScript doesn't support more than
1138 * 16-bit characters...
1139 */
1140
1141 if ((ch = getc(fp)) == EOF)
1142 return (EOF);
1143
1144 if (ch < 0xc0 || !UTF8) /* One byte character? */
1145 return (ch);
1146 else if ((ch & 0xe0) == 0xc0)
1147 {
1148 /*
1149 * Two byte character...
1150 */
1151
1152 if ((next = getc(fp)) == EOF)
1153 return (EOF);
1154 else
1155 return (((ch & 0x1f) << 6) | (next & 0x3f));
1156 }
1157 else if ((ch & 0xf0) == 0xe0)
1158 {
1159 /*
1160 * Three byte character...
1161 */
1162
1163 if ((next = getc(fp)) == EOF)
1164 return (EOF);
1165
1166 ch = ((ch & 0x0f) << 6) | (next & 0x3f);
1167
1168 if ((next = getc(fp)) == EOF)
1169 return (EOF);
1170 else
1171 return ((ch << 6) | (next & 0x3f));
1172 }
1173 else
1174 {
1175 /*
1176 * More than three bytes... We don't support that...
1177 */
1178
1179 return (EOF);
1180 }
1181 }
1182
1183
1184 /*
1185 * End of "$Id: textcommon.c,v 1.16.2.14 2004/02/25 20:01:37 mike Exp $".
1186 */