]>
git.ipfire.org Git - thirdparty/cups.git/blob - filter/textcommon.c
2 * "$Id: textcommon.c 6649 2007-07-11 21:46:42Z mike $"
4 * Common text filter routines for CUPS.
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
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/".
15 * This file is subject to the Apple OS-Developed Software exception.
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...
25 * Include necessary headers...
28 #include "textcommon.h"
29 #include <cups/language-private.h>
36 int 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 */
44 lchar_t
**Page
= NULL
; /* Page characters */
45 int NumPages
= 0; /* Number of pages in document */
46 float CharsPerInch
= 10; /* Number of character columns per inch */
47 float LinesPerInch
= 6; /* Number of lines per inch */
48 int NumKeywords
= 0; /* Number of known keywords */
49 char **Keywords
= NULL
; /* List of known keywords */
56 static char *code_keywords
[] = /* List of known C/C++ keywords... */
129 *sh_keywords
[] = /* List of known Boure/Korn/zsh/bash keywords... */
185 *csh_keywords
[] = /* List of known csh/tcsh keywords... */
253 *perl_keywords
[] = /* List of known perl keywords... */
473 static int compare_keywords(const void *, const void *);
474 static int getutf8(FILE *fp
);
478 * 'TextMain()' - Standard main entry for text filters.
481 int /* O - Exit status */
482 TextMain(const char *name
, /* I - Name of filter */
483 int argc
, /* I - Number of command-line arguments */
484 char *argv
[]) /* I - Command-line arguments */
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 */
506 * Make sure status messages are not buffered...
509 setbuf(stderr
, NULL
);
512 * Check command-line...
515 if (argc
< 6 || argc
> 7)
517 _cupsLangPrintf(stderr
,
518 _("Usage: %s job-id user title copies options [file]"),
524 * If we have 7 arguments, print the file named on the command-line.
525 * Otherwise, send stdin instead...
533 * Try to open the print file...
536 if ((fp
= fopen(argv
[6], "rb")) == NULL
)
538 perror("DEBUG: unable to open print file - ");
544 * Process command-line options and write the prolog...
548 num_options
= cupsParseOptions(argv
[5], 0, &options
);
550 if ((val
= cupsGetOption("prettyprint", num_options
, options
)) != NULL
&&
551 _cups_strcasecmp(val
, "no") && _cups_strcasecmp(val
, "off") &&
552 _cups_strcasecmp(val
, "false"))
555 PageRight
= PageWidth
- 36.0f
;
556 PageBottom
= PageBottom
> 36.0f
? PageBottom
: 36.0f
;
557 PageTop
= PageLength
- 36.0f
;
561 if ((val
= getenv("CONTENT_TYPE")) == NULL
)
563 PrettyPrint
= PRETTY_PLAIN
;
567 else if (_cups_strcasecmp(val
, "application/x-cshell") == 0)
569 PrettyPrint
= PRETTY_SHELL
;
570 NumKeywords
= sizeof(csh_keywords
) / sizeof(csh_keywords
[0]);
571 Keywords
= csh_keywords
;
573 else if (_cups_strcasecmp(val
, "application/x-csource") == 0)
575 PrettyPrint
= PRETTY_CODE
;
576 NumKeywords
= sizeof(code_keywords
) / sizeof(code_keywords
[0]);
577 Keywords
= code_keywords
;
579 else if (_cups_strcasecmp(val
, "application/x-perl") == 0)
581 PrettyPrint
= PRETTY_PERL
;
582 NumKeywords
= sizeof(perl_keywords
) / sizeof(perl_keywords
[0]);
583 Keywords
= perl_keywords
;
585 else if (_cups_strcasecmp(val
, "application/x-shell") == 0)
587 PrettyPrint
= PRETTY_SHELL
;
588 NumKeywords
= sizeof(sh_keywords
) / sizeof(sh_keywords
[0]);
589 Keywords
= sh_keywords
;
593 PrettyPrint
= PRETTY_PLAIN
;
599 ppd
= SetCommonOptions(num_options
, options
, 1);
601 if ((val
= cupsGetOption("wrap", num_options
, options
)) == NULL
)
604 WrapLines
= !_cups_strcasecmp(val
, "true") || !_cups_strcasecmp(val
, "on") ||
605 !_cups_strcasecmp(val
, "yes");
607 if ((val
= cupsGetOption("columns", num_options
, options
)) != NULL
)
609 PageColumns
= atoi(val
);
613 _cupsLangPrintFilter(stderr
, "ERROR", _("Bad columns value %d."),
619 if ((val
= cupsGetOption("cpi", num_options
, options
)) != NULL
)
621 CharsPerInch
= atof(val
);
623 if (CharsPerInch
<= 0.0)
625 _cupsLangPrintFilter(stderr
, "ERROR", _("Bad cpi value %f."),
631 if ((val
= cupsGetOption("lpi", num_options
, options
)) != NULL
)
633 LinesPerInch
= atof(val
);
635 if (LinesPerInch
<= 0.0)
637 _cupsLangPrintFilter(stderr
, "ERROR", _("Bad lpi value %f."),
644 PageTop
-= 216.0f
/ LinesPerInch
;
646 Copies
= atoi(argv
[4]);
648 WriteProlog(argv
[3], argv
[2], getenv("CLASSIFICATION"),
649 cupsGetOption("page-label", num_options
, options
), ppd
);
652 * Read text from the specified source and print it...
665 while ((ch
= getutf8(fp
)) >= 0)
670 * BS Backspace (0x08)
671 * HT Horizontal tab; next 8th column (0x09)
672 * LF Line feed; forward full line (0x0a)
673 * VT Vertical tab; reverse full line (0x0b)
674 * FF Form feed (0x0c)
675 * CR Carriage return (0x0d)
676 * ESC 7 Reverse full line (0x1b 0x37)
677 * ESC 8 Reverse half line (0x1b 0x38)
678 * ESC 9 Forward half line (0x1b 0x39)
683 case 0x08 : /* BS - backspace for boldface & underline */
691 case 0x09 : /* HT - tab to next 8th column */
692 if (PrettyPrint
&& keyptr
> keyword
)
697 if (bsearch(&keyptr
, Keywords
, NumKeywords
, sizeof(char *),
701 * Put keywords in boldface...
704 i
= page_column
* (ColumnWidth
+ ColumnGutter
);
706 while (keycol
< column
)
708 Page
[line
][keycol
+ i
].attr
|= ATTR_BOLD
;
714 column
= (column
+ 8) & ~7;
716 if (column
>= ColumnWidth
&& WrapLines
)
717 { /* Wrap text to margins */
721 if (line
>= SizeLines
)
726 if (page_column
>= PageColumns
)
742 * All but MacOS/Darwin treat CR as was intended by ANSI
743 * folks, namely to move to column 0/1. Some programs still
744 * use this to do boldfacing and underlining...
751 * MacOS/Darwin still need to treat CR as a line ending.
756 if ((nextch
= getc(fp
)) != 0x0a)
761 #endif /* !__APPLE__ */
763 case 0x0a : /* LF - output current line */
764 if (PrettyPrint
&& keyptr
> keyword
)
769 if (bsearch(&keyptr
, Keywords
, NumKeywords
, sizeof(char *),
773 * Put keywords in boldface...
776 i
= page_column
* (ColumnWidth
+ ColumnGutter
);
778 while (keycol
< column
)
780 Page
[line
][keycol
+ i
].attr
|= ATTR_BOLD
;
790 if (!ccomment
&& !cstring
)
791 attr
&= ~(ATTR_ITALIC
| ATTR_BOLD
| ATTR_RED
| ATTR_GREEN
| ATTR_BLUE
);
793 if (line
>= SizeLines
)
798 if (page_column
>= PageColumns
)
806 case 0x0b : /* VT - move up 1 line */
813 if (!ccomment
&& !cstring
)
814 attr
&= ~(ATTR_ITALIC
| ATTR_BOLD
| ATTR_RED
| ATTR_GREEN
| ATTR_BLUE
);
817 case 0x0c : /* FF - eject current page... */
818 if (PrettyPrint
&& keyptr
> keyword
)
823 if (bsearch(&keyptr
, Keywords
, NumKeywords
, sizeof(char *),
827 * Put keywords in boldface...
830 i
= page_column
* (ColumnWidth
+ ColumnGutter
);
832 while (keycol
< column
)
834 Page
[line
][keycol
+ i
].attr
|= ATTR_BOLD
;
845 if (!ccomment
&& !cstring
)
846 attr
&= ~(ATTR_ITALIC
| ATTR_BOLD
| ATTR_RED
| ATTR_GREEN
| ATTR_BLUE
);
848 if (page_column
>= PageColumns
)
855 case 0x1b : /* Escape sequence */
860 * ESC 7 Reverse full line (0x1b 0x37)
869 * ESC 8 Reverse half line (0x1b 0x38)
872 if ((attr
& ATTR_RAISED
) && line
> 0)
874 attr
&= ~ATTR_RAISED
;
877 else if (attr
& ATTR_LOWERED
)
878 attr
&= ~ATTR_LOWERED
;
885 * ESC 9 Forward half line (0x1b 0x39)
888 if ((attr
& ATTR_LOWERED
) && line
< (SizeLines
- 1))
890 attr
&= ~ATTR_LOWERED
;
893 else if (attr
& ATTR_RAISED
)
894 attr
&= ~ATTR_RAISED
;
896 attr
|= ATTR_LOWERED
;
900 default : /* All others... */
902 break; /* Ignore other control chars */
904 if (PrettyPrint
> PRETTY_PLAIN
)
907 * Do highlighting of C/C++ keywords, preprocessor commands,
911 if (ch
== ' ' && (attr
& ATTR_BOLD
))
914 * Stop bolding preprocessor command...
919 else if (!(isalnum(ch
& 255) || ch
== '_') && keyptr
> keyword
)
922 * Look for a keyword...
928 if (!(attr
& ATTR_ITALIC
) &&
929 bsearch(&keyptr
, Keywords
, NumKeywords
, sizeof(char *),
933 * Put keywords in boldface...
936 i
= page_column
* (ColumnWidth
+ ColumnGutter
);
938 while (keycol
< column
)
940 Page
[line
][keycol
+ i
].attr
|= ATTR_BOLD
;
945 else if ((isalnum(ch
& 255) || ch
== '_') && !ccomment
&& !cstring
)
948 * Add characters to the current keyword (if they'll fit).
951 if (keyptr
== keyword
)
954 if (keyptr
< (keyword
+ sizeof(keyword
) - 1))
957 else if (ch
== '\"' && lastch
!= '\\' && !ccomment
&& !cstring
)
960 * Start a C string constant...
966 else if (ch
== '*' && lastch
== '/' && !cstring
&&
967 PrettyPrint
!= PRETTY_SHELL
)
970 * Start a C-style comment...
974 attr
= ATTR_ITALIC
| ATTR_GREEN
;
976 else if (ch
== '/' && lastch
== '/' && !cstring
&&
977 PrettyPrint
== PRETTY_CODE
)
980 * Start a C++-style comment...
983 attr
= ATTR_ITALIC
| ATTR_GREEN
;
985 else if (ch
== '#' && !cstring
&& PrettyPrint
!= PRETTY_CODE
)
988 * Start a shell-style comment...
991 attr
= ATTR_ITALIC
| ATTR_GREEN
;
993 else if (ch
== '#' && column
== 0 && !ccomment
&& !cstring
&&
994 PrettyPrint
== PRETTY_CODE
)
997 * Start a preprocessor command...
1000 attr
= ATTR_BOLD
| ATTR_RED
;
1004 if (column
>= ColumnWidth
&& WrapLines
)
1005 { /* Wrap text to margins */
1009 if (line
>= SizeLines
)
1014 if (page_column
>= PageColumns
)
1023 * Add text to the current column & line...
1026 if (column
< ColumnWidth
)
1028 i
= column
+ page_column
* (ColumnWidth
+ ColumnGutter
);
1031 Page
[line
][i
].attr
= attr
;
1032 else if (ch
== ' ' && Page
[line
][i
].ch
)
1033 ch
= Page
[line
][i
].ch
;
1034 else if (ch
== Page
[line
][i
].ch
)
1035 Page
[line
][i
].attr
|= ATTR_BOLD
;
1036 else if (Page
[line
][i
].ch
== '_')
1037 Page
[line
][i
].attr
|= ATTR_UNDERLINE
;
1040 Page
[line
][i
].attr
|= ATTR_UNDERLINE
;
1042 if (Page
[line
][i
].ch
)
1043 ch
= Page
[line
][i
].ch
;
1046 Page
[line
][i
].attr
= attr
;
1048 Page
[line
][i
].ch
= ch
;
1053 if ((ch
== '{' || ch
== '}') && !ccomment
&& !cstring
&&
1054 column
< ColumnWidth
)
1057 * Highlight curley braces...
1060 Page
[line
][column
].attr
|= ATTR_BOLD
;
1062 else if ((ch
== '/' || ch
== '*') && lastch
== '/' &&
1063 column
< ColumnWidth
&& PrettyPrint
!= PRETTY_SHELL
)
1066 * Highlight first comment character...
1069 Page
[line
][column
- 1].attr
= attr
;
1071 else if (ch
== '\"' && lastch
!= '\\' && !ccomment
&& cstring
> 0)
1074 * End a C string constant...
1080 else if (ch
== '/' && lastch
== '*' && ccomment
)
1083 * End a C-style comment...
1087 attr
&= ~(ATTR_ITALIC
| ATTR_GREEN
);
1099 * Save this character for the next cycle.
1106 * Write any remaining page data...
1109 if (line
> 0 || page_column
> 0 || column
> 0)
1113 * Write the epilog and return...
1126 * 'compare_keywords()' - Compare two C/C++ keywords.
1129 static int /* O - Result of strcmp */
1130 compare_keywords(const void *k1
, /* I - First keyword */
1131 const void *k2
) /* I - Second keyword */
1133 return (strcmp(*((const char **)k1
), *((const char **)k2
)));
1138 * 'getutf8()' - Get a UTF-8 encoded wide character...
1141 static int /* O - Character or -1 on error */
1142 getutf8(FILE *fp
) /* I - File to read from */
1144 int ch
; /* Current character value */
1145 int next
; /* Next character from file */
1149 * Read the first character and process things accordingly...
1151 * UTF-8 maps 16-bit characters to:
1153 * 0 to 127 = 0xxxxxxx
1154 * 128 to 2047 = 110xxxxx 10yyyyyy (xxxxxyyyyyy)
1155 * 2048 to 65535 = 1110xxxx 10yyyyyy 10zzzzzz (xxxxyyyyyyzzzzzz)
1159 * 128 to 191 = 10xxxxxx
1161 * since this range of values is otherwise undefined unless you are
1162 * in the middle of a multi-byte character...
1164 * This code currently does not support anything beyond 16-bit
1165 * characters, in part because PostScript doesn't support more than
1166 * 16-bit characters...
1169 if ((ch
= getc(fp
)) == EOF
)
1172 if (ch
< 0xc0) /* One byte character? */
1174 else if ((ch
& 0xe0) == 0xc0)
1177 * Two byte character...
1180 if ((next
= getc(fp
)) == EOF
)
1183 return (((ch
& 0x1f) << 6) | (next
& 0x3f));
1185 else if ((ch
& 0xf0) == 0xe0)
1188 * Three byte character...
1191 if ((next
= getc(fp
)) == EOF
)
1194 ch
= ((ch
& 0x0f) << 6) | (next
& 0x3f);
1196 if ((next
= getc(fp
)) == EOF
)
1199 return ((ch
<< 6) | (next
& 0x3f));
1204 * More than three bytes... We don't support that...
1213 * End of "$Id: textcommon.c 6649 2007-07-11 21:46:42Z mike $".