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