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