4 * PPD file routines for CUPS.
6 * Copyright 2007-2012 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 * _ppdOpen() - Read a PPD file into memory.
35 * ppdOpen2() - Read a PPD file into memory.
36 * ppdOpenFd() - Read a PPD file into memory.
37 * _ppdOpenFile() - Read a PPD file into memory.
38 * ppdOpenFile() - Read a PPD file into memory.
39 * ppdSetConformance() - Set the conformance level for PPD files.
40 * ppd_add_attr() - Add an attribute to the PPD data.
41 * ppd_add_choice() - Add a choice to an option.
42 * ppd_add_size() - Add a page size.
43 * ppd_compare_attrs() - Compare two attributes.
44 * ppd_compare_choices() - Compare two choices...
45 * ppd_compare_coptions() - Compare two custom options.
46 * ppd_compare_options() - Compare two options.
47 * ppd_decode() - Decode a string value...
48 * ppd_free_filters() - Free the filters array.
49 * ppd_free_group() - Free a single UI group.
50 * ppd_free_option() - Free a single option.
51 * ppd_get_coption() - Get a custom option record.
52 * ppd_get_cparam() - Get a custom parameter record.
53 * ppd_get_group() - Find or create the named group as needed.
54 * ppd_get_option() - Find or create the named option as needed.
55 * ppd_hash_option() - Generate a hash of the option name...
56 * ppd_read() - Read a line from a PPD file, skipping comment
58 * ppd_update_filters() - Update the filters array as needed.
62 * Include necessary headers.
65 #include "cups-private.h"
66 #include "ppd-private.h"
73 #if defined(WIN32) || defined(__EMX__)
74 # define READ_BINARY "rb" /* Open a binary file for reading */
75 # define WRITE_BINARY "wb" /* Open a binary file for writing */
77 # define READ_BINARY "r" /* Open a binary file for reading */
78 # define WRITE_BINARY "w" /* Open a binary file for writing */
79 #endif /* WIN32 || __EMX__ */
81 #define ppd_free(p) if (p) free(p) /* Safe free macro */
83 #define PPD_KEYWORD 1 /* Line contained a keyword */
84 #define PPD_OPTION 2 /* Line contained an option name */
85 #define PPD_TEXT 4 /* Line contained human-readable text */
86 #define PPD_STRING 8 /* Line contained a string or code */
88 #define PPD_HASHSIZE 512 /* Size of hash */
92 * Line buffer structure...
95 typedef struct _ppd_line_s
97 char *buffer
; /* Pointer to buffer */
98 size_t bufsize
; /* Size of the buffer */
106 static ppd_attr_t
*ppd_add_attr(ppd_file_t
*ppd
, const char *name
,
107 const char *spec
, const char *text
,
109 static ppd_choice_t
*ppd_add_choice(ppd_option_t
*option
, const char *name
);
110 static ppd_size_t
*ppd_add_size(ppd_file_t
*ppd
, const char *name
);
111 static int ppd_compare_attrs(ppd_attr_t
*a
, ppd_attr_t
*b
);
112 static int ppd_compare_choices(ppd_choice_t
*a
, ppd_choice_t
*b
);
113 static int ppd_compare_coptions(ppd_coption_t
*a
,
115 static int ppd_compare_options(ppd_option_t
*a
, ppd_option_t
*b
);
116 static int ppd_decode(char *string
);
117 static void ppd_free_filters(ppd_file_t
*ppd
);
118 static void ppd_free_group(ppd_group_t
*group
);
119 static void ppd_free_option(ppd_option_t
*option
);
120 static ppd_coption_t
*ppd_get_coption(ppd_file_t
*ppd
, const char *name
);
121 static ppd_cparam_t
*ppd_get_cparam(ppd_coption_t
*opt
,
124 static ppd_group_t
*ppd_get_group(ppd_file_t
*ppd
, const char *name
,
125 const char *text
, _cups_globals_t
*cg
,
126 cups_encoding_t encoding
);
127 static ppd_option_t
*ppd_get_option(ppd_group_t
*group
, const char *name
);
128 static int ppd_hash_option(ppd_option_t
*option
);
129 static int ppd_read(cups_file_t
*fp
, _ppd_line_t
*line
,
130 char *keyword
, char *option
, char *text
,
131 char **string
, int ignoreblank
,
132 _cups_globals_t
*cg
);
133 static int ppd_update_filters(ppd_file_t
*ppd
,
134 _cups_globals_t
*cg
);
138 * 'ppdClose()' - Free all memory used by the PPD file.
142 ppdClose(ppd_file_t
*ppd
) /* I - PPD file record */
144 int i
; /* Looping var */
145 ppd_emul_t
*emul
; /* Current emulation */
146 ppd_group_t
*group
; /* Current group */
147 char **font
; /* Current font */
148 ppd_attr_t
**attr
; /* Current attribute */
149 ppd_coption_t
*coption
; /* Current custom option */
150 ppd_cparam_t
*cparam
; /* Current custom parameter */
154 * Range check arguments...
161 * Free all strings at the top level...
164 _cupsStrFree(ppd
->lang_encoding
);
165 _cupsStrFree(ppd
->nickname
);
168 _cupsStrFree(ppd
->jcl_begin
);
169 _cupsStrFree(ppd
->jcl_end
);
170 _cupsStrFree(ppd
->jcl_ps
);
173 * Free any emulations...
176 if (ppd
->num_emulations
> 0)
178 for (i
= ppd
->num_emulations
, emul
= ppd
->emulations
; i
> 0; i
--, emul
++)
180 _cupsStrFree(emul
->start
);
181 _cupsStrFree(emul
->stop
);
184 ppd_free(ppd
->emulations
);
188 * Free any UI groups, subgroups, and options...
191 if (ppd
->num_groups
> 0)
193 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
194 ppd_free_group(group
);
196 ppd_free(ppd
->groups
);
199 cupsArrayDelete(ppd
->options
);
200 cupsArrayDelete(ppd
->marked
);
203 * Free any page sizes...
206 if (ppd
->num_sizes
> 0)
207 ppd_free(ppd
->sizes
);
210 * Free any constraints...
213 if (ppd
->num_consts
> 0)
214 ppd_free(ppd
->consts
);
217 * Free any filters...
220 ppd_free_filters(ppd
);
226 if (ppd
->num_fonts
> 0)
228 for (i
= ppd
->num_fonts
, font
= ppd
->fonts
; i
> 0; i
--, font
++)
231 ppd_free(ppd
->fonts
);
235 * Free any profiles...
238 if (ppd
->num_profiles
> 0)
239 ppd_free(ppd
->profiles
);
242 * Free any attributes...
245 if (ppd
->num_attrs
> 0)
247 for (i
= ppd
->num_attrs
, attr
= ppd
->attrs
; i
> 0; i
--, attr
++)
249 _cupsStrFree((*attr
)->value
);
253 ppd_free(ppd
->attrs
);
256 cupsArrayDelete(ppd
->sorted_attrs
);
259 * Free custom options...
262 for (coption
= (ppd_coption_t
*)cupsArrayFirst(ppd
->coptions
);
264 coption
= (ppd_coption_t
*)cupsArrayNext(ppd
->coptions
))
266 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
268 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
270 switch (cparam
->type
)
272 case PPD_CUSTOM_PASSCODE
:
273 case PPD_CUSTOM_PASSWORD
:
274 case PPD_CUSTOM_STRING
:
275 _cupsStrFree(cparam
->current
.custom_string
);
285 cupsArrayDelete(coption
->params
);
290 cupsArrayDelete(ppd
->coptions
);
293 * Free constraints...
296 if (ppd
->cups_uiconstraints
)
298 _ppd_cups_uiconsts_t
*consts
; /* Current constraints */
301 for (consts
= (_ppd_cups_uiconsts_t
*)cupsArrayFirst(ppd
->cups_uiconstraints
);
303 consts
= (_ppd_cups_uiconsts_t
*)cupsArrayNext(ppd
->cups_uiconstraints
))
305 free(consts
->constraints
);
309 cupsArrayDelete(ppd
->cups_uiconstraints
);
313 * Free any PPD cache/mapping data...
317 _ppdCacheDestroy(ppd
->cache
);
320 * Free the whole record...
328 * 'ppdErrorString()' - Returns the text assocated with a status.
330 * @since CUPS 1.1.19/OS X 10.3@
333 const char * /* O - Status string */
334 ppdErrorString(ppd_status_t status
) /* I - PPD status */
336 static const char * const messages
[] =/* Status messages */
339 _("Unable to open PPD file"),
340 _("NULL PPD file pointer"),
341 _("Memory allocation error"),
342 _("Missing PPD-Adobe-4.x header"),
343 _("Missing value string"),
346 _("OpenGroup without a CloseGroup first"),
347 _("Bad OpenUI/JCLOpenUI"),
348 _("OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"),
349 _("Bad OrderDependency"),
350 _("Bad UIConstraints"),
351 _("Missing asterisk in column 1"),
352 _("Line longer than the maximum allowed (255 characters)"),
353 _("Illegal control character"),
354 _("Illegal main keyword string"),
355 _("Illegal option keyword string"),
356 _("Illegal translation string"),
357 _("Illegal whitespace character"),
358 _("Bad custom parameter"),
359 _("Missing option keyword"),
360 _("Bad value string"),
361 _("Missing CloseGroup")
365 if (status
< PPD_OK
|| status
>= PPD_MAX_STATUS
)
366 return (_cupsLangString(cupsLangDefault(), _("Unknown")));
368 return (_cupsLangString(cupsLangDefault(), messages
[status
]));
373 * '_ppdGetEncoding()' - Get the CUPS encoding value for the given
377 cups_encoding_t
/* O - CUPS encoding value */
378 _ppdGetEncoding(const char *name
) /* I - LanguageEncoding string */
380 if (!_cups_strcasecmp(name
, "ISOLatin1"))
381 return (CUPS_ISO8859_1
);
382 else if (!_cups_strcasecmp(name
, "ISOLatin2"))
383 return (CUPS_ISO8859_2
);
384 else if (!_cups_strcasecmp(name
, "ISOLatin5"))
385 return (CUPS_ISO8859_5
);
386 else if (!_cups_strcasecmp(name
, "JIS83-RKSJ"))
387 return (CUPS_JIS_X0213
);
388 else if (!_cups_strcasecmp(name
, "MacStandard"))
389 return (CUPS_MAC_ROMAN
);
390 else if (!_cups_strcasecmp(name
, "WindowsANSI"))
391 return (CUPS_WINDOWS_1252
);
398 * 'ppdLastError()' - Return the status from the last ppdOpen*().
400 * @since CUPS 1.1.19/OS X 10.3@
403 ppd_status_t
/* O - Status code */
404 ppdLastError(int *line
) /* O - Line number */
406 _cups_globals_t
*cg
= _cupsGlobals();
411 *line
= cg
->ppd_line
;
413 return (cg
->ppd_status
);
418 * '_ppdOpen()' - Read a PPD file into memory.
420 * @since CUPS 1.2/OS X 10.5@
423 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
425 cups_file_t
*fp
, /* I - File to read from */
426 _ppd_localization_t localization
) /* I - Localization to load */
428 int i
, j
, k
; /* Looping vars */
429 int count
; /* Temporary count */
430 _ppd_line_t line
; /* Line buffer */
431 ppd_file_t
*ppd
; /* PPD file record */
432 ppd_group_t
*group
, /* Current group */
433 *subgroup
; /* Current sub-group */
434 ppd_option_t
*option
; /* Current option */
435 ppd_choice_t
*choice
; /* Current choice */
436 ppd_const_t
*constraint
; /* Current constraint */
437 ppd_size_t
*size
; /* Current page size */
438 int mask
; /* Line data mask */
439 char keyword
[PPD_MAX_NAME
],
440 /* Keyword from file */
442 /* Option from file */
444 /* Human-readable text from file */
445 *string
, /* Code/text from file */
446 *sptr
, /* Pointer into string */
447 *nameptr
, /* Pointer into name */
448 *temp
, /* Temporary string pointer */
449 **tempfonts
; /* Temporary fonts pointer */
450 float order
; /* Order dependency number */
451 ppd_section_t section
; /* Order dependency section */
452 ppd_profile_t
*profile
; /* Pointer to color profile */
453 char **filter
; /* Pointer to filter */
454 struct lconv
*loc
; /* Locale data */
455 int ui_keyword
; /* Is this line a UI keyword? */
456 cups_lang_t
*lang
; /* Language data */
457 cups_encoding_t encoding
; /* Encoding of PPD file */
458 _cups_globals_t
*cg
= _cupsGlobals();
460 char custom_name
[PPD_MAX_NAME
];
461 /* CustomFoo attribute name */
462 ppd_attr_t
*custom_attr
; /* CustomFoo attribute */
463 char ll
[4], /* Language + '.' */
464 ll_CC
[7]; /* Language + country + '.' */
465 size_t ll_len
= 0, /* Language length */
466 ll_CC_len
= 0; /* Language + country length */
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 */
528 static const char * const color_keywords
[] = /* Keywords associated with color profiles */
535 DEBUG_printf(("_ppdOpen(fp=%p)", fp
));
538 * Default to "OK" status...
541 cg
->ppd_status
= PPD_OK
;
545 * Range check input...
550 cg
->ppd_status
= PPD_NULL_FILE
;
555 * If only loading a single localization set up the strings to match...
558 if (localization
== _PPD_LOCALIZATION_DEFAULT
)
560 if ((lang
= cupsLangDefault()) == NULL
)
563 snprintf(ll_CC
, sizeof(ll_CC
), "%s.", lang
->language
);
564 snprintf(ll
, sizeof(ll
), "%2.2s.", lang
->language
);
566 ll_CC_len
= strlen(ll_CC
);
569 DEBUG_printf(("2_ppdOpen: Loading localizations matching \"%s\" and \"%s\"",
574 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
580 mask
= ppd_read(fp
, &line
, keyword
, name
, text
, &string
, 0, cg
);
582 DEBUG_printf(("2_ppdOpen: mask=%x, keyword=\"%s\"...", mask
, keyword
));
585 strcmp(keyword
, "PPD-Adobe") ||
586 string
== NULL
|| string
[0] != '4')
589 * Either this is not a PPD file, or it is not a 4.x PPD file.
592 if (cg
->ppd_status
== PPD_OK
)
593 cg
->ppd_status
= PPD_MISSING_PPDADOBE4
;
595 _cupsStrFree(string
);
596 ppd_free(line
.buffer
);
601 DEBUG_printf(("2_ppdOpen: keyword=%s, string=%p", keyword
, string
));
603 _cupsStrFree(string
);
606 * Allocate memory for the PPD file record...
609 if ((ppd
= calloc(1, sizeof(ppd_file_t
))) == NULL
)
611 cg
->ppd_status
= PPD_ALLOC_ERROR
;
613 _cupsStrFree(string
);
614 ppd_free(line
.buffer
);
619 ppd
->language_level
= 2;
620 ppd
->color_device
= 0;
621 ppd
->colorspace
= PPD_CS_N
;
622 ppd
->landscape
= -90;
623 ppd
->coptions
= cupsArrayNew((cups_array_func_t
)ppd_compare_coptions
,
627 * Read lines from the PPD file and add them to the file record...
635 encoding
= CUPS_ISO8859_1
;
638 while ((mask
= ppd_read(fp
, &line
, keyword
, name
, text
, &string
, 1, cg
)) != 0)
640 DEBUG_printf(("2_ppdOpen: mask=%x, keyword=\"%s\", name=\"%s\", "
641 "text=\"%s\", string=%d chars...", mask
, keyword
, name
, text
,
642 string
? (int)strlen(string
) : 0));
644 if (strncmp(keyword
, "Default", 7) && !string
&&
645 cg
->ppd_conform
!= PPD_CONFORM_RELAXED
)
648 * Need a string value!
651 cg
->ppd_status
= PPD_MISSING_VALUE
;
659 * Certain main keywords (as defined by the PPD spec) may be used
660 * without the usual OpenUI/CloseUI stuff. Presumably this is just
661 * so that Adobe wouldn't completely break compatibility with PPD
662 * files prior to v4.0 of the spec, but it is hopelessly
663 * inconsistent... Catch these main keywords and automatically
664 * create the corresponding option, as needed...
670 * Previous line was a UI keyword...
678 * If we are filtering out keyword localizations, see if this line needs to
682 if (localization
!= _PPD_LOCALIZATION_ALL
&&
683 (temp
= strchr(keyword
, '.')) != NULL
&&
684 ((temp
- keyword
) == 2 || (temp
- keyword
) == 5) &&
685 _cups_isalpha(keyword
[0]) &&
686 _cups_isalpha(keyword
[1]) &&
687 (keyword
[2] == '.' ||
688 (keyword
[2] == '_' && _cups_isalpha(keyword
[3]) &&
689 _cups_isalpha(keyword
[4]) && keyword
[5] == '.')))
691 if (localization
== _PPD_LOCALIZATION_NONE
||
692 (localization
== _PPD_LOCALIZATION_DEFAULT
&&
693 strncmp(ll_CC
, keyword
, ll_CC_len
) &&
694 strncmp(ll
, keyword
, ll_len
)))
696 DEBUG_printf(("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword
));
699 else if (localization
== _PPD_LOCALIZATION_ICC_PROFILES
)
702 * Only load localizations for the color profile related keywords...
706 i
< (int)(sizeof(color_keywords
) / sizeof(color_keywords
[0]));
709 if (!_cups_strcasecmp(temp
, color_keywords
[i
]))
713 if (i
>= (int)(sizeof(color_keywords
) / sizeof(color_keywords
[0])))
715 DEBUG_printf(("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword
));
721 if (option
== NULL
&&
722 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
723 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
))
725 for (i
= 0; i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])); i
++)
726 if (!strcmp(keyword
, ui_keywords
[i
]))
729 if (i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])))
732 * Create the option in the appropriate group...
737 DEBUG_printf(("2_ppdOpen: FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!",
742 if ((group
= ppd_get_group(ppd
, "General", _("General"), cg
,
746 DEBUG_printf(("2_ppdOpen: Adding to group %s...", group
->text
));
747 option
= ppd_get_option(group
, keyword
);
751 option
= ppd_get_option(group
, keyword
);
755 cg
->ppd_status
= PPD_ALLOC_ERROR
;
761 * Now fill in the initial information for the option...
764 if (!strncmp(keyword
, "JCL", 3))
765 option
->section
= PPD_ORDER_JCL
;
767 option
->section
= PPD_ORDER_ANY
;
769 option
->order
= 10.0f
;
772 option
->ui
= PPD_UI_BOOLEAN
;
774 option
->ui
= PPD_UI_PICKONE
;
776 for (j
= 0; j
< ppd
->num_attrs
; j
++)
777 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
778 !strcmp(ppd
->attrs
[j
]->name
+ 7, keyword
) &&
779 ppd
->attrs
[j
]->value
)
781 DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
782 option
->keyword
, ppd
->attrs
[j
]->value
));
783 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
784 sizeof(option
->defchoice
));
788 if (!strcmp(keyword
, "PageSize"))
789 strlcpy(option
->text
, _("Media Size"), sizeof(option
->text
));
790 else if (!strcmp(keyword
, "MediaType"))
791 strlcpy(option
->text
, _("Media Type"), sizeof(option
->text
));
792 else if (!strcmp(keyword
, "InputSlot"))
793 strlcpy(option
->text
, _("Media Source"), sizeof(option
->text
));
794 else if (!strcmp(keyword
, "ColorModel"))
795 strlcpy(option
->text
, _("Output Mode"), sizeof(option
->text
));
796 else if (!strcmp(keyword
, "Resolution"))
797 strlcpy(option
->text
, _("Resolution"), sizeof(option
->text
));
799 strlcpy(option
->text
, keyword
, sizeof(option
->text
));
803 if (!strcmp(keyword
, "LanguageLevel"))
804 ppd
->language_level
= atoi(string
);
805 else if (!strcmp(keyword
, "LanguageEncoding"))
808 * Say all PPD files are UTF-8, since we convert to UTF-8...
811 ppd
->lang_encoding
= _cupsStrAlloc("UTF-8");
812 encoding
= _ppdGetEncoding(string
);
814 else if (!strcmp(keyword
, "LanguageVersion"))
815 ppd
->lang_version
= string
;
816 else if (!strcmp(keyword
, "Manufacturer"))
817 ppd
->manufacturer
= string
;
818 else if (!strcmp(keyword
, "ModelName"))
819 ppd
->modelname
= string
;
820 else if (!strcmp(keyword
, "Protocols"))
821 ppd
->protocols
= string
;
822 else if (!strcmp(keyword
, "PCFileName"))
823 ppd
->pcfilename
= string
;
824 else if (!strcmp(keyword
, "NickName"))
826 if (encoding
!= CUPS_UTF8
)
828 cups_utf8_t utf8
[256]; /* UTF-8 version of NickName */
831 cupsCharsetToUTF8(utf8
, string
, sizeof(utf8
), encoding
);
832 ppd
->nickname
= _cupsStrAlloc((char *)utf8
);
835 ppd
->nickname
= _cupsStrAlloc(string
);
837 else if (!strcmp(keyword
, "Product"))
838 ppd
->product
= string
;
839 else if (!strcmp(keyword
, "ShortNickName"))
840 ppd
->shortnickname
= string
;
841 else if (!strcmp(keyword
, "TTRasterizer"))
842 ppd
->ttrasterizer
= string
;
843 else if (!strcmp(keyword
, "JCLBegin"))
845 ppd
->jcl_begin
= _cupsStrAlloc(string
);
846 ppd_decode(ppd
->jcl_begin
); /* Decode quoted string */
848 else if (!strcmp(keyword
, "JCLEnd"))
850 ppd
->jcl_end
= _cupsStrAlloc(string
);
851 ppd_decode(ppd
->jcl_end
); /* Decode quoted string */
853 else if (!strcmp(keyword
, "JCLToPSInterpreter"))
855 ppd
->jcl_ps
= _cupsStrAlloc(string
);
856 ppd_decode(ppd
->jcl_ps
); /* Decode quoted string */
858 else if (!strcmp(keyword
, "AccurateScreensSupport"))
859 ppd
->accurate_screens
= !strcmp(string
, "True");
860 else if (!strcmp(keyword
, "ColorDevice"))
861 ppd
->color_device
= !strcmp(string
, "True");
862 else if (!strcmp(keyword
, "ContoneOnly"))
863 ppd
->contone_only
= !strcmp(string
, "True");
864 else if (!strcmp(keyword
, "cupsFlipDuplex"))
865 ppd
->flip_duplex
= !strcmp(string
, "True");
866 else if (!strcmp(keyword
, "cupsManualCopies"))
867 ppd
->manual_copies
= !strcmp(string
, "True");
868 else if (!strcmp(keyword
, "cupsModelNumber"))
869 ppd
->model_number
= atoi(string
);
870 else if (!strcmp(keyword
, "cupsColorProfile"))
872 if (ppd
->num_profiles
== 0)
873 profile
= malloc(sizeof(ppd_profile_t
));
875 profile
= realloc(ppd
->profiles
, sizeof(ppd_profile_t
) *
876 (ppd
->num_profiles
+ 1));
880 cg
->ppd_status
= PPD_ALLOC_ERROR
;
885 ppd
->profiles
= profile
;
886 profile
+= ppd
->num_profiles
;
887 ppd
->num_profiles
++;
889 memset(profile
, 0, sizeof(ppd_profile_t
));
890 strlcpy(profile
->resolution
, name
, sizeof(profile
->resolution
));
891 strlcpy(profile
->media_type
, text
, sizeof(profile
->media_type
));
893 profile
->density
= (float)_cupsStrScand(string
, &sptr
, loc
);
894 profile
->gamma
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
895 profile
->matrix
[0][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
896 profile
->matrix
[0][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
897 profile
->matrix
[0][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
898 profile
->matrix
[1][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
899 profile
->matrix
[1][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
900 profile
->matrix
[1][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
901 profile
->matrix
[2][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
902 profile
->matrix
[2][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
903 profile
->matrix
[2][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
905 else if (!strcmp(keyword
, "cupsFilter"))
907 if (ppd
->num_filters
== 0)
908 filter
= malloc(sizeof(char *));
910 filter
= realloc(ppd
->filters
, sizeof(char *) * (ppd
->num_filters
+ 1));
914 cg
->ppd_status
= PPD_ALLOC_ERROR
;
919 ppd
->filters
= filter
;
920 filter
+= ppd
->num_filters
;
924 * Retain a copy of the filter string...
927 *filter
= _cupsStrRetain(string
);
929 else if (!strcmp(keyword
, "Throughput"))
930 ppd
->throughput
= atoi(string
);
931 else if (!strcmp(keyword
, "Font"))
934 * Add this font to the list of available fonts...
937 if (ppd
->num_fonts
== 0)
938 tempfonts
= (char **)malloc(sizeof(char *));
940 tempfonts
= (char **)realloc(ppd
->fonts
,
941 sizeof(char *) * (ppd
->num_fonts
+ 1));
943 if (tempfonts
== NULL
)
945 cg
->ppd_status
= PPD_ALLOC_ERROR
;
950 ppd
->fonts
= tempfonts
;
951 ppd
->fonts
[ppd
->num_fonts
] = _cupsStrAlloc(name
);
954 else if (!strncmp(keyword
, "ParamCustom", 11))
956 ppd_coption_t
*coption
; /* Custom option */
957 ppd_cparam_t
*cparam
; /* Custom parameter */
958 int corder
; /* Order number */
959 char ctype
[33], /* Data type */
960 cminimum
[65], /* Minimum value */
961 cmaximum
[65]; /* Maximum value */
965 * Get the custom option and parameter...
968 if ((coption
= ppd_get_coption(ppd
, keyword
+ 11)) == NULL
)
970 cg
->ppd_status
= PPD_ALLOC_ERROR
;
975 if ((cparam
= ppd_get_cparam(coption
, name
, text
)) == NULL
)
977 cg
->ppd_status
= PPD_ALLOC_ERROR
;
983 * Get the parameter data...
987 sscanf(string
, "%d%32s%64s%64s", &corder
, ctype
, cminimum
,
990 cg
->ppd_status
= PPD_BAD_CUSTOM_PARAM
;
995 cparam
->order
= corder
;
997 if (!strcmp(ctype
, "curve"))
999 cparam
->type
= PPD_CUSTOM_CURVE
;
1000 cparam
->minimum
.custom_curve
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
1001 cparam
->maximum
.custom_curve
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
1003 else if (!strcmp(ctype
, "int"))
1005 cparam
->type
= PPD_CUSTOM_INT
;
1006 cparam
->minimum
.custom_int
= atoi(cminimum
);
1007 cparam
->maximum
.custom_int
= atoi(cmaximum
);
1009 else if (!strcmp(ctype
, "invcurve"))
1011 cparam
->type
= PPD_CUSTOM_INVCURVE
;
1012 cparam
->minimum
.custom_invcurve
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
1013 cparam
->maximum
.custom_invcurve
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
1015 else if (!strcmp(ctype
, "passcode"))
1017 cparam
->type
= PPD_CUSTOM_PASSCODE
;
1018 cparam
->minimum
.custom_passcode
= atoi(cminimum
);
1019 cparam
->maximum
.custom_passcode
= atoi(cmaximum
);
1021 else if (!strcmp(ctype
, "password"))
1023 cparam
->type
= PPD_CUSTOM_PASSWORD
;
1024 cparam
->minimum
.custom_password
= atoi(cminimum
);
1025 cparam
->maximum
.custom_password
= atoi(cmaximum
);
1027 else if (!strcmp(ctype
, "points"))
1029 cparam
->type
= PPD_CUSTOM_POINTS
;
1030 cparam
->minimum
.custom_points
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
1031 cparam
->maximum
.custom_points
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
1033 else if (!strcmp(ctype
, "real"))
1035 cparam
->type
= PPD_CUSTOM_REAL
;
1036 cparam
->minimum
.custom_real
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
1037 cparam
->maximum
.custom_real
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
1039 else if (!strcmp(ctype
, "string"))
1041 cparam
->type
= PPD_CUSTOM_STRING
;
1042 cparam
->minimum
.custom_string
= atoi(cminimum
);
1043 cparam
->maximum
.custom_string
= atoi(cmaximum
);
1047 cg
->ppd_status
= PPD_BAD_CUSTOM_PARAM
;
1053 * Now special-case for CustomPageSize...
1056 if (!strcmp(coption
->keyword
, "PageSize"))
1058 if (!strcmp(name
, "Width"))
1060 ppd
->custom_min
[0] = cparam
->minimum
.custom_points
;
1061 ppd
->custom_max
[0] = cparam
->maximum
.custom_points
;
1063 else if (!strcmp(name
, "Height"))
1065 ppd
->custom_min
[1] = cparam
->minimum
.custom_points
;
1066 ppd
->custom_max
[1] = cparam
->maximum
.custom_points
;
1070 else if (!strcmp(keyword
, "HWMargins"))
1072 for (i
= 0, sptr
= string
; i
< 4; i
++)
1073 ppd
->custom_margins
[i
] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
1075 else if (!strncmp(keyword
, "Custom", 6) && !strcmp(name
, "True") && !option
)
1077 ppd_option_t
*custom_option
; /* Custom option */
1079 DEBUG_puts("2_ppdOpen: Processing Custom option...");
1082 * Get the option and custom option...
1085 if (!ppd_get_coption(ppd
, keyword
+ 6))
1087 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1092 if (option
&& !_cups_strcasecmp(option
->keyword
, keyword
+ 6))
1093 custom_option
= option
;
1095 custom_option
= ppdFindOption(ppd
, keyword
+ 6);
1100 * Add the "custom" option...
1103 if ((choice
= ppdFindChoice(custom_option
, "Custom")) == NULL
)
1104 if ((choice
= ppd_add_choice(custom_option
, "Custom")) == NULL
)
1106 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1108 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1113 strlcpy(choice
->text
, text
[0] ? text
: _("Custom"),
1114 sizeof(choice
->text
));
1116 choice
->code
= _cupsStrAlloc(string
);
1118 if (custom_option
->section
== PPD_ORDER_JCL
)
1119 ppd_decode(choice
->code
);
1123 * Now process custom page sizes specially...
1126 if (!strcmp(keyword
, "CustomPageSize"))
1129 * Add a "Custom" page size entry...
1132 ppd
->variable_sizes
= 1;
1134 ppd_add_size(ppd
, "Custom");
1136 if (option
&& !_cups_strcasecmp(option
->keyword
, "PageRegion"))
1137 custom_option
= option
;
1139 custom_option
= ppdFindOption(ppd
, "PageRegion");
1143 if ((choice
= ppdFindChoice(custom_option
, "Custom")) == NULL
)
1144 if ((choice
= ppd_add_choice(custom_option
, "Custom")) == NULL
)
1146 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1148 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1153 strlcpy(choice
->text
, text
[0] ? text
: _("Custom"),
1154 sizeof(choice
->text
));
1158 else if (!strcmp(keyword
, "LandscapeOrientation"))
1160 if (!strcmp(string
, "Minus90"))
1161 ppd
->landscape
= -90;
1162 else if (!strcmp(string
, "Plus90"))
1163 ppd
->landscape
= 90;
1165 else if (!strcmp(keyword
, "Emulators") && string
)
1167 for (count
= 1, sptr
= string
; sptr
!= NULL
;)
1168 if ((sptr
= strchr(sptr
, ' ')) != NULL
)
1171 while (*sptr
== ' ')
1175 ppd
->num_emulations
= count
;
1176 if ((ppd
->emulations
= calloc(count
, sizeof(ppd_emul_t
))) == NULL
)
1178 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1183 for (i
= 0, sptr
= string
; i
< count
; i
++)
1185 for (nameptr
= ppd
->emulations
[i
].name
;
1186 *sptr
!= '\0' && *sptr
!= ' ';
1188 if (nameptr
< (ppd
->emulations
[i
].name
+ sizeof(ppd
->emulations
[i
].name
) - 1))
1193 while (*sptr
== ' ')
1197 else if (!strncmp(keyword
, "StartEmulator_", 14))
1201 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1202 if (!strcmp(keyword
+ 14, ppd
->emulations
[i
].name
))
1204 ppd
->emulations
[i
].start
= string
;
1208 else if (!strncmp(keyword
, "StopEmulator_", 13))
1212 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1213 if (!strcmp(keyword
+ 13, ppd
->emulations
[i
].name
))
1215 ppd
->emulations
[i
].stop
= string
;
1219 else if (!strcmp(keyword
, "JobPatchFile"))
1222 * CUPS STR #3421: Check for "*JobPatchFile: int: string"
1225 if (isdigit(*string
& 255))
1227 for (sptr
= string
+ 1; isdigit(*sptr
& 255); sptr
++);
1232 * Found "*JobPatchFile: int: string"...
1235 cg
->ppd_status
= PPD_BAD_VALUE
;
1241 if (!name
[0] && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1244 * Found "*JobPatchFile: string"...
1247 cg
->ppd_status
= PPD_MISSING_OPTION_KEYWORD
;
1252 if (ppd
->patches
== NULL
)
1253 ppd
->patches
= strdup(string
);
1256 temp
= realloc(ppd
->patches
, strlen(ppd
->patches
) +
1257 strlen(string
) + 1);
1260 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1265 ppd
->patches
= temp
;
1267 memcpy(ppd
->patches
+ strlen(ppd
->patches
), string
, strlen(string
) + 1);
1270 else if (!strcmp(keyword
, "OpenUI"))
1273 * Don't allow nesting of options...
1276 if (option
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1278 cg
->ppd_status
= PPD_NESTED_OPEN_UI
;
1284 * Add an option record to the current sub-group, group, or file...
1287 DEBUG_printf(("2_ppdOpen: name=\"%s\" (%d)", name
, (int)strlen(name
)));
1290 _cups_strcpy(name
, name
+ 1); /* Eliminate leading asterisk */
1292 for (i
= (int)strlen(name
) - 1; i
> 0 && _cups_isspace(name
[i
]); i
--)
1293 name
[i
] = '\0'; /* Eliminate trailing spaces */
1295 DEBUG_printf(("2_ppdOpen: OpenUI of %s in group %s...", name
,
1296 group
? group
->text
: "(null)"));
1298 if (subgroup
!= NULL
)
1299 option
= ppd_get_option(subgroup
, name
);
1300 else if (group
== NULL
)
1302 if ((group
= ppd_get_group(ppd
, "General", _("General"), cg
,
1306 DEBUG_printf(("2_ppdOpen: Adding to group %s...", group
->text
));
1307 option
= ppd_get_option(group
, name
);
1311 option
= ppd_get_option(group
, name
);
1315 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1321 * Now fill in the initial information for the option...
1324 if (string
&& !strcmp(string
, "PickMany"))
1325 option
->ui
= PPD_UI_PICKMANY
;
1326 else if (string
&& !strcmp(string
, "Boolean"))
1327 option
->ui
= PPD_UI_BOOLEAN
;
1328 else if (string
&& !strcmp(string
, "PickOne"))
1329 option
->ui
= PPD_UI_PICKONE
;
1330 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1332 cg
->ppd_status
= PPD_BAD_OPEN_UI
;
1337 option
->ui
= PPD_UI_PICKONE
;
1339 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1340 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
1341 !strcmp(ppd
->attrs
[j
]->name
+ 7, name
) &&
1342 ppd
->attrs
[j
]->value
)
1344 DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
1345 option
->keyword
, ppd
->attrs
[j
]->value
));
1346 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
1347 sizeof(option
->defchoice
));
1352 cupsCharsetToUTF8((cups_utf8_t
*)option
->text
, text
,
1353 sizeof(option
->text
), encoding
);
1356 if (!strcmp(name
, "PageSize"))
1357 strlcpy(option
->text
, _("Media Size"), sizeof(option
->text
));
1358 else if (!strcmp(name
, "MediaType"))
1359 strlcpy(option
->text
, _("Media Type"), sizeof(option
->text
));
1360 else if (!strcmp(name
, "InputSlot"))
1361 strlcpy(option
->text
, _("Media Source"), sizeof(option
->text
));
1362 else if (!strcmp(name
, "ColorModel"))
1363 strlcpy(option
->text
, _("Output Mode"), sizeof(option
->text
));
1364 else if (!strcmp(name
, "Resolution"))
1365 strlcpy(option
->text
, _("Resolution"), sizeof(option
->text
));
1367 strlcpy(option
->text
, name
, sizeof(option
->text
));
1370 option
->section
= PPD_ORDER_ANY
;
1372 _cupsStrFree(string
);
1376 * Add a custom option choice if we have already seen a CustomFoo
1380 if (!_cups_strcasecmp(name
, "PageRegion"))
1381 strlcpy(custom_name
, "CustomPageSize", sizeof(custom_name
));
1383 snprintf(custom_name
, sizeof(custom_name
), "Custom%s", name
);
1385 if ((custom_attr
= ppdFindAttr(ppd
, custom_name
, "True")) != NULL
)
1387 if ((choice
= ppdFindChoice(option
, "Custom")) == NULL
)
1388 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
1390 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1392 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1397 strlcpy(choice
->text
,
1398 custom_attr
->text
[0] ? custom_attr
->text
: _("Custom"),
1399 sizeof(choice
->text
));
1400 choice
->code
= _cupsStrRetain(custom_attr
->value
);
1403 else if (!strcmp(keyword
, "JCLOpenUI"))
1406 * Don't allow nesting of options...
1409 if (option
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1411 cg
->ppd_status
= PPD_NESTED_OPEN_UI
;
1417 * Find the JCL group, and add if needed...
1420 group
= ppd_get_group(ppd
, "JCL", _("JCL"), cg
, encoding
);
1426 * Add an option record to the current JCLs...
1430 _cups_strcpy(name
, name
+ 1);
1432 option
= ppd_get_option(group
, name
);
1436 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1442 * Now fill in the initial information for the option...
1445 if (string
&& !strcmp(string
, "PickMany"))
1446 option
->ui
= PPD_UI_PICKMANY
;
1447 else if (string
&& !strcmp(string
, "Boolean"))
1448 option
->ui
= PPD_UI_BOOLEAN
;
1449 else if (string
&& !strcmp(string
, "PickOne"))
1450 option
->ui
= PPD_UI_PICKONE
;
1453 cg
->ppd_status
= PPD_BAD_OPEN_UI
;
1458 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1459 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
1460 !strcmp(ppd
->attrs
[j
]->name
+ 7, name
) &&
1461 ppd
->attrs
[j
]->value
)
1463 DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
1464 option
->keyword
, ppd
->attrs
[j
]->value
));
1465 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
1466 sizeof(option
->defchoice
));
1471 cupsCharsetToUTF8((cups_utf8_t
*)option
->text
, text
,
1472 sizeof(option
->text
), encoding
);
1474 strlcpy(option
->text
, name
, sizeof(option
->text
));
1476 option
->section
= PPD_ORDER_JCL
;
1479 _cupsStrFree(string
);
1483 * Add a custom option choice if we have already seen a CustomFoo
1487 snprintf(custom_name
, sizeof(custom_name
), "Custom%s", name
);
1489 if ((custom_attr
= ppdFindAttr(ppd
, custom_name
, "True")) != NULL
)
1491 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
1493 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1495 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1500 strlcpy(choice
->text
,
1501 custom_attr
->text
[0] ? custom_attr
->text
: _("Custom"),
1502 sizeof(choice
->text
));
1503 choice
->code
= _cupsStrRetain(custom_attr
->value
);
1506 else if (!strcmp(keyword
, "CloseUI") || !strcmp(keyword
, "JCLCloseUI"))
1510 _cupsStrFree(string
);
1513 else if (!strcmp(keyword
, "OpenGroup"))
1516 * Open a new group...
1521 cg
->ppd_status
= PPD_NESTED_OPEN_GROUP
;
1528 cg
->ppd_status
= PPD_BAD_OPEN_GROUP
;
1534 * Separate the group name from the text (name/text)...
1537 if ((sptr
= strchr(string
, '/')) != NULL
)
1543 * Fix up the text...
1549 * Find/add the group...
1552 group
= ppd_get_group(ppd
, string
, sptr
, cg
, encoding
);
1557 _cupsStrFree(string
);
1560 else if (!strcmp(keyword
, "CloseGroup"))
1564 _cupsStrFree(string
);
1567 else if (!strcmp(keyword
, "OrderDependency"))
1569 order
= (float)_cupsStrScand(string
, &sptr
, loc
);
1571 if (!sptr
|| sscanf(sptr
, "%40s%40s", name
, keyword
) != 2)
1573 cg
->ppd_status
= PPD_BAD_ORDER_DEPENDENCY
;
1578 if (keyword
[0] == '*')
1579 _cups_strcpy(keyword
, keyword
+ 1);
1581 if (!strcmp(name
, "ExitServer"))
1582 section
= PPD_ORDER_EXIT
;
1583 else if (!strcmp(name
, "Prolog"))
1584 section
= PPD_ORDER_PROLOG
;
1585 else if (!strcmp(name
, "DocumentSetup"))
1586 section
= PPD_ORDER_DOCUMENT
;
1587 else if (!strcmp(name
, "PageSetup"))
1588 section
= PPD_ORDER_PAGE
;
1589 else if (!strcmp(name
, "JCLSetup"))
1590 section
= PPD_ORDER_JCL
;
1592 section
= PPD_ORDER_ANY
;
1600 * Only valid for Non-UI options...
1603 for (i
= ppd
->num_groups
, gtemp
= ppd
->groups
; i
> 0; i
--, gtemp
++)
1604 if (gtemp
->text
[0] == '\0')
1608 for (i
= 0; i
< gtemp
->num_options
; i
++)
1609 if (!strcmp(keyword
, gtemp
->options
[i
].keyword
))
1611 gtemp
->options
[i
].section
= section
;
1612 gtemp
->options
[i
].order
= order
;
1618 option
->section
= section
;
1619 option
->order
= order
;
1622 _cupsStrFree(string
);
1625 else if (!strncmp(keyword
, "Default", 7))
1631 * Drop UI text, if any, from value...
1634 if (strchr(string
, '/') != NULL
)
1635 *strchr(string
, '/') = '\0';
1638 * Assign the default value as appropriate...
1641 if (!strcmp(keyword
, "DefaultColorSpace"))
1644 * Set default colorspace...
1647 if (!strcmp(string
, "CMY"))
1648 ppd
->colorspace
= PPD_CS_CMY
;
1649 else if (!strcmp(string
, "CMYK"))
1650 ppd
->colorspace
= PPD_CS_CMYK
;
1651 else if (!strcmp(string
, "RGB"))
1652 ppd
->colorspace
= PPD_CS_RGB
;
1653 else if (!strcmp(string
, "RGBK"))
1654 ppd
->colorspace
= PPD_CS_RGBK
;
1655 else if (!strcmp(string
, "N"))
1656 ppd
->colorspace
= PPD_CS_N
;
1658 ppd
->colorspace
= PPD_CS_GRAY
;
1660 else if (option
&& !strcmp(keyword
+ 7, option
->keyword
))
1663 * Set the default as part of the current option...
1666 DEBUG_printf(("2_ppdOpen: Setting %s to %s...", keyword
, string
));
1668 strlcpy(option
->defchoice
, string
, sizeof(option
->defchoice
));
1670 DEBUG_printf(("2_ppdOpen: %s is now %s...", keyword
, option
->defchoice
));
1675 * Lookup option and set if it has been defined...
1678 ppd_option_t
*toption
; /* Temporary option */
1681 if ((toption
= ppdFindOption(ppd
, keyword
+ 7)) != NULL
)
1683 DEBUG_printf(("2_ppdOpen: Setting %s to %s...", keyword
, string
));
1684 strlcpy(toption
->defchoice
, string
, sizeof(toption
->defchoice
));
1688 else if (!strcmp(keyword
, "UIConstraints") ||
1689 !strcmp(keyword
, "NonUIConstraints"))
1693 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1697 if (ppd
->num_consts
== 0)
1698 constraint
= calloc(2, sizeof(ppd_const_t
));
1700 constraint
= realloc(ppd
->consts
,
1701 (ppd
->num_consts
+ 2) * sizeof(ppd_const_t
));
1703 if (constraint
== NULL
)
1705 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1710 ppd
->consts
= constraint
;
1711 constraint
+= ppd
->num_consts
;
1714 switch (sscanf(string
, "%40s%40s%40s%40s", constraint
->option1
,
1715 constraint
->choice1
, constraint
->option2
,
1716 constraint
->choice2
))
1718 case 0 : /* Error */
1719 case 1 : /* Error */
1720 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1723 case 2 : /* Two options... */
1725 * Check for broken constraints like "* Option"...
1728 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1729 (!strcmp(constraint
->option1
, "*") ||
1730 !strcmp(constraint
->choice1
, "*")))
1732 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1737 * The following strcpy's are safe, as optionN and
1738 * choiceN are all the same size (size defined by PPD spec...)
1741 if (constraint
->option1
[0] == '*')
1742 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1743 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1745 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1749 if (constraint
->choice1
[0] == '*')
1750 _cups_strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1751 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1753 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1757 constraint
->choice1
[0] = '\0';
1758 constraint
->choice2
[0] = '\0';
1761 case 3 : /* Two options, one choice... */
1763 * Check for broken constraints like "* Option"...
1766 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1767 (!strcmp(constraint
->option1
, "*") ||
1768 !strcmp(constraint
->choice1
, "*") ||
1769 !strcmp(constraint
->option2
, "*")))
1771 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1776 * The following _cups_strcpy's are safe, as optionN and
1777 * choiceN are all the same size (size defined by PPD spec...)
1780 if (constraint
->option1
[0] == '*')
1781 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1782 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1784 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1788 if (constraint
->choice1
[0] == '*')
1790 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1791 constraint
->option2
[0] == '*')
1793 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1797 _cups_strcpy(constraint
->choice2
, constraint
->option2
);
1798 _cups_strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1799 constraint
->choice1
[0] = '\0';
1803 if (constraint
->option2
[0] == '*')
1804 _cups_strcpy(constraint
->option2
, constraint
->option2
+ 1);
1805 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1807 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1811 constraint
->choice2
[0] = '\0';
1815 case 4 : /* Two options, two choices... */
1817 * Check for broken constraints like "* Option"...
1820 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1821 (!strcmp(constraint
->option1
, "*") ||
1822 !strcmp(constraint
->choice1
, "*") ||
1823 !strcmp(constraint
->option2
, "*") ||
1824 !strcmp(constraint
->choice2
, "*")))
1826 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1830 if (constraint
->option1
[0] == '*')
1831 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1832 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1834 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1838 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1839 constraint
->choice1
[0] == '*')
1841 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1845 if (constraint
->option2
[0] == '*')
1846 _cups_strcpy(constraint
->option2
, constraint
->option2
+ 1);
1847 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1849 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1853 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1854 constraint
->choice2
[0] == '*')
1856 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1863 * Don't add this one as an attribute...
1866 _cupsStrFree(string
);
1869 else if (!strcmp(keyword
, "PaperDimension"))
1871 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1872 size
= ppd_add_size(ppd
, name
);
1877 * Unable to add or find size!
1880 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1885 size
->width
= (float)_cupsStrScand(string
, &sptr
, loc
);
1886 size
->length
= (float)_cupsStrScand(sptr
, NULL
, loc
);
1888 _cupsStrFree(string
);
1891 else if (!strcmp(keyword
, "ImageableArea"))
1893 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1894 size
= ppd_add_size(ppd
, name
);
1899 * Unable to add or find size!
1902 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1907 size
->left
= (float)_cupsStrScand(string
, &sptr
, loc
);
1908 size
->bottom
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
1909 size
->right
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
1910 size
->top
= (float)_cupsStrScand(sptr
, NULL
, loc
);
1912 _cupsStrFree(string
);
1915 else if (option
!= NULL
&&
1916 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
1917 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
) &&
1918 !strcmp(keyword
, option
->keyword
))
1920 DEBUG_printf(("2_ppdOpen: group=%p, subgroup=%p", group
, subgroup
));
1922 if (!strcmp(keyword
, "PageSize"))
1925 * Add a page size...
1928 if (ppdPageSize(ppd
, name
) == NULL
)
1929 ppd_add_size(ppd
, name
);
1933 * Add the option choice...
1936 if ((choice
= ppd_add_choice(option
, name
)) == NULL
)
1938 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1944 cupsCharsetToUTF8((cups_utf8_t
*)choice
->text
, text
,
1945 sizeof(choice
->text
), encoding
);
1946 else if (!strcmp(name
, "True"))
1947 strlcpy(choice
->text
, _("Yes"), sizeof(choice
->text
));
1948 else if (!strcmp(name
, "False"))
1949 strlcpy(choice
->text
, _("No"), sizeof(choice
->text
));
1951 strlcpy(choice
->text
, name
, sizeof(choice
->text
));
1953 if (option
->section
== PPD_ORDER_JCL
)
1954 ppd_decode(string
); /* Decode quoted string */
1956 choice
->code
= string
;
1957 string
= NULL
; /* Don't add as an attribute below */
1961 * Add remaining lines with keywords and string values as attributes...
1965 (mask
& (PPD_KEYWORD
| PPD_STRING
)) == (PPD_KEYWORD
| PPD_STRING
))
1966 ppd_add_attr(ppd
, keyword
, name
, text
, string
);
1968 _cupsStrFree(string
);
1972 * Check for a missing CloseGroup...
1975 if (group
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1977 cg
->ppd_status
= PPD_MISSING_CLOSE_GROUP
;
1981 ppd_free(line
.buffer
);
1984 * Reset language preferences...
1988 if (!cupsFileEOF(fp
))
1989 DEBUG_printf(("1_ppdOpen: Premature EOF at %lu...\n",
1990 (unsigned long)cupsFileTell(fp
)));
1993 if (cg
->ppd_status
!= PPD_OK
)
1996 * Had an error reading the PPD file, cannot continue!
2005 * Update the filters array as needed...
2008 if (!ppd_update_filters(ppd
, cg
))
2016 * Create the sorted options array and set the option back-pointer for
2017 * each choice and custom option...
2020 ppd
->options
= cupsArrayNew2((cups_array_func_t
)ppd_compare_options
, NULL
,
2021 (cups_ahash_func_t
)ppd_hash_option
,
2024 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
2028 for (j
= group
->num_options
, option
= group
->options
;
2032 ppd_coption_t
*coption
; /* Custom option */
2035 cupsArrayAdd(ppd
->options
, option
);
2037 for (k
= 0; k
< option
->num_choices
; k
++)
2038 option
->choices
[k
].option
= option
;
2040 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)) != NULL
)
2041 coption
->option
= option
;
2046 * Create an array to track the marked choices...
2049 ppd
->marked
= cupsArrayNew((cups_array_func_t
)ppd_compare_choices
, NULL
);
2052 * Return the PPD file structure...
2058 * Common exit point for errors to save code size...
2063 _cupsStrFree(string
);
2064 ppd_free(line
.buffer
);
2073 * 'ppdOpen()' - Read a PPD file into memory.
2076 ppd_file_t
* /* O - PPD file record */
2077 ppdOpen(FILE *fp
) /* I - File to read from */
2079 ppd_file_t
*ppd
; /* PPD file record */
2080 cups_file_t
*cf
; /* CUPS file */
2084 * Reopen the stdio file as a CUPS file...
2087 if ((cf
= cupsFileOpenFd(fileno(fp
), "r")) == NULL
)
2091 * Load the PPD file using the newer API...
2094 ppd
= _ppdOpen(cf
, _PPD_LOCALIZATION_DEFAULT
);
2097 * Close the CUPS file and return the PPD...
2107 * 'ppdOpen2()' - Read a PPD file into memory.
2109 * @since CUPS 1.2/OS X 10.5@
2112 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2113 ppdOpen2(cups_file_t
*fp
) /* I - File to read from */
2115 return _ppdOpen(fp
, _PPD_LOCALIZATION_DEFAULT
);
2120 * 'ppdOpenFd()' - Read a PPD file into memory.
2123 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2124 ppdOpenFd(int fd
) /* I - File to read from */
2126 cups_file_t
*fp
; /* CUPS file pointer */
2127 ppd_file_t
*ppd
; /* PPD file record */
2128 _cups_globals_t
*cg
= _cupsGlobals();
2133 * Set the line number to 0...
2139 * Range check input...
2144 cg
->ppd_status
= PPD_NULL_FILE
;
2150 * Try to open the file and parse it...
2153 if ((fp
= cupsFileOpenFd(fd
, "r")) != NULL
)
2161 cg
->ppd_status
= PPD_FILE_OPEN_ERROR
;
2170 * '_ppdOpenFile()' - Read a PPD file into memory.
2173 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2174 _ppdOpenFile(const char *filename
, /* I - File to read from */
2175 _ppd_localization_t localization
) /* I - Localization to load */
2177 cups_file_t
*fp
; /* File pointer */
2178 ppd_file_t
*ppd
; /* PPD file record */
2179 _cups_globals_t
*cg
= _cupsGlobals();
2184 * Set the line number to 0...
2190 * Range check input...
2193 if (filename
== NULL
)
2195 cg
->ppd_status
= PPD_NULL_FILE
;
2201 * Try to open the file and parse it...
2204 if ((fp
= cupsFileOpen(filename
, "r")) != NULL
)
2206 ppd
= _ppdOpen(fp
, localization
);
2212 cg
->ppd_status
= PPD_FILE_OPEN_ERROR
;
2221 * 'ppdOpenFile()' - Read a PPD file into memory.
2224 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2225 ppdOpenFile(const char *filename
) /* I - File to read from */
2227 return _ppdOpenFile(filename
, _PPD_LOCALIZATION_DEFAULT
);
2232 * 'ppdSetConformance()' - Set the conformance level for PPD files.
2234 * @since CUPS 1.1.20/OS X 10.4@
2238 ppdSetConformance(ppd_conform_t c
) /* I - Conformance level */
2240 _cups_globals_t
*cg
= _cupsGlobals();
2244 cg
->ppd_conform
= c
;
2249 * 'ppd_add_attr()' - Add an attribute to the PPD data.
2252 static ppd_attr_t
* /* O - New attribute */
2253 ppd_add_attr(ppd_file_t
*ppd
, /* I - PPD file data */
2254 const char *name
, /* I - Attribute name */
2255 const char *spec
, /* I - Specifier string, if any */
2256 const char *text
, /* I - Text string, if any */
2257 const char *value
) /* I - Value of attribute */
2259 ppd_attr_t
**ptr
, /* New array */
2260 *temp
; /* New attribute */
2264 * Range check input...
2267 if (ppd
== NULL
|| name
== NULL
|| spec
== NULL
)
2271 * Create the array as needed...
2274 if (!ppd
->sorted_attrs
)
2275 ppd
->sorted_attrs
= cupsArrayNew((cups_array_func_t
)ppd_compare_attrs
,
2279 * Allocate memory for the new attribute...
2282 if (ppd
->num_attrs
== 0)
2283 ptr
= malloc(sizeof(ppd_attr_t
*));
2285 ptr
= realloc(ppd
->attrs
, (ppd
->num_attrs
+ 1) * sizeof(ppd_attr_t
*));
2291 ptr
+= ppd
->num_attrs
;
2293 if ((temp
= calloc(1, sizeof(ppd_attr_t
))) == NULL
)
2304 strlcpy(temp
->name
, name
, sizeof(temp
->name
));
2305 strlcpy(temp
->spec
, spec
, sizeof(temp
->spec
));
2306 strlcpy(temp
->text
, text
, sizeof(temp
->text
));
2307 temp
->value
= (char *)value
;
2310 * Add the attribute to the sorted array...
2313 cupsArrayAdd(ppd
->sorted_attrs
, temp
);
2316 * Return the attribute...
2324 * 'ppd_add_choice()' - Add a choice to an option.
2327 static ppd_choice_t
* /* O - Named choice */
2328 ppd_add_choice(ppd_option_t
*option
, /* I - Option */
2329 const char *name
) /* I - Name of choice */
2331 ppd_choice_t
*choice
; /* Choice */
2334 if (option
->num_choices
== 0)
2335 choice
= malloc(sizeof(ppd_choice_t
));
2337 choice
= realloc(option
->choices
,
2338 sizeof(ppd_choice_t
) * (option
->num_choices
+ 1));
2343 option
->choices
= choice
;
2344 choice
+= option
->num_choices
;
2345 option
->num_choices
++;
2347 memset(choice
, 0, sizeof(ppd_choice_t
));
2348 strlcpy(choice
->choice
, name
, sizeof(choice
->choice
));
2355 * 'ppd_add_size()' - Add a page size.
2358 static ppd_size_t
* /* O - Named size */
2359 ppd_add_size(ppd_file_t
*ppd
, /* I - PPD file */
2360 const char *name
) /* I - Name of size */
2362 ppd_size_t
*size
; /* Size */
2365 if (ppd
->num_sizes
== 0)
2366 size
= malloc(sizeof(ppd_size_t
));
2368 size
= realloc(ppd
->sizes
, sizeof(ppd_size_t
) * (ppd
->num_sizes
+ 1));
2374 size
+= ppd
->num_sizes
;
2377 memset(size
, 0, sizeof(ppd_size_t
));
2378 strlcpy(size
->name
, name
, sizeof(size
->name
));
2385 * 'ppd_compare_attrs()' - Compare two attributes.
2388 static int /* O - Result of comparison */
2389 ppd_compare_attrs(ppd_attr_t
*a
, /* I - First attribute */
2390 ppd_attr_t
*b
) /* I - Second attribute */
2392 return (_cups_strcasecmp(a
->name
, b
->name
));
2397 * 'ppd_compare_choices()' - Compare two choices...
2400 static int /* O - Result of comparison */
2401 ppd_compare_choices(ppd_choice_t
*a
, /* I - First choice */
2402 ppd_choice_t
*b
) /* I - Second choice */
2404 return (strcmp(a
->option
->keyword
, b
->option
->keyword
));
2409 * 'ppd_compare_coptions()' - Compare two custom options.
2412 static int /* O - Result of comparison */
2413 ppd_compare_coptions(ppd_coption_t
*a
, /* I - First option */
2414 ppd_coption_t
*b
) /* I - Second option */
2416 return (_cups_strcasecmp(a
->keyword
, b
->keyword
));
2421 * 'ppd_compare_options()' - Compare two options.
2424 static int /* O - Result of comparison */
2425 ppd_compare_options(ppd_option_t
*a
, /* I - First option */
2426 ppd_option_t
*b
) /* I - Second option */
2428 return (_cups_strcasecmp(a
->keyword
, b
->keyword
));
2433 * 'ppd_decode()' - Decode a string value...
2436 static int /* O - Length of decoded string */
2437 ppd_decode(char *string
) /* I - String to decode */
2439 char *inptr
, /* Input pointer */
2440 *outptr
; /* Output pointer */
2446 while (*inptr
!= '\0')
2447 if (*inptr
== '<' && isxdigit(inptr
[1] & 255))
2450 * Convert hex to 8-bit values...
2454 while (isxdigit(*inptr
& 255))
2456 if (_cups_isalpha(*inptr
))
2457 *outptr
= (tolower(*inptr
) - 'a' + 10) << 4;
2459 *outptr
= (*inptr
- '0') << 4;
2463 if (!isxdigit(*inptr
& 255))
2466 if (_cups_isalpha(*inptr
))
2467 *outptr
|= tolower(*inptr
) - 'a' + 10;
2469 *outptr
|= *inptr
- '0';
2475 while (*inptr
!= '>' && *inptr
!= '\0')
2477 while (*inptr
== '>')
2481 *outptr
++ = *inptr
++;
2485 return ((int)(outptr
- string
));
2490 * 'ppd_free_filters()' - Free the filters array.
2494 ppd_free_filters(ppd_file_t
*ppd
) /* I - PPD file */
2496 int i
; /* Looping var */
2497 char **filter
; /* Current filter */
2500 if (ppd
->num_filters
> 0)
2502 for (i
= ppd
->num_filters
, filter
= ppd
->filters
; i
> 0; i
--, filter
++)
2503 _cupsStrFree(*filter
);
2505 ppd_free(ppd
->filters
);
2507 ppd
->num_filters
= 0;
2508 ppd
->filters
= NULL
;
2514 * 'ppd_free_group()' - Free a single UI group.
2518 ppd_free_group(ppd_group_t
*group
) /* I - Group to free */
2520 int i
; /* Looping var */
2521 ppd_option_t
*option
; /* Current option */
2522 ppd_group_t
*subgroup
; /* Current sub-group */
2525 if (group
->num_options
> 0)
2527 for (i
= group
->num_options
, option
= group
->options
;
2530 ppd_free_option(option
);
2532 ppd_free(group
->options
);
2535 if (group
->num_subgroups
> 0)
2537 for (i
= group
->num_subgroups
, subgroup
= group
->subgroups
;
2540 ppd_free_group(subgroup
);
2542 ppd_free(group
->subgroups
);
2548 * 'ppd_free_option()' - Free a single option.
2552 ppd_free_option(ppd_option_t
*option
) /* I - Option to free */
2554 int i
; /* Looping var */
2555 ppd_choice_t
*choice
; /* Current choice */
2558 if (option
->num_choices
> 0)
2560 for (i
= option
->num_choices
, choice
= option
->choices
;
2564 _cupsStrFree(choice
->code
);
2567 ppd_free(option
->choices
);
2573 * 'ppd_get_coption()' - Get a custom option record.
2576 static ppd_coption_t
* /* O - Custom option... */
2577 ppd_get_coption(ppd_file_t
*ppd
, /* I - PPD file */
2578 const char *name
) /* I - Name of option */
2580 ppd_coption_t
*copt
; /* New custom option */
2584 * See if the option already exists...
2587 if ((copt
= ppdFindCustomOption(ppd
, name
)) != NULL
)
2591 * Not found, so create the custom option record...
2594 if ((copt
= calloc(1, sizeof(ppd_coption_t
))) == NULL
)
2597 strlcpy(copt
->keyword
, name
, sizeof(copt
->keyword
));
2599 copt
->params
= cupsArrayNew((cups_array_func_t
)NULL
, NULL
);
2601 cupsArrayAdd(ppd
->coptions
, copt
);
2604 * Return the new record...
2612 * 'ppd_get_cparam()' - Get a custom parameter record.
2615 static ppd_cparam_t
* /* O - Extended option... */
2616 ppd_get_cparam(ppd_coption_t
*opt
, /* I - PPD file */
2617 const char *param
, /* I - Name of parameter */
2618 const char *text
) /* I - Human-readable text */
2620 ppd_cparam_t
*cparam
; /* New custom parameter */
2624 * See if the parameter already exists...
2627 if ((cparam
= ppdFindCustomParam(opt
, param
)) != NULL
)
2631 * Not found, so create the custom parameter record...
2634 if ((cparam
= calloc(1, sizeof(ppd_cparam_t
))) == NULL
)
2637 strlcpy(cparam
->name
, param
, sizeof(cparam
->name
));
2638 strlcpy(cparam
->text
, text
[0] ? text
: param
, sizeof(cparam
->text
));
2641 * Add this record to the array...
2644 cupsArrayAdd(opt
->params
, cparam
);
2647 * Return the new record...
2655 * 'ppd_get_group()' - Find or create the named group as needed.
2658 static ppd_group_t
* /* O - Named group */
2659 ppd_get_group(ppd_file_t
*ppd
, /* I - PPD file */
2660 const char *name
, /* I - Name of group */
2661 const char *text
, /* I - Text for group */
2662 _cups_globals_t
*cg
, /* I - Global data */
2663 cups_encoding_t encoding
) /* I - Encoding of text */
2665 int i
; /* Looping var */
2666 ppd_group_t
*group
; /* Group */
2669 DEBUG_printf(("7ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)",
2670 ppd
, name
, text
, cg
));
2672 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
2673 if (!strcmp(group
->name
, name
))
2678 DEBUG_printf(("8ppd_get_group: Adding group %s...", name
));
2680 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&& strlen(text
) >= sizeof(group
->text
))
2682 cg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
2687 if (ppd
->num_groups
== 0)
2688 group
= malloc(sizeof(ppd_group_t
));
2690 group
= realloc(ppd
->groups
,
2691 (ppd
->num_groups
+ 1) * sizeof(ppd_group_t
));
2695 cg
->ppd_status
= PPD_ALLOC_ERROR
;
2700 ppd
->groups
= group
;
2701 group
+= ppd
->num_groups
;
2704 memset(group
, 0, sizeof(ppd_group_t
));
2705 strlcpy(group
->name
, name
, sizeof(group
->name
));
2707 cupsCharsetToUTF8((cups_utf8_t
*)group
->text
, text
,
2708 sizeof(group
->text
), encoding
);
2716 * 'ppd_get_option()' - Find or create the named option as needed.
2719 static ppd_option_t
* /* O - Named option */
2720 ppd_get_option(ppd_group_t
*group
, /* I - Group */
2721 const char *name
) /* I - Name of option */
2723 int i
; /* Looping var */
2724 ppd_option_t
*option
; /* Option */
2727 DEBUG_printf(("7ppd_get_option(group=%p(\"%s\"), name=\"%s\")",
2728 group
, group
->name
, name
));
2730 for (i
= group
->num_options
, option
= group
->options
; i
> 0; i
--, option
++)
2731 if (!strcmp(option
->keyword
, name
))
2736 if (group
->num_options
== 0)
2737 option
= malloc(sizeof(ppd_option_t
));
2739 option
= realloc(group
->options
,
2740 (group
->num_options
+ 1) * sizeof(ppd_option_t
));
2745 group
->options
= option
;
2746 option
+= group
->num_options
;
2747 group
->num_options
++;
2749 memset(option
, 0, sizeof(ppd_option_t
));
2750 strlcpy(option
->keyword
, name
, sizeof(option
->keyword
));
2758 * 'ppd_hash_option()' - Generate a hash of the option name...
2761 static int /* O - Hash index */
2762 ppd_hash_option(ppd_option_t
*option
) /* I - Option */
2764 int hash
= 0; /* Hash index */
2765 const char *k
; /* Pointer into keyword */
2768 for (hash
= option
->keyword
[0], k
= option
->keyword
+ 1; *k
;)
2769 hash
= 33 * hash
+ *k
++;
2771 return (hash
& 511);
2776 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2780 static int /* O - Bitmask of fields read */
2781 ppd_read(cups_file_t
*fp
, /* I - File to read from */
2782 _ppd_line_t
*line
, /* I - Line buffer */
2783 char *keyword
, /* O - Keyword from line */
2784 char *option
, /* O - Option from line */
2785 char *text
, /* O - Human-readable text from line */
2786 char **string
, /* O - Code/string data */
2787 int ignoreblank
, /* I - Ignore blank lines? */
2788 _cups_globals_t
*cg
) /* I - Global data */
2790 int ch
, /* Character from file */
2791 col
, /* Column in line */
2792 colon
, /* Colon seen? */
2793 endquote
, /* Waiting for an end quote */
2794 mask
, /* Mask to be returned */
2795 startline
, /* Start line */
2796 textlen
; /* Length of text */
2797 char *keyptr
, /* Keyword pointer */
2798 *optptr
, /* Option pointer */
2799 *textptr
, /* Text pointer */
2800 *strptr
, /* Pointer into string */
2801 *lineptr
; /* Current position in line buffer */
2805 * Now loop until we have a valid line...
2810 startline
= cg
->ppd_line
+ 1;
2814 line
->bufsize
= 1024;
2815 line
->buffer
= malloc(1024);
2827 lineptr
= line
->buffer
;
2831 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2833 if (lineptr
>= (line
->buffer
+ line
->bufsize
- 1))
2836 * Expand the line buffer...
2839 char *temp
; /* Temporary line pointer */
2842 line
->bufsize
+= 1024;
2843 if (line
->bufsize
> 262144)
2846 * Don't allow lines longer than 256k!
2849 cg
->ppd_line
= startline
;
2850 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2855 temp
= realloc(line
->buffer
, line
->bufsize
);
2858 cg
->ppd_line
= startline
;
2859 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2864 lineptr
= temp
+ (lineptr
- line
->buffer
);
2865 line
->buffer
= temp
;
2868 if (ch
== '\r' || ch
== '\n')
2871 * Line feed or carriage return...
2880 * Check for a trailing line feed...
2883 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2890 cupsFileGetChar(fp
);
2893 if (lineptr
== line
->buffer
&& ignoreblank
)
2894 continue; /* Skip blank lines */
2898 if (!endquote
) /* Continue for multi-line text */
2903 else if (ch
< ' ' && ch
!= '\t' && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2906 * Other control characters...
2909 cg
->ppd_line
= startline
;
2910 cg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
2914 else if (ch
!= 0x1a)
2917 * Any other character...
2923 if (col
> (PPD_MAX_LINE
- 1))
2926 * Line is too long...
2929 cg
->ppd_line
= startline
;
2930 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2935 if (ch
== ':' && strncmp(line
->buffer
, "*%", 2) != 0)
2938 if (ch
== '\"' && colon
)
2939 endquote
= !endquote
;
2946 * Didn't finish this quoted string...
2949 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2952 else if (ch
== '\r' || ch
== '\n')
2960 * Check for a trailing line feed...
2963 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2966 cupsFileGetChar(fp
);
2969 else if (ch
< ' ' && ch
!= '\t' && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2972 * Other control characters...
2975 cg
->ppd_line
= startline
;
2976 cg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
2980 else if (ch
!= 0x1a)
2984 if (col
> (PPD_MAX_LINE
- 1))
2987 * Line is too long...
2990 cg
->ppd_line
= startline
;
2991 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
3001 * Didn't finish this line...
3004 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
3005 if (ch
== '\r' || ch
== '\n')
3008 * Line feed or carriage return...
3017 * Check for a trailing line feed...
3020 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
3023 cupsFileGetChar(fp
);
3028 else if (ch
< ' ' && ch
!= '\t' && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
3031 * Other control characters...
3034 cg
->ppd_line
= startline
;
3035 cg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
3039 else if (ch
!= 0x1a)
3043 if (col
> (PPD_MAX_LINE
- 1))
3046 * Line is too long...
3049 cg
->ppd_line
= startline
;
3050 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
3057 if (lineptr
> line
->buffer
&& lineptr
[-1] == '\n')
3062 DEBUG_printf(("9ppd_read: LINE=\"%s\"", line
->buffer
));
3065 * The dynamically created PPDs for older style OS X
3066 * drivers include a large blob of data inserted as comments
3067 * at the end of the file. As an optimization we can stop
3068 * reading the PPD when we get to the start of this data.
3071 if (!strcmp(line
->buffer
, "*%APLWORKSET START"))
3074 if (ch
== EOF
&& lineptr
== line
->buffer
)
3082 lineptr
= line
->buffer
+ 1;
3089 if ((!line
->buffer
[0] || /* Blank line */
3090 !strncmp(line
->buffer
, "*%", 2) || /* Comment line */
3091 !strcmp(line
->buffer
, "*End")) && /* End of multi-line string */
3092 ignoreblank
) /* Ignore these? */
3094 startline
= cg
->ppd_line
+ 1;
3098 if (!strcmp(line
->buffer
, "*")) /* (Bad) comment line */
3100 if (cg
->ppd_conform
== PPD_CONFORM_RELAXED
)
3102 startline
= cg
->ppd_line
+ 1;
3107 cg
->ppd_line
= startline
;
3108 cg
->ppd_status
= PPD_ILLEGAL_MAIN_KEYWORD
;
3114 if (line
->buffer
[0] != '*') /* All lines start with an asterisk */
3117 * Allow lines consisting of just whitespace...
3120 for (lineptr
= line
->buffer
; *lineptr
; lineptr
++)
3121 if (*lineptr
&& !_cups_isspace(*lineptr
))
3126 cg
->ppd_status
= PPD_MISSING_ASTERISK
;
3129 else if (ignoreblank
)
3141 while (*lineptr
&& *lineptr
!= ':' && !_cups_isspace(*lineptr
))
3143 if (*lineptr
<= ' ' || *lineptr
> 126 || *lineptr
== '/' ||
3144 (keyptr
- keyword
) >= (PPD_MAX_NAME
- 1))
3146 cg
->ppd_status
= PPD_ILLEGAL_MAIN_KEYWORD
;
3150 *keyptr
++ = *lineptr
++;
3155 if (!strcmp(keyword
, "End"))
3158 mask
|= PPD_KEYWORD
;
3160 if (_cups_isspace(*lineptr
))
3163 * Get an option name...
3166 while (_cups_isspace(*lineptr
))
3171 while (*lineptr
&& !_cups_isspace(*lineptr
) && *lineptr
!= ':' &&
3174 if (*lineptr
<= ' ' || *lineptr
> 126 ||
3175 (optptr
- option
) >= (PPD_MAX_NAME
- 1))
3177 cg
->ppd_status
= PPD_ILLEGAL_OPTION_KEYWORD
;
3181 *optptr
++ = *lineptr
++;
3186 if (_cups_isspace(*lineptr
) && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
3188 cg
->ppd_status
= PPD_ILLEGAL_WHITESPACE
;
3192 while (_cups_isspace(*lineptr
))
3197 if (*lineptr
== '/')
3200 * Get human-readable text...
3207 while (*lineptr
!= '\0' && *lineptr
!= '\n' && *lineptr
!= ':')
3209 if (((unsigned char)*lineptr
< ' ' && *lineptr
!= '\t') ||
3210 (textptr
- text
) >= (PPD_MAX_LINE
- 1))
3212 cg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
3216 *textptr
++ = *lineptr
++;
3220 textlen
= ppd_decode(text
);
3222 if (textlen
> PPD_MAX_TEXT
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
3224 cg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
3232 if (_cups_isspace(*lineptr
) && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
3234 cg
->ppd_status
= PPD_ILLEGAL_WHITESPACE
;
3238 while (_cups_isspace(*lineptr
))
3241 if (*lineptr
== ':')
3244 * Get string after triming leading and trailing whitespace...
3248 while (_cups_isspace(*lineptr
))
3251 strptr
= lineptr
+ strlen(lineptr
) - 1;
3252 while (strptr
>= lineptr
&& _cups_isspace(*strptr
))
3255 if (*strptr
== '\"')
3258 * Quoted string by itself, remove quotes...
3265 *string
= _cupsStrAlloc(lineptr
);
3277 * 'ppd_update_filters()' - Update the filters array as needed.
3279 * This function re-populates the filters array with cupsFilter2 entries that
3280 * have been stripped of the destination MIME media types and any maxsize hints.
3282 * (All for backwards-compatibility)
3285 static int /* O - 1 on success, 0 on failure */
3286 ppd_update_filters(ppd_file_t
*ppd
,/* I - PPD file */
3287 _cups_globals_t
*cg
) /* I - Global data */
3289 ppd_attr_t
*attr
; /* Current cupsFilter2 value */
3290 char srcsuper
[16], /* Source MIME media type */
3292 dstsuper
[16], /* Destination MIME media type */
3294 program
[1024], /* Command to run */
3295 *ptr
, /* Pointer into command to run */
3296 buffer
[1024], /* Re-written cupsFilter value */
3297 **filter
; /* Current filter */
3298 int cost
; /* Cost of filter */
3301 DEBUG_printf(("4ppd_update_filters(ppd=%p, cg=%p)", ppd
, cg
));
3304 * See if we have any cupsFilter2 lines...
3307 if ((attr
= ppdFindAttr(ppd
, "cupsFilter2", NULL
)) == NULL
)
3309 DEBUG_puts("5ppd_update_filters: No cupsFilter2 keywords present.");
3314 * Yes, free the cupsFilter-defined filters and re-build...
3317 ppd_free_filters(ppd
);
3322 * Parse the cupsFilter2 string:
3324 * src/type dst/type cost program
3325 * src/type dst/type cost maxsize(n) program
3328 DEBUG_printf(("5ppd_update_filters: cupsFilter2=\"%s\"", attr
->value
));
3330 if (sscanf(attr
->value
, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
3331 srcsuper
, srctype
, dstsuper
, dsttype
, &cost
, program
) != 6)
3333 DEBUG_puts("5ppd_update_filters: Bad cupsFilter2 line.");
3334 cg
->ppd_status
= PPD_BAD_VALUE
;
3339 DEBUG_printf(("5ppd_update_filters: srcsuper=\"%s\", srctype=\"%s\", "
3340 "dstsuper=\"%s\", dsttype=\"%s\", cost=%d, program=\"%s\"",
3341 srcsuper
, srctype
, dstsuper
, dsttype
, cost
, program
));
3343 if (!strncmp(program
, "maxsize(", 8) &&
3344 (ptr
= strchr(program
+ 8, ')')) != NULL
)
3346 DEBUG_puts("5ppd_update_filters: Found maxsize(nnn).");
3349 while (_cups_isspace(*ptr
))
3352 _cups_strcpy(program
, ptr
);
3353 DEBUG_printf(("5ppd_update_filters: New program=\"%s\"", program
));
3357 * Convert to cupsFilter format:
3359 * src/type cost program
3362 snprintf(buffer
, sizeof(buffer
), "%s/%s %d %s", srcsuper
, srctype
, cost
,
3364 DEBUG_printf(("5ppd_update_filters: Adding \"%s\".", buffer
));
3367 * Add a cupsFilter-compatible string to the filters array.
3370 if (ppd
->num_filters
== 0)
3371 filter
= malloc(sizeof(char *));
3373 filter
= realloc(ppd
->filters
, sizeof(char *) * (ppd
->num_filters
+ 1));
3377 DEBUG_puts("5ppd_update_filters: Out of memory.");
3378 cg
->ppd_status
= PPD_ALLOC_ERROR
;
3383 ppd
->filters
= filter
;
3384 filter
+= ppd
->num_filters
;
3385 ppd
->num_filters
++;
3387 *filter
= _cupsStrAlloc(buffer
);
3389 while ((attr
= ppdFindNextAttr(ppd
, "cupsFilter2", NULL
)) != NULL
);
3391 DEBUG_puts("5ppd_update_filters: Completed OK.");