2 * "$Id: ppd.c 7552 2008-05-12 17:42:15Z mike $"
4 * PPD file routines for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2008 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
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 * PostScript is a trademark of Adobe Systems, Inc.
17 * This code and any derivative of it may be used and distributed
18 * freely under the terms of the GNU General Public License when
19 * used with GNU Ghostscript or its derivatives. Use of the code
20 * (or any derivative of it) with software other than GNU
21 * GhostScript (or its derivatives) is governed by the CUPS license
24 * This file is subject to the Apple OS-Developed Software exception.
28 * ppdClose() - Free all memory used by the PPD file.
29 * ppdErrorString() - Returns the text assocated with a status.
30 * _ppdGetEncoding() - Get the CUPS encoding value for the given
32 * ppdLastError() - Return the status from the last ppdOpen*().
33 * ppdOpen() - Read a PPD file into memory.
34 * ppdOpen2() - Read a PPD file into memory.
35 * ppdOpenFd() - Read a PPD file into memory.
36 * ppdOpenFile() - Read a PPD file into memory.
37 * ppdSetConformance() - Set the conformance level for PPD files.
38 * ppd_add_attr() - Add an attribute to the PPD data.
39 * ppd_add_choice() - Add a choice to an option.
40 * ppd_add_size() - Add a page size.
41 * ppd_compare_attrs() - Compare two attributes.
42 * ppd_compare_choices() - Compare two choices...
43 * ppd_compare_coptions() - Compare two custom options.
44 * ppd_compare_cparams() - Compare two custom parameters.
45 * ppd_compare_options() - Compare two options.
46 * ppd_decode() - Decode a string value...
47 * ppd_free_group() - Free a single UI group.
48 * ppd_free_option() - Free a single option.
49 * ppd_get_coption() - Get a custom option record.
50 * ppd_get_cparam() - Get a custom parameter record.
51 * ppd_get_group() - Find or create the named group as needed.
52 * ppd_get_option() - Find or create the named option as needed.
53 * ppd_hash_option() - Generate a hash of the option name...
54 * ppd_read() - Read a line from a PPD file, skipping comment
59 * Include necessary headers.
71 #if defined(WIN32) || defined(__EMX__)
72 # define READ_BINARY "rb" /* Open a binary file for reading */
73 # define WRITE_BINARY "wb" /* Open a binary file for writing */
75 # define READ_BINARY "r" /* Open a binary file for reading */
76 # define WRITE_BINARY "w" /* Open a binary file for writing */
77 #endif /* WIN32 || __EMX__ */
79 #define ppd_free(p) if (p) free(p) /* Safe free macro */
81 #define PPD_KEYWORD 1 /* Line contained a keyword */
82 #define PPD_OPTION 2 /* Line contained an option name */
83 #define PPD_TEXT 4 /* Line contained human-readable text */
84 #define PPD_STRING 8 /* Line contained a string or code */
86 #define PPD_HASHSIZE 512 /* Size of hash */
90 * Line buffer structure...
93 typedef struct _ppd_line_s
95 char *buffer
; /* Pointer to buffer */
96 size_t bufsize
; /* Size of the buffer */
104 static ppd_attr_t
*ppd_add_attr(ppd_file_t
*ppd
, const char *name
,
105 const char *spec
, const char *text
,
107 static ppd_choice_t
*ppd_add_choice(ppd_option_t
*option
, const char *name
);
108 static ppd_size_t
*ppd_add_size(ppd_file_t
*ppd
, const char *name
);
109 static int ppd_compare_attrs(ppd_attr_t
*a
, ppd_attr_t
*b
);
110 static int ppd_compare_choices(ppd_choice_t
*a
, ppd_choice_t
*b
);
111 static int ppd_compare_coptions(ppd_coption_t
*a
,
113 static int ppd_compare_cparams(ppd_cparam_t
*a
, ppd_cparam_t
*b
);
114 static int ppd_compare_options(ppd_option_t
*a
, ppd_option_t
*b
);
115 static int ppd_decode(char *string
);
116 static void ppd_free_group(ppd_group_t
*group
);
117 static void ppd_free_option(ppd_option_t
*option
);
118 static ppd_coption_t
*ppd_get_coption(ppd_file_t
*ppd
, const char *name
);
119 static ppd_cparam_t
*ppd_get_cparam(ppd_coption_t
*opt
,
122 static ppd_group_t
*ppd_get_group(ppd_file_t
*ppd
, const char *name
,
123 const char *text
, _cups_globals_t
*cg
,
124 cups_encoding_t encoding
);
125 static ppd_option_t
*ppd_get_option(ppd_group_t
*group
, const char *name
);
126 static int ppd_hash_option(ppd_option_t
*option
);
127 static int ppd_read(cups_file_t
*fp
, _ppd_line_t
*line
,
128 char *keyword
, char *option
, char *text
,
129 char **string
, int ignoreblank
,
130 _cups_globals_t
*cg
);
134 * 'ppdClose()' - Free all memory used by the PPD file.
138 ppdClose(ppd_file_t
*ppd
) /* I - PPD file record */
140 int i
; /* Looping var */
141 ppd_emul_t
*emul
; /* Current emulation */
142 ppd_group_t
*group
; /* Current group */
143 char **font
; /* Current font */
144 char **filter
; /* Current filter */
145 ppd_attr_t
**attr
; /* Current attribute */
146 ppd_coption_t
*coption
; /* Current custom option */
147 ppd_cparam_t
*cparam
; /* Current custom parameter */
151 * Range check arguments...
158 * Free all strings at the top level...
161 _cupsStrFree(ppd
->lang_encoding
);
162 _cupsStrFree(ppd
->nickname
);
163 _cupsStrFree(ppd
->patches
);
164 _cupsStrFree(ppd
->jcl_begin
);
165 _cupsStrFree(ppd
->jcl_end
);
166 _cupsStrFree(ppd
->jcl_ps
);
169 * Free any emulations...
172 if (ppd
->num_emulations
> 0)
174 for (i
= ppd
->num_emulations
, emul
= ppd
->emulations
; i
> 0; i
--, emul
++)
176 _cupsStrFree(emul
->start
);
177 _cupsStrFree(emul
->stop
);
180 ppd_free(ppd
->emulations
);
184 * Free any UI groups, subgroups, and options...
187 if (ppd
->num_groups
> 0)
189 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
190 ppd_free_group(group
);
192 ppd_free(ppd
->groups
);
195 cupsArrayDelete(ppd
->options
);
196 cupsArrayDelete(ppd
->marked
);
199 * Free any page sizes...
202 if (ppd
->num_sizes
> 0)
203 ppd_free(ppd
->sizes
);
206 * Free any constraints...
209 if (ppd
->num_consts
> 0)
210 ppd_free(ppd
->consts
);
213 * Free any filters...
216 if (ppd
->num_filters
> 0)
218 for (i
= ppd
->num_filters
, filter
= ppd
->filters
; i
> 0; i
--, filter
++)
219 _cupsStrFree(*filter
);
221 ppd_free(ppd
->filters
);
228 if (ppd
->num_fonts
> 0)
230 for (i
= ppd
->num_fonts
, font
= ppd
->fonts
; i
> 0; i
--, font
++)
233 ppd_free(ppd
->fonts
);
237 * Free any profiles...
240 if (ppd
->num_profiles
> 0)
241 ppd_free(ppd
->profiles
);
244 * Free any attributes...
247 if (ppd
->num_attrs
> 0)
249 for (i
= ppd
->num_attrs
, attr
= ppd
->attrs
; i
> 0; i
--, attr
++)
251 _cupsStrFree((*attr
)->value
);
255 ppd_free(ppd
->attrs
);
258 cupsArrayDelete(ppd
->sorted_attrs
);
261 * Free custom options...
264 for (coption
= (ppd_coption_t
*)cupsArrayFirst(ppd
->coptions
);
266 coption
= (ppd_coption_t
*)cupsArrayNext(ppd
->coptions
))
268 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
270 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
272 switch (cparam
->type
)
274 case PPD_CUSTOM_PASSCODE
:
275 case PPD_CUSTOM_PASSWORD
:
276 case PPD_CUSTOM_STRING
:
277 _cupsStrFree(cparam
->current
.custom_string
);
287 cupsArrayDelete(coption
->params
);
292 cupsArrayDelete(ppd
->coptions
);
295 * Free the whole record...
303 * 'ppdErrorString()' - Returns the text assocated with a status.
305 * @since CUPS 1.1.19@
308 const char * /* O - Status string */
309 ppdErrorString(ppd_status_t status
) /* I - PPD status */
311 static const char * const messages
[] =/* Status messages */
314 _("Unable to open PPD file"),
315 _("NULL PPD file pointer"),
316 _("Memory allocation error"),
317 _("Missing PPD-Adobe-4.x header"),
318 _("Missing value string"),
321 _("OpenGroup without a CloseGroup first"),
322 _("Bad OpenUI/JCLOpenUI"),
323 _("OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"),
324 _("Bad OrderDependency"),
325 _("Bad UIConstraints"),
326 _("Missing asterisk in column 1"),
327 _("Line longer than the maximum allowed (255 characters)"),
328 _("Illegal control character"),
329 _("Illegal main keyword string"),
330 _("Illegal option keyword string"),
331 _("Illegal translation string"),
332 _("Illegal whitespace character"),
333 _("Bad custom parameter")
337 if (status
< PPD_OK
|| status
> PPD_ILLEGAL_WHITESPACE
)
338 return (_cupsLangString(cupsLangDefault(), _("Unknown")));
340 return (_cupsLangString(cupsLangDefault(), messages
[status
]));
345 * '_ppdGetEncoding()' - Get the CUPS encoding value for the given
349 cups_encoding_t
/* O - CUPS encoding value */
350 _ppdGetEncoding(const char *name
) /* I - LanguageEncoding string */
352 if (!strcasecmp(name
, "ISOLatin1"))
353 return (CUPS_ISO8859_1
);
354 else if (!strcasecmp(name
, "ISOLatin2"))
355 return (CUPS_ISO8859_2
);
356 else if (!strcasecmp(name
, "ISOLatin5"))
357 return (CUPS_ISO8859_5
);
358 else if (!strcasecmp(name
, "JIS83-RKSJ"))
359 return (CUPS_WINDOWS_932
);
360 else if (!strcasecmp(name
, "MacStandard"))
361 return (CUPS_MAC_ROMAN
);
362 else if (!strcasecmp(name
, "WindowsANSI"))
363 return (CUPS_WINDOWS_1252
);
370 * 'ppdLastError()' - Return the status from the last ppdOpen*().
372 * @since CUPS 1.1.19@
375 ppd_status_t
/* O - Status code */
376 ppdLastError(int *line
) /* O - Line number */
378 _cups_globals_t
*cg
= _cupsGlobals();
383 *line
= cg
->ppd_line
;
385 return (cg
->ppd_status
);
390 * 'ppdOpen()' - Read a PPD file into memory.
393 ppd_file_t
* /* O - PPD file record */
394 ppdOpen(FILE *fp
) /* I - File to read from */
396 ppd_file_t
*ppd
; /* PPD file record */
397 cups_file_t
*cf
; /* CUPS file */
401 * Reopen the stdio file as a CUPS file...
404 if ((cf
= cupsFileOpenFd(fileno(fp
), "r")) == NULL
)
408 * Load the PPD file using the newer API...
414 * Close the CUPS file and return the PPD...
424 * 'ppdOpen2()' - Read a PPD file into memory.
429 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
430 ppdOpen2(cups_file_t
*fp
) /* I - File to read from */
432 int i
, j
, k
; /* Looping vars */
433 int count
; /* Temporary count */
434 _ppd_line_t line
; /* Line buffer */
435 ppd_file_t
*ppd
; /* PPD file record */
436 ppd_group_t
*group
, /* Current group */
437 *subgroup
; /* Current sub-group */
438 ppd_option_t
*option
; /* Current option */
439 ppd_choice_t
*choice
; /* Current choice */
440 ppd_const_t
*constraint
; /* Current constraint */
441 ppd_size_t
*size
; /* Current page size */
442 int mask
; /* Line data mask */
443 char keyword
[PPD_MAX_NAME
],
444 /* Keyword from file */
446 /* Option from file */
448 /* Human-readable text from file */
449 *string
, /* Code/text from file */
450 *sptr
, /* Pointer into string */
451 *nameptr
, /* Pointer into name */
452 *temp
, /* Temporary string pointer */
453 **tempfonts
; /* Temporary fonts pointer */
454 float order
; /* Order dependency number */
455 ppd_section_t section
; /* Order dependency section */
456 ppd_profile_t
*profile
; /* Pointer to color profile */
457 char **filter
; /* Pointer to filter */
458 cups_lang_t
*language
; /* Default language */
459 struct lconv
*loc
; /* Locale data */
460 int ui_keyword
; /* Is this line a UI keyword? */
461 cups_encoding_t encoding
; /* Encoding of PPD file */
462 _cups_globals_t
*cg
= _cupsGlobals();
464 char custom_name
[PPD_MAX_NAME
];
465 /* CustomFoo attribute name */
466 ppd_attr_t
*custom_attr
; /* CustomFoo attribute */
467 static const char * const ui_keywords
[] =
469 #ifdef CUPS_USE_FULL_UI_KEYWORDS_LIST
471 * Adobe defines some 41 keywords as "UI", meaning that they are
472 * user interface elements and that they should be treated as such
473 * even if the PPD creator doesn't use Open/CloseUI around them.
475 * Since this can cause previously invisible options to appear and
476 * confuse users, the default is to only treat the PageSize and
477 * PageRegion keywords this way.
479 /* Boolean keywords */
489 /* PickOne keywords */
502 "JCLFrameBufferSize",
523 #else /* !CUPS_USE_FULL_UI_KEYWORDS_LIST */
526 #endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */
531 * Default to "OK" status...
534 cg
->ppd_status
= PPD_OK
;
538 * Range check input...
543 cg
->ppd_status
= PPD_NULL_FILE
;
548 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
554 mask
= ppd_read(fp
, &line
, keyword
, name
, text
, &string
, 0, cg
);
556 DEBUG_printf(("mask=%x, keyword=\"%s\"...\n", mask
, keyword
));
559 strcmp(keyword
, "PPD-Adobe") ||
560 string
== NULL
|| string
[0] != '4')
563 * Either this is not a PPD file, or it is not a 4.x PPD file.
566 if (cg
->ppd_status
== PPD_OK
)
567 cg
->ppd_status
= PPD_MISSING_PPDADOBE4
;
569 _cupsStrFree(string
);
574 DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword
, string
));
576 _cupsStrFree(string
);
579 * Allocate memory for the PPD file record...
582 if ((ppd
= calloc(1, sizeof(ppd_file_t
))) == NULL
)
584 cg
->ppd_status
= PPD_ALLOC_ERROR
;
589 ppd
->language_level
= 2;
590 ppd
->color_device
= 0;
591 ppd
->colorspace
= PPD_CS_N
;
592 ppd
->landscape
= -90;
593 ppd
->coptions
= cupsArrayNew((cups_array_func_t
)ppd_compare_coptions
,
597 * Get the default language for the user...
600 language
= cupsLangDefault();
604 * Read lines from the PPD file and add them to the file record...
612 encoding
= CUPS_ISO8859_1
;
614 while ((mask
= ppd_read(fp
, &line
, keyword
, name
, text
, &string
, 1, cg
)) != 0)
616 DEBUG_printf(("mask=%x, keyword=\"%s\", name=\"%s\", text=\"%s\", "
617 "string=%d chars...", mask
, keyword
, name
, text
,
618 string
? (int)strlen(string
) : 0));
620 if (strncmp(keyword
, "Default", 7) && !string
)
623 * Need a string value!
626 cg
->ppd_status
= PPD_MISSING_VALUE
;
632 * Certain main keywords (as defined by the PPD spec) may be used
633 * without the usual OpenUI/CloseUI stuff. Presumably this is just
634 * so that Adobe wouldn't completely break compatibility with PPD
635 * files prior to v4.0 of the spec, but it is hopelessly
636 * inconsistent... Catch these main keywords and automatically
637 * create the corresponding option, as needed...
643 * Previous line was a UI keyword...
650 if (option
== NULL
&&
651 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
652 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
))
654 for (i
= 0; i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])); i
++)
655 if (!strcmp(keyword
, ui_keywords
[i
]))
658 if (i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])))
661 * Create the option in the appropriate group...
666 DEBUG_printf(("**** FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!\n",
671 if ((group
= ppd_get_group(ppd
, "General", _("General"), cg
,
675 DEBUG_printf(("Adding to group %s...\n", group
->text
));
676 option
= ppd_get_option(group
, keyword
);
680 option
= ppd_get_option(group
, keyword
);
684 cg
->ppd_status
= PPD_ALLOC_ERROR
;
690 * Now fill in the initial information for the option...
693 if (!strncmp(keyword
, "JCL", 3))
694 option
->section
= PPD_ORDER_JCL
;
696 option
->section
= PPD_ORDER_ANY
;
698 option
->order
= 10.0f
;
701 option
->ui
= PPD_UI_BOOLEAN
;
703 option
->ui
= PPD_UI_PICKONE
;
705 for (j
= 0; j
< ppd
->num_attrs
; j
++)
706 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
707 !strcmp(ppd
->attrs
[j
]->name
+ 7, keyword
) &&
708 ppd
->attrs
[j
]->value
)
710 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
711 option
->keyword
, ppd
->attrs
[j
]->value
));
712 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
713 sizeof(option
->defchoice
));
717 if (!strcmp(keyword
, "PageSize"))
718 strlcpy(option
->text
, _("Media Size"), sizeof(option
->text
));
719 else if (!strcmp(keyword
, "MediaType"))
720 strlcpy(option
->text
, _("Media Type"), sizeof(option
->text
));
721 else if (!strcmp(keyword
, "InputSlot"))
722 strlcpy(option
->text
, _("Media Source"), sizeof(option
->text
));
723 else if (!strcmp(keyword
, "ColorModel"))
724 strlcpy(option
->text
, _("Output Mode"), sizeof(option
->text
));
725 else if (!strcmp(keyword
, "Resolution"))
726 strlcpy(option
->text
, _("Resolution"), sizeof(option
->text
));
728 strlcpy(option
->text
, keyword
, sizeof(option
->text
));
732 if (!strcmp(keyword
, "LanguageLevel"))
733 ppd
->language_level
= atoi(string
);
734 else if (!strcmp(keyword
, "LanguageEncoding"))
737 * Say all PPD files are UTF-8, since we convert to UTF-8...
740 ppd
->lang_encoding
= _cupsStrAlloc("UTF-8");
741 encoding
= _ppdGetEncoding(string
);
743 else if (!strcmp(keyword
, "LanguageVersion"))
744 ppd
->lang_version
= string
;
745 else if (!strcmp(keyword
, "Manufacturer"))
746 ppd
->manufacturer
= string
;
747 else if (!strcmp(keyword
, "ModelName"))
748 ppd
->modelname
= string
;
749 else if (!strcmp(keyword
, "Protocols"))
750 ppd
->protocols
= string
;
751 else if (!strcmp(keyword
, "PCFileName"))
752 ppd
->pcfilename
= string
;
753 else if (!strcmp(keyword
, "NickName"))
755 if (encoding
!= CUPS_UTF8
)
757 cups_utf8_t utf8
[256]; /* UTF-8 version of NickName */
760 cupsCharsetToUTF8(utf8
, string
, sizeof(utf8
), encoding
);
761 ppd
->nickname
= _cupsStrAlloc((char *)utf8
);
764 ppd
->nickname
= _cupsStrAlloc(string
);
766 else if (!strcmp(keyword
, "Product"))
767 ppd
->product
= string
;
768 else if (!strcmp(keyword
, "ShortNickName"))
769 ppd
->shortnickname
= string
;
770 else if (!strcmp(keyword
, "TTRasterizer"))
771 ppd
->ttrasterizer
= string
;
772 else if (!strcmp(keyword
, "JCLBegin"))
774 ppd
->jcl_begin
= _cupsStrAlloc(string
);
775 ppd_decode(ppd
->jcl_begin
); /* Decode quoted string */
777 else if (!strcmp(keyword
, "JCLEnd"))
779 ppd
->jcl_end
= _cupsStrAlloc(string
);
780 ppd_decode(ppd
->jcl_end
); /* Decode quoted string */
782 else if (!strcmp(keyword
, "JCLToPSInterpreter"))
784 ppd
->jcl_ps
= _cupsStrAlloc(string
);
785 ppd_decode(ppd
->jcl_ps
); /* Decode quoted string */
787 else if (!strcmp(keyword
, "AccurateScreensSupport"))
788 ppd
->accurate_screens
= !strcmp(string
, "True");
789 else if (!strcmp(keyword
, "ColorDevice"))
790 ppd
->color_device
= !strcmp(string
, "True");
791 else if (!strcmp(keyword
, "ContoneOnly"))
792 ppd
->contone_only
= !strcmp(string
, "True");
793 else if (!strcmp(keyword
, "cupsFlipDuplex"))
794 ppd
->flip_duplex
= !strcmp(string
, "True");
795 else if (!strcmp(keyword
, "cupsManualCopies"))
796 ppd
->manual_copies
= !strcmp(string
, "True");
797 else if (!strcmp(keyword
, "cupsModelNumber"))
798 ppd
->model_number
= atoi(string
);
799 else if (!strcmp(keyword
, "cupsColorProfile"))
801 if (ppd
->num_profiles
== 0)
802 profile
= malloc(sizeof(ppd_profile_t
));
804 profile
= realloc(ppd
->profiles
, sizeof(ppd_profile_t
) *
805 (ppd
->num_profiles
+ 1));
809 cg
->ppd_status
= PPD_ALLOC_ERROR
;
814 ppd
->profiles
= profile
;
815 profile
+= ppd
->num_profiles
;
816 ppd
->num_profiles
++;
818 memset(profile
, 0, sizeof(ppd_profile_t
));
819 strlcpy(profile
->resolution
, name
, sizeof(profile
->resolution
));
820 strlcpy(profile
->media_type
, text
, sizeof(profile
->media_type
));
822 profile
->density
= (float)_cupsStrScand(string
, &sptr
, loc
);
823 profile
->gamma
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
824 profile
->matrix
[0][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
825 profile
->matrix
[0][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
826 profile
->matrix
[0][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
827 profile
->matrix
[1][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
828 profile
->matrix
[1][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
829 profile
->matrix
[1][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
830 profile
->matrix
[2][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
831 profile
->matrix
[2][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
832 profile
->matrix
[2][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
834 else if (!strcmp(keyword
, "cupsFilter"))
836 if (ppd
->num_filters
== 0)
837 filter
= malloc(sizeof(char *));
839 filter
= realloc(ppd
->filters
, sizeof(char *) * (ppd
->num_filters
+ 1));
843 cg
->ppd_status
= PPD_ALLOC_ERROR
;
848 ppd
->filters
= filter
;
849 filter
+= ppd
->num_filters
;
853 * Copy filter string and prevent it from being freed below...
859 else if (!strcmp(keyword
, "Throughput"))
860 ppd
->throughput
= atoi(string
);
861 else if (!strcmp(keyword
, "Font"))
864 * Add this font to the list of available fonts...
867 if (ppd
->num_fonts
== 0)
868 tempfonts
= (char **)malloc(sizeof(char *));
870 tempfonts
= (char **)realloc(ppd
->fonts
,
871 sizeof(char *) * (ppd
->num_fonts
+ 1));
873 if (tempfonts
== NULL
)
875 cg
->ppd_status
= PPD_ALLOC_ERROR
;
880 ppd
->fonts
= tempfonts
;
881 ppd
->fonts
[ppd
->num_fonts
] = _cupsStrAlloc(name
);
884 else if (!strncmp(keyword
, "ParamCustom", 11))
886 ppd_coption_t
*coption
; /* Custom option */
887 ppd_cparam_t
*cparam
; /* Custom parameter */
888 int corder
; /* Order number */
889 char ctype
[33], /* Data type */
890 cminimum
[65], /* Minimum value */
891 cmaximum
[65]; /* Maximum value */
895 * Get the custom option and parameter...
898 if ((coption
= ppd_get_coption(ppd
, keyword
+ 11)) == NULL
)
900 cg
->ppd_status
= PPD_ALLOC_ERROR
;
905 if ((cparam
= ppd_get_cparam(coption
, name
, text
)) == NULL
)
907 cg
->ppd_status
= PPD_ALLOC_ERROR
;
913 * Get the parameter data...
916 if (sscanf(string
, "%d%32s%64s%64s", &corder
, ctype
, cminimum
,
919 cg
->ppd_status
= PPD_BAD_CUSTOM_PARAM
;
924 cparam
->order
= corder
;
926 if (!strcmp(ctype
, "curve"))
928 cparam
->type
= PPD_CUSTOM_CURVE
;
929 cparam
->minimum
.custom_curve
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
930 cparam
->maximum
.custom_curve
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
932 else if (!strcmp(ctype
, "int"))
934 cparam
->type
= PPD_CUSTOM_INT
;
935 cparam
->minimum
.custom_int
= atoi(cminimum
);
936 cparam
->maximum
.custom_int
= atoi(cmaximum
);
938 else if (!strcmp(ctype
, "invcurve"))
940 cparam
->type
= PPD_CUSTOM_INVCURVE
;
941 cparam
->minimum
.custom_invcurve
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
942 cparam
->maximum
.custom_invcurve
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
944 else if (!strcmp(ctype
, "passcode"))
946 cparam
->type
= PPD_CUSTOM_PASSCODE
;
947 cparam
->minimum
.custom_passcode
= atoi(cminimum
);
948 cparam
->maximum
.custom_passcode
= atoi(cmaximum
);
950 else if (!strcmp(ctype
, "password"))
952 cparam
->type
= PPD_CUSTOM_PASSWORD
;
953 cparam
->minimum
.custom_password
= atoi(cminimum
);
954 cparam
->maximum
.custom_password
= atoi(cmaximum
);
956 else if (!strcmp(ctype
, "points"))
958 cparam
->type
= PPD_CUSTOM_POINTS
;
959 cparam
->minimum
.custom_points
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
960 cparam
->maximum
.custom_points
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
962 else if (!strcmp(ctype
, "real"))
964 cparam
->type
= PPD_CUSTOM_REAL
;
965 cparam
->minimum
.custom_real
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
966 cparam
->maximum
.custom_real
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
968 else if (!strcmp(ctype
, "string"))
970 cparam
->type
= PPD_CUSTOM_STRING
;
971 cparam
->minimum
.custom_string
= atoi(cminimum
);
972 cparam
->maximum
.custom_string
= atoi(cmaximum
);
976 cg
->ppd_status
= PPD_BAD_CUSTOM_PARAM
;
982 * Now special-case for CustomPageSize...
985 if (!strcmp(coption
->keyword
, "PageSize"))
987 if (!strcmp(name
, "Width"))
989 ppd
->custom_min
[0] = cparam
->minimum
.custom_points
;
990 ppd
->custom_max
[0] = cparam
->maximum
.custom_points
;
992 else if (!strcmp(name
, "Height"))
994 ppd
->custom_min
[1] = cparam
->minimum
.custom_points
;
995 ppd
->custom_max
[1] = cparam
->maximum
.custom_points
;
999 else if (!strcmp(keyword
, "HWMargins"))
1001 for (i
= 0, sptr
= string
; i
< 4; i
++)
1002 ppd
->custom_margins
[i
] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
1004 else if (!strncmp(keyword
, "Custom", 6) && !strcmp(name
, "True") && !option
)
1006 ppd_option_t
*custom_option
; /* Custom option */
1008 DEBUG_puts("Processing Custom option...");
1011 * Get the option and custom option...
1014 if (!ppd_get_coption(ppd
, keyword
+ 6))
1016 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1021 if (option
&& !strcasecmp(option
->keyword
, keyword
+ 6))
1022 custom_option
= option
;
1024 custom_option
= ppdFindOption(ppd
, keyword
+ 6);
1029 * Add the "custom" option...
1032 if ((choice
= ppd_add_choice(custom_option
, "Custom")) == NULL
)
1034 DEBUG_puts("Unable to add Custom choice!");
1036 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1041 strlcpy(choice
->text
, text
[0] ? text
: _("Custom"),
1042 sizeof(choice
->text
));
1044 choice
->code
= _cupsStrAlloc(string
);
1048 * Now process custom page sizes specially...
1051 if (!strcmp(keyword
, "CustomPageSize"))
1054 * Add a "Custom" page size entry...
1057 ppd
->variable_sizes
= 1;
1059 ppd_add_size(ppd
, "Custom");
1061 if (option
&& !strcasecmp(option
->keyword
, "PageRegion"))
1062 custom_option
= option
;
1064 custom_option
= ppdFindOption(ppd
, "PageRegion");
1068 if ((choice
= ppd_add_choice(custom_option
, "Custom")) == NULL
)
1070 DEBUG_puts("Unable to add Custom choice!");
1072 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1077 strlcpy(choice
->text
, text
[0] ? text
: _("Custom"),
1078 sizeof(choice
->text
));
1082 else if (!strcmp(keyword
, "LandscapeOrientation"))
1084 if (!strcmp(string
, "Minus90"))
1085 ppd
->landscape
= -90;
1086 else if (!strcmp(string
, "Plus90"))
1087 ppd
->landscape
= 90;
1089 else if (!strcmp(keyword
, "Emulators") && string
)
1091 for (count
= 1, sptr
= string
; sptr
!= NULL
;)
1092 if ((sptr
= strchr(sptr
, ' ')) != NULL
)
1095 while (*sptr
== ' ')
1099 ppd
->num_emulations
= count
;
1100 if ((ppd
->emulations
= calloc(count
, sizeof(ppd_emul_t
))) == NULL
)
1102 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1107 for (i
= 0, sptr
= string
; i
< count
; i
++)
1109 for (nameptr
= ppd
->emulations
[i
].name
;
1110 *sptr
!= '\0' && *sptr
!= ' ';
1112 if (nameptr
< (ppd
->emulations
[i
].name
+ sizeof(ppd
->emulations
[i
].name
) - 1))
1117 while (*sptr
== ' ')
1121 else if (!strncmp(keyword
, "StartEmulator_", 14))
1125 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1126 if (!strcmp(keyword
+ 14, ppd
->emulations
[i
].name
))
1128 ppd
->emulations
[i
].start
= string
;
1132 else if (!strncmp(keyword
, "StopEmulator_", 13))
1136 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1137 if (!strcmp(keyword
+ 13, ppd
->emulations
[i
].name
))
1139 ppd
->emulations
[i
].stop
= string
;
1143 else if (!strcmp(keyword
, "JobPatchFile"))
1145 if (ppd
->patches
== NULL
)
1146 ppd
->patches
= _cupsStrAlloc(string
);
1149 temp
= realloc(ppd
->patches
, strlen(ppd
->patches
) +
1150 strlen(string
) + 1);
1153 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1158 ppd
->patches
= temp
;
1160 strcpy(ppd
->patches
+ strlen(ppd
->patches
), string
);
1163 else if (!strcmp(keyword
, "OpenUI"))
1166 * Don't allow nesting of options...
1169 if (option
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1171 cg
->ppd_status
= PPD_NESTED_OPEN_UI
;
1177 * Add an option record to the current sub-group, group, or file...
1180 DEBUG_printf(("name=\"%s\" (%d)\n", name
, (int)strlen(name
)));
1183 _cups_strcpy(name
, name
+ 1); /* Eliminate leading asterisk */
1185 for (i
= (int)strlen(name
) - 1; i
> 0 && isspace(name
[i
] & 255); i
--)
1186 name
[i
] = '\0'; /* Eliminate trailing spaces */
1188 DEBUG_printf(("OpenUI of %s in group %s...\n", name
,
1189 group
? group
->text
: "(null)"));
1191 if (subgroup
!= NULL
)
1192 option
= ppd_get_option(subgroup
, name
);
1193 else if (group
== NULL
)
1195 if ((group
= ppd_get_group(ppd
, "General", _("General"), cg
,
1199 DEBUG_printf(("Adding to group %s...\n", group
->text
));
1200 option
= ppd_get_option(group
, name
);
1204 option
= ppd_get_option(group
, name
);
1208 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1214 * Now fill in the initial information for the option...
1217 if (string
&& !strcmp(string
, "PickMany"))
1218 option
->ui
= PPD_UI_PICKMANY
;
1219 else if (string
&& !strcmp(string
, "Boolean"))
1220 option
->ui
= PPD_UI_BOOLEAN
;
1221 else if (string
&& !strcmp(string
, "PickOne"))
1222 option
->ui
= PPD_UI_PICKONE
;
1223 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1225 cg
->ppd_status
= PPD_BAD_OPEN_UI
;
1230 option
->ui
= PPD_UI_PICKONE
;
1232 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1233 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
1234 !strcmp(ppd
->attrs
[j
]->name
+ 7, name
) &&
1235 ppd
->attrs
[j
]->value
)
1237 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
1238 option
->keyword
, ppd
->attrs
[j
]->value
));
1239 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
1240 sizeof(option
->defchoice
));
1245 cupsCharsetToUTF8((cups_utf8_t
*)option
->text
, text
,
1246 sizeof(option
->text
), encoding
);
1249 if (!strcmp(name
, "PageSize"))
1250 strlcpy(option
->text
, _("Media Size"), sizeof(option
->text
));
1251 else if (!strcmp(name
, "MediaType"))
1252 strlcpy(option
->text
, _("Media Type"), sizeof(option
->text
));
1253 else if (!strcmp(name
, "InputSlot"))
1254 strlcpy(option
->text
, _("Media Source"), sizeof(option
->text
));
1255 else if (!strcmp(name
, "ColorModel"))
1256 strlcpy(option
->text
, _("Output Mode"), sizeof(option
->text
));
1257 else if (!strcmp(name
, "Resolution"))
1258 strlcpy(option
->text
, _("Resolution"), sizeof(option
->text
));
1260 strlcpy(option
->text
, name
, sizeof(option
->text
));
1263 option
->section
= PPD_ORDER_ANY
;
1265 _cupsStrFree(string
);
1269 * Add a custom option choice if we have already seen a CustomFoo
1273 if (!strcasecmp(name
, "PageRegion"))
1274 strcpy(custom_name
, "CustomPageSize");
1276 snprintf(custom_name
, sizeof(custom_name
), "Custom%s", name
);
1278 if ((custom_attr
= ppdFindAttr(ppd
, custom_name
, "True")) != NULL
)
1280 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
1282 DEBUG_puts("Unable to add Custom choice!");
1284 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1289 strlcpy(choice
->text
,
1290 custom_attr
->text
[0] ? custom_attr
->text
: _("Custom"),
1291 sizeof(choice
->text
));
1292 choice
->code
= _cupsStrAlloc(custom_attr
->value
);
1295 else if (!strcmp(keyword
, "JCLOpenUI"))
1298 * Don't allow nesting of options...
1301 if (option
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1303 cg
->ppd_status
= PPD_NESTED_OPEN_UI
;
1309 * Find the JCL group, and add if needed...
1312 group
= ppd_get_group(ppd
, "JCL", _("JCL"), cg
, encoding
);
1318 * Add an option record to the current JCLs...
1322 _cups_strcpy(name
, name
+ 1);
1324 option
= ppd_get_option(group
, name
);
1328 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1334 * Now fill in the initial information for the option...
1337 if (string
&& !strcmp(string
, "PickMany"))
1338 option
->ui
= PPD_UI_PICKMANY
;
1339 else if (string
&& !strcmp(string
, "Boolean"))
1340 option
->ui
= PPD_UI_BOOLEAN
;
1341 else if (string
&& !strcmp(string
, "PickOne"))
1342 option
->ui
= PPD_UI_PICKONE
;
1345 cg
->ppd_status
= PPD_BAD_OPEN_UI
;
1350 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1351 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
1352 !strcmp(ppd
->attrs
[j
]->name
+ 7, name
) &&
1353 ppd
->attrs
[j
]->value
)
1355 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
1356 option
->keyword
, ppd
->attrs
[j
]->value
));
1357 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
1358 sizeof(option
->defchoice
));
1363 cupsCharsetToUTF8((cups_utf8_t
*)option
->text
, text
,
1364 sizeof(option
->text
), encoding
);
1366 strlcpy(option
->text
, name
, sizeof(option
->text
));
1368 option
->section
= PPD_ORDER_JCL
;
1371 _cupsStrFree(string
);
1375 * Add a custom option choice if we have already seen a CustomFoo
1379 snprintf(custom_name
, sizeof(custom_name
), "Custom%s", name
);
1381 if ((custom_attr
= ppdFindAttr(ppd
, custom_name
, "True")) != NULL
)
1383 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
1385 DEBUG_puts("Unable to add Custom choice!");
1387 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1392 strlcpy(choice
->text
,
1393 custom_attr
->text
[0] ? custom_attr
->text
: _("Custom"),
1394 sizeof(choice
->text
));
1395 choice
->code
= _cupsStrAlloc(custom_attr
->value
);
1398 else if (!strcmp(keyword
, "CloseUI") || !strcmp(keyword
, "JCLCloseUI"))
1402 _cupsStrFree(string
);
1405 else if (!strcmp(keyword
, "OpenGroup"))
1408 * Open a new group...
1413 cg
->ppd_status
= PPD_NESTED_OPEN_GROUP
;
1420 cg
->ppd_status
= PPD_BAD_OPEN_GROUP
;
1426 * Separate the group name from the text (name/text)...
1429 if ((sptr
= strchr(string
, '/')) != NULL
)
1435 * Fix up the text...
1441 * Find/add the group...
1444 group
= ppd_get_group(ppd
, string
, sptr
, cg
, encoding
);
1449 _cupsStrFree(string
);
1452 else if (!strcmp(keyword
, "CloseGroup"))
1456 _cupsStrFree(string
);
1459 else if (!strcmp(keyword
, "OrderDependency"))
1461 order
= (float)_cupsStrScand(string
, &sptr
, loc
);
1463 if (!sptr
|| sscanf(sptr
, "%40s%40s", name
, keyword
) != 2)
1465 cg
->ppd_status
= PPD_BAD_ORDER_DEPENDENCY
;
1470 if (keyword
[0] == '*')
1471 _cups_strcpy(keyword
, keyword
+ 1);
1473 if (!strcmp(name
, "ExitServer"))
1474 section
= PPD_ORDER_EXIT
;
1475 else if (!strcmp(name
, "Prolog"))
1476 section
= PPD_ORDER_PROLOG
;
1477 else if (!strcmp(name
, "DocumentSetup"))
1478 section
= PPD_ORDER_DOCUMENT
;
1479 else if (!strcmp(name
, "PageSetup"))
1480 section
= PPD_ORDER_PAGE
;
1481 else if (!strcmp(name
, "JCLSetup"))
1482 section
= PPD_ORDER_JCL
;
1484 section
= PPD_ORDER_ANY
;
1492 * Only valid for Non-UI options...
1495 for (i
= ppd
->num_groups
, gtemp
= ppd
->groups
; i
> 0; i
--, gtemp
++)
1496 if (gtemp
->text
[0] == '\0')
1500 for (i
= 0; i
< gtemp
->num_options
; i
++)
1501 if (!strcmp(keyword
, gtemp
->options
[i
].keyword
))
1503 gtemp
->options
[i
].section
= section
;
1504 gtemp
->options
[i
].order
= order
;
1510 option
->section
= section
;
1511 option
->order
= order
;
1514 _cupsStrFree(string
);
1517 else if (!strncmp(keyword
, "Default", 7))
1523 * Drop UI text, if any, from value...
1526 if (strchr(string
, '/') != NULL
)
1527 *strchr(string
, '/') = '\0';
1530 * Assign the default value as appropriate...
1533 if (!strcmp(keyword
, "DefaultColorSpace"))
1536 * Set default colorspace...
1539 if (!strcmp(string
, "CMY"))
1540 ppd
->colorspace
= PPD_CS_CMY
;
1541 else if (!strcmp(string
, "CMYK"))
1542 ppd
->colorspace
= PPD_CS_CMYK
;
1543 else if (!strcmp(string
, "RGB"))
1544 ppd
->colorspace
= PPD_CS_RGB
;
1545 else if (!strcmp(string
, "RGBK"))
1546 ppd
->colorspace
= PPD_CS_RGBK
;
1547 else if (!strcmp(string
, "N"))
1548 ppd
->colorspace
= PPD_CS_N
;
1550 ppd
->colorspace
= PPD_CS_GRAY
;
1552 else if (option
&& !strcmp(keyword
+ 7, option
->keyword
))
1555 * Set the default as part of the current option...
1558 DEBUG_printf(("Setting %s to %s...\n", keyword
, string
));
1560 strlcpy(option
->defchoice
, string
, sizeof(option
->defchoice
));
1562 DEBUG_printf(("%s is now %s...\n", keyword
, option
->defchoice
));
1567 * Lookup option and set if it has been defined...
1570 ppd_option_t
*toption
; /* Temporary option */
1573 if ((toption
= ppdFindOption(ppd
, keyword
+ 7)) != NULL
)
1575 DEBUG_printf(("Setting %s to %s...\n", keyword
, string
));
1576 strlcpy(toption
->defchoice
, string
, sizeof(toption
->defchoice
));
1580 else if (!strcmp(keyword
, "UIConstraints") ||
1581 !strcmp(keyword
, "NonUIConstraints"))
1583 if (ppd
->num_consts
== 0)
1584 constraint
= calloc(2, sizeof(ppd_const_t
));
1586 constraint
= realloc(ppd
->consts
,
1587 (ppd
->num_consts
+ 2) * sizeof(ppd_const_t
));
1589 if (constraint
== NULL
)
1591 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1596 ppd
->consts
= constraint
;
1597 constraint
+= ppd
->num_consts
;
1600 switch (sscanf(string
, "%40s%40s%40s%40s", constraint
->option1
,
1601 constraint
->choice1
, constraint
->option2
,
1602 constraint
->choice2
))
1604 case 0 : /* Error */
1605 case 1 : /* Error */
1606 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1609 case 2 : /* Two options... */
1611 * Check for broken constraints like "* Option"...
1614 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1615 (!strcmp(constraint
->option1
, "*") ||
1616 !strcmp(constraint
->choice1
, "*")))
1618 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1623 * The following strcpy's are safe, as optionN and
1624 * choiceN are all the same size (size defined by PPD spec...)
1627 if (constraint
->option1
[0] == '*')
1628 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1629 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1631 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1635 if (constraint
->choice1
[0] == '*')
1636 _cups_strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1637 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1639 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1643 constraint
->choice1
[0] = '\0';
1644 constraint
->choice2
[0] = '\0';
1647 case 3 : /* Two options, one choice... */
1649 * Check for broken constraints like "* Option"...
1652 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1653 (!strcmp(constraint
->option1
, "*") ||
1654 !strcmp(constraint
->choice1
, "*") ||
1655 !strcmp(constraint
->option2
, "*")))
1657 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1662 * The following _cups_strcpy's are safe, as optionN and
1663 * choiceN are all the same size (size defined by PPD spec...)
1666 if (constraint
->option1
[0] == '*')
1667 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1668 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1670 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1674 if (constraint
->choice1
[0] == '*')
1676 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1677 constraint
->option2
[0] == '*')
1679 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1683 _cups_strcpy(constraint
->choice2
, constraint
->option2
);
1684 _cups_strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1685 constraint
->choice1
[0] = '\0';
1689 if (constraint
->option2
[0] == '*')
1690 _cups_strcpy(constraint
->option2
, constraint
->option2
+ 1);
1691 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1693 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1697 constraint
->choice2
[0] = '\0';
1701 case 4 : /* Two options, two choices... */
1703 * Check for broken constraints like "* Option"...
1706 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1707 (!strcmp(constraint
->option1
, "*") ||
1708 !strcmp(constraint
->choice1
, "*") ||
1709 !strcmp(constraint
->option2
, "*") ||
1710 !strcmp(constraint
->choice2
, "*")))
1712 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1716 if (constraint
->option1
[0] == '*')
1717 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1718 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1720 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1724 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1725 constraint
->choice1
[0] == '*')
1727 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1731 if (constraint
->option2
[0] == '*')
1732 _cups_strcpy(constraint
->option2
, constraint
->option2
+ 1);
1733 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1735 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1739 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1740 constraint
->choice2
[0] == '*')
1742 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1749 * Don't add this one as an attribute...
1752 _cupsStrFree(string
);
1755 else if (!strcmp(keyword
, "PaperDimension"))
1757 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1758 size
= ppd_add_size(ppd
, name
);
1763 * Unable to add or find size!
1766 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1771 size
->width
= (float)_cupsStrScand(string
, &sptr
, loc
);
1772 size
->length
= (float)_cupsStrScand(sptr
, NULL
, loc
);
1774 _cupsStrFree(string
);
1777 else if (!strcmp(keyword
, "ImageableArea"))
1779 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1780 size
= ppd_add_size(ppd
, name
);
1785 * Unable to add or find size!
1788 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1793 size
->left
= (float)_cupsStrScand(string
, &sptr
, loc
);
1794 size
->bottom
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
1795 size
->right
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
1796 size
->top
= (float)_cupsStrScand(sptr
, NULL
, loc
);
1798 _cupsStrFree(string
);
1801 else if (option
!= NULL
&&
1802 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
1803 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
) &&
1804 !strcmp(keyword
, option
->keyword
))
1806 DEBUG_printf(("group = %p, subgroup = %p\n", group
, subgroup
));
1808 if (!strcmp(keyword
, "PageSize"))
1811 * Add a page size...
1814 if (ppdPageSize(ppd
, name
) == NULL
)
1815 ppd_add_size(ppd
, name
);
1819 * Add the option choice...
1822 if ((choice
= ppd_add_choice(option
, name
)) == NULL
)
1824 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1830 cupsCharsetToUTF8((cups_utf8_t
*)choice
->text
, text
,
1831 sizeof(choice
->text
), encoding
);
1832 else if (!strcmp(name
, "True"))
1833 strcpy(choice
->text
, _("Yes"));
1834 else if (!strcmp(name
, "False"))
1835 strcpy(choice
->text
, _("No"));
1837 strlcpy(choice
->text
, name
, sizeof(choice
->text
));
1839 if (option
->section
== PPD_ORDER_JCL
)
1840 ppd_decode(string
); /* Decode quoted string */
1842 choice
->code
= string
;
1843 string
= NULL
; /* Don't add as an attribute below */
1847 * Add remaining lines with keywords and string values as attributes...
1851 (mask
& (PPD_KEYWORD
| PPD_STRING
)) == (PPD_KEYWORD
| PPD_STRING
))
1852 ppd_add_attr(ppd
, keyword
, name
, text
, string
);
1854 _cupsStrFree(string
);
1861 * Reset language preferences...
1864 cupsLangFree(language
);
1867 if (!cupsFileEOF(fp
))
1868 DEBUG_printf(("Premature EOF at %lu...\n",
1869 (unsigned long)cupsFileTell(fp
)));
1872 if (cg
->ppd_status
!= PPD_OK
)
1875 * Had an error reading the PPD file, cannot continue!
1884 * Create the sorted options array and set the option back-pointer for
1885 * each choice and custom option...
1888 ppd
->options
= cupsArrayNew2((cups_array_func_t
)ppd_compare_options
, NULL
,
1889 (cups_ahash_func_t
)ppd_hash_option
,
1892 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
1896 for (j
= group
->num_options
, option
= group
->options
;
1900 ppd_coption_t
*coption
; /* Custom option */
1903 cupsArrayAdd(ppd
->options
, option
);
1905 for (k
= 0; k
< option
->num_choices
; k
++)
1906 option
->choices
[k
].option
= option
;
1908 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)) != NULL
)
1909 coption
->option
= option
;
1914 * Create an array to track the marked choices...
1917 ppd
->marked
= cupsArrayNew((cups_array_func_t
)ppd_compare_choices
, NULL
);
1920 * Return the PPD file structure...
1926 * Common exit point for errors to save code size...
1934 _cupsStrFree(string
);
1938 cupsLangFree(language
);
1945 * 'ppdOpenFd()' - Read a PPD file into memory.
1948 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
1949 ppdOpenFd(int fd
) /* I - File to read from */
1951 cups_file_t
*fp
; /* CUPS file pointer */
1952 ppd_file_t
*ppd
; /* PPD file record */
1953 _cups_globals_t
*cg
= _cupsGlobals();
1958 * Set the line number to 0...
1964 * Range check input...
1969 cg
->ppd_status
= PPD_NULL_FILE
;
1975 * Try to open the file and parse it...
1978 if ((fp
= cupsFileOpenFd(fd
, "r")) != NULL
)
1986 cg
->ppd_status
= PPD_FILE_OPEN_ERROR
;
1995 * 'ppdOpenFile()' - Read a PPD file into memory.
1998 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
1999 ppdOpenFile(const char *filename
) /* I - File to read from */
2001 cups_file_t
*fp
; /* File pointer */
2002 ppd_file_t
*ppd
; /* PPD file record */
2003 _cups_globals_t
*cg
= _cupsGlobals();
2008 * Set the line number to 0...
2014 * Range check input...
2017 if (filename
== NULL
)
2019 cg
->ppd_status
= PPD_NULL_FILE
;
2025 * Try to open the file and parse it...
2028 if ((fp
= cupsFileOpen(filename
, "r")) != NULL
)
2036 cg
->ppd_status
= PPD_FILE_OPEN_ERROR
;
2045 * 'ppdSetConformance()' - Set the conformance level for PPD files.
2047 * @since CUPS 1.1.20@
2051 ppdSetConformance(ppd_conform_t c
) /* I - Conformance level */
2053 _cups_globals_t
*cg
= _cupsGlobals();
2057 cg
->ppd_conform
= c
;
2062 * 'ppd_add_attr()' - Add an attribute to the PPD data.
2065 static ppd_attr_t
* /* O - New attribute */
2066 ppd_add_attr(ppd_file_t
*ppd
, /* I - PPD file data */
2067 const char *name
, /* I - Attribute name */
2068 const char *spec
, /* I - Specifier string, if any */
2069 const char *text
, /* I - Text string, if any */
2070 const char *value
) /* I - Value of attribute */
2072 ppd_attr_t
**ptr
, /* New array */
2073 *temp
; /* New attribute */
2077 * Range check input...
2080 if (ppd
== NULL
|| name
== NULL
|| spec
== NULL
)
2084 * Create the array as needed...
2087 if (!ppd
->sorted_attrs
)
2088 ppd
->sorted_attrs
= cupsArrayNew((cups_array_func_t
)ppd_compare_attrs
,
2092 * Allocate memory for the new attribute...
2095 if (ppd
->num_attrs
== 0)
2096 ptr
= malloc(sizeof(ppd_attr_t
*));
2098 ptr
= realloc(ppd
->attrs
, (ppd
->num_attrs
+ 1) * sizeof(ppd_attr_t
*));
2104 ptr
+= ppd
->num_attrs
;
2106 if ((temp
= calloc(1, sizeof(ppd_attr_t
))) == NULL
)
2117 strlcpy(temp
->name
, name
, sizeof(temp
->name
));
2118 strlcpy(temp
->spec
, spec
, sizeof(temp
->spec
));
2119 strlcpy(temp
->text
, text
, sizeof(temp
->text
));
2120 temp
->value
= (char *)value
;
2123 * Add the attribute to the sorted array...
2126 cupsArrayAdd(ppd
->sorted_attrs
, temp
);
2129 * Return the attribute...
2137 * 'ppd_add_choice()' - Add a choice to an option.
2140 static ppd_choice_t
* /* O - Named choice */
2141 ppd_add_choice(ppd_option_t
*option
, /* I - Option */
2142 const char *name
) /* I - Name of choice */
2144 ppd_choice_t
*choice
; /* Choice */
2147 if (option
->num_choices
== 0)
2148 choice
= malloc(sizeof(ppd_choice_t
));
2150 choice
= realloc(option
->choices
,
2151 sizeof(ppd_choice_t
) * (option
->num_choices
+ 1));
2156 option
->choices
= choice
;
2157 choice
+= option
->num_choices
;
2158 option
->num_choices
++;
2160 memset(choice
, 0, sizeof(ppd_choice_t
));
2161 strlcpy(choice
->choice
, name
, sizeof(choice
->choice
));
2168 * 'ppd_add_size()' - Add a page size.
2171 static ppd_size_t
* /* O - Named size */
2172 ppd_add_size(ppd_file_t
*ppd
, /* I - PPD file */
2173 const char *name
) /* I - Name of size */
2175 ppd_size_t
*size
; /* Size */
2178 if (ppd
->num_sizes
== 0)
2179 size
= malloc(sizeof(ppd_size_t
));
2181 size
= realloc(ppd
->sizes
, sizeof(ppd_size_t
) * (ppd
->num_sizes
+ 1));
2187 size
+= ppd
->num_sizes
;
2190 memset(size
, 0, sizeof(ppd_size_t
));
2191 strlcpy(size
->name
, name
, sizeof(size
->name
));
2198 * 'ppd_compare_attrs()' - Compare two attributes.
2201 static int /* O - Result of comparison */
2202 ppd_compare_attrs(ppd_attr_t
*a
, /* I - First attribute */
2203 ppd_attr_t
*b
) /* I - Second attribute */
2205 int ret
; /* Result of comparison */
2208 if ((ret
= strcasecmp(a
->name
, b
->name
)) != 0)
2211 return (strcasecmp(a
->spec
, b
->spec
));
2216 * 'ppd_compare_choices()' - Compare two choices...
2219 static int /* O - Result of comparison */
2220 ppd_compare_choices(ppd_choice_t
*a
, /* I - First choice */
2221 ppd_choice_t
*b
) /* I - Second choice */
2223 return (strcmp(a
->option
->keyword
, b
->option
->keyword
));
2228 * 'ppd_compare_coptions()' - Compare two custom options.
2231 static int /* O - Result of comparison */
2232 ppd_compare_coptions(ppd_coption_t
*a
, /* I - First option */
2233 ppd_coption_t
*b
) /* I - Second option */
2235 return (strcasecmp(a
->keyword
, b
->keyword
));
2240 * 'ppd_compare_cparams()' - Compare two custom parameters.
2243 static int /* O - Result of comparison */
2244 ppd_compare_cparams(ppd_cparam_t
*a
, /* I - First parameter */
2245 ppd_cparam_t
*b
) /* I - Second parameter */
2247 return (strcasecmp(a
->name
, b
->name
));
2252 * 'ppd_compare_options()' - Compare two options.
2255 static int /* O - Result of comparison */
2256 ppd_compare_options(ppd_option_t
*a
, /* I - First option */
2257 ppd_option_t
*b
) /* I - Second option */
2259 return (strcasecmp(a
->keyword
, b
->keyword
));
2264 * 'ppd_decode()' - Decode a string value...
2267 static int /* O - Length of decoded string */
2268 ppd_decode(char *string
) /* I - String to decode */
2270 char *inptr
, /* Input pointer */
2271 *outptr
; /* Output pointer */
2277 while (*inptr
!= '\0')
2278 if (*inptr
== '<' && isxdigit(inptr
[1] & 255))
2281 * Convert hex to 8-bit values...
2285 while (isxdigit(*inptr
& 255))
2287 if (isalpha(*inptr
))
2288 *outptr
= (tolower(*inptr
) - 'a' + 10) << 4;
2290 *outptr
= (*inptr
- '0') << 4;
2294 if (!isxdigit(*inptr
& 255))
2297 if (isalpha(*inptr
))
2298 *outptr
|= tolower(*inptr
) - 'a' + 10;
2300 *outptr
|= *inptr
- '0';
2306 while (*inptr
!= '>' && *inptr
!= '\0')
2308 while (*inptr
== '>')
2312 *outptr
++ = *inptr
++;
2316 return ((int)(outptr
- string
));
2321 * 'ppd_free_group()' - Free a single UI group.
2325 ppd_free_group(ppd_group_t
*group
) /* I - Group to free */
2327 int i
; /* Looping var */
2328 ppd_option_t
*option
; /* Current option */
2329 ppd_group_t
*subgroup
; /* Current sub-group */
2332 if (group
->num_options
> 0)
2334 for (i
= group
->num_options
, option
= group
->options
;
2337 ppd_free_option(option
);
2339 ppd_free(group
->options
);
2342 if (group
->num_subgroups
> 0)
2344 for (i
= group
->num_subgroups
, subgroup
= group
->subgroups
;
2347 ppd_free_group(subgroup
);
2349 ppd_free(group
->subgroups
);
2355 * 'ppd_free_option()' - Free a single option.
2359 ppd_free_option(ppd_option_t
*option
) /* I - Option to free */
2361 int i
; /* Looping var */
2362 ppd_choice_t
*choice
; /* Current choice */
2365 if (option
->num_choices
> 0)
2367 for (i
= option
->num_choices
, choice
= option
->choices
;
2371 _cupsStrFree(choice
->code
);
2374 ppd_free(option
->choices
);
2380 * 'ppd_get_coption()' - Get a custom option record.
2383 static ppd_coption_t
* /* O - Custom option... */
2384 ppd_get_coption(ppd_file_t
*ppd
, /* I - PPD file */
2385 const char *name
) /* I - Name of option */
2387 ppd_coption_t
*copt
; /* New custom option */
2391 * See if the option already exists...
2394 if ((copt
= ppdFindCustomOption(ppd
, name
)) != NULL
)
2398 * Not found, so create the custom option record...
2401 if ((copt
= calloc(1, sizeof(ppd_coption_t
))) == NULL
)
2404 strlcpy(copt
->keyword
, name
, sizeof(copt
->keyword
));
2406 copt
->params
= cupsArrayNew((cups_array_func_t
)ppd_compare_cparams
, NULL
);
2408 cupsArrayAdd(ppd
->coptions
, copt
);
2411 * Return the new record...
2419 * 'ppd_get_cparam()' - Get a custom parameter record.
2422 static ppd_cparam_t
* /* O - Extended option... */
2423 ppd_get_cparam(ppd_coption_t
*opt
, /* I - PPD file */
2424 const char *param
, /* I - Name of parameter */
2425 const char *text
) /* I - Human-readable text */
2427 ppd_cparam_t
*cparam
; /* New custom parameter */
2431 * See if the parameter already exists...
2434 if ((cparam
= ppdFindCustomParam(opt
, param
)) != NULL
)
2438 * Not found, so create the custom parameter record...
2441 if ((cparam
= calloc(1, sizeof(ppd_cparam_t
))) == NULL
)
2444 strlcpy(cparam
->name
, param
, sizeof(cparam
->name
));
2445 strlcpy(cparam
->text
, text
[0] ? text
: param
, sizeof(cparam
->text
));
2448 * Add this record to the array...
2451 cupsArrayAdd(opt
->params
, cparam
);
2454 * Return the new record...
2462 * 'ppd_get_group()' - Find or create the named group as needed.
2465 static ppd_group_t
* /* O - Named group */
2466 ppd_get_group(ppd_file_t
*ppd
, /* I - PPD file */
2467 const char *name
, /* I - Name of group */
2468 const char *text
, /* I - Text for group */
2469 _cups_globals_t
*cg
, /* I - Global data */
2470 cups_encoding_t encoding
) /* I - Encoding of text */
2472 int i
; /* Looping var */
2473 ppd_group_t
*group
; /* Group */
2476 DEBUG_printf(("ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)\n",
2477 ppd
, name
, text
, cg
));
2479 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
2480 if (!strcmp(group
->name
, name
))
2485 DEBUG_printf(("Adding group %s...\n", name
));
2487 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&& strlen(text
) >= sizeof(group
->text
))
2489 cg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
2494 if (ppd
->num_groups
== 0)
2495 group
= malloc(sizeof(ppd_group_t
));
2497 group
= realloc(ppd
->groups
,
2498 (ppd
->num_groups
+ 1) * sizeof(ppd_group_t
));
2502 cg
->ppd_status
= PPD_ALLOC_ERROR
;
2507 ppd
->groups
= group
;
2508 group
+= ppd
->num_groups
;
2511 memset(group
, 0, sizeof(ppd_group_t
));
2512 strlcpy(group
->name
, name
, sizeof(group
->name
));
2514 cupsCharsetToUTF8((cups_utf8_t
*)group
->text
, text
,
2515 sizeof(group
->text
), encoding
);
2523 * 'ppd_get_option()' - Find or create the named option as needed.
2526 static ppd_option_t
* /* O - Named option */
2527 ppd_get_option(ppd_group_t
*group
, /* I - Group */
2528 const char *name
) /* I - Name of option */
2530 int i
; /* Looping var */
2531 ppd_option_t
*option
; /* Option */
2534 DEBUG_printf(("ppd_get_option(group=%p(\"%s\"), name=\"%s\")\n",
2535 group
, group
->name
, name
));
2537 for (i
= group
->num_options
, option
= group
->options
; i
> 0; i
--, option
++)
2538 if (!strcmp(option
->keyword
, name
))
2543 if (group
->num_options
== 0)
2544 option
= malloc(sizeof(ppd_option_t
));
2546 option
= realloc(group
->options
,
2547 (group
->num_options
+ 1) * sizeof(ppd_option_t
));
2552 group
->options
= option
;
2553 option
+= group
->num_options
;
2554 group
->num_options
++;
2556 memset(option
, 0, sizeof(ppd_option_t
));
2557 strlcpy(option
->keyword
, name
, sizeof(option
->keyword
));
2565 * 'ppd_hash_option()' - Generate a hash of the option name...
2568 static int /* O - Hash index */
2569 ppd_hash_option(ppd_option_t
*option
) /* I - Option */
2571 int hash
= 0; /* Hash index */
2572 const char *k
; /* Pointer into keyword */
2575 for (hash
= option
->keyword
[0], k
= option
->keyword
+ 1; *k
;)
2576 hash
= 33 * hash
+ *k
++;
2578 return (hash
& 511);
2583 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2587 static int /* O - Bitmask of fields read */
2588 ppd_read(cups_file_t
*fp
, /* I - File to read from */
2589 _ppd_line_t
*line
, /* I - Line buffer */
2590 char *keyword
, /* O - Keyword from line */
2591 char *option
, /* O - Option from line */
2592 char *text
, /* O - Human-readable text from line */
2593 char **string
, /* O - Code/string data */
2594 int ignoreblank
, /* I - Ignore blank lines? */
2595 _cups_globals_t
*cg
) /* I - Global data */
2597 int ch
, /* Character from file */
2598 col
, /* Column in line */
2599 colon
, /* Colon seen? */
2600 endquote
, /* Waiting for an end quote */
2601 mask
, /* Mask to be returned */
2602 startline
, /* Start line */
2603 textlen
; /* Length of text */
2604 char *keyptr
, /* Keyword pointer */
2605 *optptr
, /* Option pointer */
2606 *textptr
, /* Text pointer */
2607 *strptr
, /* Pointer into string */
2608 *lineptr
; /* Current position in line buffer */
2612 * Now loop until we have a valid line...
2617 startline
= cg
->ppd_line
+ 1;
2621 line
->bufsize
= 1024;
2622 line
->buffer
= malloc(1024);
2634 lineptr
= line
->buffer
;
2638 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2640 if (lineptr
>= (line
->buffer
+ line
->bufsize
- 1))
2643 * Expand the line buffer...
2646 char *temp
; /* Temporary line pointer */
2649 line
->bufsize
+= 1024;
2650 if (line
->bufsize
> 262144)
2653 * Don't allow lines longer than 256k!
2656 cg
->ppd_line
= startline
;
2657 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2662 temp
= realloc(line
->buffer
, line
->bufsize
);
2665 cg
->ppd_line
= startline
;
2666 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2671 lineptr
= temp
+ (lineptr
- line
->buffer
);
2672 line
->buffer
= temp
;
2675 if (ch
== '\r' || ch
== '\n')
2678 * Line feed or carriage return...
2687 * Check for a trailing line feed...
2690 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2697 cupsFileGetChar(fp
);
2700 if (lineptr
== line
->buffer
&& ignoreblank
)
2701 continue; /* Skip blank lines */
2705 if (!endquote
) /* Continue for multi-line text */
2710 else if (ch
< ' ' && ch
!= '\t' && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2713 * Other control characters...
2716 cg
->ppd_line
= startline
;
2717 cg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
2721 else if (ch
!= 0x1a)
2724 * Any other character...
2730 if (col
> (PPD_MAX_LINE
- 1))
2733 * Line is too long...
2736 cg
->ppd_line
= startline
;
2737 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2742 if (ch
== ':' && strncmp(line
->buffer
, "*%", 2) != 0)
2745 if (ch
== '\"' && colon
)
2746 endquote
= !endquote
;
2753 * Didn't finish this quoted string...
2756 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2759 else if (ch
== '\r' || ch
== '\n')
2767 * Check for a trailing line feed...
2770 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2773 cupsFileGetChar(fp
);
2776 else if (ch
< ' ' && ch
!= '\t' && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2779 * Other control characters...
2782 cg
->ppd_line
= startline
;
2783 cg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
2787 else if (ch
!= 0x1a)
2791 if (col
> (PPD_MAX_LINE
- 1))
2794 * Line is too long...
2797 cg
->ppd_line
= startline
;
2798 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2808 * Didn't finish this line...
2811 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2812 if (ch
== '\r' || ch
== '\n')
2815 * Line feed or carriage return...
2824 * Check for a trailing line feed...
2827 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2830 cupsFileGetChar(fp
);
2835 else if (ch
< ' ' && ch
!= '\t' && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2838 * Other control characters...
2841 cg
->ppd_line
= startline
;
2842 cg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
2846 else if (ch
!= 0x1a)
2850 if (col
> (PPD_MAX_LINE
- 1))
2853 * Line is too long...
2856 cg
->ppd_line
= startline
;
2857 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2864 if (lineptr
> line
->buffer
&& lineptr
[-1] == '\n')
2869 DEBUG_printf(("LINE=\"%s\"\n", line
->buffer
));
2872 * The dynamically created PPDs for older style Mac OS X
2873 * drivers include a large blob of data inserted as comments
2874 * at the end of the file. As an optimization we can stop
2875 * reading the PPD when we get to the start of this data.
2878 if (!strcmp(line
->buffer
, "*%APLWORKSET START"))
2881 if (ch
== EOF
&& lineptr
== line
->buffer
)
2889 lineptr
= line
->buffer
+ 1;
2896 if ((!line
->buffer
[0] || /* Blank line */
2897 !strncmp(line
->buffer
, "*%", 2) || /* Comment line */
2898 !strcmp(line
->buffer
, "*End")) && /* End of multi-line string */
2899 ignoreblank
) /* Ignore these? */
2901 startline
= cg
->ppd_line
+ 1;
2905 if (!strcmp(line
->buffer
, "*")) /* (Bad) comment line */
2907 if (cg
->ppd_conform
== PPD_CONFORM_RELAXED
)
2909 startline
= cg
->ppd_line
+ 1;
2914 cg
->ppd_line
= startline
;
2915 cg
->ppd_status
= PPD_ILLEGAL_MAIN_KEYWORD
;
2921 if (line
->buffer
[0] != '*') /* All lines start with an asterisk */
2924 * Allow lines consisting of just whitespace...
2927 for (lineptr
= line
->buffer
; *lineptr
; lineptr
++)
2928 if (!isspace(*lineptr
& 255))
2933 cg
->ppd_status
= PPD_MISSING_ASTERISK
;
2936 else if (ignoreblank
)
2948 while (*lineptr
!= '\0' && *lineptr
!= ':' && !isspace(*lineptr
& 255))
2950 if (*lineptr
<= ' ' || *lineptr
> 126 || *lineptr
== '/' ||
2951 (keyptr
- keyword
) >= (PPD_MAX_NAME
- 1))
2953 cg
->ppd_status
= PPD_ILLEGAL_MAIN_KEYWORD
;
2957 *keyptr
++ = *lineptr
++;
2962 if (!strcmp(keyword
, "End"))
2965 mask
|= PPD_KEYWORD
;
2967 /* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
2969 if (isspace(*lineptr
& 255))
2972 * Get an option name...
2975 while (isspace(*lineptr
& 255))
2980 while (*lineptr
!= '\0' && !isspace(*lineptr
& 255) && *lineptr
!= ':' &&
2983 if (*lineptr
<= ' ' || *lineptr
> 126 ||
2984 (optptr
- option
) >= (PPD_MAX_NAME
- 1))
2986 cg
->ppd_status
= PPD_ILLEGAL_OPTION_KEYWORD
;
2990 *optptr
++ = *lineptr
++;
2995 if (isspace(*lineptr
& 255) && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2997 cg
->ppd_status
= PPD_ILLEGAL_WHITESPACE
;
3001 while (isspace(*lineptr
& 255))
3006 /* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
3008 if (*lineptr
== '/')
3011 * Get human-readable text...
3018 while (*lineptr
!= '\0' && *lineptr
!= '\n' && *lineptr
!= ':')
3020 if (((unsigned char)*lineptr
< ' ' && *lineptr
!= '\t') ||
3021 (textptr
- text
) >= (PPD_MAX_LINE
- 1))
3023 cg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
3027 *textptr
++ = *lineptr
++;
3031 textlen
= ppd_decode(text
);
3033 if (textlen
> PPD_MAX_TEXT
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
3035 cg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
3042 /* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
3045 if (isspace(*lineptr
& 255) && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
3047 cg
->ppd_status
= PPD_ILLEGAL_WHITESPACE
;
3051 while (isspace(*lineptr
& 255))
3054 if (*lineptr
== ':')
3057 * Get string after triming leading and trailing whitespace...
3061 while (isspace(*lineptr
& 255))
3064 strptr
= lineptr
+ strlen(lineptr
) - 1;
3065 while (strptr
>= lineptr
&& isspace(*strptr
& 255))
3068 if (*strptr
== '\"')
3071 * Quoted string by itself, remove quotes...
3078 *string
= _cupsStrAlloc(lineptr
);
3080 /* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
3092 * End of "$Id: ppd.c 7552 2008-05-12 17:42:15Z mike $".