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