2 * "$Id: ppd.c 6937 2007-09-10 21:13:31Z mike $"
4 * PPD file routines for the Common UNIX Printing System (CUPS).
6 * Copyright 2007 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * PostScript is a trademark of Adobe Systems, Inc.
17 * This code and any derivative of it may be used and distributed
18 * freely under the terms of the GNU General Public License when
19 * used with GNU Ghostscript or its derivatives. Use of the code
20 * (or any derivative of it) with software other than GNU
21 * GhostScript (or its derivatives) is governed by the CUPS license
24 * This file is subject to the Apple OS-Developed Software exception.
28 * ppdClose() - Free all memory used by the PPD file.
29 * ppdErrorString() - Returns the text assocated with a status.
30 * _ppdGetEncoding() - Get the CUPS encoding value for the given
32 * ppdLastError() - Return the status from the last ppdOpen*().
33 * ppdOpen() - Read a PPD file into memory.
34 * ppdOpen2() - Read a PPD file into memory.
35 * ppdOpenFd() - Read a PPD file into memory.
36 * ppdOpenFile() - Read a PPD file into memory.
37 * ppdSetConformance() - Set the conformance level for PPD files.
38 * ppd_add_attr() - Add an attribute to the PPD data.
39 * ppd_add_choice() - Add a choice to an option.
40 * ppd_add_size() - Add a page size.
41 * ppd_compare_attrs() - Compare two attributes.
42 * ppd_compare_choices() - Compare two choices...
43 * ppd_compare_consts() - Compare two constraints.
44 * ppd_compare_coptions() - Compare two custom options.
45 * ppd_compare_cparams() - Compare two custom parameters.
46 * ppd_compare_options() - Compare two options.
47 * ppd_decode() - Decode a string value...
48 * ppd_free_group() - Free a single UI group.
49 * ppd_free_option() - Free a single option.
50 * ppd_get_coption() - Get a custom option record.
51 * ppd_get_cparam() - Get a custom parameter record.
52 * ppd_get_group() - Find or create the named group as needed.
53 * ppd_get_option() - Find or create the named option as needed.
54 * ppd_hash_option() - Generate a hash of the option name...
55 * ppd_read() - Read a line from a PPD file, skipping comment
60 * Include necessary headers.
72 #if defined(WIN32) || defined(__EMX__)
73 # define READ_BINARY "rb" /* Open a binary file for reading */
74 # define WRITE_BINARY "wb" /* Open a binary file for writing */
76 # define READ_BINARY "r" /* Open a binary file for reading */
77 # define WRITE_BINARY "w" /* Open a binary file for writing */
78 #endif /* WIN32 || __EMX__ */
80 #define ppd_free(p) if (p) free(p) /* Safe free macro */
82 #define PPD_KEYWORD 1 /* Line contained a keyword */
83 #define PPD_OPTION 2 /* Line contained an option name */
84 #define PPD_TEXT 4 /* Line contained human-readable text */
85 #define PPD_STRING 8 /* Line contained a string or code */
87 #define PPD_HASHSIZE 512 /* Size of hash */
91 * Line buffer structure...
94 typedef struct _ppd_line_s
96 char *buffer
; /* Pointer to buffer */
97 size_t bufsize
; /* Size of the buffer */
105 static ppd_attr_t
*ppd_add_attr(ppd_file_t
*ppd
, const char *name
,
106 const char *spec
, const char *text
,
108 static ppd_choice_t
*ppd_add_choice(ppd_option_t
*option
, const char *name
);
109 static ppd_size_t
*ppd_add_size(ppd_file_t
*ppd
, const char *name
);
110 static int ppd_compare_attrs(ppd_attr_t
*a
, ppd_attr_t
*b
);
111 static int ppd_compare_choices(ppd_choice_t
*a
, ppd_choice_t
*b
);
112 static int ppd_compare_consts(ppd_const_t
*a
, ppd_const_t
*b
);
113 static int ppd_compare_coptions(ppd_coption_t
*a
,
115 static int ppd_compare_cparams(ppd_cparam_t
*a
, ppd_cparam_t
*b
);
116 static int ppd_compare_options(ppd_option_t
*a
, ppd_option_t
*b
);
117 static int ppd_decode(char *string
);
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
);
136 * 'ppdClose()' - Free all memory used by the PPD file.
140 ppdClose(ppd_file_t
*ppd
) /* I - PPD file record */
142 int i
; /* Looping var */
143 ppd_emul_t
*emul
; /* Current emulation */
144 ppd_group_t
*group
; /* Current group */
145 char **font
; /* Current font */
146 char **filter
; /* Current filter */
147 ppd_attr_t
**attr
; /* Current attribute */
148 ppd_coption_t
*coption
; /* Current custom option */
149 ppd_cparam_t
*cparam
; /* Current custom parameter */
153 * Range check arguments...
160 * Free all strings at the top level...
163 _cupsStrFree(ppd
->lang_encoding
);
164 _cupsStrFree(ppd
->nickname
);
165 _cupsStrFree(ppd
->patches
);
166 _cupsStrFree(ppd
->jcl_begin
);
167 _cupsStrFree(ppd
->jcl_end
);
168 _cupsStrFree(ppd
->jcl_ps
);
171 * Free any emulations...
174 if (ppd
->num_emulations
> 0)
176 for (i
= ppd
->num_emulations
, emul
= ppd
->emulations
; i
> 0; i
--, emul
++)
178 _cupsStrFree(emul
->start
);
179 _cupsStrFree(emul
->stop
);
182 ppd_free(ppd
->emulations
);
186 * Free any UI groups, subgroups, and options...
189 if (ppd
->num_groups
> 0)
191 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
192 ppd_free_group(group
);
194 ppd_free(ppd
->groups
);
197 cupsArrayDelete(ppd
->options
);
198 cupsArrayDelete(ppd
->marked
);
201 * Free any page sizes...
204 if (ppd
->num_sizes
> 0)
205 ppd_free(ppd
->sizes
);
208 * Free any constraints...
211 if (ppd
->num_consts
> 0)
212 ppd_free(ppd
->consts
);
215 * Free any filters...
218 if (ppd
->num_filters
> 0)
220 for (i
= ppd
->num_filters
, filter
= ppd
->filters
; i
> 0; i
--, filter
++)
221 _cupsStrFree(*filter
);
223 ppd_free(ppd
->filters
);
230 if (ppd
->num_fonts
> 0)
232 for (i
= ppd
->num_fonts
, font
= ppd
->fonts
; i
> 0; i
--, font
++)
235 ppd_free(ppd
->fonts
);
239 * Free any profiles...
242 if (ppd
->num_profiles
> 0)
243 ppd_free(ppd
->profiles
);
246 * Free any attributes...
249 if (ppd
->num_attrs
> 0)
251 for (i
= ppd
->num_attrs
, attr
= ppd
->attrs
; i
> 0; i
--, attr
++)
253 _cupsStrFree((*attr
)->value
);
257 ppd_free(ppd
->attrs
);
260 cupsArrayDelete(ppd
->sorted_attrs
);
263 * Free custom options...
266 for (coption
= (ppd_coption_t
*)cupsArrayFirst(ppd
->coptions
);
268 coption
= (ppd_coption_t
*)cupsArrayNext(ppd
->coptions
))
270 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
272 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
274 switch (cparam
->type
)
276 case PPD_CUSTOM_PASSCODE
:
277 case PPD_CUSTOM_PASSWORD
:
278 case PPD_CUSTOM_STRING
:
279 _cupsStrFree(cparam
->current
.custom_string
);
289 cupsArrayDelete(coption
->params
);
294 cupsArrayDelete(ppd
->coptions
);
297 * Free the whole record...
305 * 'ppdErrorString()' - Returns the text assocated with a status.
307 * @since CUPS 1.1.19@
310 const char * /* O - Status string */
311 ppdErrorString(ppd_status_t status
) /* I - PPD status */
313 static const char * const messages
[] =/* Status messages */
316 _("Unable to open PPD file"),
317 _("NULL PPD file pointer"),
318 _("Memory allocation error"),
319 _("Missing PPD-Adobe-4.x header"),
320 _("Missing value string"),
323 _("OpenGroup without a CloseGroup first"),
324 _("Bad OpenUI/JCLOpenUI"),
325 _("OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"),
326 _("Bad OrderDependency"),
327 _("Bad UIConstraints"),
328 _("Missing asterisk in column 1"),
329 _("Line longer than the maximum allowed (255 characters)"),
330 _("Illegal control character"),
331 _("Illegal main keyword string"),
332 _("Illegal option keyword string"),
333 _("Illegal translation string"),
334 _("Illegal whitespace character"),
335 _("Bad custom parameter")
339 if (status
< PPD_OK
|| status
> PPD_ILLEGAL_WHITESPACE
)
340 return (_cupsLangString(cupsLangDefault(), _("Unknown")));
342 return (_cupsLangString(cupsLangDefault(), messages
[status
]));
347 * '_ppdGetEncoding()' - Get the CUPS encoding value for the given
351 cups_encoding_t
/* O - CUPS encoding value */
352 _ppdGetEncoding(const char *name
) /* I - LanguageEncoding string */
354 if (!strcasecmp(name
, "ISOLatin1"))
355 return (CUPS_ISO8859_1
);
356 else if (!strcasecmp(name
, "ISOLatin2"))
357 return (CUPS_ISO8859_2
);
358 else if (!strcasecmp(name
, "ISOLatin5"))
359 return (CUPS_ISO8859_5
);
360 else if (!strcasecmp(name
, "JIS83-RKSJ"))
361 return (CUPS_WINDOWS_932
);
362 else if (!strcasecmp(name
, "MacStandard"))
363 return (CUPS_MAC_ROMAN
);
364 else if (!strcasecmp(name
, "WindowsANSI"))
365 return (CUPS_WINDOWS_1252
);
372 * 'ppdLastError()' - Return the status from the last ppdOpen*().
374 * @since CUPS 1.1.19@
377 ppd_status_t
/* O - Status code */
378 ppdLastError(int *line
) /* O - Line number */
380 _cups_globals_t
*cg
= _cupsGlobals();
385 *line
= cg
->ppd_line
;
387 return (cg
->ppd_status
);
392 * 'ppdOpen()' - Read a PPD file into memory.
395 ppd_file_t
* /* O - PPD file record */
396 ppdOpen(FILE *fp
) /* I - File to read from */
398 ppd_file_t
*ppd
; /* PPD file record */
399 cups_file_t
*cf
; /* CUPS file */
403 * Reopen the stdio file as a CUPS file...
406 if ((cf
= cupsFileOpenFd(fileno(fp
), "r")) == NULL
)
410 * Load the PPD file using the newer API...
416 * Close the CUPS file and return the PPD...
426 * 'ppdOpen2()' - Read a PPD file into memory.
431 ppd_file_t
* /* O - PPD file record */
432 ppdOpen2(cups_file_t
*fp
) /* I - File to read from */
434 int i
, j
, k
; /* Looping vars */
435 int count
; /* Temporary count */
436 _ppd_line_t line
; /* Line buffer */
437 ppd_file_t
*ppd
; /* PPD file record */
438 ppd_group_t
*group
, /* Current group */
439 *subgroup
; /* Current sub-group */
440 ppd_option_t
*option
; /* Current option */
441 ppd_choice_t
*choice
; /* Current choice */
442 ppd_const_t
*constraint
; /* Current constraint */
443 ppd_size_t
*size
; /* Current page size */
444 int mask
; /* Line data mask */
445 char keyword
[PPD_MAX_NAME
],
446 /* Keyword from file */
448 /* Option from file */
450 /* Human-readable text from file */
451 *string
, /* Code/text from file */
452 *sptr
, /* Pointer into string */
453 *nameptr
, /* Pointer into name */
454 *temp
, /* Temporary string pointer */
455 **tempfonts
; /* Temporary fonts pointer */
456 float order
; /* Order dependency number */
457 ppd_section_t section
; /* Order dependency section */
458 ppd_profile_t
*profile
; /* Pointer to color profile */
459 char **filter
; /* Pointer to filter */
460 cups_lang_t
*language
; /* Default language */
461 struct lconv
*loc
; /* Locale data */
462 int ui_keyword
; /* Is this line a UI keyword? */
463 cups_encoding_t encoding
; /* Encoding of PPD file */
464 _cups_globals_t
*cg
= _cupsGlobals();
466 char custom_name
[PPD_MAX_NAME
];
467 /* CustomFoo attribute name */
468 ppd_attr_t
*custom_attr
; /* CustomFoo attribute */
469 static const char * const ui_keywords
[] =
471 #ifdef CUPS_USE_FULL_UI_KEYWORDS_LIST
473 * Adobe defines some 41 keywords as "UI", meaning that they are
474 * user interface elements and that they should be treated as such
475 * even if the PPD creator doesn't use Open/CloseUI around them.
477 * Since this can cause previously invisible options to appear and
478 * confuse users, the default is to only treat the PageSize and
479 * PageRegion keywords this way.
481 /* Boolean keywords */
491 /* PickOne keywords */
504 "JCLFrameBufferSize",
525 #else /* !CUPS_USE_FULL_UI_KEYWORDS_LIST */
528 #endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */
533 * Default to "OK" status...
536 cg
->ppd_status
= PPD_OK
;
540 * Range check input...
545 cg
->ppd_status
= PPD_NULL_FILE
;
550 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
556 mask
= ppd_read(fp
, &line
, keyword
, name
, text
, &string
, 0, cg
);
558 DEBUG_printf(("mask=%x, keyword=\"%s\"...\n", mask
, keyword
));
561 strcmp(keyword
, "PPD-Adobe") ||
562 string
== NULL
|| string
[0] != '4')
565 * Either this is not a PPD file, or it is not a 4.x PPD file.
568 if (cg
->ppd_status
== PPD_OK
)
569 cg
->ppd_status
= PPD_MISSING_PPDADOBE4
;
571 _cupsStrFree(string
);
576 DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword
, string
));
578 _cupsStrFree(string
);
581 * Allocate memory for the PPD file record...
584 if ((ppd
= calloc(1, sizeof(ppd_file_t
))) == NULL
)
586 cg
->ppd_status
= PPD_ALLOC_ERROR
;
591 ppd
->language_level
= 2;
592 ppd
->color_device
= 0;
593 ppd
->colorspace
= PPD_CS_GRAY
;
594 ppd
->landscape
= -90;
595 ppd
->coptions
= cupsArrayNew((cups_array_func_t
)ppd_compare_coptions
,
599 * Get the default language for the user...
602 language
= cupsLangDefault();
606 * Read lines from the PPD file and add them to the file record...
614 encoding
= CUPS_ISO8859_1
;
616 while ((mask
= ppd_read(fp
, &line
, keyword
, name
, text
, &string
, 1, cg
)) != 0)
619 printf("mask = %x, keyword = \"%s\"", mask
, keyword
);
622 printf(", name = \"%s\"", name
);
625 printf(", text = \"%s\"", text
);
629 if (strlen(string
) > 40)
630 printf(", string = %p", string
);
632 printf(", string = \"%s\"", string
);
638 if (strcmp(keyword
, "CloseUI") && strcmp(keyword
, "CloseGroup") &&
639 strcmp(keyword
, "CloseSubGroup") && strncmp(keyword
, "Default", 7) &&
640 strcmp(keyword
, "JCLCloseUI") && strcmp(keyword
, "JCLOpenUI") &&
641 strcmp(keyword
, "OpenUI") && strcmp(keyword
, "OpenGroup") &&
642 strcmp(keyword
, "OpenSubGroup") && string
== NULL
)
645 * Need a string value!
648 cg
->ppd_status
= PPD_MISSING_VALUE
;
654 * Certain main keywords (as defined by the PPD spec) may be used
655 * without the usual OpenUI/CloseUI stuff. Presumably this is just
656 * so that Adobe wouldn't completely break compatibility with PPD
657 * files prior to v4.0 of the spec, but it is hopelessly
658 * inconsistent... Catch these main keywords and automatically
659 * create the corresponding option, as needed...
665 * Previous line was a UI keyword...
672 if (option
== NULL
&&
673 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
674 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
))
676 for (i
= 0; i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])); i
++)
677 if (!strcmp(keyword
, ui_keywords
[i
]))
680 if (i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])))
683 * Create the option in the appropriate group...
688 DEBUG_printf(("**** FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!\n",
693 if ((group
= ppd_get_group(ppd
, "General", _("General"), cg
,
697 DEBUG_printf(("Adding to group %s...\n", group
->text
));
698 option
= ppd_get_option(group
, keyword
);
702 option
= ppd_get_option(group
, keyword
);
706 cg
->ppd_status
= PPD_ALLOC_ERROR
;
712 * Now fill in the initial information for the option...
715 if (!strncmp(keyword
, "JCL", 3))
716 option
->section
= PPD_ORDER_JCL
;
718 option
->section
= PPD_ORDER_ANY
;
720 option
->order
= 10.0f
;
723 option
->ui
= PPD_UI_BOOLEAN
;
725 option
->ui
= PPD_UI_PICKONE
;
727 for (j
= 0; j
< ppd
->num_attrs
; j
++)
728 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
729 !strcmp(ppd
->attrs
[j
]->name
+ 7, keyword
) &&
730 ppd
->attrs
[j
]->value
)
732 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
733 option
->keyword
, ppd
->attrs
[j
]->value
));
734 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
735 sizeof(option
->defchoice
));
739 if (!strcmp(keyword
, "PageSize"))
740 strlcpy(option
->text
, _("Media Size"), sizeof(option
->text
));
741 else if (!strcmp(keyword
, "MediaType"))
742 strlcpy(option
->text
, _("Media Type"), sizeof(option
->text
));
743 else if (!strcmp(keyword
, "InputSlot"))
744 strlcpy(option
->text
, _("Media Source"), sizeof(option
->text
));
745 else if (!strcmp(keyword
, "ColorModel"))
746 strlcpy(option
->text
, _("Output Mode"), sizeof(option
->text
));
747 else if (!strcmp(keyword
, "Resolution"))
748 strlcpy(option
->text
, _("Resolution"), sizeof(option
->text
));
750 strlcpy(option
->text
, keyword
, sizeof(option
->text
));
754 if (!strcmp(keyword
, "LanguageLevel"))
755 ppd
->language_level
= atoi(string
);
756 else if (!strcmp(keyword
, "LanguageEncoding"))
759 * Say all PPD files are UTF-8, since we convert to UTF-8...
762 ppd
->lang_encoding
= _cupsStrAlloc("UTF-8");
763 encoding
= _ppdGetEncoding(string
);
765 else if (!strcmp(keyword
, "LanguageVersion"))
766 ppd
->lang_version
= string
;
767 else if (!strcmp(keyword
, "Manufacturer"))
768 ppd
->manufacturer
= string
;
769 else if (!strcmp(keyword
, "ModelName"))
770 ppd
->modelname
= string
;
771 else if (!strcmp(keyword
, "Protocols"))
772 ppd
->protocols
= string
;
773 else if (!strcmp(keyword
, "PCFileName"))
774 ppd
->pcfilename
= string
;
775 else if (!strcmp(keyword
, "NickName"))
777 if (encoding
!= CUPS_UTF8
)
779 cups_utf8_t utf8
[256]; /* UTF-8 version of NickName */
782 cupsCharsetToUTF8(utf8
, string
, sizeof(utf8
), encoding
);
783 ppd
->nickname
= _cupsStrAlloc((char *)utf8
);
786 ppd
->nickname
= _cupsStrAlloc(string
);
788 else if (!strcmp(keyword
, "Product"))
789 ppd
->product
= string
;
790 else if (!strcmp(keyword
, "ShortNickName"))
791 ppd
->shortnickname
= string
;
792 else if (!strcmp(keyword
, "TTRasterizer"))
793 ppd
->ttrasterizer
= string
;
794 else if (!strcmp(keyword
, "JCLBegin"))
796 ppd
->jcl_begin
= _cupsStrAlloc(string
);
797 ppd_decode(ppd
->jcl_begin
); /* Decode quoted string */
799 else if (!strcmp(keyword
, "JCLEnd"))
801 ppd
->jcl_end
= _cupsStrAlloc(string
);
802 ppd_decode(ppd
->jcl_end
); /* Decode quoted string */
804 else if (!strcmp(keyword
, "JCLToPSInterpreter"))
806 ppd
->jcl_ps
= _cupsStrAlloc(string
);
807 ppd_decode(ppd
->jcl_ps
); /* Decode quoted string */
809 else if (!strcmp(keyword
, "AccurateScreensSupport"))
810 ppd
->accurate_screens
= !strcmp(string
, "True");
811 else if (!strcmp(keyword
, "ColorDevice"))
812 ppd
->color_device
= !strcmp(string
, "True");
813 else if (!strcmp(keyword
, "ContoneOnly"))
814 ppd
->contone_only
= !strcmp(string
, "True");
815 else if (!strcmp(keyword
, "cupsFlipDuplex"))
816 ppd
->flip_duplex
= !strcmp(string
, "True");
817 else if (!strcmp(keyword
, "cupsManualCopies"))
818 ppd
->manual_copies
= !strcmp(string
, "True");
819 else if (!strcmp(keyword
, "cupsModelNumber"))
820 ppd
->model_number
= atoi(string
);
821 else if (!strcmp(keyword
, "cupsColorProfile"))
823 if (ppd
->num_profiles
== 0)
824 profile
= malloc(sizeof(ppd_profile_t
));
826 profile
= realloc(ppd
->profiles
, sizeof(ppd_profile_t
) *
827 (ppd
->num_profiles
+ 1));
829 ppd
->profiles
= profile
;
830 profile
+= ppd
->num_profiles
;
831 ppd
->num_profiles
++;
833 memset(profile
, 0, sizeof(ppd_profile_t
));
834 strlcpy(profile
->resolution
, name
, sizeof(profile
->resolution
));
835 strlcpy(profile
->media_type
, text
, sizeof(profile
->media_type
));
837 profile
->density
= (float)_cupsStrScand(string
, &sptr
, loc
);
838 profile
->gamma
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
839 profile
->matrix
[0][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
840 profile
->matrix
[0][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
841 profile
->matrix
[0][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
842 profile
->matrix
[1][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
843 profile
->matrix
[1][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
844 profile
->matrix
[1][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
845 profile
->matrix
[2][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
846 profile
->matrix
[2][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
847 profile
->matrix
[2][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
849 else if (!strcmp(keyword
, "cupsFilter"))
851 if (ppd
->num_filters
== 0)
852 filter
= malloc(sizeof(char *));
854 filter
= realloc(ppd
->filters
, sizeof(char *) * (ppd
->num_filters
+ 1));
858 cg
->ppd_status
= PPD_ALLOC_ERROR
;
863 ppd
->filters
= filter
;
864 filter
+= ppd
->num_filters
;
868 * Copy filter string and prevent it from being freed below...
874 else if (!strcmp(keyword
, "Throughput"))
875 ppd
->throughput
= atoi(string
);
876 else if (!strcmp(keyword
, "Font"))
879 * Add this font to the list of available fonts...
882 if (ppd
->num_fonts
== 0)
883 tempfonts
= (char **)malloc(sizeof(char *));
885 tempfonts
= (char **)realloc(ppd
->fonts
,
886 sizeof(char *) * (ppd
->num_fonts
+ 1));
888 if (tempfonts
== NULL
)
890 cg
->ppd_status
= PPD_ALLOC_ERROR
;
895 ppd
->fonts
= tempfonts
;
896 ppd
->fonts
[ppd
->num_fonts
] = _cupsStrAlloc(name
);
899 else if (!strncmp(keyword
, "ParamCustom", 11))
901 ppd_coption_t
*coption
; /* Custom option */
902 ppd_cparam_t
*cparam
; /* Custom parameter */
903 int corder
; /* Order number */
904 char ctype
[33], /* Data type */
905 cminimum
[65], /* Minimum value */
906 cmaximum
[65]; /* Maximum value */
910 * Get the custom option and parameter...
913 if ((coption
= ppd_get_coption(ppd
, keyword
+ 11)) == NULL
)
915 cg
->ppd_status
= PPD_ALLOC_ERROR
;
920 if ((cparam
= ppd_get_cparam(coption
, name
, text
)) == NULL
)
922 cg
->ppd_status
= PPD_ALLOC_ERROR
;
928 * Get the parameter data...
931 if (sscanf(string
, "%d%32s%64s%64s", &corder
, ctype
, cminimum
,
934 cg
->ppd_status
= PPD_BAD_CUSTOM_PARAM
;
939 cparam
->order
= corder
;
941 if (!strcmp(ctype
, "curve"))
943 cparam
->type
= PPD_CUSTOM_CURVE
;
944 cparam
->minimum
.custom_curve
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
945 cparam
->maximum
.custom_curve
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
947 else if (!strcmp(ctype
, "int"))
949 cparam
->type
= PPD_CUSTOM_INT
;
950 cparam
->minimum
.custom_int
= atoi(cminimum
);
951 cparam
->maximum
.custom_int
= atoi(cmaximum
);
953 else if (!strcmp(ctype
, "invcurve"))
955 cparam
->type
= PPD_CUSTOM_INVCURVE
;
956 cparam
->minimum
.custom_invcurve
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
957 cparam
->maximum
.custom_invcurve
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
959 else if (!strcmp(ctype
, "passcode"))
961 cparam
->type
= PPD_CUSTOM_PASSCODE
;
962 cparam
->minimum
.custom_passcode
= atoi(cminimum
);
963 cparam
->maximum
.custom_passcode
= atoi(cmaximum
);
965 else if (!strcmp(ctype
, "password"))
967 cparam
->type
= PPD_CUSTOM_PASSWORD
;
968 cparam
->minimum
.custom_password
= atoi(cminimum
);
969 cparam
->maximum
.custom_password
= atoi(cmaximum
);
971 else if (!strcmp(ctype
, "points"))
973 cparam
->type
= PPD_CUSTOM_POINTS
;
974 cparam
->minimum
.custom_points
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
975 cparam
->maximum
.custom_points
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
977 else if (!strcmp(ctype
, "real"))
979 cparam
->type
= PPD_CUSTOM_REAL
;
980 cparam
->minimum
.custom_real
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
981 cparam
->maximum
.custom_real
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
983 else if (!strcmp(ctype
, "string"))
985 cparam
->type
= PPD_CUSTOM_STRING
;
986 cparam
->minimum
.custom_string
= atoi(cminimum
);
987 cparam
->maximum
.custom_string
= atoi(cmaximum
);
991 cg
->ppd_status
= PPD_BAD_CUSTOM_PARAM
;
997 * Now special-case for CustomPageSize...
1000 if (!strcmp(coption
->keyword
, "PageSize"))
1002 if (!strcmp(name
, "Width"))
1004 ppd
->custom_min
[0] = cparam
->minimum
.custom_points
;
1005 ppd
->custom_max
[0] = cparam
->maximum
.custom_points
;
1007 else if (!strcmp(name
, "Height"))
1009 ppd
->custom_min
[1] = cparam
->minimum
.custom_points
;
1010 ppd
->custom_max
[1] = cparam
->maximum
.custom_points
;
1014 else if (!strcmp(keyword
, "HWMargins"))
1016 for (i
= 0, sptr
= string
; i
< 4; i
++)
1017 ppd
->custom_margins
[i
] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
1019 else if (!strncmp(keyword
, "Custom", 6) && !strcmp(name
, "True") && !option
)
1021 ppd_option_t
*custom_option
; /* Custom option */
1023 DEBUG_puts("Processing Custom option...");
1026 * Get the option and custom option...
1029 if (!ppd_get_coption(ppd
, keyword
+ 6))
1031 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1036 if (option
&& !strcasecmp(option
->keyword
, keyword
+ 6))
1037 custom_option
= option
;
1039 custom_option
= ppdFindOption(ppd
, keyword
+ 6);
1044 * Add the "custom" option...
1047 if ((choice
= ppd_add_choice(custom_option
, "Custom")) == NULL
)
1049 DEBUG_puts("Unable to add Custom choice!");
1051 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1056 strlcpy(choice
->text
, text
[0] ? text
: _("Custom"),
1057 sizeof(choice
->text
));
1059 choice
->code
= _cupsStrAlloc(string
);
1063 * Now process custom page sizes specially...
1066 if (!strcmp(keyword
, "CustomPageSize"))
1069 * Add a "Custom" page size entry...
1072 ppd
->variable_sizes
= 1;
1074 ppd_add_size(ppd
, "Custom");
1076 if (option
&& !strcasecmp(option
->keyword
, "PageRegion"))
1077 custom_option
= option
;
1079 custom_option
= ppdFindOption(ppd
, "PageRegion");
1083 if ((choice
= ppd_add_choice(custom_option
, "Custom")) == NULL
)
1085 DEBUG_puts("Unable to add Custom choice!");
1087 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1092 strlcpy(choice
->text
, text
[0] ? text
: _("Custom"),
1093 sizeof(choice
->text
));
1097 else if (!strcmp(keyword
, "LandscapeOrientation"))
1099 if (!strcmp(string
, "Minus90"))
1100 ppd
->landscape
= -90;
1101 else if (!strcmp(string
, "Plus90"))
1102 ppd
->landscape
= 90;
1104 else if (!strcmp(keyword
, "Emulators"))
1106 for (count
= 1, sptr
= string
; sptr
!= NULL
;)
1107 if ((sptr
= strchr(sptr
, ' ')) != NULL
)
1110 while (*sptr
== ' ')
1114 ppd
->num_emulations
= count
;
1115 ppd
->emulations
= calloc(count
, sizeof(ppd_emul_t
));
1117 for (i
= 0, sptr
= string
; i
< count
; i
++)
1119 for (nameptr
= ppd
->emulations
[i
].name
;
1120 *sptr
!= '\0' && *sptr
!= ' ';
1122 if (nameptr
< (ppd
->emulations
[i
].name
+ sizeof(ppd
->emulations
[i
].name
) - 1))
1127 while (*sptr
== ' ')
1131 else if (!strncmp(keyword
, "StartEmulator_", 14))
1135 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1136 if (!strcmp(keyword
+ 14, ppd
->emulations
[i
].name
))
1138 ppd
->emulations
[i
].start
= string
;
1142 else if (!strncmp(keyword
, "StopEmulator_", 13))
1146 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1147 if (!strcmp(keyword
+ 13, ppd
->emulations
[i
].name
))
1149 ppd
->emulations
[i
].stop
= string
;
1153 else if (!strcmp(keyword
, "JobPatchFile"))
1155 if (ppd
->patches
== NULL
)
1156 ppd
->patches
= _cupsStrAlloc(string
);
1159 temp
= realloc(ppd
->patches
, strlen(ppd
->patches
) +
1160 strlen(string
) + 1);
1163 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1168 ppd
->patches
= temp
;
1170 strcpy(ppd
->patches
+ strlen(ppd
->patches
), string
);
1173 else if (!strcmp(keyword
, "OpenUI"))
1176 * Don't allow nesting of options...
1179 if (option
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1181 cg
->ppd_status
= PPD_NESTED_OPEN_UI
;
1187 * Add an option record to the current sub-group, group, or file...
1190 DEBUG_printf(("name=\"%s\" (%d)\n", name
, strlen(name
)));
1193 _cups_strcpy(name
, name
+ 1); /* Eliminate leading asterisk */
1195 for (i
= (int)strlen(name
) - 1; i
> 0 && isspace(name
[i
] & 255); i
--)
1196 name
[i
] = '\0'; /* Eliminate trailing spaces */
1198 DEBUG_printf(("OpenUI of %s in group %s...\n", name
,
1199 group
? group
->text
: "(null)"));
1201 if (subgroup
!= NULL
)
1202 option
= ppd_get_option(subgroup
, name
);
1203 else if (group
== NULL
)
1205 if ((group
= ppd_get_group(ppd
, "General", _("General"), cg
,
1209 DEBUG_printf(("Adding to group %s...\n", group
->text
));
1210 option
= ppd_get_option(group
, name
);
1214 option
= ppd_get_option(group
, name
);
1218 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1224 * Now fill in the initial information for the option...
1227 if (string
&& !strcmp(string
, "PickMany"))
1228 option
->ui
= PPD_UI_PICKMANY
;
1229 else if (string
&& !strcmp(string
, "Boolean"))
1230 option
->ui
= PPD_UI_BOOLEAN
;
1231 else if (string
&& !strcmp(string
, "PickOne"))
1232 option
->ui
= PPD_UI_PICKONE
;
1233 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1235 cg
->ppd_status
= PPD_BAD_OPEN_UI
;
1240 option
->ui
= PPD_UI_PICKONE
;
1242 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1243 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
1244 !strcmp(ppd
->attrs
[j
]->name
+ 7, name
) &&
1245 ppd
->attrs
[j
]->value
)
1247 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
1248 option
->keyword
, ppd
->attrs
[j
]->value
));
1249 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
1250 sizeof(option
->defchoice
));
1255 cupsCharsetToUTF8((cups_utf8_t
*)option
->text
, text
,
1256 sizeof(option
->text
), encoding
);
1259 if (!strcmp(name
, "PageSize"))
1260 strlcpy(option
->text
, _("Media Size"), sizeof(option
->text
));
1261 else if (!strcmp(name
, "MediaType"))
1262 strlcpy(option
->text
, _("Media Type"), sizeof(option
->text
));
1263 else if (!strcmp(name
, "InputSlot"))
1264 strlcpy(option
->text
, _("Media Source"), sizeof(option
->text
));
1265 else if (!strcmp(name
, "ColorModel"))
1266 strlcpy(option
->text
, _("Output Mode"), sizeof(option
->text
));
1267 else if (!strcmp(name
, "Resolution"))
1268 strlcpy(option
->text
, _("Resolution"), sizeof(option
->text
));
1270 strlcpy(option
->text
, name
, sizeof(option
->text
));
1273 option
->section
= PPD_ORDER_ANY
;
1275 _cupsStrFree(string
);
1279 * Add a custom option choice if we have already seen a CustomFoo
1283 if (!strcasecmp(name
, "PageRegion"))
1284 strcpy(custom_name
, "CustomPageSize");
1286 snprintf(custom_name
, sizeof(custom_name
), "Custom%s", name
);
1288 if ((custom_attr
= ppdFindAttr(ppd
, custom_name
, "True")) != NULL
)
1290 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
1292 DEBUG_puts("Unable to add Custom choice!");
1294 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1299 strlcpy(choice
->text
,
1300 custom_attr
->text
[0] ? custom_attr
->text
: _("Custom"),
1301 sizeof(choice
->text
));
1302 choice
->code
= _cupsStrAlloc(custom_attr
->value
);
1305 else if (!strcmp(keyword
, "JCLOpenUI"))
1308 * Don't allow nesting of options...
1311 if (option
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1313 cg
->ppd_status
= PPD_NESTED_OPEN_UI
;
1319 * Find the JCL group, and add if needed...
1322 group
= ppd_get_group(ppd
, "JCL", _("JCL"), cg
, encoding
);
1328 * Add an option record to the current JCLs...
1332 _cups_strcpy(name
, name
+ 1);
1334 option
= ppd_get_option(group
, name
);
1338 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1344 * Now fill in the initial information for the option...
1347 if (string
&& !strcmp(string
, "PickMany"))
1348 option
->ui
= PPD_UI_PICKMANY
;
1349 else if (string
&& !strcmp(string
, "Boolean"))
1350 option
->ui
= PPD_UI_BOOLEAN
;
1351 else if (string
&& !strcmp(string
, "PickOne"))
1352 option
->ui
= PPD_UI_PICKONE
;
1355 cg
->ppd_status
= PPD_BAD_OPEN_UI
;
1360 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1361 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
1362 !strcmp(ppd
->attrs
[j
]->name
+ 7, name
) &&
1363 ppd
->attrs
[j
]->value
)
1365 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
1366 option
->keyword
, ppd
->attrs
[j
]->value
));
1367 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
1368 sizeof(option
->defchoice
));
1373 cupsCharsetToUTF8((cups_utf8_t
*)option
->text
, text
,
1374 sizeof(option
->text
), encoding
);
1376 strlcpy(option
->text
, name
, sizeof(option
->text
));
1378 option
->section
= PPD_ORDER_JCL
;
1381 _cupsStrFree(string
);
1385 * Add a custom option choice if we have already seen a CustomFoo
1389 snprintf(custom_name
, sizeof(custom_name
), "Custom%s", name
);
1391 if ((custom_attr
= ppdFindAttr(ppd
, custom_name
, "True")) != NULL
)
1393 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
1395 DEBUG_puts("Unable to add Custom choice!");
1397 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1402 strlcpy(choice
->text
,
1403 custom_attr
->text
[0] ? custom_attr
->text
: _("Custom"),
1404 sizeof(choice
->text
));
1405 choice
->code
= _cupsStrAlloc(custom_attr
->value
);
1408 else if (!strcmp(keyword
, "CloseUI") || !strcmp(keyword
, "JCLCloseUI"))
1412 _cupsStrFree(string
);
1415 else if (!strcmp(keyword
, "OpenGroup"))
1418 * Open a new group...
1423 cg
->ppd_status
= PPD_NESTED_OPEN_GROUP
;
1430 cg
->ppd_status
= PPD_BAD_OPEN_GROUP
;
1436 * Separate the group name from the text (name/text)...
1439 if ((sptr
= strchr(string
, '/')) != NULL
)
1445 * Fix up the text...
1451 * Find/add the group...
1454 group
= ppd_get_group(ppd
, string
, sptr
, cg
, encoding
);
1459 _cupsStrFree(string
);
1462 else if (!strcmp(keyword
, "CloseGroup"))
1466 _cupsStrFree(string
);
1469 else if (!strcmp(keyword
, "OrderDependency"))
1471 order
= (float)_cupsStrScand(string
, &sptr
, loc
);
1473 if (!sptr
|| sscanf(sptr
, "%40s%40s", name
, keyword
) != 2)
1475 cg
->ppd_status
= PPD_BAD_ORDER_DEPENDENCY
;
1480 if (keyword
[0] == '*')
1481 _cups_strcpy(keyword
, keyword
+ 1);
1483 if (!strcmp(name
, "ExitServer"))
1484 section
= PPD_ORDER_EXIT
;
1485 else if (!strcmp(name
, "Prolog"))
1486 section
= PPD_ORDER_PROLOG
;
1487 else if (!strcmp(name
, "DocumentSetup"))
1488 section
= PPD_ORDER_DOCUMENT
;
1489 else if (!strcmp(name
, "PageSetup"))
1490 section
= PPD_ORDER_PAGE
;
1491 else if (!strcmp(name
, "JCLSetup"))
1492 section
= PPD_ORDER_JCL
;
1494 section
= PPD_ORDER_ANY
;
1502 * Only valid for Non-UI options...
1505 for (i
= ppd
->num_groups
, gtemp
= ppd
->groups
; i
> 0; i
--, gtemp
++)
1506 if (gtemp
->text
[0] == '\0')
1510 for (i
= 0; i
< gtemp
->num_options
; i
++)
1511 if (!strcmp(keyword
, gtemp
->options
[i
].keyword
))
1513 gtemp
->options
[i
].section
= section
;
1514 gtemp
->options
[i
].order
= order
;
1520 option
->section
= section
;
1521 option
->order
= order
;
1524 _cupsStrFree(string
);
1527 else if (!strncmp(keyword
, "Default", 7))
1533 * Drop UI text, if any, from value...
1536 if (strchr(string
, '/') != NULL
)
1537 *strchr(string
, '/') = '\0';
1540 * Assign the default value as appropriate...
1543 if (!strcmp(keyword
, "DefaultColorSpace"))
1546 * Set default colorspace...
1549 if (!strcmp(string
, "CMY"))
1550 ppd
->colorspace
= PPD_CS_CMY
;
1551 else if (!strcmp(string
, "CMYK"))
1552 ppd
->colorspace
= PPD_CS_CMYK
;
1553 else if (!strcmp(string
, "RGB"))
1554 ppd
->colorspace
= PPD_CS_RGB
;
1555 else if (!strcmp(string
, "RGBK"))
1556 ppd
->colorspace
= PPD_CS_RGBK
;
1557 else if (!strcmp(string
, "N"))
1558 ppd
->colorspace
= PPD_CS_N
;
1560 ppd
->colorspace
= PPD_CS_GRAY
;
1562 else if (option
&& !strcmp(keyword
+ 7, option
->keyword
))
1565 * Set the default as part of the current option...
1568 DEBUG_printf(("Setting %s to %s...\n", keyword
, string
));
1570 strlcpy(option
->defchoice
, string
, sizeof(option
->defchoice
));
1572 DEBUG_printf(("%s is now %s...\n", keyword
, option
->defchoice
));
1577 * Lookup option and set if it has been defined...
1580 ppd_option_t
*toption
; /* Temporary option */
1583 if ((toption
= ppdFindOption(ppd
, keyword
+ 7)) != NULL
)
1585 DEBUG_printf(("Setting %s to %s...\n", keyword
, string
));
1586 strlcpy(toption
->defchoice
, string
, sizeof(toption
->defchoice
));
1590 else if (!strcmp(keyword
, "UIConstraints") ||
1591 !strcmp(keyword
, "NonUIConstraints"))
1593 if (ppd
->num_consts
== 0)
1594 constraint
= calloc(2, sizeof(ppd_const_t
));
1596 constraint
= realloc(ppd
->consts
,
1597 (ppd
->num_consts
+ 2) * sizeof(ppd_const_t
));
1599 if (constraint
== NULL
)
1601 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1606 ppd
->consts
= constraint
;
1607 constraint
+= ppd
->num_consts
;
1610 switch (sscanf(string
, "%40s%40s%40s%40s", constraint
->option1
,
1611 constraint
->choice1
, constraint
->option2
,
1612 constraint
->choice2
))
1614 case 0 : /* Error */
1615 case 1 : /* Error */
1616 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1619 case 2 : /* Two options... */
1621 * Check for broken constraints like "* Option"...
1624 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1625 (!strcmp(constraint
->option1
, "*") ||
1626 !strcmp(constraint
->choice1
, "*")))
1628 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1633 * The following strcpy's are safe, as optionN and
1634 * choiceN are all the same size (size defined by PPD spec...)
1637 if (constraint
->option1
[0] == '*')
1638 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1639 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1641 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1645 if (constraint
->choice1
[0] == '*')
1646 _cups_strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1647 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1649 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1653 constraint
->choice1
[0] = '\0';
1654 constraint
->choice2
[0] = '\0';
1657 case 3 : /* Two options, one choice... */
1659 * Check for broken constraints like "* Option"...
1662 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1663 (!strcmp(constraint
->option1
, "*") ||
1664 !strcmp(constraint
->choice1
, "*") ||
1665 !strcmp(constraint
->option2
, "*")))
1667 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1672 * The following _cups_strcpy's are safe, as optionN and
1673 * choiceN are all the same size (size defined by PPD spec...)
1676 if (constraint
->option1
[0] == '*')
1677 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1678 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1680 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1684 if (constraint
->choice1
[0] == '*')
1686 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1687 constraint
->option2
[0] == '*')
1689 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1693 _cups_strcpy(constraint
->choice2
, constraint
->option2
);
1694 _cups_strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1695 constraint
->choice1
[0] = '\0';
1699 if (constraint
->option2
[0] == '*')
1700 _cups_strcpy(constraint
->option2
, constraint
->option2
+ 1);
1701 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1703 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1707 constraint
->choice2
[0] = '\0';
1711 case 4 : /* Two options, two choices... */
1713 * Check for broken constraints like "* Option"...
1716 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1717 (!strcmp(constraint
->option1
, "*") ||
1718 !strcmp(constraint
->choice1
, "*") ||
1719 !strcmp(constraint
->option2
, "*") ||
1720 !strcmp(constraint
->choice2
, "*")))
1722 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1726 if (constraint
->option1
[0] == '*')
1727 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1728 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1730 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1734 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1735 constraint
->choice1
[0] == '*')
1737 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1741 if (constraint
->option2
[0] == '*')
1742 _cups_strcpy(constraint
->option2
, constraint
->option2
+ 1);
1743 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1745 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1749 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1750 constraint
->choice2
[0] == '*')
1752 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1759 * For CustomPageSize and InputSlot/ManualFeed, create a duplicate
1760 * constraint for PageRegion...
1763 if (!strcasecmp(constraint
->option1
, "CustomPageSize") &&
1764 (!strcasecmp(constraint
->option2
, "InputSlot") ||
1765 !strcasecmp(constraint
->option2
, "ManualFeed")))
1769 strcpy(constraint
[1].option1
, "PageRegion");
1770 strcpy(constraint
[1].choice1
, "Custom");
1771 strcpy(constraint
[1].option2
, constraint
->option2
);
1772 strcpy(constraint
[1].choice2
, constraint
->choice2
);
1774 else if (!strcasecmp(constraint
->option2
, "CustomPageSize") &&
1775 (!strcasecmp(constraint
->option1
, "InputSlot") ||
1776 !strcasecmp(constraint
->option1
, "ManualFeed")))
1780 strcpy(constraint
[1].option1
, constraint
->option1
);
1781 strcpy(constraint
[1].choice1
, constraint
->choice1
);
1782 strcpy(constraint
[1].option2
, "PageRegion");
1783 strcpy(constraint
[1].choice2
, "Custom");
1787 * Handle CustomFoo option constraints...
1790 if (!strncasecmp(constraint
->option1
, "Custom", 6) &&
1791 !strcasecmp(constraint
->choice1
, "True"))
1793 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 6);
1794 strcpy(constraint
->choice1
, "Custom");
1797 if (!strncasecmp(constraint
->option2
, "Custom", 6) &&
1798 !strcasecmp(constraint
->choice2
, "True"))
1800 _cups_strcpy(constraint
->option2
, constraint
->option2
+ 6);
1801 strcpy(constraint
->choice2
, "Custom");
1805 * Don't add this one as an attribute...
1808 _cupsStrFree(string
);
1811 else if (!strcmp(keyword
, "PaperDimension"))
1813 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1814 size
= ppd_add_size(ppd
, name
);
1819 * Unable to add or find size!
1822 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1827 size
->width
= (float)_cupsStrScand(string
, &sptr
, loc
);
1828 size
->length
= (float)_cupsStrScand(sptr
, NULL
, loc
);
1830 _cupsStrFree(string
);
1833 else if (!strcmp(keyword
, "ImageableArea"))
1835 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1836 size
= ppd_add_size(ppd
, name
);
1841 * Unable to add or find size!
1844 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1849 size
->left
= (float)_cupsStrScand(string
, &sptr
, loc
);
1850 size
->bottom
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
1851 size
->right
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
1852 size
->top
= (float)_cupsStrScand(sptr
, NULL
, loc
);
1854 _cupsStrFree(string
);
1857 else if (option
!= NULL
&&
1858 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
1859 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
) &&
1860 !strcmp(keyword
, option
->keyword
))
1862 DEBUG_printf(("group = %p, subgroup = %p\n", group
, subgroup
));
1864 if (!strcmp(keyword
, "PageSize"))
1867 * Add a page size...
1870 if (ppdPageSize(ppd
, name
) == NULL
)
1871 ppd_add_size(ppd
, name
);
1875 * Add the option choice...
1878 choice
= ppd_add_choice(option
, name
);
1881 cupsCharsetToUTF8((cups_utf8_t
*)choice
->text
, text
,
1882 sizeof(choice
->text
), encoding
);
1883 else if (!strcmp(name
, "True"))
1884 strcpy(choice
->text
, _("Yes"));
1885 else if (!strcmp(name
, "False"))
1886 strcpy(choice
->text
, _("No"));
1888 strlcpy(choice
->text
, name
, sizeof(choice
->text
));
1890 if (option
->section
== PPD_ORDER_JCL
)
1891 ppd_decode(string
); /* Decode quoted string */
1893 choice
->code
= string
;
1894 string
= NULL
; /* Don't add as an attribute below */
1898 * Add remaining lines with keywords and string values as attributes...
1902 (mask
& (PPD_KEYWORD
| PPD_STRING
)) == (PPD_KEYWORD
| PPD_STRING
))
1903 ppd_add_attr(ppd
, keyword
, name
, text
, string
);
1905 _cupsStrFree(string
);
1912 * Reset language preferences...
1915 cupsLangFree(language
);
1918 if (!cupsFileEOF(fp
))
1919 printf("Premature EOF at %lu...\n", (unsigned long)cupsFileTell(fp
));
1922 if (cg
->ppd_status
!= PPD_OK
)
1925 * Had an error reading the PPD file, cannot continue!
1934 * Create the sorted options array and set the option back-pointer for
1935 * each choice and custom option...
1938 ppd
->options
= cupsArrayNew2((cups_array_func_t
)ppd_compare_options
, NULL
,
1939 (cups_ahash_func_t
)ppd_hash_option
,
1942 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
1946 for (j
= group
->num_options
, option
= group
->options
;
1950 ppd_coption_t
*coption
; /* Custom option */
1953 cupsArrayAdd(ppd
->options
, option
);
1955 for (k
= 0; k
< option
->num_choices
; k
++)
1956 option
->choices
[k
].option
= option
;
1958 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)) != NULL
)
1959 coption
->option
= option
;
1964 * Sort the constraints...
1967 if (ppd
->num_consts
> 1)
1968 qsort(ppd
->consts
, ppd
->num_consts
, sizeof(ppd_const_t
),
1969 (int (*)(const void *, const void *))ppd_compare_consts
);
1972 * Create an array to track the marked choices...
1975 ppd
->marked
= cupsArrayNew((cups_array_func_t
)ppd_compare_choices
, NULL
);
1978 * Return the PPD file structure...
1984 * Common exit point for errors to save code size...
1992 _cupsStrFree(string
);
1996 cupsLangFree(language
);
2003 * 'ppdOpenFd()' - Read a PPD file into memory.
2006 ppd_file_t
* /* O - PPD file record */
2007 ppdOpenFd(int fd
) /* I - File to read from */
2009 cups_file_t
*fp
; /* CUPS file pointer */
2010 ppd_file_t
*ppd
; /* PPD file record */
2011 _cups_globals_t
*cg
= _cupsGlobals();
2016 * Set the line number to 0...
2022 * Range check input...
2027 cg
->ppd_status
= PPD_NULL_FILE
;
2033 * Try to open the file and parse it...
2036 if ((fp
= cupsFileOpenFd(fd
, "r")) != NULL
)
2044 cg
->ppd_status
= PPD_FILE_OPEN_ERROR
;
2053 * 'ppdOpenFile()' - Read a PPD file into memory.
2056 ppd_file_t
* /* O - PPD file record */
2057 ppdOpenFile(const char *filename
) /* I - File to read from */
2059 cups_file_t
*fp
; /* File pointer */
2060 ppd_file_t
*ppd
; /* PPD file record */
2061 _cups_globals_t
*cg
= _cupsGlobals();
2066 * Set the line number to 0...
2072 * Range check input...
2075 if (filename
== NULL
)
2077 cg
->ppd_status
= PPD_NULL_FILE
;
2083 * Try to open the file and parse it...
2086 if ((fp
= cupsFileOpen(filename
, "r")) != NULL
)
2094 cg
->ppd_status
= PPD_FILE_OPEN_ERROR
;
2103 * 'ppdSetConformance()' - Set the conformance level for PPD files.
2105 * @since CUPS 1.1.20@
2109 ppdSetConformance(ppd_conform_t c
) /* I - Conformance level */
2111 _cups_globals_t
*cg
= _cupsGlobals();
2115 cg
->ppd_conform
= c
;
2120 * 'ppd_add_attr()' - Add an attribute to the PPD data.
2123 static ppd_attr_t
* /* O - New attribute */
2124 ppd_add_attr(ppd_file_t
*ppd
, /* I - PPD file data */
2125 const char *name
, /* I - Attribute name */
2126 const char *spec
, /* I - Specifier string, if any */
2127 const char *text
, /* I - Text string, if any */
2128 const char *value
) /* I - Value of attribute */
2130 ppd_attr_t
**ptr
, /* New array */
2131 *temp
; /* New attribute */
2135 * Range check input...
2138 if (ppd
== NULL
|| name
== NULL
|| spec
== NULL
)
2142 * Create the array as needed...
2145 if (!ppd
->sorted_attrs
)
2146 ppd
->sorted_attrs
= cupsArrayNew((cups_array_func_t
)ppd_compare_attrs
,
2150 * Allocate memory for the new attribute...
2153 if (ppd
->num_attrs
== 0)
2154 ptr
= malloc(sizeof(ppd_attr_t
*));
2156 ptr
= realloc(ppd
->attrs
, (ppd
->num_attrs
+ 1) * sizeof(ppd_attr_t
*));
2162 ptr
+= ppd
->num_attrs
;
2164 if ((temp
= calloc(1, sizeof(ppd_attr_t
))) == NULL
)
2175 strlcpy(temp
->name
, name
, sizeof(temp
->name
));
2176 strlcpy(temp
->spec
, spec
, sizeof(temp
->spec
));
2177 strlcpy(temp
->text
, text
, sizeof(temp
->text
));
2178 temp
->value
= (char *)value
;
2181 * Add the attribute to the sorted array...
2184 cupsArrayAdd(ppd
->sorted_attrs
, temp
);
2187 * Return the attribute...
2195 * 'ppd_add_choice()' - Add a choice to an option.
2198 static ppd_choice_t
* /* O - Named choice */
2199 ppd_add_choice(ppd_option_t
*option
, /* I - Option */
2200 const char *name
) /* I - Name of choice */
2202 ppd_choice_t
*choice
; /* Choice */
2205 if (option
->num_choices
== 0)
2206 choice
= malloc(sizeof(ppd_choice_t
));
2208 choice
= realloc(option
->choices
,
2209 sizeof(ppd_choice_t
) * (option
->num_choices
+ 1));
2214 option
->choices
= choice
;
2215 choice
+= option
->num_choices
;
2216 option
->num_choices
++;
2218 memset(choice
, 0, sizeof(ppd_choice_t
));
2219 strlcpy(choice
->choice
, name
, sizeof(choice
->choice
));
2226 * 'ppd_add_size()' - Add a page size.
2229 static ppd_size_t
* /* O - Named size */
2230 ppd_add_size(ppd_file_t
*ppd
, /* I - PPD file */
2231 const char *name
) /* I - Name of size */
2233 ppd_size_t
*size
; /* Size */
2236 if (ppd
->num_sizes
== 0)
2237 size
= malloc(sizeof(ppd_size_t
));
2239 size
= realloc(ppd
->sizes
, sizeof(ppd_size_t
) * (ppd
->num_sizes
+ 1));
2245 size
+= ppd
->num_sizes
;
2248 memset(size
, 0, sizeof(ppd_size_t
));
2249 strlcpy(size
->name
, name
, sizeof(size
->name
));
2256 * 'ppd_compare_attrs()' - Compare two attributes.
2259 static int /* O - Result of comparison */
2260 ppd_compare_attrs(ppd_attr_t
*a
, /* I - First attribute */
2261 ppd_attr_t
*b
) /* I - Second attribute */
2263 int ret
; /* Result of comparison */
2266 if ((ret
= strcasecmp(a
->name
, b
->name
)) != 0)
2269 return (strcasecmp(a
->spec
, b
->spec
));
2274 * 'ppd_compare_choices()' - Compare two choices...
2277 static int /* O - Result of comparison */
2278 ppd_compare_choices(ppd_choice_t
*a
, /* I - First choice */
2279 ppd_choice_t
*b
) /* I - Second choice */
2281 return (strcmp(a
->option
->keyword
, b
->option
->keyword
));
2286 * 'ppd_compare_consts()' - Compare two constraints.
2289 static int /* O - Result of comparison */
2290 ppd_compare_consts(ppd_const_t
*a
, /* I - First constraint */
2291 ppd_const_t
*b
) /* I - Second constraint */
2293 int ret
; /* Result of comparison */
2296 if ((ret
= strcmp(a
->option1
, b
->option1
)) != 0)
2298 else if ((ret
= strcmp(a
->choice1
, b
->choice1
)) != 0)
2300 else if ((ret
= strcmp(a
->option2
, b
->option2
)) != 0)
2303 return (strcmp(a
->choice2
, b
->choice2
));
2308 * 'ppd_compare_coptions()' - Compare two custom options.
2311 static int /* O - Result of comparison */
2312 ppd_compare_coptions(ppd_coption_t
*a
, /* I - First option */
2313 ppd_coption_t
*b
) /* I - Second option */
2315 return (strcasecmp(a
->keyword
, b
->keyword
));
2320 * 'ppd_compare_cparams()' - Compare two custom parameters.
2323 static int /* O - Result of comparison */
2324 ppd_compare_cparams(ppd_cparam_t
*a
, /* I - First parameter */
2325 ppd_cparam_t
*b
) /* I - Second parameter */
2327 return (strcasecmp(a
->name
, b
->name
));
2332 * 'ppd_compare_options()' - Compare two options.
2335 static int /* O - Result of comparison */
2336 ppd_compare_options(ppd_option_t
*a
, /* I - First option */
2337 ppd_option_t
*b
) /* I - Second option */
2339 return (strcasecmp(a
->keyword
, b
->keyword
));
2344 * 'ppd_decode()' - Decode a string value...
2347 static int /* O - Length of decoded string */
2348 ppd_decode(char *string
) /* I - String to decode */
2350 char *inptr
, /* Input pointer */
2351 *outptr
; /* Output pointer */
2357 while (*inptr
!= '\0')
2358 if (*inptr
== '<' && isxdigit(inptr
[1] & 255))
2361 * Convert hex to 8-bit values...
2365 while (isxdigit(*inptr
& 255))
2367 if (isalpha(*inptr
))
2368 *outptr
= (tolower(*inptr
) - 'a' + 10) << 4;
2370 *outptr
= (*inptr
- '0') << 4;
2374 if (!isxdigit(*inptr
& 255))
2377 if (isalpha(*inptr
))
2378 *outptr
|= tolower(*inptr
) - 'a' + 10;
2380 *outptr
|= *inptr
- '0';
2386 while (*inptr
!= '>' && *inptr
!= '\0')
2388 while (*inptr
== '>')
2392 *outptr
++ = *inptr
++;
2396 return ((int)(outptr
- string
));
2401 * 'ppd_free_group()' - Free a single UI group.
2405 ppd_free_group(ppd_group_t
*group
) /* I - Group to free */
2407 int i
; /* Looping var */
2408 ppd_option_t
*option
; /* Current option */
2409 ppd_group_t
*subgroup
; /* Current sub-group */
2412 if (group
->num_options
> 0)
2414 for (i
= group
->num_options
, option
= group
->options
;
2417 ppd_free_option(option
);
2419 ppd_free(group
->options
);
2422 if (group
->num_subgroups
> 0)
2424 for (i
= group
->num_subgroups
, subgroup
= group
->subgroups
;
2427 ppd_free_group(subgroup
);
2429 ppd_free(group
->subgroups
);
2435 * 'ppd_free_option()' - Free a single option.
2439 ppd_free_option(ppd_option_t
*option
) /* I - Option to free */
2441 int i
; /* Looping var */
2442 ppd_choice_t
*choice
; /* Current choice */
2445 if (option
->num_choices
> 0)
2447 for (i
= option
->num_choices
, choice
= option
->choices
;
2451 _cupsStrFree(choice
->code
);
2454 ppd_free(option
->choices
);
2460 * 'ppd_get_coption()' - Get a custom option record.
2463 static ppd_coption_t
* /* O - Custom option... */
2464 ppd_get_coption(ppd_file_t
*ppd
, /* I - PPD file */
2465 const char *name
) /* I - Name of option */
2467 ppd_coption_t
*copt
; /* New custom option */
2471 * See if the option already exists...
2474 if ((copt
= ppdFindCustomOption(ppd
, name
)) != NULL
)
2478 * Not found, so create the custom option record...
2481 if ((copt
= calloc(1, sizeof(ppd_coption_t
))) == NULL
)
2484 strlcpy(copt
->keyword
, name
, sizeof(copt
->keyword
));
2486 copt
->params
= cupsArrayNew((cups_array_func_t
)ppd_compare_cparams
, NULL
);
2488 cupsArrayAdd(ppd
->coptions
, copt
);
2491 * Return the new record...
2499 * 'ppd_get_cparam()' - Get a custom parameter record.
2502 static ppd_cparam_t
* /* O - Extended option... */
2503 ppd_get_cparam(ppd_coption_t
*opt
, /* I - PPD file */
2504 const char *param
, /* I - Name of parameter */
2505 const char *text
) /* I - Human-readable text */
2507 ppd_cparam_t
*cparam
; /* New custom parameter */
2511 * See if the parameter already exists...
2514 if ((cparam
= ppdFindCustomParam(opt
, param
)) != NULL
)
2518 * Not found, so create the custom parameter record...
2521 if ((cparam
= calloc(1, sizeof(ppd_cparam_t
))) == NULL
)
2524 strlcpy(cparam
->name
, param
, sizeof(cparam
->name
));
2525 strlcpy(cparam
->text
, text
[0] ? text
: param
, sizeof(cparam
->text
));
2528 * Add this record to the array...
2531 cupsArrayAdd(opt
->params
, cparam
);
2534 * Return the new record...
2542 * 'ppd_get_group()' - Find or create the named group as needed.
2545 static ppd_group_t
* /* O - Named group */
2546 ppd_get_group(ppd_file_t
*ppd
, /* I - PPD file */
2547 const char *name
, /* I - Name of group */
2548 const char *text
, /* I - Text for group */
2549 _cups_globals_t
*cg
, /* I - Global data */
2550 cups_encoding_t encoding
) /* I - Encoding of text */
2552 int i
; /* Looping var */
2553 ppd_group_t
*group
; /* Group */
2556 DEBUG_printf(("ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)\n",
2557 ppd
, name
, text
, cg
));
2559 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
2560 if (!strcmp(group
->name
, name
))
2565 DEBUG_printf(("Adding group %s...\n", name
));
2567 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&& strlen(text
) >= sizeof(group
->text
))
2569 cg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
2574 if (ppd
->num_groups
== 0)
2575 group
= malloc(sizeof(ppd_group_t
));
2577 group
= realloc(ppd
->groups
,
2578 (ppd
->num_groups
+ 1) * sizeof(ppd_group_t
));
2582 cg
->ppd_status
= PPD_ALLOC_ERROR
;
2587 ppd
->groups
= group
;
2588 group
+= ppd
->num_groups
;
2591 memset(group
, 0, sizeof(ppd_group_t
));
2592 strlcpy(group
->name
, name
, sizeof(group
->name
));
2594 cupsCharsetToUTF8((cups_utf8_t
*)group
->text
, text
,
2595 sizeof(group
->text
), encoding
);
2603 * 'ppd_get_option()' - Find or create the named option as needed.
2606 static ppd_option_t
* /* O - Named option */
2607 ppd_get_option(ppd_group_t
*group
, /* I - Group */
2608 const char *name
) /* I - Name of option */
2610 int i
; /* Looping var */
2611 ppd_option_t
*option
; /* Option */
2614 DEBUG_printf(("ppd_get_option(group=%p(\"%s\"), name=\"%s\")\n",
2615 group
, group
->name
, name
));
2617 for (i
= group
->num_options
, option
= group
->options
; i
> 0; i
--, option
++)
2618 if (!strcmp(option
->keyword
, name
))
2623 if (group
->num_options
== 0)
2624 option
= malloc(sizeof(ppd_option_t
));
2626 option
= realloc(group
->options
,
2627 (group
->num_options
+ 1) * sizeof(ppd_option_t
));
2632 group
->options
= option
;
2633 option
+= group
->num_options
;
2634 group
->num_options
++;
2636 memset(option
, 0, sizeof(ppd_option_t
));
2637 strlcpy(option
->keyword
, name
, sizeof(option
->keyword
));
2645 * 'ppd_hash_option()' - Generate a hash of the option name...
2648 static int /* O - Hash index */
2649 ppd_hash_option(ppd_option_t
*option
) /* I - Option */
2651 int hash
= 0; /* Hash index */
2652 const char *k
; /* Pointer into keyword */
2655 for (hash
= option
->keyword
[0], k
= option
->keyword
+ 1; *k
;)
2656 hash
= 33 * hash
+ *k
++;
2658 return (hash
& 511);
2663 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2667 static int /* O - Bitmask of fields read */
2668 ppd_read(cups_file_t
*fp
, /* I - File to read from */
2669 _ppd_line_t
*line
, /* I - Line buffer */
2670 char *keyword
, /* O - Keyword from line */
2671 char *option
, /* O - Option from line */
2672 char *text
, /* O - Human-readable text from line */
2673 char **string
, /* O - Code/string data */
2674 int ignoreblank
, /* I - Ignore blank lines? */
2675 _cups_globals_t
*cg
) /* I - Global data */
2677 int ch
, /* Character from file */
2678 col
, /* Column in line */
2679 colon
, /* Colon seen? */
2680 endquote
, /* Waiting for an end quote */
2681 mask
, /* Mask to be returned */
2682 startline
, /* Start line */
2683 textlen
; /* Length of text */
2684 char *keyptr
, /* Keyword pointer */
2685 *optptr
, /* Option pointer */
2686 *textptr
, /* Text pointer */
2687 *strptr
, /* Pointer into string */
2688 *lineptr
; /* Current position in line buffer */
2692 * Now loop until we have a valid line...
2697 startline
= cg
->ppd_line
+ 1;
2701 line
->bufsize
= 1024;
2702 line
->buffer
= malloc(1024);
2714 lineptr
= line
->buffer
;
2718 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2720 if (lineptr
>= (line
->buffer
+ line
->bufsize
- 1))
2723 * Expand the line buffer...
2726 char *temp
; /* Temporary line pointer */
2729 line
->bufsize
+= 1024;
2730 if (line
->bufsize
> 262144)
2733 * Don't allow lines longer than 256k!
2736 cg
->ppd_line
= startline
;
2737 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2742 temp
= realloc(line
->buffer
, line
->bufsize
);
2745 cg
->ppd_line
= startline
;
2746 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2751 lineptr
= temp
+ (lineptr
- line
->buffer
);
2752 line
->buffer
= temp
;
2755 if (ch
== '\r' || ch
== '\n')
2758 * Line feed or carriage return...
2767 * Check for a trailing line feed...
2770 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2777 cupsFileGetChar(fp
);
2780 if (lineptr
== line
->buffer
&& ignoreblank
)
2781 continue; /* Skip blank lines */
2785 if (!endquote
) /* Continue for multi-line text */
2790 else if (ch
< ' ' && ch
!= '\t' && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2793 * Other control characters...
2796 cg
->ppd_line
= startline
;
2797 cg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
2801 else if (ch
!= 0x1a)
2804 * Any other character...
2810 if (col
> (PPD_MAX_LINE
- 1))
2813 * Line is too long...
2816 cg
->ppd_line
= startline
;
2817 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2822 if (ch
== ':' && strncmp(line
->buffer
, "*%", 2) != 0)
2825 if (ch
== '\"' && colon
)
2826 endquote
= !endquote
;
2833 * Didn't finish this quoted string...
2836 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2839 else if (ch
== '\r' || ch
== '\n')
2847 * Check for a trailing line feed...
2850 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2853 cupsFileGetChar(fp
);
2858 else if (ch
< ' ' && ch
!= '\t' && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2861 * Other control characters...
2864 cg
->ppd_line
= startline
;
2865 cg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
2869 else if (ch
!= 0x1a)
2873 if (col
> (PPD_MAX_LINE
- 1))
2876 * Line is too long...
2879 cg
->ppd_line
= startline
;
2880 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2890 * Didn't finish this line...
2893 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2894 if (ch
== '\r' || ch
== '\n')
2897 * Line feed or carriage return...
2906 * Check for a trailing line feed...
2909 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2912 cupsFileGetChar(fp
);
2917 else if (ch
< ' ' && ch
!= '\t' && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2920 * Other control characters...
2923 cg
->ppd_line
= startline
;
2924 cg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
2928 else if (ch
!= 0x1a)
2932 if (col
> (PPD_MAX_LINE
- 1))
2935 * Line is too long...
2938 cg
->ppd_line
= startline
;
2939 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2946 if (lineptr
> line
->buffer
&& lineptr
[-1] == '\n')
2951 DEBUG_printf(("LINE = \"%s\"\n", line
));
2954 * The dynamically created PPDs for older style Mac OS X
2955 * drivers include a large blob of data inserted as comments
2956 * at the end of the file. As an optimization we can stop
2957 * reading the PPD when we get to the start of this data.
2960 if (!strcmp(line
->buffer
, "*%APLWORKSET START"))
2963 if (ch
== EOF
&& lineptr
== line
->buffer
)
2971 lineptr
= line
->buffer
+ 1;
2978 if ((!line
->buffer
[0] || /* Blank line */
2979 !strncmp(line
->buffer
, "*%", 2) || /* Comment line */
2980 !strcmp(line
->buffer
, "*End")) && /* End of multi-line string */
2981 ignoreblank
) /* Ignore these? */
2983 startline
= cg
->ppd_line
+ 1;
2987 if (!strcmp(line
->buffer
, "*")) /* (Bad) comment line */
2989 if (cg
->ppd_conform
== PPD_CONFORM_RELAXED
)
2991 startline
= cg
->ppd_line
+ 1;
2996 cg
->ppd_line
= startline
;
2997 cg
->ppd_status
= PPD_ILLEGAL_MAIN_KEYWORD
;
3003 if (line
->buffer
[0] != '*') /* All lines start with an asterisk */
3006 * Allow lines consisting of just whitespace...
3009 for (lineptr
= line
->buffer
; *lineptr
; lineptr
++)
3010 if (!isspace(*lineptr
& 255))
3015 cg
->ppd_status
= PPD_MISSING_ASTERISK
;
3018 else if (ignoreblank
)
3030 while (*lineptr
!= '\0' && *lineptr
!= ':' && !isspace(*lineptr
& 255))
3032 if (*lineptr
<= ' ' || *lineptr
> 126 || *lineptr
== '/' ||
3033 (keyptr
- keyword
) >= (PPD_MAX_NAME
- 1))
3035 cg
->ppd_status
= PPD_ILLEGAL_MAIN_KEYWORD
;
3039 *keyptr
++ = *lineptr
++;
3044 if (!strcmp(keyword
, "End"))
3047 mask
|= PPD_KEYWORD
;
3049 /* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
3051 if (isspace(*lineptr
& 255))
3054 * Get an option name...
3057 while (isspace(*lineptr
& 255))
3062 while (*lineptr
!= '\0' && !isspace(*lineptr
& 255) && *lineptr
!= ':' &&
3065 if (*lineptr
<= ' ' || *lineptr
> 126 ||
3066 (optptr
- option
) >= (PPD_MAX_NAME
- 1))
3068 cg
->ppd_status
= PPD_ILLEGAL_OPTION_KEYWORD
;
3072 *optptr
++ = *lineptr
++;
3077 if (isspace(*lineptr
& 255) && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
3079 cg
->ppd_status
= PPD_ILLEGAL_WHITESPACE
;
3083 while (isspace(*lineptr
& 255))
3088 /* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
3090 if (*lineptr
== '/')
3093 * Get human-readable text...
3100 while (*lineptr
!= '\0' && *lineptr
!= '\n' && *lineptr
!= ':')
3102 if (((unsigned char)*lineptr
< ' ' && *lineptr
!= '\t') ||
3103 (textptr
- text
) >= (PPD_MAX_LINE
- 1))
3105 cg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
3109 *textptr
++ = *lineptr
++;
3113 textlen
= ppd_decode(text
);
3115 if (textlen
> PPD_MAX_TEXT
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
3117 cg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
3124 /* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
3127 if (isspace(*lineptr
& 255) && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
3129 cg
->ppd_status
= PPD_ILLEGAL_WHITESPACE
;
3133 while (isspace(*lineptr
& 255))
3136 if (*lineptr
== ':')
3139 * Get string after triming leading and trailing whitespace...
3143 while (isspace(*lineptr
& 255))
3146 strptr
= lineptr
+ strlen(lineptr
) - 1;
3147 while (strptr
>= lineptr
&& isspace(*strptr
& 255))
3150 if (*strptr
== '\"')
3153 * Quoted string by itself, remove quotes...
3160 *string
= _cupsStrAlloc(lineptr
);
3162 /* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
3174 * End of "$Id: ppd.c 6937 2007-09-10 21:13:31Z mike $".