]>
git.ipfire.org Git - thirdparty/cups.git/blob - filter/textcommon.c
dc6da405e16f7687d7ffc97d3bd89446f4895cab
2 * "$Id: textcommon.c,v 1.16.2.10 2002/08/19 16:49:52 mike Exp $"
4 * Common text filter routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2002 by Easy Software Products.
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
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * This file is subject to the Apple OS-Developed Software exception.
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...
34 * Include necessary headers...
37 #include "textcommon.h"
44 int WrapLines
= 1, /* Wrap text in lines */
45 SizeLines
= 60, /* Number of lines on a page */
46 SizeColumns
= 80, /* Number of columns on a line */
47 PageColumns
= 1, /* Number of columns on a page */
48 ColumnGutter
= 0, /* Number of characters between text columns */
49 ColumnWidth
= 80, /* Width of each column */
50 PrettyPrint
= 0, /* Do pretty code formatting */
51 Copies
= 1; /* Number of copies */
52 lchar_t
**Page
= NULL
; /* Page characters */
53 int NumPages
= 0; /* Number of pages in document */
54 float CharsPerInch
= 10; /* Number of character columns per inch */
55 float LinesPerInch
= 6; /* Number of lines per inch */
56 int UTF8
= 0; /* Use UTF-8 encoding? */
57 int NumKeywords
= 0; /* Number of known keywords */
58 char **Keywords
= NULL
; /* List of known keywords */
65 static char *code_keywords
[] = /* List of known C/C++ keywords... */
137 *sh_keywords
[] = /* List of known Boure/Korn/zsh/bash keywords... */
193 *csh_keywords
[] = /* List of known csh/tcsh keywords... */
261 *perl_keywords
[] = /* List of known perl keywords... */
481 static int compare_keywords(const void *, const void *);
482 static int getutf8(FILE *fp
);
486 * 'TextMain()' - Standard main entry for text filters.
489 int /* O - Exit status */
490 TextMain(const char *name
, /* I - Name of filter */
491 int argc
, /* I - Number of command-line arguments */
492 char *argv
[]) /* I - Command-line arguments */
494 FILE *fp
; /* Print file */
495 ppd_file_t
*ppd
; /* PPD file */
496 int i
, /* Looping var */
497 ch
, /* Current char from file */
498 lastch
, /* Previous char from file */
499 attr
, /* Current attribute */
500 line
, /* Current line */
501 column
, /* Current column */
502 page_column
; /* Current page column */
503 int num_options
; /* Number of print options */
504 cups_option_t
*options
; /* Print options */
505 const char *val
; /* Option value */
506 char keyword
[64], /* Keyword string */
507 *keyptr
; /* Pointer into string */
508 int keycol
; /* Column where keyword starts */
509 int ccomment
; /* Inside a C-style comment? */
510 int cstring
; /* Inside a C string */
514 * Make sure status messages are not buffered...
517 setbuf(stderr
, NULL
);
520 * Check command-line...
523 if (argc
< 6 || argc
> 7)
525 fprintf(stderr
, "ERROR: %s job-id user title copies options [file]\n",
531 * If we have 7 arguments, print the file named on the command-line.
532 * Otherwise, send stdin instead...
540 * Try to open the print file...
543 if ((fp
= fopen(argv
[6], "rb")) == NULL
)
545 perror("ERROR: unable to open print file - ");
551 * Process command-line options and write the prolog...
555 num_options
= cupsParseOptions(argv
[5], 0, &options
);
557 if ((val
= cupsGetOption("prettyprint", num_options
, options
)) != NULL
&&
558 strcasecmp(val
, "no") != 0 && strcasecmp(val
, "off") != 0 &&
559 strcasecmp(val
, "false") != 0)
562 PageRight
= PageWidth
- 36.0f
;
563 PageBottom
= PageBottom
> 36.0f
? PageBottom
: 36.0f
;
564 PageTop
= PageLength
- 36.0f
;
568 if ((val
= getenv("CONTENT_TYPE")) == NULL
)
570 PrettyPrint
= PRETTY_CODE
;
571 NumKeywords
= sizeof(code_keywords
) / sizeof(code_keywords
[0]);
572 Keywords
= code_keywords
;
574 else if (strcasecmp(val
, "application/x-cshell") == 0)
576 PrettyPrint
= PRETTY_SHELL
;
577 NumKeywords
= sizeof(csh_keywords
) / sizeof(csh_keywords
[0]);
578 Keywords
= csh_keywords
;
580 else if (strcasecmp(val
, "application/x-perl") == 0)
582 PrettyPrint
= PRETTY_PERL
;
583 NumKeywords
= sizeof(perl_keywords
) / sizeof(perl_keywords
[0]);
584 Keywords
= perl_keywords
;
586 else if (strcasecmp(val
, "application/x-shell") == 0)
588 PrettyPrint
= PRETTY_SHELL
;
589 NumKeywords
= sizeof(sh_keywords
) / sizeof(sh_keywords
[0]);
590 Keywords
= sh_keywords
;
594 PrettyPrint
= PRETTY_CODE
;
595 NumKeywords
= sizeof(code_keywords
) / sizeof(code_keywords
[0]);
596 Keywords
= code_keywords
;
600 ppd
= SetCommonOptions(num_options
, options
, 1);
602 if ((val
= cupsGetOption("wrap", num_options
, options
)) == NULL
)
605 WrapLines
= strcasecmp(val
, "true") == 0;
607 if ((val
= cupsGetOption("columns", num_options
, options
)) != NULL
)
608 PageColumns
= atoi(val
);
610 if ((val
= cupsGetOption("cpi", num_options
, options
)) != NULL
)
611 CharsPerInch
= atof(val
);
613 if ((val
= cupsGetOption("lpi", num_options
, options
)) != NULL
)
614 LinesPerInch
= atof(val
);
617 PageTop
-= 216.0f
/ LinesPerInch
;
619 Copies
= atoi(argv
[4]);
621 WriteProlog(argv
[3], argv
[2], getenv("CLASSIFICATION"),
622 cupsGetOption("page-label", num_options
, options
), ppd
);
625 * Read text from the specified source and print it...
638 while ((ch
= getutf8(fp
)) >= 0)
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)
656 case 0x08 : /* BS - backspace for boldface & underline */
664 case 0x09 : /* HT - tab to next 8th column */
665 if (PrettyPrint
&& keyptr
> keyword
)
670 if (bsearch(&keyptr
, Keywords
, NumKeywords
, sizeof(char *),
674 * Put keywords in boldface...
677 i
= page_column
* (ColumnWidth
+ ColumnGutter
);
679 while (keycol
< column
)
681 Page
[line
][keycol
+ i
].attr
|= ATTR_BOLD
;
687 column
= (column
+ 8) & ~7;
689 if (column
>= ColumnWidth
&& WrapLines
)
690 { /* Wrap text to margins */
694 if (line
>= SizeLines
)
699 if (page_column
>= PageColumns
)
713 * All but MacOS/Darwin treat CR as was intended by ANSI
714 * folks, namely to move to column 0/1. Some programs still
715 * use this to do boldfacing and underlining...
722 * MacOS/Darwin still need to treat CR as a line ending.
727 if ((nextch
= getc(fp
)) != 0x0a)
732 #endif /* !__APPLE__ */
734 case 0x0a : /* LF - output current line */
735 if (PrettyPrint
&& keyptr
> keyword
)
740 if (bsearch(&keyptr
, Keywords
, NumKeywords
, sizeof(char *),
744 * Put keywords in boldface...
747 i
= page_column
* (ColumnWidth
+ ColumnGutter
);
749 while (keycol
< column
)
751 Page
[line
][keycol
+ i
].attr
|= ATTR_BOLD
;
761 if (!ccomment
&& !cstring
)
762 attr
&= ~(ATTR_ITALIC
| ATTR_BOLD
| ATTR_RED
| ATTR_GREEN
| ATTR_BLUE
);
764 if (line
>= SizeLines
)
769 if (page_column
>= PageColumns
)
777 case 0x0b : /* VT - move up 1 line */
784 if (!ccomment
&& !cstring
)
785 attr
&= ~(ATTR_ITALIC
| ATTR_BOLD
| ATTR_RED
| ATTR_GREEN
| ATTR_BLUE
);
788 case 0x0c : /* FF - eject current page... */
789 if (PrettyPrint
&& keyptr
> keyword
)
794 if (bsearch(&keyptr
, Keywords
, NumKeywords
, sizeof(char *),
798 * Put keywords in boldface...
801 i
= page_column
* (ColumnWidth
+ ColumnGutter
);
803 while (keycol
< column
)
805 Page
[line
][keycol
+ i
].attr
|= ATTR_BOLD
;
816 if (!ccomment
&& !cstring
)
817 attr
&= ~(ATTR_ITALIC
| ATTR_BOLD
| ATTR_RED
| ATTR_GREEN
| ATTR_BLUE
);
819 if (page_column
>= PageColumns
)
826 case 0x1b : /* Escape sequence */
831 * ESC 7 Reverse full line (0x1b 0x37)
840 * ESC 8 Reverse half line (0x1b 0x38)
843 if ((attr
& ATTR_RAISED
) && line
> 0)
845 attr
&= ~ATTR_RAISED
;
848 else if (attr
& ATTR_LOWERED
)
849 attr
&= ~ATTR_LOWERED
;
856 * ESC 9 Forward half line (0x1b 0x39)
859 if ((attr
& ATTR_LOWERED
) && line
< (SizeLines
- 1))
861 attr
&= ~ATTR_LOWERED
;
864 else if (attr
& ATTR_RAISED
)
865 attr
&= ~ATTR_RAISED
;
867 attr
|= ATTR_LOWERED
;
871 default : /* All others... */
873 break; /* Ignore other control chars */
878 * Do highlighting of C/C++ keywords, preprocessor commands,
882 if ((ch
== ' ' || ch
== '\t') && (attr
& ATTR_BOLD
))
885 * Stop bolding preprocessor command...
890 else if (!(isalnum(ch
) || ch
== '_') && keyptr
> keyword
)
893 * Look for a keyword...
899 if (!(attr
& ATTR_ITALIC
) &&
900 bsearch(&keyptr
, Keywords
, NumKeywords
, sizeof(char *),
904 * Put keywords in boldface...
907 i
= page_column
* (ColumnWidth
+ ColumnGutter
);
909 while (keycol
< column
)
911 Page
[line
][keycol
+ i
].attr
|= ATTR_BOLD
;
916 else if ((isalnum(ch
) || ch
== '_') && !ccomment
&& !cstring
)
919 * Add characters to the current keyword (if they'll fit).
922 if (keyptr
== keyword
)
925 if (keyptr
< (keyword
+ sizeof(keyword
) - 1))
928 else if (ch
== '\"' && lastch
!= '\\' && !ccomment
&& !cstring
)
931 * Start a C string constant...
937 else if (ch
== '*' && lastch
== '/' && !cstring
&&
938 PrettyPrint
!= PRETTY_SHELL
)
941 * Start a C-style comment...
945 attr
|= ATTR_ITALIC
| ATTR_GREEN
;
947 else if (ch
== '/' && lastch
== '/' && !cstring
&&
948 PrettyPrint
== PRETTY_CODE
)
951 * Start a C++-style comment...
954 attr
|= ATTR_ITALIC
| ATTR_GREEN
;
956 else if (ch
== '#' && !cstring
&& PrettyPrint
!= PRETTY_CODE
)
959 * Start a shell-style comment...
962 attr
|= ATTR_ITALIC
| ATTR_GREEN
;
964 else if (ch
== '#' && column
== 0 && !ccomment
&& !cstring
&&
965 PrettyPrint
== PRETTY_CODE
)
968 * Start a preprocessor command...
971 attr
|= ATTR_BOLD
| ATTR_RED
;
975 if (column
>= ColumnWidth
&& WrapLines
)
976 { /* Wrap text to margins */
980 if (line
>= SizeLines
)
985 if (page_column
>= PageColumns
)
994 * Add text to the current column & line...
997 if (column
< ColumnWidth
)
999 i
= column
+ page_column
* (ColumnWidth
+ ColumnGutter
);
1002 Page
[line
][i
].attr
= attr
;
1003 else if (ch
== ' ' && Page
[line
][i
].ch
)
1004 ch
= Page
[line
][i
].ch
;
1005 else if (ch
== Page
[line
][i
].ch
)
1006 Page
[line
][i
].attr
|= ATTR_BOLD
;
1007 else if (Page
[line
][i
].ch
== '_')
1008 Page
[line
][i
].attr
|= ATTR_UNDERLINE
;
1011 Page
[line
][i
].attr
|= ATTR_UNDERLINE
;
1013 if (Page
[line
][i
].ch
)
1014 ch
= Page
[line
][i
].ch
;
1017 Page
[line
][i
].attr
= attr
;
1019 Page
[line
][i
].ch
= ch
;
1024 if ((ch
== '{' || ch
== '}') && !ccomment
&& !cstring
&&
1025 column
< ColumnWidth
)
1028 * Highlight curley braces...
1031 Page
[line
][column
].attr
|= ATTR_BOLD
;
1033 else if ((ch
== '/' || ch
== '*') && lastch
== '/' &&
1034 column
< ColumnWidth
&& PrettyPrint
!= PRETTY_SHELL
)
1037 * Highlight first comment character...
1040 Page
[line
][column
- 1].attr
= attr
;
1042 else if (ch
== '\"' && lastch
!= '\\' && !ccomment
&& cstring
> 0)
1045 * End a C string constant...
1051 else if (ch
== '/' && lastch
== '*' && ccomment
)
1054 * End a C-style comment...
1058 attr
&= ~(ATTR_ITALIC
| ATTR_GREEN
);
1070 * Save this character for the next cycle.
1077 * Write any remaining page data...
1080 if (line
> 0 || page_column
> 0 || column
> 0)
1084 * Write the epilog and return...
1097 * 'compare_keywords()' - Compare two C/C++ keywords.
1100 static int /* O - Result of strcmp */
1101 compare_keywords(const void *k1
, /* I - First keyword */
1102 const void *k2
) /* I - Second keyword */
1104 return (strcmp(*((const char **)k1
), *((const char **)k2
)));
1109 * 'getutf8()' - Get a UTF-8 encoded wide character...
1112 static int /* O - Character or -1 on error */
1113 getutf8(FILE *fp
) /* I - File to read from */
1115 int ch
; /* Current character value */
1116 int next
; /* Next character from file */
1120 * Read the first character and process things accordingly...
1122 * UTF-8 maps 16-bit characters to:
1124 * 0 to 127 = 0xxxxxxx
1125 * 128 to 2047 = 110xxxxx 10yyyyyy (xxxxxyyyyyy)
1126 * 2048 to 65535 = 1110xxxx 10yyyyyy 10zzzzzz (xxxxyyyyyyzzzzzz)
1130 * 128 to 191 = 10xxxxxx
1132 * since this range of values is otherwise undefined unless you are
1133 * in the middle of a multi-byte character...
1135 * This code currently does not support anything beyond 16-bit
1136 * characters, in part because PostScript doesn't support more than
1137 * 16-bit characters...
1140 if ((ch
= getc(fp
)) == EOF
)
1143 if (ch
< 0xc0 || !UTF8
) /* One byte character? */
1145 else if ((ch
& 0xe0) == 0xc0)
1148 * Two byte character...
1151 if ((next
= getc(fp
)) == EOF
)
1154 return (((ch
& 0x1f) << 6) | (next
& 0x3f));
1156 else if ((ch
& 0xf0) == 0xe0)
1159 * Three byte character...
1162 if ((next
= getc(fp
)) == EOF
)
1165 ch
= ((ch
& 0x0f) << 6) | (next
& 0x3f);
1167 if ((next
= getc(fp
)) == EOF
)
1170 return ((ch
<< 6) | (next
& 0x3f));
1175 * More than three bytes... We don't support that...
1184 * End of "$Id: textcommon.c,v 1.16.2.10 2002/08/19 16:49:52 mike Exp $".