]>
git.ipfire.org Git - thirdparty/cups.git/blob - filter/textcommon.c
4 * Common text filter routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-1999 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
26 * TextMain() - Standard main entry for text filters.
27 * compare_keywords() - Compare two C/C++ keywords.
28 * getutf8() - Get a UTF-8 encoded wide character...
32 * Include necessary headers...
35 #include "textcommon.h"
42 int WrapLines
= 1, /* Wrap text in lines */
43 SizeLines
= 60, /* Number of lines on a page */
44 SizeColumns
= 80, /* Number of columns on a line */
45 PageColumns
= 1, /* Number of columns on a page */
46 ColumnGutter
= 0, /* Number of characters between text columns */
47 ColumnWidth
= 80, /* Width of each column */
48 PrettyPrint
= 0, /* Do pretty code formatting */
49 Copies
= 1; /* Number of copies */
50 lchar_t
**Page
= NULL
; /* Page characters */
51 int NumPages
= 0; /* Number of pages in document */
52 int CharsPerInch
= 10; /* Number of character columns per inch */
53 int LinesPerInch
= 6; /* Number of lines per inch */
54 int UTF8
= 0; /* Use UTF-8 encoding? */
55 char *Keywords
[] = /* List of known keywords... */
130 static int compare_keywords(const void *, const void *);
131 static int getutf8(FILE *fp
);
135 * 'TextMain()' - Standard main entry for text filters.
138 int /* O - Exit status */
139 TextMain(char *name
, /* I - Name of filter */
140 int argc
, /* I - Number of command-line arguments */
141 char *argv
[]) /* I - Command-line arguments */
143 FILE *fp
; /* Print file */
144 ppd_file_t
*ppd
; /* PPD file */
145 int i
, /* Looping var */
146 ch
, /* Current char from file */
147 lastch
, /* Previous char from file */
148 attr
, /* Current attribute */
149 line
, /* Current line */
150 column
, /* Current column */
151 page_column
; /* Current page column */
152 int num_options
; /* Number of print options */
153 cups_option_t
*options
; /* Print options */
154 const char *val
; /* Option value */
155 char keyword
[64], /* Keyword string */
156 *keyptr
; /* Pointer into string */
157 int keycol
; /* Column where keyword starts */
158 int ccomment
; /* Inside a C-style comment? */
159 int cstring
; /* Inside a C string */
162 if (argc
< 6 || argc
> 7)
164 fprintf(stderr
, "ERROR: %s job-id user title copies options [file]\n",
170 * If we have 7 arguments, print the file named on the command-line.
171 * Otherwise, send stdin instead...
179 * Try to open the print file...
182 if ((fp
= fopen(argv
[6], "rb")) == NULL
)
184 perror("ERROR: unable to open print file - ");
190 * Process command-line options and write the prolog...
194 num_options
= cupsParseOptions(argv
[5], 0, &options
);
196 if ((val
= cupsGetOption("prettyprint", num_options
, options
)) != NULL
)
200 PageRight
= PageWidth
- 36.0f
;
201 PageBottom
= PageBottom
> 36.0f
? PageBottom
: 36.0f
;
202 PageTop
= PageLength
- 36.0f
;
207 if ((ppd
= SetCommonOptions(num_options
, options
, 1)) != NULL
)
210 WrapLines
= cupsGetOption("nowrap", num_options
, options
) == NULL
;
212 if ((val
= cupsGetOption("columns", num_options
, options
)) != NULL
)
213 PageColumns
= atoi(val
);
215 if ((val
= cupsGetOption("cpi", num_options
, options
)) != NULL
)
216 CharsPerInch
= atoi(val
);
218 if ((val
= cupsGetOption("lpi", num_options
, options
)) != NULL
)
219 LinesPerInch
= atoi(val
);
221 if ((val
= cupsGetOption("prettyprint", num_options
, options
)) != NULL
)
222 PageTop
-= 216.0f
/ LinesPerInch
;
224 Copies
= atoi(argv
[4]);
226 WriteProlog(argv
[3], argv
[2], ppd
);
229 * Read text from the specified source and print it...
241 while ((ch
= getutf8(fp
)) >= 0)
246 * BS Backspace (0x08)
247 * HT Horizontal tab; next 8th column (0x09)
248 * LF Line feed; forward full line (0x0a)
249 * VT Vertical tab; reverse full line (0x0b)
250 * FF Form feed (0x0c)
251 * CR Carriage return (0x0d)
252 * ESC 7 Reverse full line (0x1b 0x37)
253 * ESC 8 Reverse half line (0x1b 0x38)
254 * ESC 9 Forward half line (0x1b 0x39)
259 case 0x08 : /* BS - backspace for boldface & underline */
267 case 0x09 : /* HT - tab to next 8th column */
268 if (PrettyPrint
&& keyptr
> keyword
)
273 if (bsearch(&keyptr
, Keywords
, sizeof(Keywords
) / sizeof(Keywords
[0]),
274 sizeof(Keywords
[0]), compare_keywords
))
277 * Put keywords in boldface...
280 i
= page_column
* (ColumnWidth
+ ColumnGutter
);
282 while (keycol
< column
)
284 Page
[line
][keycol
+ i
].attr
|= ATTR_BOLD
;
290 column
= (column
+ 8) & ~7;
292 if (column
>= ColumnWidth
&& WrapLines
)
293 { /* Wrap text to margins */
297 if (line
>= SizeLines
)
302 if (page_column
>= PageColumns
)
313 case 0x0a : /* LF - output current line */
314 if (PrettyPrint
&& keyptr
> keyword
)
319 if (bsearch(&keyptr
, Keywords
, sizeof(Keywords
) / sizeof(Keywords
[0]),
320 sizeof(Keywords
[0]), compare_keywords
))
323 * Put keywords in boldface...
326 i
= page_column
* (ColumnWidth
+ ColumnGutter
);
328 while (keycol
< column
)
330 Page
[line
][keycol
+ i
].attr
|= ATTR_BOLD
;
340 if (!ccomment
&& !cstring
)
341 attr
&= ~(ATTR_ITALIC
| ATTR_BOLD
| ATTR_RED
| ATTR_GREEN
| ATTR_BLUE
);
343 if (line
>= SizeLines
)
348 if (page_column
>= PageColumns
)
356 case 0x0b : /* VT - move up 1 line */
363 if (!ccomment
&& !cstring
)
364 attr
&= ~(ATTR_ITALIC
| ATTR_BOLD
| ATTR_RED
| ATTR_GREEN
| ATTR_BLUE
);
367 case 0x0c : /* FF - eject current page... */
368 if (PrettyPrint
&& keyptr
> keyword
)
373 if (bsearch(&keyptr
, Keywords
, sizeof(Keywords
) / sizeof(Keywords
[0]),
374 sizeof(Keywords
[0]), compare_keywords
))
377 * Put keywords in boldface...
380 i
= page_column
* (ColumnWidth
+ ColumnGutter
);
382 while (keycol
< column
)
384 Page
[line
][keycol
+ i
].attr
|= ATTR_BOLD
;
395 if (!ccomment
&& !cstring
)
396 attr
&= ~(ATTR_ITALIC
| ATTR_BOLD
| ATTR_RED
| ATTR_GREEN
| ATTR_BLUE
);
398 if (page_column
>= PageColumns
)
409 case 0x1b : /* Escape sequence */
414 * ESC 7 Reverse full line (0x1b 0x37)
423 * ESC 8 Reverse half line (0x1b 0x38)
426 if ((attr
& ATTR_RAISED
) && line
> 0)
428 attr
&= ~ATTR_RAISED
;
431 else if (attr
& ATTR_LOWERED
)
432 attr
&= ~ATTR_LOWERED
;
439 * ESC 9 Forward half line (0x1b 0x39)
442 if ((attr
& ATTR_LOWERED
) && line
< (SizeLines
- 1))
444 attr
&= ~ATTR_LOWERED
;
447 else if (attr
& ATTR_RAISED
)
448 attr
&= ~ATTR_RAISED
;
450 attr
|= ATTR_LOWERED
;
454 default : /* All others... */
456 break; /* Ignore other control chars */
461 * Do highlighting of C/C++ keywords, preprocessor commands,
465 if ((ch
== ' ' || ch
== '\t') && (attr
& ATTR_BOLD
))
468 * Stop bolding preprocessor command...
473 else if (!(isalnum(ch
) || ch
== '_') && keyptr
> keyword
)
476 * Look for a keyword...
482 if (!(attr
& ATTR_ITALIC
) &&
483 bsearch(&keyptr
, Keywords
, sizeof(Keywords
) / sizeof(Keywords
[0]),
484 sizeof(Keywords
[0]), compare_keywords
))
487 * Put keywords in boldface...
490 i
= page_column
* (ColumnWidth
+ ColumnGutter
);
492 while (keycol
< column
)
494 Page
[line
][keycol
+ i
].attr
|= ATTR_BOLD
;
499 else if ((isalnum(ch
) || ch
== '_') && !ccomment
&& !cstring
)
502 * Add characters to the current keyword (if they'll fit).
505 if (keyptr
== keyword
)
508 if (keyptr
< (keyword
+ sizeof(keyword
) - 1))
511 else if (ch
== '\"' && lastch
!= '\\' && !ccomment
&& !cstring
)
514 * Start a C string constant...
520 else if (ch
== '*' && lastch
== '/' && !cstring
)
523 * Start a C-style comment...
527 attr
|= ATTR_ITALIC
| ATTR_GREEN
;
529 else if (ch
== '/' && lastch
== '/' && !cstring
)
532 * Start a C++-style comment...
535 attr
|= ATTR_ITALIC
| ATTR_GREEN
;
537 else if (ch
== '#' && column
== 0 && !ccomment
&& !cstring
)
540 * Start a preprocessor command...
543 attr
|= ATTR_BOLD
| ATTR_RED
;
547 if (column
>= ColumnWidth
&& WrapLines
)
548 { /* Wrap text to margins */
552 if (line
>= SizeLines
)
557 if (page_column
>= PageColumns
)
566 * Add text to the current column & line...
569 if (column
< ColumnWidth
)
571 i
= column
+ page_column
* (ColumnWidth
+ ColumnGutter
);
574 Page
[line
][i
].attr
= attr
;
575 else if (ch
== Page
[line
][i
].ch
)
576 Page
[line
][i
].attr
|= ATTR_BOLD
;
577 else if (Page
[line
][i
].ch
== '_')
578 Page
[line
][i
].attr
|= ATTR_UNDERLINE
;
580 Page
[line
][i
].attr
= attr
;
582 Page
[line
][i
].ch
= ch
;
587 if ((ch
== '{' || ch
== '}') && !ccomment
&& !cstring
&&
588 column
< ColumnWidth
)
591 * Highlight curley braces...
594 Page
[line
][i
].attr
|= ATTR_BOLD
;
596 else if ((ch
== '/' || ch
== '*') && lastch
== '/' &&
597 column
< ColumnWidth
)
600 * Highlight first comment character...
603 Page
[line
][i
- 1].attr
= attr
;
605 else if (ch
== '\"' && lastch
!= '\\' && !ccomment
&& cstring
> 0)
608 * End a C string constant...
614 else if (ch
== '/' && lastch
== '*' && ccomment
)
617 * End a C-style comment...
621 attr
&= ~(ATTR_ITALIC
| ATTR_GREEN
);
633 * Save this character for the next cycle.
640 * Write any remaining page data...
643 if (line
> 0 || page_column
> 0 || column
> 0)
647 * Write the epilog and return...
657 * 'compare_keywords()' - Compare two C/C++ keywords.
660 static int /* O - Result of strcmp */
661 compare_keywords(const void *k1
, /* I - First keyword */
662 const void *k2
) /* I - Second keyword */
664 return (strcmp(*((const char **)k1
), *((const char **)k2
)));
669 * 'getutf8()' - Get a UTF-8 encoded wide character...
672 static int /* O - Character or -1 on error */
673 getutf8(FILE *fp
) /* I - File to read from */
675 int ch
; /* Current character value */
676 int next
; /* Next character from file */
680 * Read the first character and process things accordingly...
682 * UTF-8 maps 16-bit characters to:
684 * 0 to 127 = 0xxxxxxx
685 * 128 to 2047 = 110xxxxx 10yyyyyy (xxxxxyyyyyy)
686 * 2048 to 65535 = 1110xxxx 10yyyyyy 10zzzzzz (xxxxyyyyyyzzzzzz)
690 * 128 to 191 = 10xxxxxx
692 * since this range of values is otherwise undefined unless you are
693 * in the middle of a multi-byte character...
695 * This code currently does not support anything beyond 16-bit
696 * characters, in part because PostScript doesn't support more than
697 * 16-bit characters...
700 if ((ch
= getc(fp
)) == EOF
)
703 if (ch
< 0xc0 || !UTF8
) /* One byte character? */
705 else if ((ch
& 0xe0) == 0xc0)
708 * Two byte character...
711 if ((next
= getc(fp
)) == EOF
)
714 return (((ch
& 0x1f) << 6) | (next
& 0x3f));
716 else if ((ch
& 0xf0) == 0xe0)
719 * Three byte character...
722 if ((next
= getc(fp
)) == EOF
)
725 ch
= ((ch
& 0x0f) << 6) | (next
& 0x3f);
727 if ((next
= getc(fp
)) == EOF
)
730 return ((ch
<< 6) | (next
& 0x3f));
735 * More than three bytes... We don't support that...