2 * "$Id: ppd.c 9901 2011-08-17 21:01:53Z mike $"
4 * PPD file routines for CUPS.
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * PostScript is a trademark of Adobe Systems, Inc.
17 * This code and any derivative of it may be used and distributed
18 * freely under the terms of the GNU General Public License when
19 * used with GNU Ghostscript or its derivatives. Use of the code
20 * (or any derivative of it) with software other than GNU
21 * GhostScript (or its derivatives) is governed by the CUPS license
24 * This file is subject to the Apple OS-Developed Software exception.
28 * ppdClose() - Free all memory used by the PPD file.
29 * ppdErrorString() - Returns the text assocated with a status.
30 * _ppdGetEncoding() - Get the CUPS encoding value for the given
32 * ppdLastError() - Return the status from the last ppdOpen*().
33 * ppdOpen() - Read a PPD file into memory.
34 * ppdOpen2() - Read a PPD file into memory.
35 * ppdOpenFd() - Read a PPD file into memory.
36 * ppdOpenFile() - Read a PPD file into memory.
37 * ppdSetConformance() - Set the conformance level for PPD files.
38 * ppd_add_attr() - Add an attribute to the PPD data.
39 * ppd_add_choice() - Add a choice to an option.
40 * ppd_add_size() - Add a page size.
41 * ppd_compare_attrs() - Compare two attributes.
42 * ppd_compare_choices() - Compare two choices...
43 * ppd_compare_coptions() - Compare two custom options.
44 * ppd_compare_options() - Compare two options.
45 * ppd_decode() - Decode a string value...
46 * ppd_free_filters() - Free the filters array.
47 * ppd_free_group() - Free a single UI group.
48 * ppd_free_option() - Free a single option.
49 * ppd_get_coption() - Get a custom option record.
50 * ppd_get_cparam() - Get a custom parameter record.
51 * ppd_get_group() - Find or create the named group as needed.
52 * ppd_get_option() - Find or create the named option as needed.
53 * ppd_hash_option() - Generate a hash of the option name...
54 * ppd_read() - Read a line from a PPD file, skipping comment
56 * ppd_update_filters() - Update the filters array as needed.
60 * Include necessary headers.
63 #include "cups-private.h"
64 #include "ppd-private.h"
71 #if defined(WIN32) || defined(__EMX__)
72 # define READ_BINARY "rb" /* Open a binary file for reading */
73 # define WRITE_BINARY "wb" /* Open a binary file for writing */
75 # define READ_BINARY "r" /* Open a binary file for reading */
76 # define WRITE_BINARY "w" /* Open a binary file for writing */
77 #endif /* WIN32 || __EMX__ */
79 #define ppd_free(p) if (p) free(p) /* Safe free macro */
81 #define PPD_KEYWORD 1 /* Line contained a keyword */
82 #define PPD_OPTION 2 /* Line contained an option name */
83 #define PPD_TEXT 4 /* Line contained human-readable text */
84 #define PPD_STRING 8 /* Line contained a string or code */
86 #define PPD_HASHSIZE 512 /* Size of hash */
90 * Line buffer structure...
93 typedef struct _ppd_line_s
95 char *buffer; /* Pointer to buffer */
96 size_t bufsize; /* Size of the buffer */
104 static ppd_attr_t *ppd_add_attr(ppd_file_t *ppd, const char *name,
105 const char *spec, const char *text,
107 static ppd_choice_t *ppd_add_choice(ppd_option_t *option, const char *name);
108 static ppd_size_t *ppd_add_size(ppd_file_t *ppd, const char *name);
109 static int ppd_compare_attrs(ppd_attr_t *a, ppd_attr_t *b);
110 static int ppd_compare_choices(ppd_choice_t *a, ppd_choice_t *b);
111 static int ppd_compare_coptions(ppd_coption_t *a,
113 static int ppd_compare_options(ppd_option_t *a, ppd_option_t *b);
114 static int ppd_decode(char *string);
115 static void ppd_free_filters(ppd_file_t *ppd);
116 static void ppd_free_group(ppd_group_t *group);
117 static void ppd_free_option(ppd_option_t *option);
118 static ppd_coption_t *ppd_get_coption(ppd_file_t *ppd, const char *name);
119 static ppd_cparam_t *ppd_get_cparam(ppd_coption_t *opt,
122 static ppd_group_t *ppd_get_group(ppd_file_t *ppd, const char *name,
123 const char *text, _cups_globals_t *cg,
124 cups_encoding_t encoding);
125 static ppd_option_t *ppd_get_option(ppd_group_t *group, const char *name);
126 static int ppd_hash_option(ppd_option_t *option);
127 static int ppd_read(cups_file_t *fp, _ppd_line_t *line,
128 char *keyword, char *option, char *text,
129 char **string, int ignoreblank,
130 _cups_globals_t *cg);
131 static int ppd_update_filters(ppd_file_t *ppd,
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 ppd_attr_t **attr; /* Current attribute */
147 ppd_coption_t *coption; /* Current custom option */
148 ppd_cparam_t *cparam; /* Current custom parameter */
152 * Range check arguments...
159 * Free all strings at the top level...
162 _cupsStrFree(ppd->lang_encoding);
163 _cupsStrFree(ppd->nickname);
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 ppd_free_filters(ppd);
224 if (ppd->num_fonts > 0)
226 for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++)
229 ppd_free(ppd->fonts);
233 * Free any profiles...
236 if (ppd->num_profiles > 0)
237 ppd_free(ppd->profiles);
240 * Free any attributes...
243 if (ppd->num_attrs > 0)
245 for (i = ppd->num_attrs, attr = ppd->attrs; i > 0; i --, attr ++)
247 _cupsStrFree((*attr)->value);
251 ppd_free(ppd->attrs);
254 cupsArrayDelete(ppd->sorted_attrs);
257 * Free custom options...
260 for (coption = (ppd_coption_t *)cupsArrayFirst(ppd->coptions);
262 coption = (ppd_coption_t *)cupsArrayNext(ppd->coptions))
264 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
266 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
268 switch (cparam->type)
270 case PPD_CUSTOM_PASSCODE :
271 case PPD_CUSTOM_PASSWORD :
272 case PPD_CUSTOM_STRING :
273 _cupsStrFree(cparam->current.custom_string);
283 cupsArrayDelete(coption->params);
288 cupsArrayDelete(ppd->coptions);
291 * Free constraints...
294 if (ppd->cups_uiconstraints)
296 _ppd_cups_uiconsts_t *consts; /* Current constraints */
299 for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints);
301 consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints))
303 free(consts->constraints);
307 cupsArrayDelete(ppd->cups_uiconstraints);
311 * Free any PPD cache/mapping data...
315 _ppdCacheDestroy(ppd->cache);
318 * Free the whole record...
326 * 'ppdErrorString()' - Returns the text assocated with a status.
328 * @since CUPS 1.1.19/Mac OS X 10.3@
331 const char * /* O - Status string */
332 ppdErrorString(ppd_status_t status) /* I - PPD status */
334 static const char * const messages[] =/* Status messages */
337 _("Unable to open PPD file"),
338 _("NULL PPD file pointer"),
339 _("Memory allocation error"),
340 _("Missing PPD-Adobe-4.x header"),
341 _("Missing value string"),
344 _("OpenGroup without a CloseGroup first"),
345 _("Bad OpenUI/JCLOpenUI"),
346 _("OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"),
347 _("Bad OrderDependency"),
348 _("Bad UIConstraints"),
349 _("Missing asterisk in column 1"),
350 _("Line longer than the maximum allowed (255 characters)"),
351 _("Illegal control character"),
352 _("Illegal main keyword string"),
353 _("Illegal option keyword string"),
354 _("Illegal translation string"),
355 _("Illegal whitespace character"),
356 _("Bad custom parameter"),
357 _("Missing option keyword"),
358 _("Bad value string"),
359 _("Missing CloseGroup")
363 if (status < PPD_OK || status >= PPD_MAX_STATUS)
364 return (_cupsLangString(cupsLangDefault(), _("Unknown")));
366 return (_cupsLangString(cupsLangDefault(), messages[status]));
371 * '_ppdGetEncoding()' - Get the CUPS encoding value for the given
375 cups_encoding_t /* O - CUPS encoding value */
376 _ppdGetEncoding(const char *name) /* I - LanguageEncoding string */
378 if (!_cups_strcasecmp(name, "ISOLatin1"))
379 return (CUPS_ISO8859_1);
380 else if (!_cups_strcasecmp(name, "ISOLatin2"))
381 return (CUPS_ISO8859_2);
382 else if (!_cups_strcasecmp(name, "ISOLatin5"))
383 return (CUPS_ISO8859_5);
384 else if (!_cups_strcasecmp(name, "JIS83-RKSJ"))
385 return (CUPS_JIS_X0213);
386 else if (!_cups_strcasecmp(name, "MacStandard"))
387 return (CUPS_MAC_ROMAN);
388 else if (!_cups_strcasecmp(name, "WindowsANSI"))
389 return (CUPS_WINDOWS_1252);
396 * 'ppdLastError()' - Return the status from the last ppdOpen*().
398 * @since CUPS 1.1.19/Mac OS X 10.3@
401 ppd_status_t /* O - Status code */
402 ppdLastError(int *line) /* O - Line number */
404 _cups_globals_t *cg = _cupsGlobals();
409 *line = cg->ppd_line;
411 return (cg->ppd_status);
416 * 'ppdOpen()' - Read a PPD file into memory.
419 ppd_file_t * /* O - PPD file record */
420 ppdOpen(FILE *fp) /* I - File to read from */
422 ppd_file_t *ppd; /* PPD file record */
423 cups_file_t *cf; /* CUPS file */
427 * Reopen the stdio file as a CUPS file...
430 if ((cf = cupsFileOpenFd(fileno(fp), "r")) == NULL)
434 * Load the PPD file using the newer API...
440 * Close the CUPS file and return the PPD...
450 * 'ppdOpen2()' - Read a PPD file into memory.
452 * @since CUPS 1.2/Mac OS X 10.5@
455 ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
456 ppdOpen2(cups_file_t *fp) /* I - File to read from */
458 int i, j, k; /* Looping vars */
459 int count; /* Temporary count */
460 _ppd_line_t line; /* Line buffer */
461 ppd_file_t *ppd; /* PPD file record */
462 ppd_group_t *group, /* Current group */
463 *subgroup; /* Current sub-group */
464 ppd_option_t *option; /* Current option */
465 ppd_choice_t *choice; /* Current choice */
466 ppd_const_t *constraint; /* Current constraint */
467 ppd_size_t *size; /* Current page size */
468 int mask; /* Line data mask */
469 char keyword[PPD_MAX_NAME],
470 /* Keyword from file */
472 /* Option from file */
474 /* Human-readable text from file */
475 *string, /* Code/text from file */
476 *sptr, /* Pointer into string */
477 *nameptr, /* Pointer into name */
478 *temp, /* Temporary string pointer */
479 **tempfonts; /* Temporary fonts pointer */
480 float order; /* Order dependency number */
481 ppd_section_t section; /* Order dependency section */
482 ppd_profile_t *profile; /* Pointer to color profile */
483 char **filter; /* Pointer to filter */
484 struct lconv *loc; /* Locale data */
485 int ui_keyword; /* Is this line a UI keyword? */
486 cups_encoding_t encoding; /* Encoding of PPD file */
487 _cups_globals_t *cg = _cupsGlobals();
489 char custom_name[PPD_MAX_NAME];
490 /* CustomFoo attribute name */
491 ppd_attr_t *custom_attr; /* CustomFoo attribute */
492 static const char * const ui_keywords[] =
494 #ifdef CUPS_USE_FULL_UI_KEYWORDS_LIST
496 * Adobe defines some 41 keywords as "UI", meaning that they are
497 * user interface elements and that they should be treated as such
498 * even if the PPD creator doesn't use Open/CloseUI around them.
500 * Since this can cause previously invisible options to appear and
501 * confuse users, the default is to only treat the PageSize and
502 * PageRegion keywords this way.
504 /* Boolean keywords */
514 /* PickOne keywords */
527 "JCLFrameBufferSize",
548 #else /* !CUPS_USE_FULL_UI_KEYWORDS_LIST */
551 #endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */
555 DEBUG_printf(("ppdOpen2(fp=%p)", fp));
558 * Default to "OK" status...
561 cg->ppd_status = PPD_OK;
565 * Range check input...
570 cg->ppd_status = PPD_NULL_FILE;
575 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
581 mask = ppd_read(fp, &line, keyword, name, text, &string, 0, cg);
583 DEBUG_printf(("2ppdOpen2: mask=%x, keyword=\"%s\"...", mask, keyword));
586 strcmp(keyword, "PPD-Adobe") ||
587 string == NULL || string[0] != '4')
590 * Either this is not a PPD file, or it is not a 4.x PPD file.
593 if (cg->ppd_status == PPD_OK)
594 cg->ppd_status = PPD_MISSING_PPDADOBE4;
596 _cupsStrFree(string);
597 ppd_free(line.buffer);
602 DEBUG_printf(("2ppdOpen2: keyword=%s, string=%p", keyword, string));
604 _cupsStrFree(string);
607 * Allocate memory for the PPD file record...
610 if ((ppd = calloc(1, sizeof(ppd_file_t))) == NULL)
612 cg->ppd_status = PPD_ALLOC_ERROR;
614 _cupsStrFree(string);
615 ppd_free(line.buffer);
620 ppd->language_level = 2;
621 ppd->color_device = 0;
622 ppd->colorspace = PPD_CS_N;
623 ppd->landscape = -90;
624 ppd->coptions = cupsArrayNew((cups_array_func_t)ppd_compare_coptions,
628 * Read lines from the PPD file and add them to the file record...
636 encoding = CUPS_ISO8859_1;
639 while ((mask = ppd_read(fp, &line, keyword, name, text, &string, 1, cg)) != 0)
641 DEBUG_printf(("2ppdOpen2: mask=%x, keyword=\"%s\", name=\"%s\", "
642 "text=\"%s\", string=%d chars...", mask, keyword, name, text,
643 string ? (int)strlen(string) : 0));
645 if (strncmp(keyword, "Default", 7) && !string &&
646 cg->ppd_conform != PPD_CONFORM_RELAXED)
649 * Need a string value!
652 cg->ppd_status = PPD_MISSING_VALUE;
660 * Certain main keywords (as defined by the PPD spec) may be used
661 * without the usual OpenUI/CloseUI stuff. Presumably this is just
662 * so that Adobe wouldn't completely break compatibility with PPD
663 * files prior to v4.0 of the spec, but it is hopelessly
664 * inconsistent... Catch these main keywords and automatically
665 * create the corresponding option, as needed...
671 * Previous line was a UI keyword...
678 if (option == NULL &&
679 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
680 (PPD_KEYWORD | PPD_OPTION | PPD_STRING))
682 for (i = 0; i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])); i ++)
683 if (!strcmp(keyword, ui_keywords[i]))
686 if (i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])))
689 * Create the option in the appropriate group...
694 DEBUG_printf(("2ppdOpen2: FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!",
699 if ((group = ppd_get_group(ppd, "General", _("General"), cg,
703 DEBUG_printf(("2ppdOpen2: Adding to group %s...", group->text));
704 option = ppd_get_option(group, keyword);
708 option = ppd_get_option(group, keyword);
712 cg->ppd_status = PPD_ALLOC_ERROR;
718 * Now fill in the initial information for the option...
721 if (!strncmp(keyword, "JCL", 3))
722 option->section = PPD_ORDER_JCL;
724 option->section = PPD_ORDER_ANY;
726 option->order = 10.0f;
729 option->ui = PPD_UI_BOOLEAN;
731 option->ui = PPD_UI_PICKONE;
733 for (j = 0; j < ppd->num_attrs; j ++)
734 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
735 !strcmp(ppd->attrs[j]->name + 7, keyword) &&
736 ppd->attrs[j]->value)
738 DEBUG_printf(("2ppdOpen2: Setting Default%s to %s via attribute...",
739 option->keyword, ppd->attrs[j]->value));
740 strlcpy(option->defchoice, ppd->attrs[j]->value,
741 sizeof(option->defchoice));
745 if (!strcmp(keyword, "PageSize"))
746 strlcpy(option->text, _("Media Size"), sizeof(option->text));
747 else if (!strcmp(keyword, "MediaType"))
748 strlcpy(option->text, _("Media Type"), sizeof(option->text));
749 else if (!strcmp(keyword, "InputSlot"))
750 strlcpy(option->text, _("Media Source"), sizeof(option->text));
751 else if (!strcmp(keyword, "ColorModel"))
752 strlcpy(option->text, _("Output Mode"), sizeof(option->text));
753 else if (!strcmp(keyword, "Resolution"))
754 strlcpy(option->text, _("Resolution"), sizeof(option->text));
756 strlcpy(option->text, keyword, sizeof(option->text));
760 if (!strcmp(keyword, "LanguageLevel"))
761 ppd->language_level = atoi(string);
762 else if (!strcmp(keyword, "LanguageEncoding"))
765 * Say all PPD files are UTF-8, since we convert to UTF-8...
768 ppd->lang_encoding = _cupsStrAlloc("UTF-8");
769 encoding = _ppdGetEncoding(string);
771 else if (!strcmp(keyword, "LanguageVersion"))
772 ppd->lang_version = string;
773 else if (!strcmp(keyword, "Manufacturer"))
774 ppd->manufacturer = string;
775 else if (!strcmp(keyword, "ModelName"))
776 ppd->modelname = string;
777 else if (!strcmp(keyword, "Protocols"))
778 ppd->protocols = string;
779 else if (!strcmp(keyword, "PCFileName"))
780 ppd->pcfilename = string;
781 else if (!strcmp(keyword, "NickName"))
783 if (encoding != CUPS_UTF8)
785 cups_utf8_t utf8[256]; /* UTF-8 version of NickName */
788 cupsCharsetToUTF8(utf8, string, sizeof(utf8), encoding);
789 ppd->nickname = _cupsStrAlloc((char *)utf8);
792 ppd->nickname = _cupsStrAlloc(string);
794 else if (!strcmp(keyword, "Product"))
795 ppd->product = string;
796 else if (!strcmp(keyword, "ShortNickName"))
797 ppd->shortnickname = string;
798 else if (!strcmp(keyword, "TTRasterizer"))
799 ppd->ttrasterizer = string;
800 else if (!strcmp(keyword, "JCLBegin"))
802 ppd->jcl_begin = _cupsStrAlloc(string);
803 ppd_decode(ppd->jcl_begin); /* Decode quoted string */
805 else if (!strcmp(keyword, "JCLEnd"))
807 ppd->jcl_end = _cupsStrAlloc(string);
808 ppd_decode(ppd->jcl_end); /* Decode quoted string */
810 else if (!strcmp(keyword, "JCLToPSInterpreter"))
812 ppd->jcl_ps = _cupsStrAlloc(string);
813 ppd_decode(ppd->jcl_ps); /* Decode quoted string */
815 else if (!strcmp(keyword, "AccurateScreensSupport"))
816 ppd->accurate_screens = !strcmp(string, "True");
817 else if (!strcmp(keyword, "ColorDevice"))
818 ppd->color_device = !strcmp(string, "True");
819 else if (!strcmp(keyword, "ContoneOnly"))
820 ppd->contone_only = !strcmp(string, "True");
821 else if (!strcmp(keyword, "cupsFlipDuplex"))
822 ppd->flip_duplex = !strcmp(string, "True");
823 else if (!strcmp(keyword, "cupsManualCopies"))
824 ppd->manual_copies = !strcmp(string, "True");
825 else if (!strcmp(keyword, "cupsModelNumber"))
826 ppd->model_number = atoi(string);
827 else if (!strcmp(keyword, "cupsColorProfile"))
829 if (ppd->num_profiles == 0)
830 profile = malloc(sizeof(ppd_profile_t));
832 profile = realloc(ppd->profiles, sizeof(ppd_profile_t) *
833 (ppd->num_profiles + 1));
837 cg->ppd_status = PPD_ALLOC_ERROR;
842 ppd->profiles = profile;
843 profile += ppd->num_profiles;
844 ppd->num_profiles ++;
846 memset(profile, 0, sizeof(ppd_profile_t));
847 strlcpy(profile->resolution, name, sizeof(profile->resolution));
848 strlcpy(profile->media_type, text, sizeof(profile->media_type));
850 profile->density = (float)_cupsStrScand(string, &sptr, loc);
851 profile->gamma = (float)_cupsStrScand(sptr, &sptr, loc);
852 profile->matrix[0][0] = (float)_cupsStrScand(sptr, &sptr, loc);
853 profile->matrix[0][1] = (float)_cupsStrScand(sptr, &sptr, loc);
854 profile->matrix[0][2] = (float)_cupsStrScand(sptr, &sptr, loc);
855 profile->matrix[1][0] = (float)_cupsStrScand(sptr, &sptr, loc);
856 profile->matrix[1][1] = (float)_cupsStrScand(sptr, &sptr, loc);
857 profile->matrix[1][2] = (float)_cupsStrScand(sptr, &sptr, loc);
858 profile->matrix[2][0] = (float)_cupsStrScand(sptr, &sptr, loc);
859 profile->matrix[2][1] = (float)_cupsStrScand(sptr, &sptr, loc);
860 profile->matrix[2][2] = (float)_cupsStrScand(sptr, &sptr, loc);
862 else if (!strcmp(keyword, "cupsFilter"))
864 if (ppd->num_filters == 0)
865 filter = malloc(sizeof(char *));
867 filter = realloc(ppd->filters, sizeof(char *) * (ppd->num_filters + 1));
871 cg->ppd_status = PPD_ALLOC_ERROR;
876 ppd->filters = filter;
877 filter += ppd->num_filters;
881 * Retain a copy of the filter string...
884 *filter = _cupsStrRetain(string);
886 else if (!strcmp(keyword, "Throughput"))
887 ppd->throughput = atoi(string);
888 else if (!strcmp(keyword, "Font"))
891 * Add this font to the list of available fonts...
894 if (ppd->num_fonts == 0)
895 tempfonts = (char **)malloc(sizeof(char *));
897 tempfonts = (char **)realloc(ppd->fonts,
898 sizeof(char *) * (ppd->num_fonts + 1));
900 if (tempfonts == NULL)
902 cg->ppd_status = PPD_ALLOC_ERROR;
907 ppd->fonts = tempfonts;
908 ppd->fonts[ppd->num_fonts] = _cupsStrAlloc(name);
911 else if (!strncmp(keyword, "ParamCustom", 11))
913 ppd_coption_t *coption; /* Custom option */
914 ppd_cparam_t *cparam; /* Custom parameter */
915 int corder; /* Order number */
916 char ctype[33], /* Data type */
917 cminimum[65], /* Minimum value */
918 cmaximum[65]; /* Maximum value */
922 * Get the custom option and parameter...
925 if ((coption = ppd_get_coption(ppd, keyword + 11)) == NULL)
927 cg->ppd_status = PPD_ALLOC_ERROR;
932 if ((cparam = ppd_get_cparam(coption, name, text)) == NULL)
934 cg->ppd_status = PPD_ALLOC_ERROR;
940 * Get the parameter data...
944 sscanf(string, "%d%32s%64s%64s", &corder, ctype, cminimum,
947 cg->ppd_status = PPD_BAD_CUSTOM_PARAM;
952 cparam->order = corder;
954 if (!strcmp(ctype, "curve"))
956 cparam->type = PPD_CUSTOM_CURVE;
957 cparam->minimum.custom_curve = (float)_cupsStrScand(cminimum, NULL, loc);
958 cparam->maximum.custom_curve = (float)_cupsStrScand(cmaximum, NULL, loc);
960 else if (!strcmp(ctype, "int"))
962 cparam->type = PPD_CUSTOM_INT;
963 cparam->minimum.custom_int = atoi(cminimum);
964 cparam->maximum.custom_int = atoi(cmaximum);
966 else if (!strcmp(ctype, "invcurve"))
968 cparam->type = PPD_CUSTOM_INVCURVE;
969 cparam->minimum.custom_invcurve = (float)_cupsStrScand(cminimum, NULL, loc);
970 cparam->maximum.custom_invcurve = (float)_cupsStrScand(cmaximum, NULL, loc);
972 else if (!strcmp(ctype, "passcode"))
974 cparam->type = PPD_CUSTOM_PASSCODE;
975 cparam->minimum.custom_passcode = atoi(cminimum);
976 cparam->maximum.custom_passcode = atoi(cmaximum);
978 else if (!strcmp(ctype, "password"))
980 cparam->type = PPD_CUSTOM_PASSWORD;
981 cparam->minimum.custom_password = atoi(cminimum);
982 cparam->maximum.custom_password = atoi(cmaximum);
984 else if (!strcmp(ctype, "points"))
986 cparam->type = PPD_CUSTOM_POINTS;
987 cparam->minimum.custom_points = (float)_cupsStrScand(cminimum, NULL, loc);
988 cparam->maximum.custom_points = (float)_cupsStrScand(cmaximum, NULL, loc);
990 else if (!strcmp(ctype, "real"))
992 cparam->type = PPD_CUSTOM_REAL;
993 cparam->minimum.custom_real = (float)_cupsStrScand(cminimum, NULL, loc);
994 cparam->maximum.custom_real = (float)_cupsStrScand(cmaximum, NULL, loc);
996 else if (!strcmp(ctype, "string"))
998 cparam->type = PPD_CUSTOM_STRING;
999 cparam->minimum.custom_string = atoi(cminimum);
1000 cparam->maximum.custom_string = atoi(cmaximum);
1004 cg->ppd_status = PPD_BAD_CUSTOM_PARAM;
1010 * Now special-case for CustomPageSize...
1013 if (!strcmp(coption->keyword, "PageSize"))
1015 if (!strcmp(name, "Width"))
1017 ppd->custom_min[0] = cparam->minimum.custom_points;
1018 ppd->custom_max[0] = cparam->maximum.custom_points;
1020 else if (!strcmp(name, "Height"))
1022 ppd->custom_min[1] = cparam->minimum.custom_points;
1023 ppd->custom_max[1] = cparam->maximum.custom_points;
1027 else if (!strcmp(keyword, "HWMargins"))
1029 for (i = 0, sptr = string; i < 4; i ++)
1030 ppd->custom_margins[i] = (float)_cupsStrScand(sptr, &sptr, loc);
1032 else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True") && !option)
1034 ppd_option_t *custom_option; /* Custom option */
1036 DEBUG_puts("2ppdOpen2: Processing Custom option...");
1039 * Get the option and custom option...
1042 if (!ppd_get_coption(ppd, keyword + 6))
1044 cg->ppd_status = PPD_ALLOC_ERROR;
1049 if (option && !_cups_strcasecmp(option->keyword, keyword + 6))
1050 custom_option = option;
1052 custom_option = ppdFindOption(ppd, keyword + 6);
1057 * Add the "custom" option...
1060 if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
1061 if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
1063 DEBUG_puts("1ppdOpen2: Unable to add Custom choice!");
1065 cg->ppd_status = PPD_ALLOC_ERROR;
1070 strlcpy(choice->text, text[0] ? text : _("Custom"),
1071 sizeof(choice->text));
1073 choice->code = _cupsStrAlloc(string);
1075 if (custom_option->section == PPD_ORDER_JCL)
1076 ppd_decode(choice->code);
1080 * Now process custom page sizes specially...
1083 if (!strcmp(keyword, "CustomPageSize"))
1086 * Add a "Custom" page size entry...
1089 ppd->variable_sizes = 1;
1091 ppd_add_size(ppd, "Custom");
1093 if (option && !_cups_strcasecmp(option->keyword, "PageRegion"))
1094 custom_option = option;
1096 custom_option = ppdFindOption(ppd, "PageRegion");
1100 if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
1101 if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
1103 DEBUG_puts("1ppdOpen2: Unable to add Custom choice!");
1105 cg->ppd_status = PPD_ALLOC_ERROR;
1110 strlcpy(choice->text, text[0] ? text : _("Custom"),
1111 sizeof(choice->text));
1115 else if (!strcmp(keyword, "LandscapeOrientation"))
1117 if (!strcmp(string, "Minus90"))
1118 ppd->landscape = -90;
1119 else if (!strcmp(string, "Plus90"))
1120 ppd->landscape = 90;
1122 else if (!strcmp(keyword, "Emulators") && string)
1124 for (count = 1, sptr = string; sptr != NULL;)
1125 if ((sptr = strchr(sptr, ' ')) != NULL)
1128 while (*sptr == ' ')
1132 ppd->num_emulations = count;
1133 if ((ppd->emulations = calloc(count, sizeof(ppd_emul_t))) == NULL)
1135 cg->ppd_status = PPD_ALLOC_ERROR;
1140 for (i = 0, sptr = string; i < count; i ++)
1142 for (nameptr = ppd->emulations[i].name;
1143 *sptr != '\0' && *sptr != ' ';
1145 if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1))
1150 while (*sptr == ' ')
1154 else if (!strncmp(keyword, "StartEmulator_", 14))
1158 for (i = 0; i < ppd->num_emulations; i ++)
1159 if (!strcmp(keyword + 14, ppd->emulations[i].name))
1161 ppd->emulations[i].start = string;
1165 else if (!strncmp(keyword, "StopEmulator_", 13))
1169 for (i = 0; i < ppd->num_emulations; i ++)
1170 if (!strcmp(keyword + 13, ppd->emulations[i].name))
1172 ppd->emulations[i].stop = string;
1176 else if (!strcmp(keyword, "JobPatchFile"))
1179 * CUPS STR #3421: Check for "*JobPatchFile: int: string"
1182 if (isdigit(*string & 255))
1184 for (sptr = string + 1; isdigit(*sptr & 255); sptr ++);
1189 * Found "*JobPatchFile: int: string"...
1192 cg->ppd_status = PPD_BAD_VALUE;
1198 if (!name[0] && cg->ppd_conform == PPD_CONFORM_STRICT)
1201 * Found "*JobPatchFile: string"...
1204 cg->ppd_status = PPD_MISSING_OPTION_KEYWORD;
1209 if (ppd->patches == NULL)
1210 ppd->patches = strdup(string);
1213 temp = realloc(ppd->patches, strlen(ppd->patches) +
1214 strlen(string) + 1);
1217 cg->ppd_status = PPD_ALLOC_ERROR;
1222 ppd->patches = temp;
1224 strcpy(ppd->patches + strlen(ppd->patches), string);
1227 else if (!strcmp(keyword, "OpenUI"))
1230 * Don't allow nesting of options...
1233 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
1235 cg->ppd_status = PPD_NESTED_OPEN_UI;
1241 * Add an option record to the current sub-group, group, or file...
1244 DEBUG_printf(("2ppdOpen2: name=\"%s\" (%d)", name, (int)strlen(name)));
1247 _cups_strcpy(name, name + 1); /* Eliminate leading asterisk */
1249 for (i = (int)strlen(name) - 1; i > 0 && _cups_isspace(name[i]); i --)
1250 name[i] = '\0'; /* Eliminate trailing spaces */
1252 DEBUG_printf(("2ppdOpen2: OpenUI of %s in group %s...", name,
1253 group ? group->text : "(null)"));
1255 if (subgroup != NULL)
1256 option = ppd_get_option(subgroup, name);
1257 else if (group == NULL)
1259 if ((group = ppd_get_group(ppd, "General", _("General"), cg,
1263 DEBUG_printf(("2ppdOpen2: Adding to group %s...", group->text));
1264 option = ppd_get_option(group, name);
1268 option = ppd_get_option(group, name);
1272 cg->ppd_status = PPD_ALLOC_ERROR;
1278 * Now fill in the initial information for the option...
1281 if (string && !strcmp(string, "PickMany"))
1282 option->ui = PPD_UI_PICKMANY;
1283 else if (string && !strcmp(string, "Boolean"))
1284 option->ui = PPD_UI_BOOLEAN;
1285 else if (string && !strcmp(string, "PickOne"))
1286 option->ui = PPD_UI_PICKONE;
1287 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1289 cg->ppd_status = PPD_BAD_OPEN_UI;
1294 option->ui = PPD_UI_PICKONE;
1296 for (j = 0; j < ppd->num_attrs; j ++)
1297 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
1298 !strcmp(ppd->attrs[j]->name + 7, name) &&
1299 ppd->attrs[j]->value)
1301 DEBUG_printf(("2ppdOpen2: Setting Default%s to %s via attribute...",
1302 option->keyword, ppd->attrs[j]->value));
1303 strlcpy(option->defchoice, ppd->attrs[j]->value,
1304 sizeof(option->defchoice));
1309 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1310 sizeof(option->text), encoding);
1313 if (!strcmp(name, "PageSize"))
1314 strlcpy(option->text, _("Media Size"), sizeof(option->text));
1315 else if (!strcmp(name, "MediaType"))
1316 strlcpy(option->text, _("Media Type"), sizeof(option->text));
1317 else if (!strcmp(name, "InputSlot"))
1318 strlcpy(option->text, _("Media Source"), sizeof(option->text));
1319 else if (!strcmp(name, "ColorModel"))
1320 strlcpy(option->text, _("Output Mode"), sizeof(option->text));
1321 else if (!strcmp(name, "Resolution"))
1322 strlcpy(option->text, _("Resolution"), sizeof(option->text));
1324 strlcpy(option->text, name, sizeof(option->text));
1327 option->section = PPD_ORDER_ANY;
1329 _cupsStrFree(string);
1333 * Add a custom option choice if we have already seen a CustomFoo
1337 if (!_cups_strcasecmp(name, "PageRegion"))
1338 strcpy(custom_name, "CustomPageSize");
1340 snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
1342 if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
1344 if ((choice = ppdFindChoice(option, "Custom")) == NULL)
1345 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
1347 DEBUG_puts("1ppdOpen2: Unable to add Custom choice!");
1349 cg->ppd_status = PPD_ALLOC_ERROR;
1354 strlcpy(choice->text,
1355 custom_attr->text[0] ? custom_attr->text : _("Custom"),
1356 sizeof(choice->text));
1357 choice->code = _cupsStrRetain(custom_attr->value);
1360 else if (!strcmp(keyword, "JCLOpenUI"))
1363 * Don't allow nesting of options...
1366 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
1368 cg->ppd_status = PPD_NESTED_OPEN_UI;
1374 * Find the JCL group, and add if needed...
1377 group = ppd_get_group(ppd, "JCL", _("JCL"), cg, encoding);
1383 * Add an option record to the current JCLs...
1387 _cups_strcpy(name, name + 1);
1389 option = ppd_get_option(group, name);
1393 cg->ppd_status = PPD_ALLOC_ERROR;
1399 * Now fill in the initial information for the option...
1402 if (string && !strcmp(string, "PickMany"))
1403 option->ui = PPD_UI_PICKMANY;
1404 else if (string && !strcmp(string, "Boolean"))
1405 option->ui = PPD_UI_BOOLEAN;
1406 else if (string && !strcmp(string, "PickOne"))
1407 option->ui = PPD_UI_PICKONE;
1410 cg->ppd_status = PPD_BAD_OPEN_UI;
1415 for (j = 0; j < ppd->num_attrs; j ++)
1416 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
1417 !strcmp(ppd->attrs[j]->name + 7, name) &&
1418 ppd->attrs[j]->value)
1420 DEBUG_printf(("2ppdOpen2: Setting Default%s to %s via attribute...",
1421 option->keyword, ppd->attrs[j]->value));
1422 strlcpy(option->defchoice, ppd->attrs[j]->value,
1423 sizeof(option->defchoice));
1428 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1429 sizeof(option->text), encoding);
1431 strlcpy(option->text, name, sizeof(option->text));
1433 option->section = PPD_ORDER_JCL;
1436 _cupsStrFree(string);
1440 * Add a custom option choice if we have already seen a CustomFoo
1444 snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
1446 if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
1448 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
1450 DEBUG_puts("1ppdOpen2: Unable to add Custom choice!");
1452 cg->ppd_status = PPD_ALLOC_ERROR;
1457 strlcpy(choice->text,
1458 custom_attr->text[0] ? custom_attr->text : _("Custom"),
1459 sizeof(choice->text));
1460 choice->code = _cupsStrRetain(custom_attr->value);
1463 else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI"))
1467 _cupsStrFree(string);
1470 else if (!strcmp(keyword, "OpenGroup"))
1473 * Open a new group...
1478 cg->ppd_status = PPD_NESTED_OPEN_GROUP;
1485 cg->ppd_status = PPD_BAD_OPEN_GROUP;
1491 * Separate the group name from the text (name/text)...
1494 if ((sptr = strchr(string, '/')) != NULL)
1500 * Fix up the text...
1506 * Find/add the group...
1509 group = ppd_get_group(ppd, string, sptr, cg, encoding);
1514 _cupsStrFree(string);
1517 else if (!strcmp(keyword, "CloseGroup"))
1521 _cupsStrFree(string);
1524 else if (!strcmp(keyword, "OrderDependency"))
1526 order = (float)_cupsStrScand(string, &sptr, loc);
1528 if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2)
1530 cg->ppd_status = PPD_BAD_ORDER_DEPENDENCY;
1535 if (keyword[0] == '*')
1536 _cups_strcpy(keyword, keyword + 1);
1538 if (!strcmp(name, "ExitServer"))
1539 section = PPD_ORDER_EXIT;
1540 else if (!strcmp(name, "Prolog"))
1541 section = PPD_ORDER_PROLOG;
1542 else if (!strcmp(name, "DocumentSetup"))
1543 section = PPD_ORDER_DOCUMENT;
1544 else if (!strcmp(name, "PageSetup"))
1545 section = PPD_ORDER_PAGE;
1546 else if (!strcmp(name, "JCLSetup"))
1547 section = PPD_ORDER_JCL;
1549 section = PPD_ORDER_ANY;
1557 * Only valid for Non-UI options...
1560 for (i = ppd->num_groups, gtemp = ppd->groups; i > 0; i --, gtemp ++)
1561 if (gtemp->text[0] == '\0')
1565 for (i = 0; i < gtemp->num_options; i ++)
1566 if (!strcmp(keyword, gtemp->options[i].keyword))
1568 gtemp->options[i].section = section;
1569 gtemp->options[i].order = order;
1575 option->section = section;
1576 option->order = order;
1579 _cupsStrFree(string);
1582 else if (!strncmp(keyword, "Default", 7))
1588 * Drop UI text, if any, from value...
1591 if (strchr(string, '/') != NULL)
1592 *strchr(string, '/') = '\0';
1595 * Assign the default value as appropriate...
1598 if (!strcmp(keyword, "DefaultColorSpace"))
1601 * Set default colorspace...
1604 if (!strcmp(string, "CMY"))
1605 ppd->colorspace = PPD_CS_CMY;
1606 else if (!strcmp(string, "CMYK"))
1607 ppd->colorspace = PPD_CS_CMYK;
1608 else if (!strcmp(string, "RGB"))
1609 ppd->colorspace = PPD_CS_RGB;
1610 else if (!strcmp(string, "RGBK"))
1611 ppd->colorspace = PPD_CS_RGBK;
1612 else if (!strcmp(string, "N"))
1613 ppd->colorspace = PPD_CS_N;
1615 ppd->colorspace = PPD_CS_GRAY;
1617 else if (option && !strcmp(keyword + 7, option->keyword))
1620 * Set the default as part of the current option...
1623 DEBUG_printf(("2ppdOpen2: Setting %s to %s...", keyword, string));
1625 strlcpy(option->defchoice, string, sizeof(option->defchoice));
1627 DEBUG_printf(("2ppdOpen2: %s is now %s...", keyword, option->defchoice));
1632 * Lookup option and set if it has been defined...
1635 ppd_option_t *toption; /* Temporary option */
1638 if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL)
1640 DEBUG_printf(("2ppdOpen2: Setting %s to %s...", keyword, string));
1641 strlcpy(toption->defchoice, string, sizeof(toption->defchoice));
1645 else if (!strcmp(keyword, "UIConstraints") ||
1646 !strcmp(keyword, "NonUIConstraints"))
1650 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1654 if (ppd->num_consts == 0)
1655 constraint = calloc(2, sizeof(ppd_const_t));
1657 constraint = realloc(ppd->consts,
1658 (ppd->num_consts + 2) * sizeof(ppd_const_t));
1660 if (constraint == NULL)
1662 cg->ppd_status = PPD_ALLOC_ERROR;
1667 ppd->consts = constraint;
1668 constraint += ppd->num_consts;
1671 switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1,
1672 constraint->choice1, constraint->option2,
1673 constraint->choice2))
1675 case 0 : /* Error */
1676 case 1 : /* Error */
1677 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1680 case 2 : /* Two options... */
1682 * Check for broken constraints like "* Option"...
1685 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1686 (!strcmp(constraint->option1, "*") ||
1687 !strcmp(constraint->choice1, "*")))
1689 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1694 * The following strcpy's are safe, as optionN and
1695 * choiceN are all the same size (size defined by PPD spec...)
1698 if (constraint->option1[0] == '*')
1699 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1700 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1702 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1706 if (constraint->choice1[0] == '*')
1707 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1708 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1710 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1714 constraint->choice1[0] = '\0';
1715 constraint->choice2[0] = '\0';
1718 case 3 : /* Two options, one choice... */
1720 * Check for broken constraints like "* Option"...
1723 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1724 (!strcmp(constraint->option1, "*") ||
1725 !strcmp(constraint->choice1, "*") ||
1726 !strcmp(constraint->option2, "*")))
1728 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1733 * The following _cups_strcpy's are safe, as optionN and
1734 * choiceN are all the same size (size defined by PPD spec...)
1737 if (constraint->option1[0] == '*')
1738 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1739 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1741 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1745 if (constraint->choice1[0] == '*')
1747 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1748 constraint->option2[0] == '*')
1750 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1754 _cups_strcpy(constraint->choice2, constraint->option2);
1755 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1756 constraint->choice1[0] = '\0';
1760 if (constraint->option2[0] == '*')
1761 _cups_strcpy(constraint->option2, constraint->option2 + 1);
1762 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1764 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1768 constraint->choice2[0] = '\0';
1772 case 4 : /* Two options, two choices... */
1774 * Check for broken constraints like "* Option"...
1777 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1778 (!strcmp(constraint->option1, "*") ||
1779 !strcmp(constraint->choice1, "*") ||
1780 !strcmp(constraint->option2, "*") ||
1781 !strcmp(constraint->choice2, "*")))
1783 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1787 if (constraint->option1[0] == '*')
1788 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1789 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1791 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1795 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1796 constraint->choice1[0] == '*')
1798 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1802 if (constraint->option2[0] == '*')
1803 _cups_strcpy(constraint->option2, constraint->option2 + 1);
1804 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1806 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1810 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1811 constraint->choice2[0] == '*')
1813 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1820 * Don't add this one as an attribute...
1823 _cupsStrFree(string);
1826 else if (!strcmp(keyword, "PaperDimension"))
1828 if ((size = ppdPageSize(ppd, name)) == NULL)
1829 size = ppd_add_size(ppd, name);
1834 * Unable to add or find size!
1837 cg->ppd_status = PPD_ALLOC_ERROR;
1842 size->width = (float)_cupsStrScand(string, &sptr, loc);
1843 size->length = (float)_cupsStrScand(sptr, NULL, loc);
1845 _cupsStrFree(string);
1848 else if (!strcmp(keyword, "ImageableArea"))
1850 if ((size = ppdPageSize(ppd, name)) == NULL)
1851 size = ppd_add_size(ppd, name);
1856 * Unable to add or find size!
1859 cg->ppd_status = PPD_ALLOC_ERROR;
1864 size->left = (float)_cupsStrScand(string, &sptr, loc);
1865 size->bottom = (float)_cupsStrScand(sptr, &sptr, loc);
1866 size->right = (float)_cupsStrScand(sptr, &sptr, loc);
1867 size->top = (float)_cupsStrScand(sptr, NULL, loc);
1869 _cupsStrFree(string);
1872 else if (option != NULL &&
1873 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
1874 (PPD_KEYWORD | PPD_OPTION | PPD_STRING) &&
1875 !strcmp(keyword, option->keyword))
1877 DEBUG_printf(("2ppdOpen2: group=%p, subgroup=%p", group, subgroup));
1879 if (!strcmp(keyword, "PageSize"))
1882 * Add a page size...
1885 if (ppdPageSize(ppd, name) == NULL)
1886 ppd_add_size(ppd, name);
1890 * Add the option choice...
1893 if ((choice = ppd_add_choice(option, name)) == NULL)
1895 cg->ppd_status = PPD_ALLOC_ERROR;
1901 cupsCharsetToUTF8((cups_utf8_t *)choice->text, text,
1902 sizeof(choice->text), encoding);
1903 else if (!strcmp(name, "True"))
1904 strcpy(choice->text, _("Yes"));
1905 else if (!strcmp(name, "False"))
1906 strcpy(choice->text, _("No"));
1908 strlcpy(choice->text, name, sizeof(choice->text));
1910 if (option->section == PPD_ORDER_JCL)
1911 ppd_decode(string); /* Decode quoted string */
1913 choice->code = string;
1914 string = NULL; /* Don't add as an attribute below */
1918 * Add remaining lines with keywords and string values as attributes...
1922 (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
1923 ppd_add_attr(ppd, keyword, name, text, string);
1925 _cupsStrFree(string);
1929 * Check for a missing CloseGroup...
1932 if (group && cg->ppd_conform == PPD_CONFORM_STRICT)
1934 cg->ppd_status = PPD_MISSING_CLOSE_GROUP;
1938 ppd_free(line.buffer);
1941 * Reset language preferences...
1945 if (!cupsFileEOF(fp))
1946 DEBUG_printf(("1ppdOpen2: Premature EOF at %lu...\n",
1947 (unsigned long)cupsFileTell(fp)));
1950 if (cg->ppd_status != PPD_OK)
1953 * Had an error reading the PPD file, cannot continue!
1962 * Update the filters array as needed...
1965 if (!ppd_update_filters(ppd, cg))
1973 * Create the sorted options array and set the option back-pointer for
1974 * each choice and custom option...
1977 ppd->options = cupsArrayNew2((cups_array_func_t)ppd_compare_options, NULL,
1978 (cups_ahash_func_t)ppd_hash_option,
1981 for (i = ppd->num_groups, group = ppd->groups;
1985 for (j = group->num_options, option = group->options;
1989 ppd_coption_t *coption; /* Custom option */
1992 cupsArrayAdd(ppd->options, option);
1994 for (k = 0; k < option->num_choices; k ++)
1995 option->choices[k].option = option;
1997 if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
1998 coption->option = option;
2003 * Create an array to track the marked choices...
2006 ppd->marked = cupsArrayNew((cups_array_func_t)ppd_compare_choices, NULL);
2009 * Return the PPD file structure...
2015 * Common exit point for errors to save code size...
2020 _cupsStrFree(string);
2021 ppd_free(line.buffer);
2030 * 'ppdOpenFd()' - Read a PPD file into memory.
2033 ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2034 ppdOpenFd(int fd) /* I - File to read from */
2036 cups_file_t *fp; /* CUPS file pointer */
2037 ppd_file_t *ppd; /* PPD file record */
2038 _cups_globals_t *cg = _cupsGlobals();
2043 * Set the line number to 0...
2049 * Range check input...
2054 cg->ppd_status = PPD_NULL_FILE;
2060 * Try to open the file and parse it...
2063 if ((fp = cupsFileOpenFd(fd, "r")) != NULL)
2071 cg->ppd_status = PPD_FILE_OPEN_ERROR;
2080 * 'ppdOpenFile()' - Read a PPD file into memory.
2083 ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2084 ppdOpenFile(const char *filename) /* I - File to read from */
2086 cups_file_t *fp; /* File pointer */
2087 ppd_file_t *ppd; /* PPD file record */
2088 _cups_globals_t *cg = _cupsGlobals();
2093 * Set the line number to 0...
2099 * Range check input...
2102 if (filename == NULL)
2104 cg->ppd_status = PPD_NULL_FILE;
2110 * Try to open the file and parse it...
2113 if ((fp = cupsFileOpen(filename, "r")) != NULL)
2121 cg->ppd_status = PPD_FILE_OPEN_ERROR;
2130 * 'ppdSetConformance()' - Set the conformance level for PPD files.
2132 * @since CUPS 1.1.20/Mac OS X 10.4@
2136 ppdSetConformance(ppd_conform_t c) /* I - Conformance level */
2138 _cups_globals_t *cg = _cupsGlobals();
2142 cg->ppd_conform = c;
2147 * 'ppd_add_attr()' - Add an attribute to the PPD data.
2150 static ppd_attr_t * /* O - New attribute */
2151 ppd_add_attr(ppd_file_t *ppd, /* I - PPD file data */
2152 const char *name, /* I - Attribute name */
2153 const char *spec, /* I - Specifier string, if any */
2154 const char *text, /* I - Text string, if any */
2155 const char *value) /* I - Value of attribute */
2157 ppd_attr_t **ptr, /* New array */
2158 *temp; /* New attribute */
2162 * Range check input...
2165 if (ppd == NULL || name == NULL || spec == NULL)
2169 * Create the array as needed...
2172 if (!ppd->sorted_attrs)
2173 ppd->sorted_attrs = cupsArrayNew((cups_array_func_t)ppd_compare_attrs,
2177 * Allocate memory for the new attribute...
2180 if (ppd->num_attrs == 0)
2181 ptr = malloc(sizeof(ppd_attr_t *));
2183 ptr = realloc(ppd->attrs, (ppd->num_attrs + 1) * sizeof(ppd_attr_t *));
2189 ptr += ppd->num_attrs;
2191 if ((temp = calloc(1, sizeof(ppd_attr_t))) == NULL)
2202 strlcpy(temp->name, name, sizeof(temp->name));
2203 strlcpy(temp->spec, spec, sizeof(temp->spec));
2204 strlcpy(temp->text, text, sizeof(temp->text));
2205 temp->value = (char *)value;
2208 * Add the attribute to the sorted array...
2211 cupsArrayAdd(ppd->sorted_attrs, temp);
2214 * Return the attribute...
2222 * 'ppd_add_choice()' - Add a choice to an option.
2225 static ppd_choice_t * /* O - Named choice */
2226 ppd_add_choice(ppd_option_t *option, /* I - Option */
2227 const char *name) /* I - Name of choice */
2229 ppd_choice_t *choice; /* Choice */
2232 if (option->num_choices == 0)
2233 choice = malloc(sizeof(ppd_choice_t));
2235 choice = realloc(option->choices,
2236 sizeof(ppd_choice_t) * (option->num_choices + 1));
2241 option->choices = choice;
2242 choice += option->num_choices;
2243 option->num_choices ++;
2245 memset(choice, 0, sizeof(ppd_choice_t));
2246 strlcpy(choice->choice, name, sizeof(choice->choice));
2253 * 'ppd_add_size()' - Add a page size.
2256 static ppd_size_t * /* O - Named size */
2257 ppd_add_size(ppd_file_t *ppd, /* I - PPD file */
2258 const char *name) /* I - Name of size */
2260 ppd_size_t *size; /* Size */
2263 if (ppd->num_sizes == 0)
2264 size = malloc(sizeof(ppd_size_t));
2266 size = realloc(ppd->sizes, sizeof(ppd_size_t) * (ppd->num_sizes + 1));
2272 size += ppd->num_sizes;
2275 memset(size, 0, sizeof(ppd_size_t));
2276 strlcpy(size->name, name, sizeof(size->name));
2283 * 'ppd_compare_attrs()' - Compare two attributes.
2286 static int /* O - Result of comparison */
2287 ppd_compare_attrs(ppd_attr_t *a, /* I - First attribute */
2288 ppd_attr_t *b) /* I - Second attribute */
2290 return (_cups_strcasecmp(a->name, b->name));
2295 * 'ppd_compare_choices()' - Compare two choices...
2298 static int /* O - Result of comparison */
2299 ppd_compare_choices(ppd_choice_t *a, /* I - First choice */
2300 ppd_choice_t *b) /* I - Second choice */
2302 return (strcmp(a->option->keyword, b->option->keyword));
2307 * 'ppd_compare_coptions()' - Compare two custom options.
2310 static int /* O - Result of comparison */
2311 ppd_compare_coptions(ppd_coption_t *a, /* I - First option */
2312 ppd_coption_t *b) /* I - Second option */
2314 return (_cups_strcasecmp(a->keyword, b->keyword));
2319 * 'ppd_compare_options()' - Compare two options.
2322 static int /* O - Result of comparison */
2323 ppd_compare_options(ppd_option_t *a, /* I - First option */
2324 ppd_option_t *b) /* I - Second option */
2326 return (_cups_strcasecmp(a->keyword, b->keyword));
2331 * 'ppd_decode()' - Decode a string value...
2334 static int /* O - Length of decoded string */
2335 ppd_decode(char *string) /* I - String to decode */
2337 char *inptr, /* Input pointer */
2338 *outptr; /* Output pointer */
2344 while (*inptr != '\0')
2345 if (*inptr == '<' && isxdigit(inptr[1] & 255))
2348 * Convert hex to 8-bit values...
2352 while (isxdigit(*inptr & 255))
2354 if (_cups_isalpha(*inptr))
2355 *outptr = (tolower(*inptr) - 'a' + 10) << 4;
2357 *outptr = (*inptr - '0') << 4;
2361 if (!isxdigit(*inptr & 255))
2364 if (_cups_isalpha(*inptr))
2365 *outptr |= tolower(*inptr) - 'a' + 10;
2367 *outptr |= *inptr - '0';
2373 while (*inptr != '>' && *inptr != '\0')
2375 while (*inptr == '>')
2379 *outptr++ = *inptr++;
2383 return ((int)(outptr - string));
2388 * 'ppd_free_filters()' - Free the filters array.
2392 ppd_free_filters(ppd_file_t *ppd) /* I - PPD file */
2394 int i; /* Looping var */
2395 char **filter; /* Current filter */
2398 if (ppd->num_filters > 0)
2400 for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++)
2401 _cupsStrFree(*filter);
2403 ppd_free(ppd->filters);
2405 ppd->num_filters = 0;
2406 ppd->filters = NULL;
2412 * 'ppd_free_group()' - Free a single UI group.
2416 ppd_free_group(ppd_group_t *group) /* I - Group to free */
2418 int i; /* Looping var */
2419 ppd_option_t *option; /* Current option */
2420 ppd_group_t *subgroup; /* Current sub-group */
2423 if (group->num_options > 0)
2425 for (i = group->num_options, option = group->options;
2428 ppd_free_option(option);
2430 ppd_free(group->options);
2433 if (group->num_subgroups > 0)
2435 for (i = group->num_subgroups, subgroup = group->subgroups;
2438 ppd_free_group(subgroup);
2440 ppd_free(group->subgroups);
2446 * 'ppd_free_option()' - Free a single option.
2450 ppd_free_option(ppd_option_t *option) /* I - Option to free */
2452 int i; /* Looping var */
2453 ppd_choice_t *choice; /* Current choice */
2456 if (option->num_choices > 0)
2458 for (i = option->num_choices, choice = option->choices;
2462 _cupsStrFree(choice->code);
2465 ppd_free(option->choices);
2471 * 'ppd_get_coption()' - Get a custom option record.
2474 static ppd_coption_t * /* O - Custom option... */
2475 ppd_get_coption(ppd_file_t *ppd, /* I - PPD file */
2476 const char *name) /* I - Name of option */
2478 ppd_coption_t *copt; /* New custom option */
2482 * See if the option already exists...
2485 if ((copt = ppdFindCustomOption(ppd, name)) != NULL)
2489 * Not found, so create the custom option record...
2492 if ((copt = calloc(1, sizeof(ppd_coption_t))) == NULL)
2495 strlcpy(copt->keyword, name, sizeof(copt->keyword));
2497 copt->params = cupsArrayNew((cups_array_func_t)NULL, NULL);
2499 cupsArrayAdd(ppd->coptions, copt);
2502 * Return the new record...
2510 * 'ppd_get_cparam()' - Get a custom parameter record.
2513 static ppd_cparam_t * /* O - Extended option... */
2514 ppd_get_cparam(ppd_coption_t *opt, /* I - PPD file */
2515 const char *param, /* I - Name of parameter */
2516 const char *text) /* I - Human-readable text */
2518 ppd_cparam_t *cparam; /* New custom parameter */
2522 * See if the parameter already exists...
2525 if ((cparam = ppdFindCustomParam(opt, param)) != NULL)
2529 * Not found, so create the custom parameter record...
2532 if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL)
2535 strlcpy(cparam->name, param, sizeof(cparam->name));
2536 strlcpy(cparam->text, text[0] ? text : param, sizeof(cparam->text));
2539 * Add this record to the array...
2542 cupsArrayAdd(opt->params, cparam);
2545 * Return the new record...
2553 * 'ppd_get_group()' - Find or create the named group as needed.
2556 static ppd_group_t * /* O - Named group */
2557 ppd_get_group(ppd_file_t *ppd, /* I - PPD file */
2558 const char *name, /* I - Name of group */
2559 const char *text, /* I - Text for group */
2560 _cups_globals_t *cg, /* I - Global data */
2561 cups_encoding_t encoding) /* I - Encoding of text */
2563 int i; /* Looping var */
2564 ppd_group_t *group; /* Group */
2567 DEBUG_printf(("7ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)",
2568 ppd, name, text, cg));
2570 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
2571 if (!strcmp(group->name, name))
2576 DEBUG_printf(("8ppd_get_group: Adding group %s...", name));
2578 if (cg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
2580 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2585 if (ppd->num_groups == 0)
2586 group = malloc(sizeof(ppd_group_t));
2588 group = realloc(ppd->groups,
2589 (ppd->num_groups + 1) * sizeof(ppd_group_t));
2593 cg->ppd_status = PPD_ALLOC_ERROR;
2598 ppd->groups = group;
2599 group += ppd->num_groups;
2602 memset(group, 0, sizeof(ppd_group_t));
2603 strlcpy(group->name, name, sizeof(group->name));
2605 cupsCharsetToUTF8((cups_utf8_t *)group->text, text,
2606 sizeof(group->text), encoding);
2614 * 'ppd_get_option()' - Find or create the named option as needed.
2617 static ppd_option_t * /* O - Named option */
2618 ppd_get_option(ppd_group_t *group, /* I - Group */
2619 const char *name) /* I - Name of option */
2621 int i; /* Looping var */
2622 ppd_option_t *option; /* Option */
2625 DEBUG_printf(("7ppd_get_option(group=%p(\"%s\"), name=\"%s\")",
2626 group, group->name, name));
2628 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
2629 if (!strcmp(option->keyword, name))
2634 if (group->num_options == 0)
2635 option = malloc(sizeof(ppd_option_t));
2637 option = realloc(group->options,
2638 (group->num_options + 1) * sizeof(ppd_option_t));
2643 group->options = option;
2644 option += group->num_options;
2645 group->num_options ++;
2647 memset(option, 0, sizeof(ppd_option_t));
2648 strlcpy(option->keyword, name, sizeof(option->keyword));
2656 * 'ppd_hash_option()' - Generate a hash of the option name...
2659 static int /* O - Hash index */
2660 ppd_hash_option(ppd_option_t *option) /* I - Option */
2662 int hash = 0; /* Hash index */
2663 const char *k; /* Pointer into keyword */
2666 for (hash = option->keyword[0], k = option->keyword + 1; *k;)
2667 hash = 33 * hash + *k++;
2669 return (hash & 511);
2674 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2678 static int /* O - Bitmask of fields read */
2679 ppd_read(cups_file_t *fp, /* I - File to read from */
2680 _ppd_line_t *line, /* I - Line buffer */
2681 char *keyword, /* O - Keyword from line */
2682 char *option, /* O - Option from line */
2683 char *text, /* O - Human-readable text from line */
2684 char **string, /* O - Code/string data */
2685 int ignoreblank, /* I - Ignore blank lines? */
2686 _cups_globals_t *cg) /* I - Global data */
2688 int ch, /* Character from file */
2689 col, /* Column in line */
2690 colon, /* Colon seen? */
2691 endquote, /* Waiting for an end quote */
2692 mask, /* Mask to be returned */
2693 startline, /* Start line */
2694 textlen; /* Length of text */
2695 char *keyptr, /* Keyword pointer */
2696 *optptr, /* Option pointer */
2697 *textptr, /* Text pointer */
2698 *strptr, /* Pointer into string */
2699 *lineptr; /* Current position in line buffer */
2703 * Now loop until we have a valid line...
2708 startline = cg->ppd_line + 1;
2712 line->bufsize = 1024;
2713 line->buffer = malloc(1024);
2725 lineptr = line->buffer;
2729 while ((ch = cupsFileGetChar(fp)) != EOF)
2731 if (lineptr >= (line->buffer + line->bufsize - 1))
2734 * Expand the line buffer...
2737 char *temp; /* Temporary line pointer */
2740 line->bufsize += 1024;
2741 if (line->bufsize > 262144)
2744 * Don't allow lines longer than 256k!
2747 cg->ppd_line = startline;
2748 cg->ppd_status = PPD_LINE_TOO_LONG;
2753 temp = realloc(line->buffer, line->bufsize);
2756 cg->ppd_line = startline;
2757 cg->ppd_status = PPD_LINE_TOO_LONG;
2762 lineptr = temp + (lineptr - line->buffer);
2763 line->buffer = temp;
2766 if (ch == '\r' || ch == '\n')
2769 * Line feed or carriage return...
2778 * Check for a trailing line feed...
2781 if ((ch = cupsFilePeekChar(fp)) == EOF)
2788 cupsFileGetChar(fp);
2791 if (lineptr == line->buffer && ignoreblank)
2792 continue; /* Skip blank lines */
2796 if (!endquote) /* Continue for multi-line text */
2801 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2804 * Other control characters...
2807 cg->ppd_line = startline;
2808 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2812 else if (ch != 0x1a)
2815 * Any other character...
2821 if (col > (PPD_MAX_LINE - 1))
2824 * Line is too long...
2827 cg->ppd_line = startline;
2828 cg->ppd_status = PPD_LINE_TOO_LONG;
2833 if (ch == ':' && strncmp(line->buffer, "*%", 2) != 0)
2836 if (ch == '\"' && colon)
2837 endquote = !endquote;
2844 * Didn't finish this quoted string...
2847 while ((ch = cupsFileGetChar(fp)) != EOF)
2850 else if (ch == '\r' || ch == '\n')
2858 * Check for a trailing line feed...
2861 if ((ch = cupsFilePeekChar(fp)) == EOF)
2864 cupsFileGetChar(fp);
2867 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2870 * Other control characters...
2873 cg->ppd_line = startline;
2874 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2878 else if (ch != 0x1a)
2882 if (col > (PPD_MAX_LINE - 1))
2885 * Line is too long...
2888 cg->ppd_line = startline;
2889 cg->ppd_status = PPD_LINE_TOO_LONG;
2899 * Didn't finish this line...
2902 while ((ch = cupsFileGetChar(fp)) != EOF)
2903 if (ch == '\r' || ch == '\n')
2906 * Line feed or carriage return...
2915 * Check for a trailing line feed...
2918 if ((ch = cupsFilePeekChar(fp)) == EOF)
2921 cupsFileGetChar(fp);
2926 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2929 * Other control characters...
2932 cg->ppd_line = startline;
2933 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2937 else if (ch != 0x1a)
2941 if (col > (PPD_MAX_LINE - 1))
2944 * Line is too long...
2947 cg->ppd_line = startline;
2948 cg->ppd_status = PPD_LINE_TOO_LONG;
2955 if (lineptr > line->buffer && lineptr[-1] == '\n')
2960 DEBUG_printf(("9ppd_read: LINE=\"%s\"", line->buffer));
2963 * The dynamically created PPDs for older style Mac OS X
2964 * drivers include a large blob of data inserted as comments
2965 * at the end of the file. As an optimization we can stop
2966 * reading the PPD when we get to the start of this data.
2969 if (!strcmp(line->buffer, "*%APLWORKSET START"))
2972 if (ch == EOF && lineptr == line->buffer)
2980 lineptr = line->buffer + 1;
2987 if ((!line->buffer[0] || /* Blank line */
2988 !strncmp(line->buffer, "*%", 2) || /* Comment line */
2989 !strcmp(line->buffer, "*End")) && /* End of multi-line string */
2990 ignoreblank) /* Ignore these? */
2992 startline = cg->ppd_line + 1;
2996 if (!strcmp(line->buffer, "*")) /* (Bad) comment line */
2998 if (cg->ppd_conform == PPD_CONFORM_RELAXED)
3000 startline = cg->ppd_line + 1;
3005 cg->ppd_line = startline;
3006 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
3012 if (line->buffer[0] != '*') /* All lines start with an asterisk */
3015 * Allow lines consisting of just whitespace...
3018 for (lineptr = line->buffer; *lineptr; lineptr ++)
3019 if (*lineptr && !_cups_isspace(*lineptr))
3024 cg->ppd_status = PPD_MISSING_ASTERISK;
3027 else if (ignoreblank)
3039 while (*lineptr && *lineptr != ':' && !_cups_isspace(*lineptr))
3041 if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
3042 (keyptr - keyword) >= (PPD_MAX_NAME - 1))
3044 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
3048 *keyptr++ = *lineptr++;
3053 if (!strcmp(keyword, "End"))
3056 mask |= PPD_KEYWORD;
3058 if (_cups_isspace(*lineptr))
3061 * Get an option name...
3064 while (_cups_isspace(*lineptr))
3069 while (*lineptr && !_cups_isspace(*lineptr) && *lineptr != ':' &&
3072 if (*lineptr <= ' ' || *lineptr > 126 ||
3073 (optptr - option) >= (PPD_MAX_NAME - 1))
3075 cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
3079 *optptr++ = *lineptr++;
3084 if (_cups_isspace(*lineptr) && cg->ppd_conform == PPD_CONFORM_STRICT)
3086 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
3090 while (_cups_isspace(*lineptr))
3095 if (*lineptr == '/')
3098 * Get human-readable text...
3105 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
3107 if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
3108 (textptr - text) >= (PPD_MAX_LINE - 1))
3110 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
3114 *textptr++ = *lineptr++;
3118 textlen = ppd_decode(text);
3120 if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT)
3122 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
3130 if (_cups_isspace(*lineptr) && cg->ppd_conform == PPD_CONFORM_STRICT)
3132 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
3136 while (_cups_isspace(*lineptr))
3139 if (*lineptr == ':')
3142 * Get string after triming leading and trailing whitespace...
3146 while (_cups_isspace(*lineptr))
3149 strptr = lineptr + strlen(lineptr) - 1;
3150 while (strptr >= lineptr && _cups_isspace(*strptr))
3153 if (*strptr == '\"')
3156 * Quoted string by itself, remove quotes...
3163 *string = _cupsStrAlloc(lineptr);
3175 * 'ppd_update_filters()' - Update the filters array as needed.
3177 * This function re-populates the filters array with cupsFilter2 entries that
3178 * have been stripped of the destination MIME media types and any maxsize hints.
3180 * (All for backwards-compatibility)
3183 static int /* O - 1 on success, 0 on failure */
3184 ppd_update_filters(ppd_file_t *ppd,/* I - PPD file */
3185 _cups_globals_t *cg) /* I - Global data */
3187 ppd_attr_t *attr; /* Current cupsFilter2 value */
3188 char srcsuper[16], /* Source MIME media type */
3190 dstsuper[16], /* Destination MIME media type */
3192 program[1024], /* Command to run */
3193 *ptr, /* Pointer into command to run */
3194 buffer[1024], /* Re-written cupsFilter value */
3195 **filter; /* Current filter */
3196 int cost; /* Cost of filter */
3199 DEBUG_printf(("4ppd_update_filters(ppd=%p, cg=%p)", ppd, cg));
3202 * See if we have any cupsFilter2 lines...
3205 if ((attr = ppdFindAttr(ppd, "cupsFilter2", NULL)) == NULL)
3207 DEBUG_puts("5ppd_update_filters: No cupsFilter2 keywords present.");
3212 * Yes, free the cupsFilter-defined filters and re-build...
3215 ppd_free_filters(ppd);
3220 * Parse the cupsFilter2 string:
3222 * src/type dst/type cost program
3223 * src/type dst/type cost maxsize(n) program
3226 DEBUG_printf(("5ppd_update_filters: cupsFilter2=\"%s\"", attr->value));
3228 if (sscanf(attr->value, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
3229 srcsuper, srctype, dstsuper, dsttype, &cost, program) != 6)
3231 DEBUG_puts("5ppd_update_filters: Bad cupsFilter2 line.");
3232 cg->ppd_status = PPD_BAD_VALUE;
3237 DEBUG_printf(("5ppd_update_filters: srcsuper=\"%s\", srctype=\"%s\", "
3238 "dstsuper=\"%s\", dsttype=\"%s\", cost=%d, program=\"%s\"",
3239 srcsuper, srctype, dstsuper, dsttype, cost, program));
3241 if (!strncmp(program, "maxsize(", 8) &&
3242 (ptr = strchr(program + 8, ')')) != NULL)
3244 DEBUG_puts("5ppd_update_filters: Found maxsize(nnn).");
3247 while (_cups_isspace(*ptr))
3250 _cups_strcpy(program, ptr);
3251 DEBUG_printf(("5ppd_update_filters: New program=\"%s\"", program));
3255 * Convert to cupsFilter format:
3257 * src/type cost program
3260 snprintf(buffer, sizeof(buffer), "%s/%s %d %s", srcsuper, srctype, cost,
3262 DEBUG_printf(("5ppd_update_filters: Adding \"%s\".", buffer));
3265 * Add a cupsFilter-compatible string to the filters array.
3268 if (ppd->num_filters == 0)
3269 filter = malloc(sizeof(char *));
3271 filter = realloc(ppd->filters, sizeof(char *) * (ppd->num_filters + 1));
3275 DEBUG_puts("5ppd_update_filters: Out of memory.");
3276 cg->ppd_status = PPD_ALLOC_ERROR;
3281 ppd->filters = filter;
3282 filter += ppd->num_filters;
3283 ppd->num_filters ++;
3285 *filter = _cupsStrAlloc(buffer);
3287 while ((attr = ppdFindNextAttr(ppd, "cupsFilter2", NULL)) != NULL);
3289 DEBUG_puts("5ppd_update_filters: Completed OK.");
3295 * End of "$Id: ppd.c 9901 2011-08-17 21:01:53Z mike $".