]> git.ipfire.org Git - thirdparty/cups.git/blame - filter/textcommon.c
Load cups into easysw/current.
[thirdparty/cups.git] / filter / textcommon.c
CommitLineData
ef416fc2 1/*
bc44d920 2 * "$Id: textcommon.c 6649 2007-07-11 21:46:42Z mike $"
ef416fc2 3 *
4 * Common text filter routines for the Common UNIX Printing System (CUPS).
5 *
bc44d920 6 * Copyright 2007 by Apple Inc.
c0e1af83 7 * Copyright 1997-2007 by Easy Software Products.
ef416fc2 8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 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/".
ef416fc2 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"
c0e1af83 29#include <cups/i18n.h>
ef416fc2 30
31
32/*
33 * Globals...
34 */
35
36int 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 */
44lchar_t **Page = NULL; /* Page characters */
45int NumPages = 0; /* Number of pages in document */
46float CharsPerInch = 10; /* Number of character columns per inch */
47float LinesPerInch = 6; /* Number of lines per inch */
48int UTF8 = 0; /* Use UTF-8 encoding? */
49int NumKeywords = 0; /* Number of known keywords */
50char **Keywords = NULL; /* List of known keywords */
51
52
53/*
54 * Local globals...
55 */
56
57static 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
474static int compare_keywords(const void *, const void *);
475static int getutf8(FILE *fp);
476
477
478/*
479 * 'TextMain()' - Standard main entry for text filters.
480 */
481
482int /* O - Exit status */
483TextMain(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 {
c0e1af83 518 fprintf(stderr, _("Usage: %s job-id user title copies options [file]\n"),
ef416fc2 519 name);
520 return (1);
521 }
522
523 /*
524 * If we have 7 arguments, print the file named on the command-line.
525 * Otherwise, send stdin instead...
526 */
527
528 if (argc == 6)
529 fp = stdin;
530 else
531 {
532 /*
533 * Try to open the print file...
534 */
535
536 if ((fp = fopen(argv[6], "rb")) == NULL)
537 {
c0e1af83 538 perror("DEBUG: unable to open print file - ");
ef416fc2 539 return (1);
540 }
541 }
542
543 /*
544 * Process command-line options and write the prolog...
545 */
546
547 options = NULL;
548 num_options = cupsParseOptions(argv[5], 0, &options);
549
550 if ((val = cupsGetOption("prettyprint", num_options, options)) != NULL &&
551 strcasecmp(val, "no") && strcasecmp(val, "off") &&
552 strcasecmp(val, "false"))
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_PLAIN;
564 NumKeywords = 0;
565 Keywords = NULL;
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-csource") == 0)
574 {
575 PrettyPrint = PRETTY_CODE;
576 NumKeywords = sizeof(code_keywords) / sizeof(code_keywords[0]);
577 Keywords = code_keywords;
578 }
579 else if (strcasecmp(val, "application/x-perl") == 0)
580 {
581 PrettyPrint = PRETTY_PERL;
582 NumKeywords = sizeof(perl_keywords) / sizeof(perl_keywords[0]);
583 Keywords = perl_keywords;
584 }
585 else if (strcasecmp(val, "application/x-shell") == 0)
586 {
587 PrettyPrint = PRETTY_SHELL;
588 NumKeywords = sizeof(sh_keywords) / sizeof(sh_keywords[0]);
589 Keywords = sh_keywords;
590 }
591 else
592 {
593 PrettyPrint = PRETTY_PLAIN;
594 NumKeywords = 0;
595 Keywords = NULL;
596 }
597 }
598
599 ppd = SetCommonOptions(num_options, options, 1);
600
601 if ((val = cupsGetOption("wrap", num_options, options)) == NULL)
602 WrapLines = 1;
603 else
604 WrapLines = !strcasecmp(val, "true") || !strcasecmp(val, "on") ||
605 !strcasecmp(val, "yes");
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
709 attr &= ~ATTR_BOLD;
710 break;
711
712 case 0x0d : /* CR */
713#ifndef __APPLE__
714 /*
715 * All but MacOS/Darwin treat CR as was intended by ANSI
716 * folks, namely to move to column 0/1. Some programs still
717 * use this to do boldfacing and underlining...
718 */
719
720 column = 0;
721 break;
722#else
723 /*
724 * MacOS/Darwin still need to treat CR as a line ending.
725 */
726
727 {
728 int nextch;
729 if ((nextch = getc(fp)) != 0x0a)
730 ungetc(nextch, fp);
731 else
732 ch = nextch;
733 }
734#endif /* !__APPLE__ */
735
736 case 0x0a : /* LF - output current line */
737 if (PrettyPrint && keyptr > keyword)
738 {
739 *keyptr = '\0';
740 keyptr = keyword;
741
742 if (bsearch(&keyptr, Keywords, NumKeywords, sizeof(char *),
743 compare_keywords))
744 {
745 /*
746 * Put keywords in boldface...
747 */
748
749 i = page_column * (ColumnWidth + ColumnGutter);
750
751 while (keycol < column)
752 {
753 Page[line][keycol + i].attr |= ATTR_BOLD;
754 keycol ++;
755 }
756 }
757 }
758
759 line ++;
760 column = 0;
761 keycol = 0;
762
763 if (!ccomment && !cstring)
764 attr &= ~(ATTR_ITALIC | ATTR_BOLD | ATTR_RED | ATTR_GREEN | ATTR_BLUE);
765
766 if (line >= SizeLines)
767 {
768 page_column ++;
769 line = 0;
770
771 if (page_column >= PageColumns)
772 {
773 WritePage();
774 page_column = 0;
775 }
776 }
777 break;
778
779 case 0x0b : /* VT - move up 1 line */
780 if (line > 0)
781 line --;
782
783 keyptr = keyword;
784 keycol = column;
785
786 if (!ccomment && !cstring)
787 attr &= ~(ATTR_ITALIC | ATTR_BOLD | ATTR_RED | ATTR_GREEN | ATTR_BLUE);
788 break;
789
790 case 0x0c : /* FF - eject current page... */
791 if (PrettyPrint && keyptr > keyword)
792 {
793 *keyptr = '\0';
794 keyptr = keyword;
795
796 if (bsearch(&keyptr, Keywords, NumKeywords, sizeof(char *),
797 compare_keywords))
798 {
799 /*
800 * Put keywords in boldface...
801 */
802
803 i = page_column * (ColumnWidth + ColumnGutter);
804
805 while (keycol < column)
806 {
807 Page[line][keycol + i].attr |= ATTR_BOLD;
808 keycol ++;
809 }
810 }
811 }
812
813 page_column ++;
814 column = 0;
815 keycol = 0;
816 line = 0;
817
818 if (!ccomment && !cstring)
819 attr &= ~(ATTR_ITALIC | ATTR_BOLD | ATTR_RED | ATTR_GREEN | ATTR_BLUE);
820
821 if (page_column >= PageColumns)
822 {
823 WritePage();
824 page_column = 0;
825 }
826 break;
827
828 case 0x1b : /* Escape sequence */
829 ch = getutf8(fp);
830 if (ch == '7')
831 {
832 /*
833 * ESC 7 Reverse full line (0x1b 0x37)
834 */
835
836 if (line > 0)
837 line --;
838 }
839 else if (ch == '8')
840 {
841 /*
842 * ESC 8 Reverse half line (0x1b 0x38)
843 */
844
845 if ((attr & ATTR_RAISED) && line > 0)
846 {
847 attr &= ~ATTR_RAISED;
848 line --;
849 }
850 else if (attr & ATTR_LOWERED)
851 attr &= ~ATTR_LOWERED;
852 else
853 attr |= ATTR_RAISED;
854 }
855 else if (ch == '9')
856 {
857 /*
858 * ESC 9 Forward half line (0x1b 0x39)
859 */
860
861 if ((attr & ATTR_LOWERED) && line < (SizeLines - 1))
862 {
863 attr &= ~ATTR_LOWERED;
864 line ++;
865 }
866 else if (attr & ATTR_RAISED)
867 attr &= ~ATTR_RAISED;
868 else
869 attr |= ATTR_LOWERED;
870 }
871 break;
872
873 default : /* All others... */
874 if (ch < ' ')
875 break; /* Ignore other control chars */
876
877 if (PrettyPrint > PRETTY_PLAIN)
878 {
879 /*
880 * Do highlighting of C/C++ keywords, preprocessor commands,
881 * and comments...
882 */
883
884 if (ch == ' ' && (attr & ATTR_BOLD))
885 {
886 /*
887 * Stop bolding preprocessor command...
888 */
889
890 attr &= ~ATTR_BOLD;
891 }
892 else if (!(isalnum(ch & 255) || ch == '_') && keyptr > keyword)
893 {
894 /*
895 * Look for a keyword...
896 */
897
898 *keyptr = '\0';
899 keyptr = keyword;
900
901 if (!(attr & ATTR_ITALIC) &&
902 bsearch(&keyptr, Keywords, NumKeywords, sizeof(char *),
903 compare_keywords))
904 {
905 /*
906 * Put keywords in boldface...
907 */
908
909 i = page_column * (ColumnWidth + ColumnGutter);
910
911 while (keycol < column)
912 {
913 Page[line][keycol + i].attr |= ATTR_BOLD;
914 keycol ++;
915 }
916 }
917 }
918 else if ((isalnum(ch & 255) || ch == '_') && !ccomment && !cstring)
919 {
920 /*
921 * Add characters to the current keyword (if they'll fit).
922 */
923
924 if (keyptr == keyword)
925 keycol = column;
926
927 if (keyptr < (keyword + sizeof(keyword) - 1))
928 *keyptr++ = ch;
929 }
930 else if (ch == '\"' && lastch != '\\' && !ccomment && !cstring)
931 {
932 /*
933 * Start a C string constant...
934 */
935
936 cstring = -1;
937 attr = ATTR_BLUE;
938 }
939 else if (ch == '*' && lastch == '/' && !cstring &&
940 PrettyPrint != PRETTY_SHELL)
941 {
942 /*
943 * Start a C-style comment...
944 */
945
946 ccomment = 1;
947 attr = ATTR_ITALIC | ATTR_GREEN;
948 }
949 else if (ch == '/' && lastch == '/' && !cstring &&
950 PrettyPrint == PRETTY_CODE)
951 {
952 /*
953 * Start a C++-style comment...
954 */
955
956 attr = ATTR_ITALIC | ATTR_GREEN;
957 }
958 else if (ch == '#' && !cstring && PrettyPrint != PRETTY_CODE)
959 {
960 /*
961 * Start a shell-style comment...
962 */
963
964 attr = ATTR_ITALIC | ATTR_GREEN;
965 }
966 else if (ch == '#' && column == 0 && !ccomment && !cstring &&
967 PrettyPrint == PRETTY_CODE)
968 {
969 /*
970 * Start a preprocessor command...
971 */
972
973 attr = ATTR_BOLD | ATTR_RED;
974 }
975 }
976
977 if (column >= ColumnWidth && WrapLines)
978 { /* Wrap text to margins */
979 column = 0;
980 line ++;
981
982 if (line >= SizeLines)
983 {
984 page_column ++;
985 line = 0;
986
987 if (page_column >= PageColumns)
988 {
989 WritePage();
990 page_column = 0;
991 }
992 }
993 }
994
995 /*
996 * Add text to the current column & line...
997 */
998
999 if (column < ColumnWidth)
1000 {
1001 i = column + page_column * (ColumnWidth + ColumnGutter);
1002
1003 if (PrettyPrint)
1004 Page[line][i].attr = attr;
1005 else if (ch == ' ' && Page[line][i].ch)
1006 ch = Page[line][i].ch;
1007 else if (ch == Page[line][i].ch)
1008 Page[line][i].attr |= ATTR_BOLD;
1009 else if (Page[line][i].ch == '_')
1010 Page[line][i].attr |= ATTR_UNDERLINE;
1011 else if (ch == '_')
1012 {
1013 Page[line][i].attr |= ATTR_UNDERLINE;
1014
1015 if (Page[line][i].ch)
1016 ch = Page[line][i].ch;
1017 }
1018 else
1019 Page[line][i].attr = attr;
1020
1021 Page[line][i].ch = ch;
1022 }
1023
1024 if (PrettyPrint)
1025 {
1026 if ((ch == '{' || ch == '}') && !ccomment && !cstring &&
1027 column < ColumnWidth)
1028 {
1029 /*
1030 * Highlight curley braces...
1031 */
1032
1033 Page[line][column].attr |= ATTR_BOLD;
1034 }
1035 else if ((ch == '/' || ch == '*') && lastch == '/' &&
1036 column < ColumnWidth && PrettyPrint != PRETTY_SHELL)
1037 {
1038 /*
1039 * Highlight first comment character...
1040 */
1041
1042 Page[line][column - 1].attr = attr;
1043 }
1044 else if (ch == '\"' && lastch != '\\' && !ccomment && cstring > 0)
1045 {
1046 /*
1047 * End a C string constant...
1048 */
1049
1050 cstring = 0;
1051 attr &= ~ATTR_BLUE;
1052 }
1053 else if (ch == '/' && lastch == '*' && ccomment)
1054 {
1055 /*
1056 * End a C-style comment...
1057 */
1058
1059 ccomment = 0;
1060 attr &= ~(ATTR_ITALIC | ATTR_GREEN);
1061 }
1062
1063 if (cstring < 0)
1064 cstring = 1;
1065 }
1066
1067 column ++;
1068 break;
1069 }
1070
1071 /*
1072 * Save this character for the next cycle.
1073 */
1074
1075 lastch = ch;
1076 }
1077
1078 /*
1079 * Write any remaining page data...
1080 */
1081
1082 if (line > 0 || page_column > 0 || column > 0)
1083 WritePage();
1084
1085 /*
1086 * Write the epilog and return...
1087 */
1088
1089 WriteEpilogue();
1090
1091 if (ppd != NULL)
1092 ppdClose(ppd);
1093
1094 return (0);
1095}
1096
1097
1098/*
1099 * 'compare_keywords()' - Compare two C/C++ keywords.
1100 */
1101
1102static int /* O - Result of strcmp */
1103compare_keywords(const void *k1, /* I - First keyword */
1104 const void *k2) /* I - Second keyword */
1105{
1106 return (strcmp(*((const char **)k1), *((const char **)k2)));
1107}
1108
1109
1110/*
1111 * 'getutf8()' - Get a UTF-8 encoded wide character...
1112 */
1113
1114static int /* O - Character or -1 on error */
1115getutf8(FILE *fp) /* I - File to read from */
1116{
1117 int ch; /* Current character value */
1118 int next; /* Next character from file */
1119
1120
1121 /*
1122 * Read the first character and process things accordingly...
1123 *
1124 * UTF-8 maps 16-bit characters to:
1125 *
1126 * 0 to 127 = 0xxxxxxx
1127 * 128 to 2047 = 110xxxxx 10yyyyyy (xxxxxyyyyyy)
1128 * 2048 to 65535 = 1110xxxx 10yyyyyy 10zzzzzz (xxxxyyyyyyzzzzzz)
1129 *
1130 * We also accept:
1131 *
1132 * 128 to 191 = 10xxxxxx
1133 *
1134 * since this range of values is otherwise undefined unless you are
1135 * in the middle of a multi-byte character...
1136 *
1137 * This code currently does not support anything beyond 16-bit
1138 * characters, in part because PostScript doesn't support more than
1139 * 16-bit characters...
1140 */
1141
1142 if ((ch = getc(fp)) == EOF)
1143 return (EOF);
1144
1145 if (ch < 0xc0 || !UTF8) /* One byte character? */
1146 return (ch);
1147 else if ((ch & 0xe0) == 0xc0)
1148 {
1149 /*
1150 * Two byte character...
1151 */
1152
1153 if ((next = getc(fp)) == EOF)
1154 return (EOF);
1155 else
1156 return (((ch & 0x1f) << 6) | (next & 0x3f));
1157 }
1158 else if ((ch & 0xf0) == 0xe0)
1159 {
1160 /*
1161 * Three byte character...
1162 */
1163
1164 if ((next = getc(fp)) == EOF)
1165 return (EOF);
1166
1167 ch = ((ch & 0x0f) << 6) | (next & 0x3f);
1168
1169 if ((next = getc(fp)) == EOF)
1170 return (EOF);
1171 else
1172 return ((ch << 6) | (next & 0x3f));
1173 }
1174 else
1175 {
1176 /*
1177 * More than three bytes... We don't support that...
1178 */
1179
1180 return (EOF);
1181 }
1182}
1183
1184
1185/*
bc44d920 1186 * End of "$Id: textcommon.c 6649 2007-07-11 21:46:42Z mike $".
ef416fc2 1187 */