4 * PPD file routines for CUPS.
6 * Copyright 2007-2014 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 * Include necessary headers.
31 #include "cups-private.h"
32 #include "ppd-private.h"
39 #define ppd_free(p) if (p) free(p) /* Safe free macro */
41 #define PPD_KEYWORD 1 /* Line contained a keyword */
42 #define PPD_OPTION 2 /* Line contained an option name */
43 #define PPD_TEXT 4 /* Line contained human-readable text */
44 #define PPD_STRING 8 /* Line contained a string or code */
46 #define PPD_HASHSIZE 512 /* Size of hash */
50 * Line buffer structure...
53 typedef struct _ppd_line_s
55 char *buffer
; /* Pointer to buffer */
56 size_t bufsize
; /* Size of the buffer */
64 static ppd_attr_t
*ppd_add_attr(ppd_file_t
*ppd
, const char *name
,
65 const char *spec
, const char *text
,
67 static ppd_choice_t
*ppd_add_choice(ppd_option_t
*option
, const char *name
);
68 static ppd_size_t
*ppd_add_size(ppd_file_t
*ppd
, const char *name
);
69 static int ppd_compare_attrs(ppd_attr_t
*a
, ppd_attr_t
*b
);
70 static int ppd_compare_choices(ppd_choice_t
*a
, ppd_choice_t
*b
);
71 static int ppd_compare_coptions(ppd_coption_t
*a
,
73 static int ppd_compare_options(ppd_option_t
*a
, ppd_option_t
*b
);
74 static int ppd_decode(char *string
);
75 static void ppd_free_filters(ppd_file_t
*ppd
);
76 static void ppd_free_group(ppd_group_t
*group
);
77 static void ppd_free_option(ppd_option_t
*option
);
78 static ppd_coption_t
*ppd_get_coption(ppd_file_t
*ppd
, const char *name
);
79 static ppd_cparam_t
*ppd_get_cparam(ppd_coption_t
*opt
,
82 static ppd_group_t
*ppd_get_group(ppd_file_t
*ppd
, const char *name
,
83 const char *text
, _cups_globals_t
*cg
,
84 cups_encoding_t encoding
);
85 static ppd_option_t
*ppd_get_option(ppd_group_t
*group
, const char *name
);
86 static int ppd_hash_option(ppd_option_t
*option
);
87 static int ppd_read(cups_file_t
*fp
, _ppd_line_t
*line
,
88 char *keyword
, char *option
, char *text
,
89 char **string
, int ignoreblank
,
91 static int ppd_update_filters(ppd_file_t
*ppd
,
96 * 'ppdClose()' - Free all memory used by the PPD file.
100 ppdClose(ppd_file_t
*ppd
) /* I - PPD file record */
102 int i
; /* Looping var */
103 ppd_emul_t
*emul
; /* Current emulation */
104 ppd_group_t
*group
; /* Current group */
105 char **font
; /* Current font */
106 ppd_attr_t
**attr
; /* Current attribute */
107 ppd_coption_t
*coption
; /* Current custom option */
108 ppd_cparam_t
*cparam
; /* Current custom parameter */
112 * Range check arguments...
119 * Free all strings at the top level...
122 _cupsStrFree(ppd
->lang_encoding
);
123 _cupsStrFree(ppd
->nickname
);
126 _cupsStrFree(ppd
->jcl_begin
);
127 _cupsStrFree(ppd
->jcl_end
);
128 _cupsStrFree(ppd
->jcl_ps
);
131 * Free any emulations...
134 if (ppd
->num_emulations
> 0)
136 for (i
= ppd
->num_emulations
, emul
= ppd
->emulations
; i
> 0; i
--, emul
++)
138 _cupsStrFree(emul
->start
);
139 _cupsStrFree(emul
->stop
);
142 ppd_free(ppd
->emulations
);
146 * Free any UI groups, subgroups, and options...
149 if (ppd
->num_groups
> 0)
151 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
152 ppd_free_group(group
);
154 ppd_free(ppd
->groups
);
157 cupsArrayDelete(ppd
->options
);
158 cupsArrayDelete(ppd
->marked
);
161 * Free any page sizes...
164 if (ppd
->num_sizes
> 0)
165 ppd_free(ppd
->sizes
);
168 * Free any constraints...
171 if (ppd
->num_consts
> 0)
172 ppd_free(ppd
->consts
);
175 * Free any filters...
178 ppd_free_filters(ppd
);
184 if (ppd
->num_fonts
> 0)
186 for (i
= ppd
->num_fonts
, font
= ppd
->fonts
; i
> 0; i
--, font
++)
189 ppd_free(ppd
->fonts
);
193 * Free any profiles...
196 if (ppd
->num_profiles
> 0)
197 ppd_free(ppd
->profiles
);
200 * Free any attributes...
203 if (ppd
->num_attrs
> 0)
205 for (i
= ppd
->num_attrs
, attr
= ppd
->attrs
; i
> 0; i
--, attr
++)
207 _cupsStrFree((*attr
)->value
);
211 ppd_free(ppd
->attrs
);
214 cupsArrayDelete(ppd
->sorted_attrs
);
217 * Free custom options...
220 for (coption
= (ppd_coption_t
*)cupsArrayFirst(ppd
->coptions
);
222 coption
= (ppd_coption_t
*)cupsArrayNext(ppd
->coptions
))
224 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
226 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
228 switch (cparam
->type
)
230 case PPD_CUSTOM_PASSCODE
:
231 case PPD_CUSTOM_PASSWORD
:
232 case PPD_CUSTOM_STRING
:
233 _cupsStrFree(cparam
->current
.custom_string
);
243 cupsArrayDelete(coption
->params
);
248 cupsArrayDelete(ppd
->coptions
);
251 * Free constraints...
254 if (ppd
->cups_uiconstraints
)
256 _ppd_cups_uiconsts_t
*consts
; /* Current constraints */
259 for (consts
= (_ppd_cups_uiconsts_t
*)cupsArrayFirst(ppd
->cups_uiconstraints
);
261 consts
= (_ppd_cups_uiconsts_t
*)cupsArrayNext(ppd
->cups_uiconstraints
))
263 free(consts
->constraints
);
267 cupsArrayDelete(ppd
->cups_uiconstraints
);
271 * Free any PPD cache/mapping data...
275 _ppdCacheDestroy(ppd
->cache
);
278 * Free the whole record...
286 * 'ppdErrorString()' - Returns the text assocated with a status.
288 * @since CUPS 1.1.19/OS X 10.3@
291 const char * /* O - Status string */
292 ppdErrorString(ppd_status_t status
) /* I - PPD status */
294 static const char * const messages
[] =/* Status messages */
297 _("Unable to open PPD file"),
298 _("NULL PPD file pointer"),
299 _("Memory allocation error"),
300 _("Missing PPD-Adobe-4.x header"),
301 _("Missing value string"),
304 _("OpenGroup without a CloseGroup first"),
305 _("Bad OpenUI/JCLOpenUI"),
306 _("OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"),
307 _("Bad OrderDependency"),
308 _("Bad UIConstraints"),
309 _("Missing asterisk in column 1"),
310 _("Line longer than the maximum allowed (255 characters)"),
311 _("Illegal control character"),
312 _("Illegal main keyword string"),
313 _("Illegal option keyword string"),
314 _("Illegal translation string"),
315 _("Illegal whitespace character"),
316 _("Bad custom parameter"),
317 _("Missing option keyword"),
318 _("Bad value string"),
319 _("Missing CloseGroup")
323 if (status
< PPD_OK
|| status
>= PPD_MAX_STATUS
)
324 return (_cupsLangString(cupsLangDefault(), _("Unknown")));
326 return (_cupsLangString(cupsLangDefault(), messages
[status
]));
331 * '_ppdGetEncoding()' - Get the CUPS encoding value for the given
335 cups_encoding_t
/* O - CUPS encoding value */
336 _ppdGetEncoding(const char *name
) /* I - LanguageEncoding string */
338 if (!_cups_strcasecmp(name
, "ISOLatin1"))
339 return (CUPS_ISO8859_1
);
340 else if (!_cups_strcasecmp(name
, "ISOLatin2"))
341 return (CUPS_ISO8859_2
);
342 else if (!_cups_strcasecmp(name
, "ISOLatin5"))
343 return (CUPS_ISO8859_5
);
344 else if (!_cups_strcasecmp(name
, "JIS83-RKSJ"))
345 return (CUPS_JIS_X0213
);
346 else if (!_cups_strcasecmp(name
, "MacStandard"))
347 return (CUPS_MAC_ROMAN
);
348 else if (!_cups_strcasecmp(name
, "WindowsANSI"))
349 return (CUPS_WINDOWS_1252
);
356 * 'ppdLastError()' - Return the status from the last ppdOpen*().
358 * @since CUPS 1.1.19/OS X 10.3@
361 ppd_status_t
/* O - Status code */
362 ppdLastError(int *line
) /* O - Line number */
364 _cups_globals_t
*cg
= _cupsGlobals();
369 *line
= cg
->ppd_line
;
371 return (cg
->ppd_status
);
376 * '_ppdOpen()' - Read a PPD file into memory.
378 * @since CUPS 1.2/OS X 10.5@
381 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
383 cups_file_t
*fp
, /* I - File to read from */
384 _ppd_localization_t localization
) /* I - Localization to load */
386 int i
, j
, k
; /* Looping vars */
387 int count
; /* Temporary count */
388 _ppd_line_t line
; /* Line buffer */
389 ppd_file_t
*ppd
; /* PPD file record */
390 ppd_group_t
*group
, /* Current group */
391 *subgroup
; /* Current sub-group */
392 ppd_option_t
*option
; /* Current option */
393 ppd_choice_t
*choice
; /* Current choice */
394 ppd_const_t
*constraint
; /* Current constraint */
395 ppd_size_t
*size
; /* Current page size */
396 int mask
; /* Line data mask */
397 char keyword
[PPD_MAX_NAME
],
398 /* Keyword from file */
400 /* Option from file */
402 /* Human-readable text from file */
403 *string
, /* Code/text from file */
404 *sptr
, /* Pointer into string */
405 *nameptr
, /* Pointer into name */
406 *temp
, /* Temporary string pointer */
407 **tempfonts
; /* Temporary fonts pointer */
408 float order
; /* Order dependency number */
409 ppd_section_t section
; /* Order dependency section */
410 ppd_profile_t
*profile
; /* Pointer to color profile */
411 char **filter
; /* Pointer to filter */
412 struct lconv
*loc
; /* Locale data */
413 int ui_keyword
; /* Is this line a UI keyword? */
414 cups_lang_t
*lang
; /* Language data */
415 cups_encoding_t encoding
; /* Encoding of PPD file */
416 _cups_globals_t
*cg
= _cupsGlobals();
418 char custom_name
[PPD_MAX_NAME
];
419 /* CustomFoo attribute name */
420 ppd_attr_t
*custom_attr
; /* CustomFoo attribute */
421 char ll
[4], /* Language + '.' */
422 ll_CC
[7]; /* Language + country + '.' */
423 size_t ll_len
= 0, /* Language length */
424 ll_CC_len
= 0; /* Language + country length */
425 static const char * const ui_keywords
[] =
427 #ifdef CUPS_USE_FULL_UI_KEYWORDS_LIST
429 * Adobe defines some 41 keywords as "UI", meaning that they are
430 * user interface elements and that they should be treated as such
431 * even if the PPD creator doesn't use Open/CloseUI around them.
433 * Since this can cause previously invisible options to appear and
434 * confuse users, the default is to only treat the PageSize and
435 * PageRegion keywords this way.
437 /* Boolean keywords */
447 /* PickOne keywords */
460 "JCLFrameBufferSize",
481 #else /* !CUPS_USE_FULL_UI_KEYWORDS_LIST */
484 #endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */
486 static const char * const color_keywords
[] = /* Keywords associated with color profiles */
493 DEBUG_printf(("_ppdOpen(fp=%p)", fp
));
496 * Default to "OK" status...
499 cg
->ppd_status
= PPD_OK
;
503 * Range check input...
508 cg
->ppd_status
= PPD_NULL_FILE
;
513 * If only loading a single localization set up the strings to match...
516 if (localization
== _PPD_LOCALIZATION_DEFAULT
)
518 if ((lang
= cupsLangDefault()) == NULL
)
521 snprintf(ll_CC
, sizeof(ll_CC
), "%s.", lang
->language
);
522 snprintf(ll
, sizeof(ll
), "%2.2s.", lang
->language
);
524 ll_CC_len
= strlen(ll_CC
);
527 DEBUG_printf(("2_ppdOpen: Loading localizations matching \"%s\" and \"%s\"",
532 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
538 mask
= ppd_read(fp
, &line
, keyword
, name
, text
, &string
, 0, cg
);
540 DEBUG_printf(("2_ppdOpen: mask=%x, keyword=\"%s\"...", mask
, keyword
));
543 strcmp(keyword
, "PPD-Adobe") ||
544 string
== NULL
|| string
[0] != '4')
547 * Either this is not a PPD file, or it is not a 4.x PPD file.
550 if (cg
->ppd_status
== PPD_OK
)
551 cg
->ppd_status
= PPD_MISSING_PPDADOBE4
;
553 _cupsStrFree(string
);
554 ppd_free(line
.buffer
);
559 DEBUG_printf(("2_ppdOpen: keyword=%s, string=%p", keyword
, string
));
561 _cupsStrFree(string
);
564 * Allocate memory for the PPD file record...
567 if ((ppd
= calloc(1, sizeof(ppd_file_t
))) == NULL
)
569 cg
->ppd_status
= PPD_ALLOC_ERROR
;
571 _cupsStrFree(string
);
572 ppd_free(line
.buffer
);
577 ppd
->language_level
= 2;
578 ppd
->color_device
= 0;
579 ppd
->colorspace
= PPD_CS_N
;
580 ppd
->landscape
= -90;
581 ppd
->coptions
= cupsArrayNew((cups_array_func_t
)ppd_compare_coptions
,
585 * Read lines from the PPD file and add them to the file record...
593 encoding
= CUPS_ISO8859_1
;
596 while ((mask
= ppd_read(fp
, &line
, keyword
, name
, text
, &string
, 1, cg
)) != 0)
598 DEBUG_printf(("2_ppdOpen: mask=%x, keyword=\"%s\", name=\"%s\", "
599 "text=\"%s\", string=%d chars...", mask
, keyword
, name
, text
,
600 string
? (int)strlen(string
) : 0));
602 if (strncmp(keyword
, "Default", 7) && !string
&&
603 cg
->ppd_conform
!= PPD_CONFORM_RELAXED
)
606 * Need a string value!
609 cg
->ppd_status
= PPD_MISSING_VALUE
;
617 * Certain main keywords (as defined by the PPD spec) may be used
618 * without the usual OpenUI/CloseUI stuff. Presumably this is just
619 * so that Adobe wouldn't completely break compatibility with PPD
620 * files prior to v4.0 of the spec, but it is hopelessly
621 * inconsistent... Catch these main keywords and automatically
622 * create the corresponding option, as needed...
628 * Previous line was a UI keyword...
636 * If we are filtering out keyword localizations, see if this line needs to
640 if (localization
!= _PPD_LOCALIZATION_ALL
&&
641 (temp
= strchr(keyword
, '.')) != NULL
&&
642 ((temp
- keyword
) == 2 || (temp
- keyword
) == 5) &&
643 _cups_isalpha(keyword
[0]) &&
644 _cups_isalpha(keyword
[1]) &&
645 (keyword
[2] == '.' ||
646 (keyword
[2] == '_' && _cups_isalpha(keyword
[3]) &&
647 _cups_isalpha(keyword
[4]) && keyword
[5] == '.')))
649 if (localization
== _PPD_LOCALIZATION_NONE
||
650 (localization
== _PPD_LOCALIZATION_DEFAULT
&&
651 strncmp(ll_CC
, keyword
, ll_CC_len
) &&
652 strncmp(ll
, keyword
, ll_len
)))
654 DEBUG_printf(("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword
));
657 else if (localization
== _PPD_LOCALIZATION_ICC_PROFILES
)
660 * Only load localizations for the color profile related keywords...
664 i
< (int)(sizeof(color_keywords
) / sizeof(color_keywords
[0]));
667 if (!_cups_strcasecmp(temp
, color_keywords
[i
]))
671 if (i
>= (int)(sizeof(color_keywords
) / sizeof(color_keywords
[0])))
673 DEBUG_printf(("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword
));
679 if (option
== NULL
&&
680 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
681 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
))
683 for (i
= 0; i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])); i
++)
684 if (!strcmp(keyword
, ui_keywords
[i
]))
687 if (i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])))
690 * Create the option in the appropriate group...
695 DEBUG_printf(("2_ppdOpen: FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!",
700 if ((group
= ppd_get_group(ppd
, "General", _("General"), cg
,
704 DEBUG_printf(("2_ppdOpen: Adding to group %s...", group
->text
));
705 option
= ppd_get_option(group
, keyword
);
709 option
= ppd_get_option(group
, keyword
);
713 cg
->ppd_status
= PPD_ALLOC_ERROR
;
719 * Now fill in the initial information for the option...
722 if (!strncmp(keyword
, "JCL", 3))
723 option
->section
= PPD_ORDER_JCL
;
725 option
->section
= PPD_ORDER_ANY
;
727 option
->order
= 10.0f
;
730 option
->ui
= PPD_UI_BOOLEAN
;
732 option
->ui
= PPD_UI_PICKONE
;
734 for (j
= 0; j
< ppd
->num_attrs
; j
++)
735 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
736 !strcmp(ppd
->attrs
[j
]->name
+ 7, keyword
) &&
737 ppd
->attrs
[j
]->value
)
739 DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
740 option
->keyword
, ppd
->attrs
[j
]->value
));
741 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
742 sizeof(option
->defchoice
));
746 if (!strcmp(keyword
, "PageSize"))
747 strlcpy(option
->text
, _("Media Size"), sizeof(option
->text
));
748 else if (!strcmp(keyword
, "MediaType"))
749 strlcpy(option
->text
, _("Media Type"), sizeof(option
->text
));
750 else if (!strcmp(keyword
, "InputSlot"))
751 strlcpy(option
->text
, _("Media Source"), sizeof(option
->text
));
752 else if (!strcmp(keyword
, "ColorModel"))
753 strlcpy(option
->text
, _("Output Mode"), sizeof(option
->text
));
754 else if (!strcmp(keyword
, "Resolution"))
755 strlcpy(option
->text
, _("Resolution"), sizeof(option
->text
));
757 strlcpy(option
->text
, keyword
, sizeof(option
->text
));
761 if (!strcmp(keyword
, "LanguageLevel"))
762 ppd
->language_level
= atoi(string
);
763 else if (!strcmp(keyword
, "LanguageEncoding"))
766 * Say all PPD files are UTF-8, since we convert to UTF-8...
769 ppd
->lang_encoding
= _cupsStrAlloc("UTF-8");
770 encoding
= _ppdGetEncoding(string
);
772 else if (!strcmp(keyword
, "LanguageVersion"))
773 ppd
->lang_version
= string
;
774 else if (!strcmp(keyword
, "Manufacturer"))
775 ppd
->manufacturer
= string
;
776 else if (!strcmp(keyword
, "ModelName"))
777 ppd
->modelname
= string
;
778 else if (!strcmp(keyword
, "Protocols"))
779 ppd
->protocols
= string
;
780 else if (!strcmp(keyword
, "PCFileName"))
781 ppd
->pcfilename
= string
;
782 else if (!strcmp(keyword
, "NickName"))
784 if (encoding
!= CUPS_UTF8
)
786 cups_utf8_t utf8
[256]; /* UTF-8 version of NickName */
789 cupsCharsetToUTF8(utf8
, string
, sizeof(utf8
), encoding
);
790 ppd
->nickname
= _cupsStrAlloc((char *)utf8
);
793 ppd
->nickname
= _cupsStrAlloc(string
);
795 else if (!strcmp(keyword
, "Product"))
796 ppd
->product
= string
;
797 else if (!strcmp(keyword
, "ShortNickName"))
798 ppd
->shortnickname
= string
;
799 else if (!strcmp(keyword
, "TTRasterizer"))
800 ppd
->ttrasterizer
= string
;
801 else if (!strcmp(keyword
, "JCLBegin"))
803 ppd
->jcl_begin
= _cupsStrAlloc(string
);
804 ppd_decode(ppd
->jcl_begin
); /* Decode quoted string */
806 else if (!strcmp(keyword
, "JCLEnd"))
808 ppd
->jcl_end
= _cupsStrAlloc(string
);
809 ppd_decode(ppd
->jcl_end
); /* Decode quoted string */
811 else if (!strcmp(keyword
, "JCLToPSInterpreter"))
813 ppd
->jcl_ps
= _cupsStrAlloc(string
);
814 ppd_decode(ppd
->jcl_ps
); /* Decode quoted string */
816 else if (!strcmp(keyword
, "AccurateScreensSupport"))
817 ppd
->accurate_screens
= !strcmp(string
, "True");
818 else if (!strcmp(keyword
, "ColorDevice"))
819 ppd
->color_device
= !strcmp(string
, "True");
820 else if (!strcmp(keyword
, "ContoneOnly"))
821 ppd
->contone_only
= !strcmp(string
, "True");
822 else if (!strcmp(keyword
, "cupsFlipDuplex"))
823 ppd
->flip_duplex
= !strcmp(string
, "True");
824 else if (!strcmp(keyword
, "cupsManualCopies"))
825 ppd
->manual_copies
= !strcmp(string
, "True");
826 else if (!strcmp(keyword
, "cupsModelNumber"))
827 ppd
->model_number
= atoi(string
);
828 else if (!strcmp(keyword
, "cupsColorProfile"))
830 if (ppd
->num_profiles
== 0)
831 profile
= malloc(sizeof(ppd_profile_t
));
833 profile
= realloc(ppd
->profiles
, sizeof(ppd_profile_t
) * (size_t)(ppd
->num_profiles
+ 1));
837 cg
->ppd_status
= PPD_ALLOC_ERROR
;
842 ppd
->profiles
= profile
;
843 profile
+= ppd
->num_profiles
;
844 ppd
->num_profiles
++;
846 memset(profile
, 0, sizeof(ppd_profile_t
));
847 strlcpy(profile
->resolution
, name
, sizeof(profile
->resolution
));
848 strlcpy(profile
->media_type
, text
, sizeof(profile
->media_type
));
850 profile
->density
= (float)_cupsStrScand(string
, &sptr
, loc
);
851 profile
->gamma
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
852 profile
->matrix
[0][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
853 profile
->matrix
[0][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
854 profile
->matrix
[0][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
855 profile
->matrix
[1][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
856 profile
->matrix
[1][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
857 profile
->matrix
[1][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
858 profile
->matrix
[2][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
859 profile
->matrix
[2][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
860 profile
->matrix
[2][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
862 else if (!strcmp(keyword
, "cupsFilter"))
864 if (ppd
->num_filters
== 0)
865 filter
= malloc(sizeof(char *));
867 filter
= realloc(ppd
->filters
, sizeof(char *) * (size_t)(ppd
->num_filters
+ 1));
871 cg
->ppd_status
= PPD_ALLOC_ERROR
;
876 ppd
->filters
= filter
;
877 filter
+= ppd
->num_filters
;
881 * Retain a copy of the filter string...
884 *filter
= _cupsStrRetain(string
);
886 else if (!strcmp(keyword
, "Throughput"))
887 ppd
->throughput
= atoi(string
);
888 else if (!strcmp(keyword
, "Font"))
891 * Add this font to the list of available fonts...
894 if (ppd
->num_fonts
== 0)
895 tempfonts
= (char **)malloc(sizeof(char *));
897 tempfonts
= (char **)realloc(ppd
->fonts
, sizeof(char *) * (size_t)(ppd
->num_fonts
+ 1));
899 if (tempfonts
== NULL
)
901 cg
->ppd_status
= PPD_ALLOC_ERROR
;
906 ppd
->fonts
= tempfonts
;
907 ppd
->fonts
[ppd
->num_fonts
] = _cupsStrAlloc(name
);
910 else if (!strncmp(keyword
, "ParamCustom", 11))
912 ppd_coption_t
*coption
; /* Custom option */
913 ppd_cparam_t
*cparam
; /* Custom parameter */
914 int corder
; /* Order number */
915 char ctype
[33], /* Data type */
916 cminimum
[65], /* Minimum value */
917 cmaximum
[65]; /* Maximum value */
921 * Get the custom option and parameter...
924 if ((coption
= ppd_get_coption(ppd
, keyword
+ 11)) == NULL
)
926 cg
->ppd_status
= PPD_ALLOC_ERROR
;
931 if ((cparam
= ppd_get_cparam(coption
, name
, text
)) == NULL
)
933 cg
->ppd_status
= PPD_ALLOC_ERROR
;
939 * Get the parameter data...
943 sscanf(string
, "%d%32s%64s%64s", &corder
, ctype
, cminimum
,
946 cg
->ppd_status
= PPD_BAD_CUSTOM_PARAM
;
951 cparam
->order
= corder
;
953 if (!strcmp(ctype
, "curve"))
955 cparam
->type
= PPD_CUSTOM_CURVE
;
956 cparam
->minimum
.custom_curve
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
957 cparam
->maximum
.custom_curve
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
959 else if (!strcmp(ctype
, "int"))
961 cparam
->type
= PPD_CUSTOM_INT
;
962 cparam
->minimum
.custom_int
= atoi(cminimum
);
963 cparam
->maximum
.custom_int
= atoi(cmaximum
);
965 else if (!strcmp(ctype
, "invcurve"))
967 cparam
->type
= PPD_CUSTOM_INVCURVE
;
968 cparam
->minimum
.custom_invcurve
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
969 cparam
->maximum
.custom_invcurve
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
971 else if (!strcmp(ctype
, "passcode"))
973 cparam
->type
= PPD_CUSTOM_PASSCODE
;
974 cparam
->minimum
.custom_passcode
= atoi(cminimum
);
975 cparam
->maximum
.custom_passcode
= atoi(cmaximum
);
977 else if (!strcmp(ctype
, "password"))
979 cparam
->type
= PPD_CUSTOM_PASSWORD
;
980 cparam
->minimum
.custom_password
= atoi(cminimum
);
981 cparam
->maximum
.custom_password
= atoi(cmaximum
);
983 else if (!strcmp(ctype
, "points"))
985 cparam
->type
= PPD_CUSTOM_POINTS
;
986 cparam
->minimum
.custom_points
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
987 cparam
->maximum
.custom_points
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
989 else if (!strcmp(ctype
, "real"))
991 cparam
->type
= PPD_CUSTOM_REAL
;
992 cparam
->minimum
.custom_real
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
993 cparam
->maximum
.custom_real
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
995 else if (!strcmp(ctype
, "string"))
997 cparam
->type
= PPD_CUSTOM_STRING
;
998 cparam
->minimum
.custom_string
= atoi(cminimum
);
999 cparam
->maximum
.custom_string
= atoi(cmaximum
);
1003 cg
->ppd_status
= PPD_BAD_CUSTOM_PARAM
;
1009 * Now special-case for CustomPageSize...
1012 if (!strcmp(coption
->keyword
, "PageSize"))
1014 if (!strcmp(name
, "Width"))
1016 ppd
->custom_min
[0] = cparam
->minimum
.custom_points
;
1017 ppd
->custom_max
[0] = cparam
->maximum
.custom_points
;
1019 else if (!strcmp(name
, "Height"))
1021 ppd
->custom_min
[1] = cparam
->minimum
.custom_points
;
1022 ppd
->custom_max
[1] = cparam
->maximum
.custom_points
;
1026 else if (!strcmp(keyword
, "HWMargins"))
1028 for (i
= 0, sptr
= string
; i
< 4; i
++)
1029 ppd
->custom_margins
[i
] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
1031 else if (!strncmp(keyword
, "Custom", 6) && !strcmp(name
, "True") && !option
)
1033 ppd_option_t
*custom_option
; /* Custom option */
1035 DEBUG_puts("2_ppdOpen: Processing Custom option...");
1038 * Get the option and custom option...
1041 if (!ppd_get_coption(ppd
, keyword
+ 6))
1043 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1048 if (option
&& !_cups_strcasecmp(option
->keyword
, keyword
+ 6))
1049 custom_option
= option
;
1051 custom_option
= ppdFindOption(ppd
, keyword
+ 6);
1056 * Add the "custom" option...
1059 if ((choice
= ppdFindChoice(custom_option
, "Custom")) == NULL
)
1060 if ((choice
= ppd_add_choice(custom_option
, "Custom")) == NULL
)
1062 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1064 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1069 strlcpy(choice
->text
, text
[0] ? text
: _("Custom"),
1070 sizeof(choice
->text
));
1072 choice
->code
= _cupsStrAlloc(string
);
1074 if (custom_option
->section
== PPD_ORDER_JCL
)
1075 ppd_decode(choice
->code
);
1079 * Now process custom page sizes specially...
1082 if (!strcmp(keyword
, "CustomPageSize"))
1085 * Add a "Custom" page size entry...
1088 ppd
->variable_sizes
= 1;
1090 ppd_add_size(ppd
, "Custom");
1092 if (option
&& !_cups_strcasecmp(option
->keyword
, "PageRegion"))
1093 custom_option
= option
;
1095 custom_option
= ppdFindOption(ppd
, "PageRegion");
1099 if ((choice
= ppdFindChoice(custom_option
, "Custom")) == NULL
)
1100 if ((choice
= ppd_add_choice(custom_option
, "Custom")) == NULL
)
1102 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1104 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1109 strlcpy(choice
->text
, text
[0] ? text
: _("Custom"),
1110 sizeof(choice
->text
));
1114 else if (!strcmp(keyword
, "LandscapeOrientation"))
1116 if (!strcmp(string
, "Minus90"))
1117 ppd
->landscape
= -90;
1118 else if (!strcmp(string
, "Plus90"))
1119 ppd
->landscape
= 90;
1121 else if (!strcmp(keyword
, "Emulators") && string
)
1123 for (count
= 1, sptr
= string
; sptr
!= NULL
;)
1124 if ((sptr
= strchr(sptr
, ' ')) != NULL
)
1127 while (*sptr
== ' ')
1131 ppd
->num_emulations
= count
;
1132 if ((ppd
->emulations
= calloc((size_t)count
, sizeof(ppd_emul_t
))) == NULL
)
1134 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1139 for (i
= 0, sptr
= string
; i
< count
; i
++)
1141 for (nameptr
= ppd
->emulations
[i
].name
;
1142 *sptr
!= '\0' && *sptr
!= ' ';
1144 if (nameptr
< (ppd
->emulations
[i
].name
+ sizeof(ppd
->emulations
[i
].name
) - 1))
1149 while (*sptr
== ' ')
1153 else if (!strncmp(keyword
, "StartEmulator_", 14))
1157 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1158 if (!strcmp(keyword
+ 14, ppd
->emulations
[i
].name
))
1160 ppd
->emulations
[i
].start
= string
;
1164 else if (!strncmp(keyword
, "StopEmulator_", 13))
1168 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1169 if (!strcmp(keyword
+ 13, ppd
->emulations
[i
].name
))
1171 ppd
->emulations
[i
].stop
= string
;
1175 else if (!strcmp(keyword
, "JobPatchFile"))
1178 * CUPS STR #3421: Check for "*JobPatchFile: int: string"
1181 if (isdigit(*string
& 255))
1183 for (sptr
= string
+ 1; isdigit(*sptr
& 255); sptr
++);
1188 * Found "*JobPatchFile: int: string"...
1191 cg
->ppd_status
= PPD_BAD_VALUE
;
1197 if (!name
[0] && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1200 * Found "*JobPatchFile: string"...
1203 cg
->ppd_status
= PPD_MISSING_OPTION_KEYWORD
;
1208 if (ppd
->patches
== NULL
)
1209 ppd
->patches
= strdup(string
);
1212 temp
= realloc(ppd
->patches
, strlen(ppd
->patches
) +
1213 strlen(string
) + 1);
1216 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1221 ppd
->patches
= temp
;
1223 memcpy(ppd
->patches
+ strlen(ppd
->patches
), string
, strlen(string
) + 1);
1226 else if (!strcmp(keyword
, "OpenUI"))
1229 * Don't allow nesting of options...
1232 if (option
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1234 cg
->ppd_status
= PPD_NESTED_OPEN_UI
;
1240 * Add an option record to the current sub-group, group, or file...
1243 DEBUG_printf(("2_ppdOpen: name=\"%s\" (%d)", name
, (int)strlen(name
)));
1246 _cups_strcpy(name
, name
+ 1); /* Eliminate leading asterisk */
1248 for (i
= (int)strlen(name
) - 1; i
> 0 && _cups_isspace(name
[i
]); i
--)
1249 name
[i
] = '\0'; /* Eliminate trailing spaces */
1251 DEBUG_printf(("2_ppdOpen: OpenUI of %s in group %s...", name
,
1252 group
? group
->text
: "(null)"));
1254 if (subgroup
!= NULL
)
1255 option
= ppd_get_option(subgroup
, name
);
1256 else if (group
== NULL
)
1258 if ((group
= ppd_get_group(ppd
, "General", _("General"), cg
,
1262 DEBUG_printf(("2_ppdOpen: Adding to group %s...", group
->text
));
1263 option
= ppd_get_option(group
, name
);
1267 option
= ppd_get_option(group
, name
);
1271 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1277 * Now fill in the initial information for the option...
1280 if (string
&& !strcmp(string
, "PickMany"))
1281 option
->ui
= PPD_UI_PICKMANY
;
1282 else if (string
&& !strcmp(string
, "Boolean"))
1283 option
->ui
= PPD_UI_BOOLEAN
;
1284 else if (string
&& !strcmp(string
, "PickOne"))
1285 option
->ui
= PPD_UI_PICKONE
;
1286 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1288 cg
->ppd_status
= PPD_BAD_OPEN_UI
;
1293 option
->ui
= PPD_UI_PICKONE
;
1295 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1296 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
1297 !strcmp(ppd
->attrs
[j
]->name
+ 7, name
) &&
1298 ppd
->attrs
[j
]->value
)
1300 DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
1301 option
->keyword
, ppd
->attrs
[j
]->value
));
1302 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
1303 sizeof(option
->defchoice
));
1308 cupsCharsetToUTF8((cups_utf8_t
*)option
->text
, text
,
1309 sizeof(option
->text
), encoding
);
1312 if (!strcmp(name
, "PageSize"))
1313 strlcpy(option
->text
, _("Media Size"), sizeof(option
->text
));
1314 else if (!strcmp(name
, "MediaType"))
1315 strlcpy(option
->text
, _("Media Type"), sizeof(option
->text
));
1316 else if (!strcmp(name
, "InputSlot"))
1317 strlcpy(option
->text
, _("Media Source"), sizeof(option
->text
));
1318 else if (!strcmp(name
, "ColorModel"))
1319 strlcpy(option
->text
, _("Output Mode"), sizeof(option
->text
));
1320 else if (!strcmp(name
, "Resolution"))
1321 strlcpy(option
->text
, _("Resolution"), sizeof(option
->text
));
1323 strlcpy(option
->text
, name
, sizeof(option
->text
));
1326 option
->section
= PPD_ORDER_ANY
;
1328 _cupsStrFree(string
);
1332 * Add a custom option choice if we have already seen a CustomFoo
1336 if (!_cups_strcasecmp(name
, "PageRegion"))
1337 strlcpy(custom_name
, "CustomPageSize", sizeof(custom_name
));
1339 snprintf(custom_name
, sizeof(custom_name
), "Custom%s", name
);
1341 if ((custom_attr
= ppdFindAttr(ppd
, custom_name
, "True")) != NULL
)
1343 if ((choice
= ppdFindChoice(option
, "Custom")) == NULL
)
1344 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
1346 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1348 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1353 strlcpy(choice
->text
,
1354 custom_attr
->text
[0] ? custom_attr
->text
: _("Custom"),
1355 sizeof(choice
->text
));
1356 choice
->code
= _cupsStrRetain(custom_attr
->value
);
1359 else if (!strcmp(keyword
, "JCLOpenUI"))
1362 * Don't allow nesting of options...
1365 if (option
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1367 cg
->ppd_status
= PPD_NESTED_OPEN_UI
;
1373 * Find the JCL group, and add if needed...
1376 group
= ppd_get_group(ppd
, "JCL", _("JCL"), cg
, encoding
);
1382 * Add an option record to the current JCLs...
1386 _cups_strcpy(name
, name
+ 1);
1388 option
= ppd_get_option(group
, name
);
1392 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1398 * Now fill in the initial information for the option...
1401 if (string
&& !strcmp(string
, "PickMany"))
1402 option
->ui
= PPD_UI_PICKMANY
;
1403 else if (string
&& !strcmp(string
, "Boolean"))
1404 option
->ui
= PPD_UI_BOOLEAN
;
1405 else if (string
&& !strcmp(string
, "PickOne"))
1406 option
->ui
= PPD_UI_PICKONE
;
1409 cg
->ppd_status
= PPD_BAD_OPEN_UI
;
1414 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1415 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
1416 !strcmp(ppd
->attrs
[j
]->name
+ 7, name
) &&
1417 ppd
->attrs
[j
]->value
)
1419 DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
1420 option
->keyword
, ppd
->attrs
[j
]->value
));
1421 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
1422 sizeof(option
->defchoice
));
1427 cupsCharsetToUTF8((cups_utf8_t
*)option
->text
, text
,
1428 sizeof(option
->text
), encoding
);
1430 strlcpy(option
->text
, name
, sizeof(option
->text
));
1432 option
->section
= PPD_ORDER_JCL
;
1435 _cupsStrFree(string
);
1439 * Add a custom option choice if we have already seen a CustomFoo
1443 snprintf(custom_name
, sizeof(custom_name
), "Custom%s", name
);
1445 if ((custom_attr
= ppdFindAttr(ppd
, custom_name
, "True")) != NULL
)
1447 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
1449 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1451 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1456 strlcpy(choice
->text
,
1457 custom_attr
->text
[0] ? custom_attr
->text
: _("Custom"),
1458 sizeof(choice
->text
));
1459 choice
->code
= _cupsStrRetain(custom_attr
->value
);
1462 else if (!strcmp(keyword
, "CloseUI") || !strcmp(keyword
, "JCLCloseUI"))
1466 _cupsStrFree(string
);
1469 else if (!strcmp(keyword
, "OpenGroup"))
1472 * Open a new group...
1477 cg
->ppd_status
= PPD_NESTED_OPEN_GROUP
;
1484 cg
->ppd_status
= PPD_BAD_OPEN_GROUP
;
1490 * Separate the group name from the text (name/text)...
1493 if ((sptr
= strchr(string
, '/')) != NULL
)
1499 * Fix up the text...
1505 * Find/add the group...
1508 group
= ppd_get_group(ppd
, string
, sptr
, cg
, encoding
);
1513 _cupsStrFree(string
);
1516 else if (!strcmp(keyword
, "CloseGroup"))
1520 _cupsStrFree(string
);
1523 else if (!strcmp(keyword
, "OrderDependency"))
1525 order
= (float)_cupsStrScand(string
, &sptr
, loc
);
1527 if (!sptr
|| sscanf(sptr
, "%40s%40s", name
, keyword
) != 2)
1529 cg
->ppd_status
= PPD_BAD_ORDER_DEPENDENCY
;
1534 if (keyword
[0] == '*')
1535 _cups_strcpy(keyword
, keyword
+ 1);
1537 if (!strcmp(name
, "ExitServer"))
1538 section
= PPD_ORDER_EXIT
;
1539 else if (!strcmp(name
, "Prolog"))
1540 section
= PPD_ORDER_PROLOG
;
1541 else if (!strcmp(name
, "DocumentSetup"))
1542 section
= PPD_ORDER_DOCUMENT
;
1543 else if (!strcmp(name
, "PageSetup"))
1544 section
= PPD_ORDER_PAGE
;
1545 else if (!strcmp(name
, "JCLSetup"))
1546 section
= PPD_ORDER_JCL
;
1548 section
= PPD_ORDER_ANY
;
1556 * Only valid for Non-UI options...
1559 for (i
= ppd
->num_groups
, gtemp
= ppd
->groups
; i
> 0; i
--, gtemp
++)
1560 if (gtemp
->text
[0] == '\0')
1564 for (i
= 0; i
< gtemp
->num_options
; i
++)
1565 if (!strcmp(keyword
, gtemp
->options
[i
].keyword
))
1567 gtemp
->options
[i
].section
= section
;
1568 gtemp
->options
[i
].order
= order
;
1574 option
->section
= section
;
1575 option
->order
= order
;
1578 _cupsStrFree(string
);
1581 else if (!strncmp(keyword
, "Default", 7))
1587 * Drop UI text, if any, from value...
1590 if (strchr(string
, '/') != NULL
)
1591 *strchr(string
, '/') = '\0';
1594 * Assign the default value as appropriate...
1597 if (!strcmp(keyword
, "DefaultColorSpace"))
1600 * Set default colorspace...
1603 if (!strcmp(string
, "CMY"))
1604 ppd
->colorspace
= PPD_CS_CMY
;
1605 else if (!strcmp(string
, "CMYK"))
1606 ppd
->colorspace
= PPD_CS_CMYK
;
1607 else if (!strcmp(string
, "RGB"))
1608 ppd
->colorspace
= PPD_CS_RGB
;
1609 else if (!strcmp(string
, "RGBK"))
1610 ppd
->colorspace
= PPD_CS_RGBK
;
1611 else if (!strcmp(string
, "N"))
1612 ppd
->colorspace
= PPD_CS_N
;
1614 ppd
->colorspace
= PPD_CS_GRAY
;
1616 else if (option
&& !strcmp(keyword
+ 7, option
->keyword
))
1619 * Set the default as part of the current option...
1622 DEBUG_printf(("2_ppdOpen: Setting %s to %s...", keyword
, string
));
1624 strlcpy(option
->defchoice
, string
, sizeof(option
->defchoice
));
1626 DEBUG_printf(("2_ppdOpen: %s is now %s...", keyword
, option
->defchoice
));
1631 * Lookup option and set if it has been defined...
1634 ppd_option_t
*toption
; /* Temporary option */
1637 if ((toption
= ppdFindOption(ppd
, keyword
+ 7)) != NULL
)
1639 DEBUG_printf(("2_ppdOpen: Setting %s to %s...", keyword
, string
));
1640 strlcpy(toption
->defchoice
, string
, sizeof(toption
->defchoice
));
1644 else if (!strcmp(keyword
, "UIConstraints") ||
1645 !strcmp(keyword
, "NonUIConstraints"))
1649 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1653 if (ppd
->num_consts
== 0)
1654 constraint
= calloc(2, sizeof(ppd_const_t
));
1656 constraint
= realloc(ppd
->consts
, (size_t)(ppd
->num_consts
+ 2) * sizeof(ppd_const_t
));
1658 if (constraint
== NULL
)
1660 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1665 ppd
->consts
= constraint
;
1666 constraint
+= ppd
->num_consts
;
1669 switch (sscanf(string
, "%40s%40s%40s%40s", constraint
->option1
,
1670 constraint
->choice1
, constraint
->option2
,
1671 constraint
->choice2
))
1673 case 0 : /* Error */
1674 case 1 : /* Error */
1675 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1678 case 2 : /* Two options... */
1680 * Check for broken constraints like "* Option"...
1683 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1684 (!strcmp(constraint
->option1
, "*") ||
1685 !strcmp(constraint
->choice1
, "*")))
1687 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1692 * The following strcpy's are safe, as optionN and
1693 * choiceN are all the same size (size defined by PPD spec...)
1696 if (constraint
->option1
[0] == '*')
1697 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1698 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1700 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1704 if (constraint
->choice1
[0] == '*')
1705 _cups_strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1706 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1708 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1712 constraint
->choice1
[0] = '\0';
1713 constraint
->choice2
[0] = '\0';
1716 case 3 : /* Two options, one choice... */
1718 * Check for broken constraints like "* Option"...
1721 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1722 (!strcmp(constraint
->option1
, "*") ||
1723 !strcmp(constraint
->choice1
, "*") ||
1724 !strcmp(constraint
->option2
, "*")))
1726 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1731 * The following _cups_strcpy's are safe, as optionN and
1732 * choiceN are all the same size (size defined by PPD spec...)
1735 if (constraint
->option1
[0] == '*')
1736 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1737 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1739 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1743 if (constraint
->choice1
[0] == '*')
1745 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1746 constraint
->option2
[0] == '*')
1748 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1752 _cups_strcpy(constraint
->choice2
, constraint
->option2
);
1753 _cups_strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1754 constraint
->choice1
[0] = '\0';
1758 if (constraint
->option2
[0] == '*')
1759 _cups_strcpy(constraint
->option2
, constraint
->option2
+ 1);
1760 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1762 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1766 constraint
->choice2
[0] = '\0';
1770 case 4 : /* Two options, two choices... */
1772 * Check for broken constraints like "* Option"...
1775 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1776 (!strcmp(constraint
->option1
, "*") ||
1777 !strcmp(constraint
->choice1
, "*") ||
1778 !strcmp(constraint
->option2
, "*") ||
1779 !strcmp(constraint
->choice2
, "*")))
1781 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1785 if (constraint
->option1
[0] == '*')
1786 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1787 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1789 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1793 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1794 constraint
->choice1
[0] == '*')
1796 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1800 if (constraint
->option2
[0] == '*')
1801 _cups_strcpy(constraint
->option2
, constraint
->option2
+ 1);
1802 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1804 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1808 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1809 constraint
->choice2
[0] == '*')
1811 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1818 * Don't add this one as an attribute...
1821 _cupsStrFree(string
);
1824 else if (!strcmp(keyword
, "PaperDimension"))
1826 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1827 size
= ppd_add_size(ppd
, name
);
1832 * Unable to add or find size!
1835 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1840 size
->width
= (float)_cupsStrScand(string
, &sptr
, loc
);
1841 size
->length
= (float)_cupsStrScand(sptr
, NULL
, loc
);
1843 _cupsStrFree(string
);
1846 else if (!strcmp(keyword
, "ImageableArea"))
1848 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1849 size
= ppd_add_size(ppd
, name
);
1854 * Unable to add or find size!
1857 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1862 size
->left
= (float)_cupsStrScand(string
, &sptr
, loc
);
1863 size
->bottom
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
1864 size
->right
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
1865 size
->top
= (float)_cupsStrScand(sptr
, NULL
, loc
);
1867 _cupsStrFree(string
);
1870 else if (option
!= NULL
&&
1871 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
1872 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
) &&
1873 !strcmp(keyword
, option
->keyword
))
1875 DEBUG_printf(("2_ppdOpen: group=%p, subgroup=%p", group
, subgroup
));
1877 if (!strcmp(keyword
, "PageSize"))
1880 * Add a page size...
1883 if (ppdPageSize(ppd
, name
) == NULL
)
1884 ppd_add_size(ppd
, name
);
1888 * Add the option choice...
1891 if ((choice
= ppd_add_choice(option
, name
)) == NULL
)
1893 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1899 cupsCharsetToUTF8((cups_utf8_t
*)choice
->text
, text
,
1900 sizeof(choice
->text
), encoding
);
1901 else if (!strcmp(name
, "True"))
1902 strlcpy(choice
->text
, _("Yes"), sizeof(choice
->text
));
1903 else if (!strcmp(name
, "False"))
1904 strlcpy(choice
->text
, _("No"), sizeof(choice
->text
));
1906 strlcpy(choice
->text
, name
, sizeof(choice
->text
));
1908 if (option
->section
== PPD_ORDER_JCL
)
1909 ppd_decode(string
); /* Decode quoted string */
1911 choice
->code
= string
;
1912 string
= NULL
; /* Don't add as an attribute below */
1916 * Add remaining lines with keywords and string values as attributes...
1920 (mask
& (PPD_KEYWORD
| PPD_STRING
)) == (PPD_KEYWORD
| PPD_STRING
))
1921 ppd_add_attr(ppd
, keyword
, name
, text
, string
);
1923 _cupsStrFree(string
);
1927 * Check for a missing CloseGroup...
1930 if (group
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1932 cg
->ppd_status
= PPD_MISSING_CLOSE_GROUP
;
1936 ppd_free(line
.buffer
);
1939 * Reset language preferences...
1943 if (!cupsFileEOF(fp
))
1944 DEBUG_printf(("1_ppdOpen: Premature EOF at %lu...\n",
1945 (unsigned long)cupsFileTell(fp
)));
1948 if (cg
->ppd_status
!= PPD_OK
)
1951 * Had an error reading the PPD file, cannot continue!
1960 * Update the filters array as needed...
1963 if (!ppd_update_filters(ppd
, cg
))
1971 * Create the sorted options array and set the option back-pointer for
1972 * each choice and custom option...
1975 ppd
->options
= cupsArrayNew2((cups_array_func_t
)ppd_compare_options
, NULL
,
1976 (cups_ahash_func_t
)ppd_hash_option
,
1979 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
1983 for (j
= group
->num_options
, option
= group
->options
;
1987 ppd_coption_t
*coption
; /* Custom option */
1990 cupsArrayAdd(ppd
->options
, option
);
1992 for (k
= 0; k
< option
->num_choices
; k
++)
1993 option
->choices
[k
].option
= option
;
1995 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)) != NULL
)
1996 coption
->option
= option
;
2001 * Create an array to track the marked choices...
2004 ppd
->marked
= cupsArrayNew((cups_array_func_t
)ppd_compare_choices
, NULL
);
2007 * Return the PPD file structure...
2013 * Common exit point for errors to save code size...
2018 _cupsStrFree(string
);
2019 ppd_free(line
.buffer
);
2028 * 'ppdOpen()' - Read a PPD file into memory.
2031 ppd_file_t
* /* O - PPD file record */
2032 ppdOpen(FILE *fp
) /* I - File to read from */
2034 ppd_file_t
*ppd
; /* PPD file record */
2035 cups_file_t
*cf
; /* CUPS file */
2039 * Reopen the stdio file as a CUPS file...
2042 if ((cf
= cupsFileOpenFd(fileno(fp
), "r")) == NULL
)
2046 * Load the PPD file using the newer API...
2049 ppd
= _ppdOpen(cf
, _PPD_LOCALIZATION_DEFAULT
);
2052 * Close the CUPS file and return the PPD...
2062 * 'ppdOpen2()' - Read a PPD file into memory.
2064 * @since CUPS 1.2/OS X 10.5@
2067 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2068 ppdOpen2(cups_file_t
*fp
) /* I - File to read from */
2070 return _ppdOpen(fp
, _PPD_LOCALIZATION_DEFAULT
);
2075 * 'ppdOpenFd()' - Read a PPD file into memory.
2078 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2079 ppdOpenFd(int fd
) /* I - File to read from */
2081 cups_file_t
*fp
; /* CUPS file pointer */
2082 ppd_file_t
*ppd
; /* PPD file record */
2083 _cups_globals_t
*cg
= _cupsGlobals();
2088 * Set the line number to 0...
2094 * Range check input...
2099 cg
->ppd_status
= PPD_NULL_FILE
;
2105 * Try to open the file and parse it...
2108 if ((fp
= cupsFileOpenFd(fd
, "r")) != NULL
)
2116 cg
->ppd_status
= PPD_FILE_OPEN_ERROR
;
2125 * '_ppdOpenFile()' - Read a PPD file into memory.
2128 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2129 _ppdOpenFile(const char *filename
, /* I - File to read from */
2130 _ppd_localization_t localization
) /* I - Localization to load */
2132 cups_file_t
*fp
; /* File pointer */
2133 ppd_file_t
*ppd
; /* PPD file record */
2134 _cups_globals_t
*cg
= _cupsGlobals();
2139 * Set the line number to 0...
2145 * Range check input...
2148 if (filename
== NULL
)
2150 cg
->ppd_status
= PPD_NULL_FILE
;
2156 * Try to open the file and parse it...
2159 if ((fp
= cupsFileOpen(filename
, "r")) != NULL
)
2161 ppd
= _ppdOpen(fp
, localization
);
2167 cg
->ppd_status
= PPD_FILE_OPEN_ERROR
;
2176 * 'ppdOpenFile()' - Read a PPD file into memory.
2179 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2180 ppdOpenFile(const char *filename
) /* I - File to read from */
2182 return _ppdOpenFile(filename
, _PPD_LOCALIZATION_DEFAULT
);
2187 * 'ppdSetConformance()' - Set the conformance level for PPD files.
2189 * @since CUPS 1.1.20/OS X 10.4@
2193 ppdSetConformance(ppd_conform_t c
) /* I - Conformance level */
2195 _cups_globals_t
*cg
= _cupsGlobals();
2199 cg
->ppd_conform
= c
;
2204 * 'ppd_add_attr()' - Add an attribute to the PPD data.
2207 static ppd_attr_t
* /* O - New attribute */
2208 ppd_add_attr(ppd_file_t
*ppd
, /* I - PPD file data */
2209 const char *name
, /* I - Attribute name */
2210 const char *spec
, /* I - Specifier string, if any */
2211 const char *text
, /* I - Text string, if any */
2212 const char *value
) /* I - Value of attribute */
2214 ppd_attr_t
**ptr
, /* New array */
2215 *temp
; /* New attribute */
2219 * Range check input...
2222 if (ppd
== NULL
|| name
== NULL
|| spec
== NULL
)
2226 * Create the array as needed...
2229 if (!ppd
->sorted_attrs
)
2230 ppd
->sorted_attrs
= cupsArrayNew((cups_array_func_t
)ppd_compare_attrs
,
2234 * Allocate memory for the new attribute...
2237 if (ppd
->num_attrs
== 0)
2238 ptr
= malloc(sizeof(ppd_attr_t
*));
2240 ptr
= realloc(ppd
->attrs
, (size_t)(ppd
->num_attrs
+ 1) * sizeof(ppd_attr_t
*));
2246 ptr
+= ppd
->num_attrs
;
2248 if ((temp
= calloc(1, sizeof(ppd_attr_t
))) == NULL
)
2259 strlcpy(temp
->name
, name
, sizeof(temp
->name
));
2260 strlcpy(temp
->spec
, spec
, sizeof(temp
->spec
));
2261 strlcpy(temp
->text
, text
, sizeof(temp
->text
));
2262 temp
->value
= (char *)value
;
2265 * Add the attribute to the sorted array...
2268 cupsArrayAdd(ppd
->sorted_attrs
, temp
);
2271 * Return the attribute...
2279 * 'ppd_add_choice()' - Add a choice to an option.
2282 static ppd_choice_t
* /* O - Named choice */
2283 ppd_add_choice(ppd_option_t
*option
, /* I - Option */
2284 const char *name
) /* I - Name of choice */
2286 ppd_choice_t
*choice
; /* Choice */
2289 if (option
->num_choices
== 0)
2290 choice
= malloc(sizeof(ppd_choice_t
));
2292 choice
= realloc(option
->choices
, sizeof(ppd_choice_t
) * (size_t)(option
->num_choices
+ 1));
2297 option
->choices
= choice
;
2298 choice
+= option
->num_choices
;
2299 option
->num_choices
++;
2301 memset(choice
, 0, sizeof(ppd_choice_t
));
2302 strlcpy(choice
->choice
, name
, sizeof(choice
->choice
));
2309 * 'ppd_add_size()' - Add a page size.
2312 static ppd_size_t
* /* O - Named size */
2313 ppd_add_size(ppd_file_t
*ppd
, /* I - PPD file */
2314 const char *name
) /* I - Name of size */
2316 ppd_size_t
*size
; /* Size */
2319 if (ppd
->num_sizes
== 0)
2320 size
= malloc(sizeof(ppd_size_t
));
2322 size
= realloc(ppd
->sizes
, sizeof(ppd_size_t
) * (size_t)(ppd
->num_sizes
+ 1));
2328 size
+= ppd
->num_sizes
;
2331 memset(size
, 0, sizeof(ppd_size_t
));
2332 strlcpy(size
->name
, name
, sizeof(size
->name
));
2339 * 'ppd_compare_attrs()' - Compare two attributes.
2342 static int /* O - Result of comparison */
2343 ppd_compare_attrs(ppd_attr_t
*a
, /* I - First attribute */
2344 ppd_attr_t
*b
) /* I - Second attribute */
2346 return (_cups_strcasecmp(a
->name
, b
->name
));
2351 * 'ppd_compare_choices()' - Compare two choices...
2354 static int /* O - Result of comparison */
2355 ppd_compare_choices(ppd_choice_t
*a
, /* I - First choice */
2356 ppd_choice_t
*b
) /* I - Second choice */
2358 return (strcmp(a
->option
->keyword
, b
->option
->keyword
));
2363 * 'ppd_compare_coptions()' - Compare two custom options.
2366 static int /* O - Result of comparison */
2367 ppd_compare_coptions(ppd_coption_t
*a
, /* I - First option */
2368 ppd_coption_t
*b
) /* I - Second option */
2370 return (_cups_strcasecmp(a
->keyword
, b
->keyword
));
2375 * 'ppd_compare_options()' - Compare two options.
2378 static int /* O - Result of comparison */
2379 ppd_compare_options(ppd_option_t
*a
, /* I - First option */
2380 ppd_option_t
*b
) /* I - Second option */
2382 return (_cups_strcasecmp(a
->keyword
, b
->keyword
));
2387 * 'ppd_decode()' - Decode a string value...
2390 static int /* O - Length of decoded string */
2391 ppd_decode(char *string
) /* I - String to decode */
2393 char *inptr
, /* Input pointer */
2394 *outptr
; /* Output pointer */
2400 while (*inptr
!= '\0')
2401 if (*inptr
== '<' && isxdigit(inptr
[1] & 255))
2404 * Convert hex to 8-bit values...
2408 while (isxdigit(*inptr
& 255))
2410 if (_cups_isalpha(*inptr
))
2411 *outptr
= (char)((tolower(*inptr
) - 'a' + 10) << 4);
2413 *outptr
= (char)((*inptr
- '0') << 4);
2417 if (!isxdigit(*inptr
& 255))
2420 if (_cups_isalpha(*inptr
))
2421 *outptr
|= (char)(tolower(*inptr
) - 'a' + 10);
2423 *outptr
|= (char)(*inptr
- '0');
2429 while (*inptr
!= '>' && *inptr
!= '\0')
2431 while (*inptr
== '>')
2435 *outptr
++ = *inptr
++;
2439 return ((int)(outptr
- string
));
2444 * 'ppd_free_filters()' - Free the filters array.
2448 ppd_free_filters(ppd_file_t
*ppd
) /* I - PPD file */
2450 int i
; /* Looping var */
2451 char **filter
; /* Current filter */
2454 if (ppd
->num_filters
> 0)
2456 for (i
= ppd
->num_filters
, filter
= ppd
->filters
; i
> 0; i
--, filter
++)
2457 _cupsStrFree(*filter
);
2459 ppd_free(ppd
->filters
);
2461 ppd
->num_filters
= 0;
2462 ppd
->filters
= NULL
;
2468 * 'ppd_free_group()' - Free a single UI group.
2472 ppd_free_group(ppd_group_t
*group
) /* I - Group to free */
2474 int i
; /* Looping var */
2475 ppd_option_t
*option
; /* Current option */
2476 ppd_group_t
*subgroup
; /* Current sub-group */
2479 if (group
->num_options
> 0)
2481 for (i
= group
->num_options
, option
= group
->options
;
2484 ppd_free_option(option
);
2486 ppd_free(group
->options
);
2489 if (group
->num_subgroups
> 0)
2491 for (i
= group
->num_subgroups
, subgroup
= group
->subgroups
;
2494 ppd_free_group(subgroup
);
2496 ppd_free(group
->subgroups
);
2502 * 'ppd_free_option()' - Free a single option.
2506 ppd_free_option(ppd_option_t
*option
) /* I - Option to free */
2508 int i
; /* Looping var */
2509 ppd_choice_t
*choice
; /* Current choice */
2512 if (option
->num_choices
> 0)
2514 for (i
= option
->num_choices
, choice
= option
->choices
;
2518 _cupsStrFree(choice
->code
);
2521 ppd_free(option
->choices
);
2527 * 'ppd_get_coption()' - Get a custom option record.
2530 static ppd_coption_t
* /* O - Custom option... */
2531 ppd_get_coption(ppd_file_t
*ppd
, /* I - PPD file */
2532 const char *name
) /* I - Name of option */
2534 ppd_coption_t
*copt
; /* New custom option */
2538 * See if the option already exists...
2541 if ((copt
= ppdFindCustomOption(ppd
, name
)) != NULL
)
2545 * Not found, so create the custom option record...
2548 if ((copt
= calloc(1, sizeof(ppd_coption_t
))) == NULL
)
2551 strlcpy(copt
->keyword
, name
, sizeof(copt
->keyword
));
2553 copt
->params
= cupsArrayNew((cups_array_func_t
)NULL
, NULL
);
2555 cupsArrayAdd(ppd
->coptions
, copt
);
2558 * Return the new record...
2566 * 'ppd_get_cparam()' - Get a custom parameter record.
2569 static ppd_cparam_t
* /* O - Extended option... */
2570 ppd_get_cparam(ppd_coption_t
*opt
, /* I - PPD file */
2571 const char *param
, /* I - Name of parameter */
2572 const char *text
) /* I - Human-readable text */
2574 ppd_cparam_t
*cparam
; /* New custom parameter */
2578 * See if the parameter already exists...
2581 if ((cparam
= ppdFindCustomParam(opt
, param
)) != NULL
)
2585 * Not found, so create the custom parameter record...
2588 if ((cparam
= calloc(1, sizeof(ppd_cparam_t
))) == NULL
)
2591 strlcpy(cparam
->name
, param
, sizeof(cparam
->name
));
2592 strlcpy(cparam
->text
, text
[0] ? text
: param
, sizeof(cparam
->text
));
2595 * Add this record to the array...
2598 cupsArrayAdd(opt
->params
, cparam
);
2601 * Return the new record...
2609 * 'ppd_get_group()' - Find or create the named group as needed.
2612 static ppd_group_t
* /* O - Named group */
2613 ppd_get_group(ppd_file_t
*ppd
, /* I - PPD file */
2614 const char *name
, /* I - Name of group */
2615 const char *text
, /* I - Text for group */
2616 _cups_globals_t
*cg
, /* I - Global data */
2617 cups_encoding_t encoding
) /* I - Encoding of text */
2619 int i
; /* Looping var */
2620 ppd_group_t
*group
; /* Group */
2623 DEBUG_printf(("7ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)",
2624 ppd
, name
, text
, cg
));
2626 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
2627 if (!strcmp(group
->name
, name
))
2632 DEBUG_printf(("8ppd_get_group: Adding group %s...", name
));
2634 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&& strlen(text
) >= sizeof(group
->text
))
2636 cg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
2641 if (ppd
->num_groups
== 0)
2642 group
= malloc(sizeof(ppd_group_t
));
2644 group
= realloc(ppd
->groups
, (size_t)(ppd
->num_groups
+ 1) * sizeof(ppd_group_t
));
2648 cg
->ppd_status
= PPD_ALLOC_ERROR
;
2653 ppd
->groups
= group
;
2654 group
+= ppd
->num_groups
;
2657 memset(group
, 0, sizeof(ppd_group_t
));
2658 strlcpy(group
->name
, name
, sizeof(group
->name
));
2660 cupsCharsetToUTF8((cups_utf8_t
*)group
->text
, text
,
2661 sizeof(group
->text
), encoding
);
2669 * 'ppd_get_option()' - Find or create the named option as needed.
2672 static ppd_option_t
* /* O - Named option */
2673 ppd_get_option(ppd_group_t
*group
, /* I - Group */
2674 const char *name
) /* I - Name of option */
2676 int i
; /* Looping var */
2677 ppd_option_t
*option
; /* Option */
2680 DEBUG_printf(("7ppd_get_option(group=%p(\"%s\"), name=\"%s\")",
2681 group
, group
->name
, name
));
2683 for (i
= group
->num_options
, option
= group
->options
; i
> 0; i
--, option
++)
2684 if (!strcmp(option
->keyword
, name
))
2689 if (group
->num_options
== 0)
2690 option
= malloc(sizeof(ppd_option_t
));
2692 option
= realloc(group
->options
, (size_t)(group
->num_options
+ 1) * sizeof(ppd_option_t
));
2697 group
->options
= option
;
2698 option
+= group
->num_options
;
2699 group
->num_options
++;
2701 memset(option
, 0, sizeof(ppd_option_t
));
2702 strlcpy(option
->keyword
, name
, sizeof(option
->keyword
));
2710 * 'ppd_hash_option()' - Generate a hash of the option name...
2713 static int /* O - Hash index */
2714 ppd_hash_option(ppd_option_t
*option
) /* I - Option */
2716 int hash
= 0; /* Hash index */
2717 const char *k
; /* Pointer into keyword */
2720 for (hash
= option
->keyword
[0], k
= option
->keyword
+ 1; *k
;)
2721 hash
= 33 * hash
+ *k
++;
2723 return (hash
& 511);
2728 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2732 static int /* O - Bitmask of fields read */
2733 ppd_read(cups_file_t
*fp
, /* I - File to read from */
2734 _ppd_line_t
*line
, /* I - Line buffer */
2735 char *keyword
, /* O - Keyword from line */
2736 char *option
, /* O - Option from line */
2737 char *text
, /* O - Human-readable text from line */
2738 char **string
, /* O - Code/string data */
2739 int ignoreblank
, /* I - Ignore blank lines? */
2740 _cups_globals_t
*cg
) /* I - Global data */
2742 int ch
, /* Character from file */
2743 col
, /* Column in line */
2744 colon
, /* Colon seen? */
2745 endquote
, /* Waiting for an end quote */
2746 mask
, /* Mask to be returned */
2747 startline
, /* Start line */
2748 textlen
; /* Length of text */
2749 char *keyptr
, /* Keyword pointer */
2750 *optptr
, /* Option pointer */
2751 *textptr
, /* Text pointer */
2752 *strptr
, /* Pointer into string */
2753 *lineptr
; /* Current position in line buffer */
2757 * Now loop until we have a valid line...
2762 startline
= cg
->ppd_line
+ 1;
2766 line
->bufsize
= 1024;
2767 line
->buffer
= malloc(1024);
2779 lineptr
= line
->buffer
;
2783 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2785 if (lineptr
>= (line
->buffer
+ line
->bufsize
- 1))
2788 * Expand the line buffer...
2791 char *temp
; /* Temporary line pointer */
2794 line
->bufsize
+= 1024;
2795 if (line
->bufsize
> 262144)
2798 * Don't allow lines longer than 256k!
2801 cg
->ppd_line
= startline
;
2802 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2807 temp
= realloc(line
->buffer
, line
->bufsize
);
2810 cg
->ppd_line
= startline
;
2811 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2816 lineptr
= temp
+ (lineptr
- line
->buffer
);
2817 line
->buffer
= temp
;
2820 if (ch
== '\r' || ch
== '\n')
2823 * Line feed or carriage return...
2832 * Check for a trailing line feed...
2835 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2842 cupsFileGetChar(fp
);
2845 if (lineptr
== line
->buffer
&& ignoreblank
)
2846 continue; /* Skip blank lines */
2850 if (!endquote
) /* Continue for multi-line text */
2855 else if (ch
< ' ' && ch
!= '\t' && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2858 * Other control characters...
2861 cg
->ppd_line
= startline
;
2862 cg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
2866 else if (ch
!= 0x1a)
2869 * Any other character...
2872 *lineptr
++ = (char)ch
;
2875 if (col
> (PPD_MAX_LINE
- 1))
2878 * Line is too long...
2881 cg
->ppd_line
= startline
;
2882 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2887 if (ch
== ':' && strncmp(line
->buffer
, "*%", 2) != 0)
2890 if (ch
== '\"' && colon
)
2891 endquote
= !endquote
;
2898 * Didn't finish this quoted string...
2901 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2904 else if (ch
== '\r' || ch
== '\n')
2912 * Check for a trailing line feed...
2915 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2918 cupsFileGetChar(fp
);
2921 else if (ch
< ' ' && ch
!= '\t' && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2924 * Other control characters...
2927 cg
->ppd_line
= startline
;
2928 cg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
2932 else if (ch
!= 0x1a)
2936 if (col
> (PPD_MAX_LINE
- 1))
2939 * Line is too long...
2942 cg
->ppd_line
= startline
;
2943 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2953 * Didn't finish this line...
2956 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2957 if (ch
== '\r' || ch
== '\n')
2960 * Line feed or carriage return...
2969 * Check for a trailing line feed...
2972 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2975 cupsFileGetChar(fp
);
2980 else if (ch
< ' ' && ch
!= '\t' && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2983 * Other control characters...
2986 cg
->ppd_line
= startline
;
2987 cg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
2991 else if (ch
!= 0x1a)
2995 if (col
> (PPD_MAX_LINE
- 1))
2998 * Line is too long...
3001 cg
->ppd_line
= startline
;
3002 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
3009 if (lineptr
> line
->buffer
&& lineptr
[-1] == '\n')
3014 DEBUG_printf(("9ppd_read: LINE=\"%s\"", line
->buffer
));
3017 * The dynamically created PPDs for older style OS X
3018 * drivers include a large blob of data inserted as comments
3019 * at the end of the file. As an optimization we can stop
3020 * reading the PPD when we get to the start of this data.
3023 if (!strcmp(line
->buffer
, "*%APLWORKSET START"))
3026 if (ch
== EOF
&& lineptr
== line
->buffer
)
3034 lineptr
= line
->buffer
+ 1;
3041 if ((!line
->buffer
[0] || /* Blank line */
3042 !strncmp(line
->buffer
, "*%", 2) || /* Comment line */
3043 !strcmp(line
->buffer
, "*End")) && /* End of multi-line string */
3044 ignoreblank
) /* Ignore these? */
3046 startline
= cg
->ppd_line
+ 1;
3050 if (!strcmp(line
->buffer
, "*")) /* (Bad) comment line */
3052 if (cg
->ppd_conform
== PPD_CONFORM_RELAXED
)
3054 startline
= cg
->ppd_line
+ 1;
3059 cg
->ppd_line
= startline
;
3060 cg
->ppd_status
= PPD_ILLEGAL_MAIN_KEYWORD
;
3066 if (line
->buffer
[0] != '*') /* All lines start with an asterisk */
3069 * Allow lines consisting of just whitespace...
3072 for (lineptr
= line
->buffer
; *lineptr
; lineptr
++)
3073 if (*lineptr
&& !_cups_isspace(*lineptr
))
3078 cg
->ppd_status
= PPD_MISSING_ASTERISK
;
3081 else if (ignoreblank
)
3093 while (*lineptr
&& *lineptr
!= ':' && !_cups_isspace(*lineptr
))
3095 if (*lineptr
<= ' ' || *lineptr
> 126 || *lineptr
== '/' ||
3096 (keyptr
- keyword
) >= (PPD_MAX_NAME
- 1))
3098 cg
->ppd_status
= PPD_ILLEGAL_MAIN_KEYWORD
;
3102 *keyptr
++ = *lineptr
++;
3107 if (!strcmp(keyword
, "End"))
3110 mask
|= PPD_KEYWORD
;
3112 if (_cups_isspace(*lineptr
))
3115 * Get an option name...
3118 while (_cups_isspace(*lineptr
))
3123 while (*lineptr
&& !_cups_isspace(*lineptr
) && *lineptr
!= ':' &&
3126 if (*lineptr
<= ' ' || *lineptr
> 126 ||
3127 (optptr
- option
) >= (PPD_MAX_NAME
- 1))
3129 cg
->ppd_status
= PPD_ILLEGAL_OPTION_KEYWORD
;
3133 *optptr
++ = *lineptr
++;
3138 if (_cups_isspace(*lineptr
) && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
3140 cg
->ppd_status
= PPD_ILLEGAL_WHITESPACE
;
3144 while (_cups_isspace(*lineptr
))
3149 if (*lineptr
== '/')
3152 * Get human-readable text...
3159 while (*lineptr
!= '\0' && *lineptr
!= '\n' && *lineptr
!= ':')
3161 if (((unsigned char)*lineptr
< ' ' && *lineptr
!= '\t') ||
3162 (textptr
- text
) >= (PPD_MAX_LINE
- 1))
3164 cg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
3168 *textptr
++ = *lineptr
++;
3172 textlen
= ppd_decode(text
);
3174 if (textlen
> PPD_MAX_TEXT
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
3176 cg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
3184 if (_cups_isspace(*lineptr
) && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
3186 cg
->ppd_status
= PPD_ILLEGAL_WHITESPACE
;
3190 while (_cups_isspace(*lineptr
))
3193 if (*lineptr
== ':')
3196 * Get string after triming leading and trailing whitespace...
3200 while (_cups_isspace(*lineptr
))
3203 strptr
= lineptr
+ strlen(lineptr
) - 1;
3204 while (strptr
>= lineptr
&& _cups_isspace(*strptr
))
3207 if (*strptr
== '\"')
3210 * Quoted string by itself, remove quotes...
3217 *string
= _cupsStrAlloc(lineptr
);
3229 * 'ppd_update_filters()' - Update the filters array as needed.
3231 * This function re-populates the filters array with cupsFilter2 entries that
3232 * have been stripped of the destination MIME media types and any maxsize hints.
3234 * (All for backwards-compatibility)
3237 static int /* O - 1 on success, 0 on failure */
3238 ppd_update_filters(ppd_file_t
*ppd
,/* I - PPD file */
3239 _cups_globals_t
*cg
) /* I - Global data */
3241 ppd_attr_t
*attr
; /* Current cupsFilter2 value */
3242 char srcsuper
[16], /* Source MIME media type */
3244 dstsuper
[16], /* Destination MIME media type */
3246 program
[1024], /* Command to run */
3247 *ptr
, /* Pointer into command to run */
3248 buffer
[1024], /* Re-written cupsFilter value */
3249 **filter
; /* Current filter */
3250 int cost
; /* Cost of filter */
3253 DEBUG_printf(("4ppd_update_filters(ppd=%p, cg=%p)", ppd
, cg
));
3256 * See if we have any cupsFilter2 lines...
3259 if ((attr
= ppdFindAttr(ppd
, "cupsFilter2", NULL
)) == NULL
)
3261 DEBUG_puts("5ppd_update_filters: No cupsFilter2 keywords present.");
3266 * Yes, free the cupsFilter-defined filters and re-build...
3269 ppd_free_filters(ppd
);
3274 * Parse the cupsFilter2 string:
3276 * src/type dst/type cost program
3277 * src/type dst/type cost maxsize(n) program
3280 DEBUG_printf(("5ppd_update_filters: cupsFilter2=\"%s\"", attr
->value
));
3282 if (sscanf(attr
->value
, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
3283 srcsuper
, srctype
, dstsuper
, dsttype
, &cost
, program
) != 6)
3285 DEBUG_puts("5ppd_update_filters: Bad cupsFilter2 line.");
3286 cg
->ppd_status
= PPD_BAD_VALUE
;
3291 DEBUG_printf(("5ppd_update_filters: srcsuper=\"%s\", srctype=\"%s\", "
3292 "dstsuper=\"%s\", dsttype=\"%s\", cost=%d, program=\"%s\"",
3293 srcsuper
, srctype
, dstsuper
, dsttype
, cost
, program
));
3295 if (!strncmp(program
, "maxsize(", 8) &&
3296 (ptr
= strchr(program
+ 8, ')')) != NULL
)
3298 DEBUG_puts("5ppd_update_filters: Found maxsize(nnn).");
3301 while (_cups_isspace(*ptr
))
3304 _cups_strcpy(program
, ptr
);
3305 DEBUG_printf(("5ppd_update_filters: New program=\"%s\"", program
));
3309 * Convert to cupsFilter format:
3311 * src/type cost program
3314 snprintf(buffer
, sizeof(buffer
), "%s/%s %d %s", srcsuper
, srctype
, cost
,
3316 DEBUG_printf(("5ppd_update_filters: Adding \"%s\".", buffer
));
3319 * Add a cupsFilter-compatible string to the filters array.
3322 if (ppd
->num_filters
== 0)
3323 filter
= malloc(sizeof(char *));
3325 filter
= realloc(ppd
->filters
, sizeof(char *) * (size_t)(ppd
->num_filters
+ 1));
3329 DEBUG_puts("5ppd_update_filters: Out of memory.");
3330 cg
->ppd_status
= PPD_ALLOC_ERROR
;
3335 ppd
->filters
= filter
;
3336 filter
+= ppd
->num_filters
;
3337 ppd
->num_filters
++;
3339 *filter
= _cupsStrAlloc(buffer
);
3341 while ((attr
= ppdFindNextAttr(ppd
, "cupsFilter2", NULL
)) != NULL
);
3343 DEBUG_puts("5ppd_update_filters: Completed OK.");