2 * "$Id: ppd.c 6586 2007-06-21 17:44:22Z mike $"
4 * PPD file routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * PostScript is a trademark of Adobe Systems, Inc.
26 * This code and any derivative of it may be used and distributed
27 * freely under the terms of the GNU General Public License when
28 * used with GNU Ghostscript or its derivatives. Use of the code
29 * (or any derivative of it) with software other than GNU
30 * GhostScript (or its derivatives) is governed by the CUPS license
33 * This file is subject to the Apple OS-Developed Software exception.
37 * ppdClose() - Free all memory used by the PPD file.
38 * ppdErrorString() - Returns the text assocated with a status.
39 * _ppdGetEncoding() - Get the CUPS encoding value for the given
41 * ppdLastError() - Return the status from the last ppdOpen*().
42 * ppdOpen() - Read a PPD file into memory.
43 * ppdOpen2() - Read a PPD file into memory.
44 * ppdOpenFd() - Read a PPD file into memory.
45 * ppdOpenFile() - Read a PPD file into memory.
46 * ppdSetConformance() - Set the conformance level for PPD files.
47 * ppd_add_attr() - Add an attribute to the PPD data.
48 * ppd_add_choice() - Add a choice to an option.
49 * ppd_add_size() - Add a page size.
50 * ppd_compare_attrs() - Compare two attributes.
51 * ppd_compare_choices() - Compare two choices...
52 * ppd_compare_consts() - Compare two constraints.
53 * ppd_compare_coptions() - Compare two custom options.
54 * ppd_compare_cparams() - Compare two custom parameters.
55 * ppd_compare_options() - Compare two options.
56 * ppd_decode() - Decode a string value...
57 * ppd_free_group() - Free a single UI group.
58 * ppd_free_option() - Free a single option.
59 * ppd_get_coption() - Get a custom option record.
60 * ppd_get_cparam() - Get a custom parameter record.
61 * ppd_get_group() - Find or create the named group as needed.
62 * ppd_get_option() - Find or create the named option as needed.
63 * ppd_hash_option() - Generate a hash of the option name...
64 * ppd_read() - Read a line from a PPD file, skipping comment
69 * Include necessary headers.
81 #if defined(WIN32) || defined(__EMX__)
82 # define READ_BINARY "rb" /* Open a binary file for reading */
83 # define WRITE_BINARY "wb" /* Open a binary file for writing */
85 # define READ_BINARY "r" /* Open a binary file for reading */
86 # define WRITE_BINARY "w" /* Open a binary file for writing */
87 #endif /* WIN32 || __EMX__ */
89 #define ppd_free(p) if (p) free(p) /* Safe free macro */
91 #define PPD_KEYWORD 1 /* Line contained a keyword */
92 #define PPD_OPTION 2 /* Line contained an option name */
93 #define PPD_TEXT 4 /* Line contained human-readable text */
94 #define PPD_STRING 8 /* Line contained a string or code */
96 #define PPD_HASHSIZE 512 /* Size of hash */
103 static ppd_attr_t
*ppd_add_attr(ppd_file_t
*ppd
, const char *name
,
104 const char *spec
, const char *text
,
106 static ppd_choice_t
*ppd_add_choice(ppd_option_t
*option
, const char *name
);
107 static ppd_size_t
*ppd_add_size(ppd_file_t
*ppd
, const char *name
);
108 static int ppd_compare_attrs(ppd_attr_t
*a
, ppd_attr_t
*b
);
109 static int ppd_compare_choices(ppd_choice_t
*a
, ppd_choice_t
*b
);
110 static int ppd_compare_consts(ppd_const_t
*a
, ppd_const_t
*b
);
111 static int ppd_compare_coptions(ppd_coption_t
*a
,
113 static int ppd_compare_cparams(ppd_cparam_t
*a
, ppd_cparam_t
*b
);
114 static int ppd_compare_options(ppd_option_t
*a
, ppd_option_t
*b
);
115 static int ppd_decode(char *string
);
116 static void ppd_free_group(ppd_group_t
*group
);
117 static void ppd_free_option(ppd_option_t
*option
);
118 static ppd_coption_t
*ppd_get_coption(ppd_file_t
*ppd
, const char *name
);
119 static ppd_cparam_t
*ppd_get_cparam(ppd_coption_t
*opt
,
122 static ppd_group_t
*ppd_get_group(ppd_file_t
*ppd
, const char *name
,
123 const char *text
, _cups_globals_t
*cg
,
124 cups_encoding_t encoding
);
125 static ppd_option_t
*ppd_get_option(ppd_group_t
*group
, const char *name
);
126 static int ppd_hash_option(ppd_option_t
*option
);
127 static int ppd_read(cups_file_t
*fp
, char *keyword
, char *option
,
128 char *text
, char **string
, int ignoreblank
,
129 _cups_globals_t
*cg
);
133 * 'ppdClose()' - Free all memory used by the PPD file.
137 ppdClose(ppd_file_t
*ppd
) /* I - PPD file record */
139 int i
; /* Looping var */
140 ppd_emul_t
*emul
; /* Current emulation */
141 ppd_group_t
*group
; /* Current group */
142 char **font
; /* Current font */
143 char **filter
; /* Current filter */
144 ppd_attr_t
**attr
; /* Current attribute */
145 ppd_coption_t
*coption
; /* Current custom option */
146 ppd_cparam_t
*cparam
; /* Current custom parameter */
150 * Range check arguments...
157 * Free all strings at the top level...
160 ppd_free(ppd
->lang_encoding
);
161 ppd_free(ppd
->nickname
);
162 ppd_free(ppd
->patches
);
163 ppd_free(ppd
->jcl_begin
);
164 ppd_free(ppd
->jcl_end
);
165 ppd_free(ppd
->jcl_ps
);
168 * Free any emulations...
171 if (ppd
->num_emulations
> 0)
173 for (i
= ppd
->num_emulations
, emul
= ppd
->emulations
; i
> 0; i
--, emul
++)
175 ppd_free(emul
->start
);
176 ppd_free(emul
->stop
);
179 ppd_free(ppd
->emulations
);
183 * Free any UI groups, subgroups, and options...
186 if (ppd
->num_groups
> 0)
188 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
189 ppd_free_group(group
);
191 ppd_free(ppd
->groups
);
194 cupsArrayDelete(ppd
->options
);
195 cupsArrayDelete(ppd
->marked
);
198 * Free any page sizes...
201 if (ppd
->num_sizes
> 0)
202 ppd_free(ppd
->sizes
);
205 * Free any constraints...
208 if (ppd
->num_consts
> 0)
209 ppd_free(ppd
->consts
);
212 * Free any filters...
215 if (ppd
->num_filters
> 0)
217 for (i
= ppd
->num_filters
, filter
= ppd
->filters
; i
> 0; i
--, filter
++)
222 ppd_free(ppd
->filters
);
229 if (ppd
->num_fonts
> 0)
231 for (i
= ppd
->num_fonts
, font
= ppd
->fonts
; i
> 0; i
--, font
++)
236 ppd_free(ppd
->fonts
);
240 * Free any profiles...
243 if (ppd
->num_profiles
> 0)
244 ppd_free(ppd
->profiles
);
247 * Free any attributes...
250 if (ppd
->num_attrs
> 0)
252 for (i
= ppd
->num_attrs
, attr
= ppd
->attrs
; i
> 0; i
--, attr
++)
254 ppd_free((*attr
)->value
);
258 ppd_free(ppd
->attrs
);
261 cupsArrayDelete(ppd
->sorted_attrs
);
264 * Free custom options...
267 for (coption
= (ppd_coption_t
*)cupsArrayFirst(ppd
->coptions
);
269 coption
= (ppd_coption_t
*)cupsArrayNext(ppd
->coptions
))
271 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
273 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
275 switch (cparam
->type
)
277 case PPD_CUSTOM_PASSCODE
:
278 case PPD_CUSTOM_PASSWORD
:
279 case PPD_CUSTOM_STRING
:
280 ppd_free(cparam
->current
.custom_string
);
290 cupsArrayDelete(coption
->params
);
295 cupsArrayDelete(ppd
->coptions
);
298 * Free the whole record...
306 * 'ppdErrorString()' - Returns the text assocated with a status.
308 * @since CUPS 1.1.19@
311 const char * /* O - Status string */
312 ppdErrorString(ppd_status_t status
) /* I - PPD status */
314 static const char * const messages
[] =/* Status messages */
317 _("Unable to open PPD file"),
318 _("NULL PPD file pointer"),
319 _("Memory allocation error"),
320 _("Missing PPD-Adobe-4.x header"),
321 _("Missing value string"),
324 _("OpenGroup without a CloseGroup first"),
325 _("Bad OpenUI/JCLOpenUI"),
326 _("OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"),
327 _("Bad OrderDependency"),
328 _("Bad UIConstraints"),
329 _("Missing asterisk in column 1"),
330 _("Line longer than the maximum allowed (255 characters)"),
331 _("Illegal control character"),
332 _("Illegal main keyword string"),
333 _("Illegal option keyword string"),
334 _("Illegal translation string"),
335 _("Illegal whitespace character"),
336 _("Bad custom parameter")
340 if (status
< PPD_OK
|| status
> PPD_ILLEGAL_WHITESPACE
)
341 return (_cupsLangString(cupsLangDefault(), _("Unknown")));
343 return (_cupsLangString(cupsLangDefault(), messages
[status
]));
348 * '_ppdGetEncoding()' - Get the CUPS encoding value for the given
352 cups_encoding_t
/* O - CUPS encoding value */
353 _ppdGetEncoding(const char *name
) /* I - LanguageEncoding string */
355 if (!strcasecmp(name
, "ISOLatin1"))
356 return (CUPS_ISO8859_1
);
357 else if (!strcasecmp(name
, "ISOLatin2"))
358 return (CUPS_ISO8859_2
);
359 else if (!strcasecmp(name
, "ISOLatin5"))
360 return (CUPS_ISO8859_5
);
361 else if (!strcasecmp(name
, "JIS83-RKSJ"))
362 return (CUPS_WINDOWS_932
);
363 else if (!strcasecmp(name
, "MacStandard"))
364 return (CUPS_MAC_ROMAN
);
365 else if (!strcasecmp(name
, "WindowsANSI"))
366 return (CUPS_WINDOWS_1252
);
373 * 'ppdLastError()' - Return the status from the last ppdOpen*().
375 * @since CUPS 1.1.19@
378 ppd_status_t
/* O - Status code */
379 ppdLastError(int *line
) /* O - Line number */
381 _cups_globals_t
*cg
= _cupsGlobals();
386 *line
= cg
->ppd_line
;
388 return (cg
->ppd_status
);
393 * 'ppdOpen()' - Read a PPD file into memory.
396 ppd_file_t
* /* O - PPD file record */
397 ppdOpen(FILE *fp
) /* I - File to read from */
399 ppd_file_t
*ppd
; /* PPD file record */
400 cups_file_t
*cf
; /* CUPS file */
404 * Reopen the stdio file as a CUPS file...
407 if ((cf
= cupsFileOpenFd(fileno(fp
), "r")) == NULL
)
411 * Load the PPD file using the newer API...
417 * Close the CUPS file and return the PPD...
427 * 'ppdOpen2()' - Read a PPD file into memory.
432 ppd_file_t
* /* O - PPD file record */
433 ppdOpen2(cups_file_t
*fp
) /* I - File to read from */
435 int i
, j
, k
; /* Looping vars */
436 int count
; /* Temporary count */
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 static const char * const ui_keywords
[] =
468 #ifdef CUPS_USE_FULL_UI_KEYWORDS_LIST
470 * Adobe defines some 41 keywords as "UI", meaning that they are
471 * user interface elements and that they should be treated as such
472 * even if the PPD creator doesn't use Open/CloseUI around them.
474 * Since this can cause previously invisible options to appear and
475 * confuse users, the default is to only treat the PageSize and
476 * PageRegion keywords this way.
478 /* Boolean keywords */
488 /* PickOne keywords */
501 "JCLFrameBufferSize",
522 #else /* !CUPS_USE_FULL_UI_KEYWORDS_LIST */
525 #endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */
530 * Default to "OK" status...
533 cg
->ppd_status
= PPD_OK
;
537 * Range check input...
542 cg
->ppd_status
= PPD_NULL_FILE
;
547 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
550 mask
= ppd_read(fp
, keyword
, name
, text
, &string
, 0, cg
);
552 DEBUG_printf(("mask=%x, keyword=\"%s\"...\n", mask
, keyword
));
555 strcmp(keyword
, "PPD-Adobe") ||
556 string
== NULL
|| string
[0] != '4')
559 * Either this is not a PPD file, or it is not a 4.x PPD file.
562 if (cg
->ppd_status
== PPD_OK
)
563 cg
->ppd_status
= PPD_MISSING_PPDADOBE4
;
570 DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword
, string
));
575 * Allocate memory for the PPD file record...
578 if ((ppd
= calloc(1, sizeof(ppd_file_t
))) == NULL
)
580 cg
->ppd_status
= PPD_ALLOC_ERROR
;
585 ppd
->language_level
= 1;
586 ppd
->color_device
= 0;
587 ppd
->colorspace
= PPD_CS_GRAY
;
588 ppd
->landscape
= -90;
589 ppd
->coptions
= cupsArrayNew((cups_array_func_t
)ppd_compare_coptions
,
593 * Get the default language for the user...
596 language
= cupsLangDefault();
600 * Read lines from the PPD file and add them to the file record...
608 encoding
= CUPS_ISO8859_1
;
610 while ((mask
= ppd_read(fp
, keyword
, name
, text
, &string
, 1, cg
)) != 0)
613 printf("mask = %x, keyword = \"%s\"", mask
, keyword
);
616 printf(", name = \"%s\"", name
);
619 printf(", text = \"%s\"", text
);
623 if (strlen(string
) > 40)
624 printf(", string = %p", string
);
626 printf(", string = \"%s\"", string
);
632 if (strcmp(keyword
, "CloseUI") && strcmp(keyword
, "CloseGroup") &&
633 strcmp(keyword
, "CloseSubGroup") && strncmp(keyword
, "Default", 7) &&
634 strcmp(keyword
, "JCLCloseUI") && strcmp(keyword
, "JCLOpenUI") &&
635 strcmp(keyword
, "OpenUI") && strcmp(keyword
, "OpenGroup") &&
636 strcmp(keyword
, "OpenSubGroup") && string
== NULL
)
639 * Need a string value!
642 cg
->ppd_status
= PPD_MISSING_VALUE
;
648 * Certain main keywords (as defined by the PPD spec) may be used
649 * without the usual OpenUI/CloseUI stuff. Presumably this is just
650 * so that Adobe wouldn't completely break compatibility with PPD
651 * files prior to v4.0 of the spec, but it is hopelessly
652 * inconsistent... Catch these main keywords and automatically
653 * create the corresponding option, as needed...
659 * Previous line was a UI keyword...
666 if (option
== NULL
&&
667 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
668 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
))
670 for (i
= 0; i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])); i
++)
671 if (!strcmp(keyword
, ui_keywords
[i
]))
674 if (i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])))
677 * Create the option in the appropriate group...
682 DEBUG_printf(("**** FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!\n",
687 if ((group
= ppd_get_group(ppd
, "General", _("General"), cg
,
691 DEBUG_printf(("Adding to group %s...\n", group
->text
));
692 option
= ppd_get_option(group
, keyword
);
696 option
= ppd_get_option(group
, keyword
);
700 cg
->ppd_status
= PPD_ALLOC_ERROR
;
706 * Now fill in the initial information for the option...
709 if (!strncmp(keyword
, "JCL", 3))
710 option
->section
= PPD_ORDER_JCL
;
712 option
->section
= PPD_ORDER_ANY
;
714 option
->order
= 10.0f
;
717 option
->ui
= PPD_UI_BOOLEAN
;
719 option
->ui
= PPD_UI_PICKONE
;
721 for (j
= 0; j
< ppd
->num_attrs
; j
++)
722 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
723 !strcmp(ppd
->attrs
[j
]->name
+ 7, keyword
) &&
724 ppd
->attrs
[j
]->value
)
726 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
727 option
->keyword
, ppd
->attrs
[j
]->value
));
728 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
729 sizeof(option
->defchoice
));
733 if (!strcmp(keyword
, "PageSize"))
734 strlcpy(option
->text
, _("Media Size"), sizeof(option
->text
));
735 else if (!strcmp(keyword
, "MediaType"))
736 strlcpy(option
->text
, _("Media Type"), sizeof(option
->text
));
737 else if (!strcmp(keyword
, "InputSlot"))
738 strlcpy(option
->text
, _("Media Source"), sizeof(option
->text
));
739 else if (!strcmp(keyword
, "ColorModel"))
740 strlcpy(option
->text
, _("Output Mode"), sizeof(option
->text
));
741 else if (!strcmp(keyword
, "Resolution"))
742 strlcpy(option
->text
, _("Resolution"), sizeof(option
->text
));
744 strlcpy(option
->text
, keyword
, sizeof(option
->text
));
748 if (!strcmp(keyword
, "LanguageLevel"))
749 ppd
->language_level
= atoi(string
);
750 else if (!strcmp(keyword
, "LanguageEncoding"))
753 * Say all PPD files are UTF-8, since we convert to UTF-8...
756 ppd
->lang_encoding
= strdup("UTF-8");
757 encoding
= _ppdGetEncoding(string
);
759 else if (!strcmp(keyword
, "LanguageVersion"))
760 ppd
->lang_version
= string
;
761 else if (!strcmp(keyword
, "Manufacturer"))
762 ppd
->manufacturer
= string
;
763 else if (!strcmp(keyword
, "ModelName"))
764 ppd
->modelname
= string
;
765 else if (!strcmp(keyword
, "Protocols"))
766 ppd
->protocols
= string
;
767 else if (!strcmp(keyword
, "PCFileName"))
768 ppd
->pcfilename
= string
;
769 else if (!strcmp(keyword
, "NickName"))
771 if (encoding
!= CUPS_UTF8
)
773 cups_utf8_t utf8
[256]; /* UTF-8 version of NickName */
776 cupsCharsetToUTF8(utf8
, string
, sizeof(utf8
), encoding
);
777 ppd
->nickname
= strdup((char *)utf8
);
780 ppd
->nickname
= strdup(string
);
782 else if (!strcmp(keyword
, "Product"))
783 ppd
->product
= string
;
784 else if (!strcmp(keyword
, "ShortNickName"))
785 ppd
->shortnickname
= string
;
786 else if (!strcmp(keyword
, "TTRasterizer"))
787 ppd
->ttrasterizer
= string
;
788 else if (!strcmp(keyword
, "JCLBegin"))
790 ppd
->jcl_begin
= strdup(string
);
791 ppd_decode(ppd
->jcl_begin
); /* Decode quoted string */
793 else if (!strcmp(keyword
, "JCLEnd"))
795 ppd
->jcl_end
= strdup(string
);
796 ppd_decode(ppd
->jcl_end
); /* Decode quoted string */
798 else if (!strcmp(keyword
, "JCLToPSInterpreter"))
800 ppd
->jcl_ps
= strdup(string
);
801 ppd_decode(ppd
->jcl_ps
); /* Decode quoted string */
803 else if (!strcmp(keyword
, "AccurateScreensSupport"))
804 ppd
->accurate_screens
= !strcmp(string
, "True");
805 else if (!strcmp(keyword
, "ColorDevice"))
806 ppd
->color_device
= !strcmp(string
, "True");
807 else if (!strcmp(keyword
, "ContoneOnly"))
808 ppd
->contone_only
= !strcmp(string
, "True");
809 else if (!strcmp(keyword
, "cupsFlipDuplex"))
810 ppd
->flip_duplex
= !strcmp(string
, "True");
811 else if (!strcmp(keyword
, "cupsManualCopies"))
812 ppd
->manual_copies
= !strcmp(string
, "True");
813 else if (!strcmp(keyword
, "cupsModelNumber"))
814 ppd
->model_number
= atoi(string
);
815 else if (!strcmp(keyword
, "cupsColorProfile"))
817 if (ppd
->num_profiles
== 0)
818 profile
= malloc(sizeof(ppd_profile_t
));
820 profile
= realloc(ppd
->profiles
, sizeof(ppd_profile_t
) *
821 (ppd
->num_profiles
+ 1));
823 ppd
->profiles
= profile
;
824 profile
+= ppd
->num_profiles
;
825 ppd
->num_profiles
++;
827 memset(profile
, 0, sizeof(ppd_profile_t
));
828 strlcpy(profile
->resolution
, name
, sizeof(profile
->resolution
));
829 strlcpy(profile
->media_type
, text
, sizeof(profile
->media_type
));
831 profile
->density
= (float)_cupsStrScand(string
, &sptr
, loc
);
832 profile
->gamma
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
833 profile
->matrix
[0][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
834 profile
->matrix
[0][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
835 profile
->matrix
[0][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
836 profile
->matrix
[1][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
837 profile
->matrix
[1][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
838 profile
->matrix
[1][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
839 profile
->matrix
[2][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
840 profile
->matrix
[2][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
841 profile
->matrix
[2][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
843 else if (!strcmp(keyword
, "cupsFilter"))
845 if (ppd
->num_filters
== 0)
846 filter
= malloc(sizeof(char *));
848 filter
= realloc(ppd
->filters
, sizeof(char *) * (ppd
->num_filters
+ 1));
854 cg
->ppd_status
= PPD_ALLOC_ERROR
;
859 ppd
->filters
= filter
;
860 filter
+= ppd
->num_filters
;
864 * Copy filter string and prevent it from being freed below...
870 else if (!strcmp(keyword
, "Throughput"))
871 ppd
->throughput
= atoi(string
);
872 else if (!strcmp(keyword
, "Font"))
875 * Add this font to the list of available fonts...
878 if (ppd
->num_fonts
== 0)
879 tempfonts
= (char **)malloc(sizeof(char *));
881 tempfonts
= (char **)realloc(ppd
->fonts
,
882 sizeof(char *) * (ppd
->num_fonts
+ 1));
884 if (tempfonts
== NULL
)
886 cg
->ppd_status
= PPD_ALLOC_ERROR
;
891 ppd
->fonts
= tempfonts
;
892 ppd
->fonts
[ppd
->num_fonts
] = strdup(name
);
895 else if (!strncmp(keyword
, "ParamCustom", 11))
897 ppd_coption_t
*coption
; /* Custom option */
898 ppd_cparam_t
*cparam
; /* Custom parameter */
899 int corder
; /* Order number */
900 char ctype
[33], /* Data type */
901 cminimum
[65], /* Minimum value */
902 cmaximum
[65]; /* Maximum value */
906 * Get the custom option and parameter...
909 if ((coption
= ppd_get_coption(ppd
, keyword
+ 11)) == NULL
)
911 cg
->ppd_status
= PPD_ALLOC_ERROR
;
916 if ((cparam
= ppd_get_cparam(coption
, name
, text
)) == NULL
)
918 cg
->ppd_status
= PPD_ALLOC_ERROR
;
924 * Get the parameter data...
927 if (sscanf(string
, "%d%32s%64s%64s", &corder
, ctype
, cminimum
,
930 cg
->ppd_status
= PPD_BAD_CUSTOM_PARAM
;
935 cparam
->order
= corder
;
937 if (!strcmp(ctype
, "curve"))
939 cparam
->type
= PPD_CUSTOM_CURVE
;
940 cparam
->minimum
.custom_curve
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
941 cparam
->maximum
.custom_curve
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
943 else if (!strcmp(ctype
, "int"))
945 cparam
->type
= PPD_CUSTOM_INT
;
946 cparam
->minimum
.custom_int
= atoi(cminimum
);
947 cparam
->maximum
.custom_int
= atoi(cmaximum
);
949 else if (!strcmp(ctype
, "invcurve"))
951 cparam
->type
= PPD_CUSTOM_INVCURVE
;
952 cparam
->minimum
.custom_invcurve
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
953 cparam
->maximum
.custom_invcurve
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
955 else if (!strcmp(ctype
, "passcode"))
957 cparam
->type
= PPD_CUSTOM_PASSCODE
;
958 cparam
->minimum
.custom_passcode
= atoi(cminimum
);
959 cparam
->maximum
.custom_passcode
= atoi(cmaximum
);
961 else if (!strcmp(ctype
, "password"))
963 cparam
->type
= PPD_CUSTOM_PASSWORD
;
964 cparam
->minimum
.custom_password
= atoi(cminimum
);
965 cparam
->maximum
.custom_password
= atoi(cmaximum
);
967 else if (!strcmp(ctype
, "points"))
969 cparam
->type
= PPD_CUSTOM_POINTS
;
970 cparam
->minimum
.custom_points
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
971 cparam
->maximum
.custom_points
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
973 else if (!strcmp(ctype
, "real"))
975 cparam
->type
= PPD_CUSTOM_REAL
;
976 cparam
->minimum
.custom_real
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
977 cparam
->maximum
.custom_real
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
979 else if (!strcmp(ctype
, "string"))
981 cparam
->type
= PPD_CUSTOM_STRING
;
982 cparam
->minimum
.custom_string
= atoi(cminimum
);
983 cparam
->maximum
.custom_string
= atoi(cmaximum
);
987 cg
->ppd_status
= PPD_BAD_CUSTOM_PARAM
;
993 * Now special-case for CustomPageSize...
996 if (!strcmp(coption
->keyword
, "PageSize"))
998 if (!strcmp(name
, "Width"))
1000 ppd
->custom_min
[0] = cparam
->minimum
.custom_points
;
1001 ppd
->custom_max
[0] = cparam
->maximum
.custom_points
;
1003 else if (!strcmp(name
, "Height"))
1005 ppd
->custom_min
[1] = cparam
->minimum
.custom_points
;
1006 ppd
->custom_max
[1] = cparam
->maximum
.custom_points
;
1010 else if (!strcmp(keyword
, "HWMargins"))
1012 for (i
= 0, sptr
= string
; i
< 4; i
++)
1013 ppd
->custom_margins
[i
] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
1015 else if (!strncmp(keyword
, "Custom", 6) && !strcmp(name
, "True") && !option
)
1017 DEBUG_puts("Processing Custom option...");
1020 * Get the option and custom option...
1023 if ((option
= ppdFindOption(ppd
, keyword
+ 6)) == NULL
)
1025 int groupidx
= -1; /* Index for current group */
1026 ppd_group_t
*gtemp
; /* Temporary group */
1029 DEBUG_printf(("%s option not found for %s...\n", keyword
+ 6, keyword
));
1032 groupidx
= group
- ppd
->groups
; /* Save index for current group */
1034 if ((gtemp
= ppd_get_group(ppd
, "General", _("General"), cg
,
1037 DEBUG_puts("Unable to get general group!");
1043 group
= ppd
->groups
+ groupidx
; /* Restore group pointer */
1045 if ((option
= ppd_get_option(gtemp
, keyword
+ 6)) == NULL
)
1047 DEBUG_printf(("Unable to get %s option!\n", keyword
+ 6));
1049 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1055 if (!ppd_get_coption(ppd
, keyword
+ 6))
1057 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1063 * Add the "custom" option...
1066 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
1068 DEBUG_puts("Unable to add Custom choice!");
1070 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1075 strlcpy(choice
->text
, text
[0] ? text
: _("Custom"),
1076 sizeof(choice
->text
));
1078 choice
->code
= string
;
1079 string
= NULL
; /* Don't add as an attribute below */
1083 * Now process custom page sizes specially...
1086 if (!strcmp(keyword
, "CustomPageSize"))
1088 ppd
->variable_sizes
= 1;
1091 * Add a "Custom" page size entry...
1094 ppd_add_size(ppd
, "Custom");
1096 if ((option
= ppdFindOption(ppd
, "PageRegion")) == NULL
)
1098 int groupidx
= -1; /* Index to current group */
1099 ppd_group_t
*gtemp
; /* Temporary group */
1102 groupidx
= group
- ppd
->groups
; /* Save index for current group */
1104 if ((gtemp
= ppd_get_group(ppd
, "General", _("General"), cg
,
1107 DEBUG_puts("Unable to get general group!");
1113 group
= ppd
->groups
+ groupidx
; /* Restore group pointer */
1115 option
= ppd_get_option(gtemp
, "PageRegion");
1118 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
1120 DEBUG_puts("Unable to add Custom choice!");
1122 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1127 strlcpy(choice
->text
, text
[0] ? text
: _("Custom"),
1128 sizeof(choice
->text
));
1132 else if (!strcmp(keyword
, "LandscapeOrientation"))
1134 if (!strcmp(string
, "Minus90"))
1135 ppd
->landscape
= -90;
1136 else if (!strcmp(string
, "Plus90"))
1137 ppd
->landscape
= 90;
1139 else if (!strcmp(keyword
, "Emulators"))
1141 for (count
= 1, sptr
= string
; sptr
!= NULL
;)
1142 if ((sptr
= strchr(sptr
, ' ')) != NULL
)
1145 while (*sptr
== ' ')
1149 ppd
->num_emulations
= count
;
1150 ppd
->emulations
= calloc(count
, sizeof(ppd_emul_t
));
1152 for (i
= 0, sptr
= string
; i
< count
; i
++)
1154 for (nameptr
= ppd
->emulations
[i
].name
;
1155 *sptr
!= '\0' && *sptr
!= ' ';
1157 if (nameptr
< (ppd
->emulations
[i
].name
+ sizeof(ppd
->emulations
[i
].name
) - 1))
1162 while (*sptr
== ' ')
1166 else if (!strncmp(keyword
, "StartEmulator_", 14))
1170 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1171 if (!strcmp(keyword
+ 14, ppd
->emulations
[i
].name
))
1173 ppd
->emulations
[i
].start
= string
;
1177 else if (!strncmp(keyword
, "StopEmulator_", 13))
1181 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1182 if (!strcmp(keyword
+ 13, ppd
->emulations
[i
].name
))
1184 ppd
->emulations
[i
].stop
= string
;
1188 else if (!strcmp(keyword
, "JobPatchFile"))
1190 if (ppd
->patches
== NULL
)
1191 ppd
->patches
= strdup(string
);
1194 temp
= realloc(ppd
->patches
, strlen(ppd
->patches
) +
1195 strlen(string
) + 1);
1198 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1203 ppd
->patches
= temp
;
1205 strcpy(ppd
->patches
+ strlen(ppd
->patches
), string
);
1208 else if (!strcmp(keyword
, "OpenUI"))
1211 * Don't allow nesting of options...
1214 if (option
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1216 cg
->ppd_status
= PPD_NESTED_OPEN_UI
;
1222 * Add an option record to the current sub-group, group, or file...
1226 _cups_strcpy(name
, name
+ 1); /* Eliminate leading asterisk */
1228 for (i
= (int)strlen(name
) - 1; i
> 0 && isspace(name
[i
] & 255); i
--)
1229 name
[i
] = '\0'; /* Eliminate trailing spaces */
1231 DEBUG_printf(("OpenUI of %s in group %s...\n", name
,
1232 group
? group
->text
: "(null)"));
1234 if (subgroup
!= NULL
)
1235 option
= ppd_get_option(subgroup
, name
);
1236 else if (group
== NULL
)
1238 if ((group
= ppd_get_group(ppd
, "General", _("General"), cg
,
1242 DEBUG_printf(("Adding to group %s...\n", group
->text
));
1243 option
= ppd_get_option(group
, name
);
1247 option
= ppd_get_option(group
, name
);
1251 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1257 * Now fill in the initial information for the option...
1260 if (string
&& !strcmp(string
, "PickMany"))
1261 option
->ui
= PPD_UI_PICKMANY
;
1262 else if (string
&& !strcmp(string
, "Boolean"))
1263 option
->ui
= PPD_UI_BOOLEAN
;
1264 else if (string
&& !strcmp(string
, "PickOne"))
1265 option
->ui
= PPD_UI_PICKONE
;
1266 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1268 cg
->ppd_status
= PPD_BAD_OPEN_UI
;
1273 option
->ui
= PPD_UI_PICKONE
;
1275 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1276 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
1277 !strcmp(ppd
->attrs
[j
]->name
+ 7, name
) &&
1278 ppd
->attrs
[j
]->value
)
1280 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
1281 option
->keyword
, ppd
->attrs
[j
]->value
));
1282 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
1283 sizeof(option
->defchoice
));
1288 cupsCharsetToUTF8((cups_utf8_t
*)option
->text
, text
,
1289 sizeof(option
->text
), encoding
);
1292 if (!strcmp(name
, "PageSize"))
1293 strlcpy(option
->text
, _("Media Size"), sizeof(option
->text
));
1294 else if (!strcmp(name
, "MediaType"))
1295 strlcpy(option
->text
, _("Media Type"), sizeof(option
->text
));
1296 else if (!strcmp(name
, "InputSlot"))
1297 strlcpy(option
->text
, _("Media Source"), sizeof(option
->text
));
1298 else if (!strcmp(name
, "ColorModel"))
1299 strlcpy(option
->text
, _("Output Mode"), sizeof(option
->text
));
1300 else if (!strcmp(name
, "Resolution"))
1301 strlcpy(option
->text
, _("Resolution"), sizeof(option
->text
));
1303 strlcpy(option
->text
, name
, sizeof(option
->text
));
1306 option
->section
= PPD_ORDER_ANY
;
1311 else if (!strcmp(keyword
, "JCLOpenUI"))
1314 * Don't allow nesting of options...
1317 if (option
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1319 cg
->ppd_status
= PPD_NESTED_OPEN_UI
;
1325 * Find the JCL group, and add if needed...
1328 group
= ppd_get_group(ppd
, "JCL", _("JCL"), cg
, encoding
);
1334 * Add an option record to the current JCLs...
1338 _cups_strcpy(name
, name
+ 1);
1340 option
= ppd_get_option(group
, name
);
1344 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1350 * Now fill in the initial information for the option...
1353 if (string
&& !strcmp(string
, "PickMany"))
1354 option
->ui
= PPD_UI_PICKMANY
;
1355 else if (string
&& !strcmp(string
, "Boolean"))
1356 option
->ui
= PPD_UI_BOOLEAN
;
1357 else if (string
&& !strcmp(string
, "PickOne"))
1358 option
->ui
= PPD_UI_PICKONE
;
1361 cg
->ppd_status
= PPD_BAD_OPEN_UI
;
1366 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1367 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
1368 !strcmp(ppd
->attrs
[j
]->name
+ 7, name
) &&
1369 ppd
->attrs
[j
]->value
)
1371 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
1372 option
->keyword
, ppd
->attrs
[j
]->value
));
1373 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
1374 sizeof(option
->defchoice
));
1379 cupsCharsetToUTF8((cups_utf8_t
*)option
->text
, text
,
1380 sizeof(option
->text
), encoding
);
1382 strlcpy(option
->text
, name
, sizeof(option
->text
));
1384 option
->section
= PPD_ORDER_JCL
;
1390 else if (!strcmp(keyword
, "CloseUI") || !strcmp(keyword
, "JCLCloseUI"))
1397 else if (!strcmp(keyword
, "OpenGroup"))
1400 * Open a new group...
1405 cg
->ppd_status
= PPD_NESTED_OPEN_GROUP
;
1412 cg
->ppd_status
= PPD_BAD_OPEN_GROUP
;
1418 * Separate the group name from the text (name/text)...
1421 if ((sptr
= strchr(string
, '/')) != NULL
)
1427 * Fix up the text...
1433 * Find/add the group...
1436 group
= ppd_get_group(ppd
, string
, sptr
, cg
, encoding
);
1444 else if (!strcmp(keyword
, "CloseGroup"))
1451 else if (!strcmp(keyword
, "OrderDependency") ||
1452 !strcmp(keyword
, "NonUIOrderDependency"))
1454 order
= (float)_cupsStrScand(string
, &sptr
, loc
);
1456 if (!sptr
|| sscanf(sptr
, "%40s%40s", name
, keyword
) != 2)
1458 cg
->ppd_status
= PPD_BAD_ORDER_DEPENDENCY
;
1463 if (keyword
[0] == '*')
1464 _cups_strcpy(keyword
, keyword
+ 1);
1466 if (!strcmp(name
, "ExitServer"))
1467 section
= PPD_ORDER_EXIT
;
1468 else if (!strcmp(name
, "Prolog"))
1469 section
= PPD_ORDER_PROLOG
;
1470 else if (!strcmp(name
, "DocumentSetup"))
1471 section
= PPD_ORDER_DOCUMENT
;
1472 else if (!strcmp(name
, "PageSetup"))
1473 section
= PPD_ORDER_PAGE
;
1474 else if (!strcmp(name
, "JCLSetup"))
1475 section
= PPD_ORDER_JCL
;
1477 section
= PPD_ORDER_ANY
;
1485 * Only valid for Non-UI options...
1488 for (i
= ppd
->num_groups
, gtemp
= ppd
->groups
; i
> 0; i
--, gtemp
++)
1489 if (gtemp
->text
[0] == '\0')
1493 for (i
= 0; i
< gtemp
->num_options
; i
++)
1494 if (!strcmp(keyword
, gtemp
->options
[i
].keyword
))
1496 gtemp
->options
[i
].section
= section
;
1497 gtemp
->options
[i
].order
= order
;
1503 option
->section
= section
;
1504 option
->order
= order
;
1510 else if (!strncmp(keyword
, "Default", 7))
1516 * Drop UI text, if any, from value...
1519 if (strchr(string
, '/') != NULL
)
1520 *strchr(string
, '/') = '\0';
1523 * Assign the default value as appropriate...
1526 if (!strcmp(keyword
, "DefaultColorSpace"))
1529 * Set default colorspace...
1532 if (!strcmp(string
, "CMY"))
1533 ppd
->colorspace
= PPD_CS_CMY
;
1534 else if (!strcmp(string
, "CMYK"))
1535 ppd
->colorspace
= PPD_CS_CMYK
;
1536 else if (!strcmp(string
, "RGB"))
1537 ppd
->colorspace
= PPD_CS_RGB
;
1538 else if (!strcmp(string
, "RGBK"))
1539 ppd
->colorspace
= PPD_CS_RGBK
;
1540 else if (!strcmp(string
, "N"))
1541 ppd
->colorspace
= PPD_CS_N
;
1543 ppd
->colorspace
= PPD_CS_GRAY
;
1545 else if (option
&& !strcmp(keyword
+ 7, option
->keyword
))
1548 * Set the default as part of the current option...
1551 DEBUG_printf(("Setting %s to %s...\n", keyword
, string
));
1553 strlcpy(option
->defchoice
, string
, sizeof(option
->defchoice
));
1555 DEBUG_printf(("%s is now %s...\n", keyword
, option
->defchoice
));
1560 * Lookup option and set if it has been defined...
1563 ppd_option_t
*toption
; /* Temporary option */
1566 if ((toption
= ppdFindOption(ppd
, keyword
+ 7)) != NULL
)
1568 DEBUG_printf(("Setting %s to %s...\n", keyword
, string
));
1569 strlcpy(toption
->defchoice
, string
, sizeof(toption
->defchoice
));
1573 else if (!strcmp(keyword
, "UIConstraints") ||
1574 !strcmp(keyword
, "NonUIConstraints"))
1576 if (ppd
->num_consts
== 0)
1577 constraint
= calloc(2, sizeof(ppd_const_t
));
1579 constraint
= realloc(ppd
->consts
,
1580 (ppd
->num_consts
+ 2) * sizeof(ppd_const_t
));
1582 if (constraint
== NULL
)
1584 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1589 ppd
->consts
= constraint
;
1590 constraint
+= ppd
->num_consts
;
1593 switch (sscanf(string
, "%40s%40s%40s%40s", constraint
->option1
,
1594 constraint
->choice1
, constraint
->option2
,
1595 constraint
->choice2
))
1597 case 0 : /* Error */
1598 case 1 : /* Error */
1599 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1602 case 2 : /* Two options... */
1604 * Check for broken constraints like "* Option"...
1607 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1608 (!strcmp(constraint
->option1
, "*") ||
1609 !strcmp(constraint
->choice1
, "*")))
1611 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1616 * The following strcpy's are safe, as optionN and
1617 * choiceN are all the same size (size defined by PPD spec...)
1620 if (constraint
->option1
[0] == '*')
1621 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1622 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1624 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1628 if (constraint
->choice1
[0] == '*')
1629 _cups_strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1630 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1632 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1636 constraint
->choice1
[0] = '\0';
1637 constraint
->choice2
[0] = '\0';
1640 case 3 : /* Two options, one choice... */
1642 * Check for broken constraints like "* Option"...
1645 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1646 (!strcmp(constraint
->option1
, "*") ||
1647 !strcmp(constraint
->choice1
, "*") ||
1648 !strcmp(constraint
->option2
, "*")))
1650 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1655 * The following _cups_strcpy's are safe, as optionN and
1656 * choiceN are all the same size (size defined by PPD spec...)
1659 if (constraint
->option1
[0] == '*')
1660 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1661 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1663 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1667 if (constraint
->choice1
[0] == '*')
1669 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1670 constraint
->option2
[0] == '*')
1672 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1676 _cups_strcpy(constraint
->choice2
, constraint
->option2
);
1677 _cups_strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1678 constraint
->choice1
[0] = '\0';
1682 if (constraint
->option2
[0] == '*')
1683 _cups_strcpy(constraint
->option2
, constraint
->option2
+ 1);
1684 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1686 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1690 constraint
->choice2
[0] = '\0';
1694 case 4 : /* Two options, two choices... */
1696 * Check for broken constraints like "* Option"...
1699 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1700 (!strcmp(constraint
->option1
, "*") ||
1701 !strcmp(constraint
->choice1
, "*") ||
1702 !strcmp(constraint
->option2
, "*") ||
1703 !strcmp(constraint
->choice2
, "*")))
1705 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1709 if (constraint
->option1
[0] == '*')
1710 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1711 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1713 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1717 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1718 constraint
->choice1
[0] == '*')
1720 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1724 if (constraint
->option2
[0] == '*')
1725 _cups_strcpy(constraint
->option2
, constraint
->option2
+ 1);
1726 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1728 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1732 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1733 constraint
->choice2
[0] == '*')
1735 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1742 * For CustomPageSize and InputSlot/ManualFeed, create a duplicate
1743 * constraint for PageRegion...
1746 if (!strcasecmp(constraint
->option1
, "CustomPageSize") &&
1747 (!strcasecmp(constraint
->option2
, "InputSlot") ||
1748 !strcasecmp(constraint
->option2
, "ManualFeed")))
1752 strcpy(constraint
[1].option1
, "PageRegion");
1753 strcpy(constraint
[1].choice1
, "Custom");
1754 strcpy(constraint
[1].option2
, constraint
->option2
);
1755 strcpy(constraint
[1].choice2
, constraint
->choice2
);
1757 else if (!strcasecmp(constraint
->option2
, "CustomPageSize") &&
1758 (!strcasecmp(constraint
->option1
, "InputSlot") ||
1759 !strcasecmp(constraint
->option1
, "ManualFeed")))
1763 strcpy(constraint
[1].option1
, constraint
->option1
);
1764 strcpy(constraint
[1].choice1
, constraint
->choice1
);
1765 strcpy(constraint
[1].option2
, "PageRegion");
1766 strcpy(constraint
[1].choice2
, "Custom");
1770 * Handle CustomFoo option constraints...
1773 if (!strncasecmp(constraint
->option1
, "Custom", 6) &&
1774 !strcasecmp(constraint
->choice1
, "True"))
1776 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 6);
1777 strcpy(constraint
->choice1
, "Custom");
1780 if (!strncasecmp(constraint
->option2
, "Custom", 6) &&
1781 !strcasecmp(constraint
->choice2
, "True"))
1783 _cups_strcpy(constraint
->option2
, constraint
->option2
+ 6);
1784 strcpy(constraint
->choice2
, "Custom");
1788 * Don't add this one as an attribute...
1794 else if (!strcmp(keyword
, "PaperDimension"))
1796 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1797 size
= ppd_add_size(ppd
, name
);
1802 * Unable to add or find size!
1805 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1810 size
->width
= (float)_cupsStrScand(string
, &sptr
, loc
);
1811 size
->length
= (float)_cupsStrScand(sptr
, NULL
, loc
);
1816 else if (!strcmp(keyword
, "ImageableArea"))
1818 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1819 size
= ppd_add_size(ppd
, name
);
1824 * Unable to add or find size!
1827 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1832 size
->left
= (float)_cupsStrScand(string
, &sptr
, loc
);
1833 size
->bottom
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
1834 size
->right
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
1835 size
->top
= (float)_cupsStrScand(sptr
, NULL
, loc
);
1840 else if (option
!= NULL
&&
1841 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
1842 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
) &&
1843 !strcmp(keyword
, option
->keyword
))
1845 DEBUG_printf(("group = %p, subgroup = %p\n", group
, subgroup
));
1847 if (!strcmp(keyword
, "PageSize"))
1850 * Add a page size...
1853 if (ppdPageSize(ppd
, name
) == NULL
)
1854 ppd_add_size(ppd
, name
);
1858 * Add the option choice...
1861 choice
= ppd_add_choice(option
, name
);
1864 cupsCharsetToUTF8((cups_utf8_t
*)choice
->text
, text
,
1865 sizeof(choice
->text
), encoding
);
1866 else if (!strcmp(name
, "True"))
1867 strcpy(choice
->text
, _("Yes"));
1868 else if (!strcmp(name
, "False"))
1869 strcpy(choice
->text
, _("No"));
1871 strlcpy(choice
->text
, name
, sizeof(choice
->text
));
1873 if (option
->section
== PPD_ORDER_JCL
)
1874 ppd_decode(string
); /* Decode quoted string */
1876 choice
->code
= string
;
1877 string
= NULL
; /* Don't add as an attribute below */
1881 * Add remaining lines with keywords and string values as attributes...
1885 (mask
& (PPD_KEYWORD
| PPD_STRING
)) == (PPD_KEYWORD
| PPD_STRING
))
1886 ppd_add_attr(ppd
, keyword
, name
, text
, string
);
1892 * Reset language preferences...
1895 cupsLangFree(language
);
1899 printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp
));
1902 if (cg
->ppd_status
!= PPD_OK
)
1905 * Had an error reading the PPD file, cannot continue!
1914 * Create the sorted options array and set the option back-pointer for
1915 * each choice and custom option...
1918 ppd
->options
= cupsArrayNew2((cups_array_func_t
)ppd_compare_options
, NULL
,
1919 (cups_ahash_func_t
)ppd_hash_option
,
1922 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
1926 for (j
= group
->num_options
, option
= group
->options
;
1930 ppd_coption_t
*coption
; /* Custom option */
1933 cupsArrayAdd(ppd
->options
, option
);
1935 for (k
= 0; k
< option
->num_choices
; k
++)
1936 option
->choices
[k
].option
= option
;
1938 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)) != NULL
)
1939 coption
->option
= option
;
1944 * Sort the constraints...
1947 if (ppd
->num_consts
> 1)
1948 qsort(ppd
->consts
, ppd
->num_consts
, sizeof(ppd_const_t
),
1949 (int (*)(const void *, const void *))ppd_compare_consts
);
1952 * Create an array to track the marked choices...
1955 ppd
->marked
= cupsArrayNew((cups_array_func_t
)ppd_compare_choices
, NULL
);
1958 * Return the PPD file structure...
1964 * Common exit point for errors to save code size...
1973 cupsLangFree(language
);
1980 * 'ppdOpenFd()' - Read a PPD file into memory.
1983 ppd_file_t
* /* O - PPD file record */
1984 ppdOpenFd(int fd
) /* I - File to read from */
1986 cups_file_t
*fp
; /* CUPS file pointer */
1987 ppd_file_t
*ppd
; /* PPD file record */
1988 _cups_globals_t
*cg
= _cupsGlobals();
1993 * Set the line number to 0...
1999 * Range check input...
2004 cg
->ppd_status
= PPD_NULL_FILE
;
2010 * Try to open the file and parse it...
2013 if ((fp
= cupsFileOpenFd(fd
, "r")) != NULL
)
2021 cg
->ppd_status
= PPD_FILE_OPEN_ERROR
;
2030 * 'ppdOpenFile()' - Read a PPD file into memory.
2033 ppd_file_t
* /* O - PPD file record */
2034 ppdOpenFile(const char *filename
) /* I - File to read from */
2036 cups_file_t
*fp
; /* 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...
2052 if (filename
== NULL
)
2054 cg
->ppd_status
= PPD_NULL_FILE
;
2060 * Try to open the file and parse it...
2063 if ((fp
= cupsFileOpen(filename
, "r")) != NULL
)
2071 cg
->ppd_status
= PPD_FILE_OPEN_ERROR
;
2080 * 'ppdSetConformance()' - Set the conformance level for PPD files.
2082 * @since CUPS 1.1.20@
2086 ppdSetConformance(ppd_conform_t c
) /* I - Conformance level */
2088 _cups_globals_t
*cg
= _cupsGlobals();
2092 cg
->ppd_conform
= c
;
2097 * 'ppd_add_attr()' - Add an attribute to the PPD data.
2100 static ppd_attr_t
* /* O - New attribute */
2101 ppd_add_attr(ppd_file_t
*ppd
, /* I - PPD file data */
2102 const char *name
, /* I - Attribute name */
2103 const char *spec
, /* I - Specifier string, if any */
2104 const char *text
, /* I - Text string, if any */
2105 const char *value
) /* I - Value of attribute */
2107 ppd_attr_t
**ptr
, /* New array */
2108 *temp
; /* New attribute */
2112 * Range check input...
2115 if (ppd
== NULL
|| name
== NULL
|| spec
== NULL
)
2119 * Create the array as needed...
2122 if (!ppd
->sorted_attrs
)
2123 ppd
->sorted_attrs
= cupsArrayNew((cups_array_func_t
)ppd_compare_attrs
,
2127 * Allocate memory for the new attribute...
2130 if (ppd
->num_attrs
== 0)
2131 ptr
= malloc(sizeof(ppd_attr_t
*));
2133 ptr
= realloc(ppd
->attrs
, (ppd
->num_attrs
+ 1) * sizeof(ppd_attr_t
*));
2139 ptr
+= ppd
->num_attrs
;
2141 if ((temp
= calloc(1, sizeof(ppd_attr_t
))) == NULL
)
2152 strlcpy(temp
->name
, name
, sizeof(temp
->name
));
2153 strlcpy(temp
->spec
, spec
, sizeof(temp
->spec
));
2154 strlcpy(temp
->text
, text
, sizeof(temp
->text
));
2155 temp
->value
= (char *)value
;
2158 * Add the attribute to the sorted array...
2161 cupsArrayAdd(ppd
->sorted_attrs
, temp
);
2164 * Return the attribute...
2172 * 'ppd_add_choice()' - Add a choice to an option.
2175 static ppd_choice_t
* /* O - Named choice */
2176 ppd_add_choice(ppd_option_t
*option
, /* I - Option */
2177 const char *name
) /* I - Name of choice */
2179 ppd_choice_t
*choice
; /* Choice */
2182 if (option
->num_choices
== 0)
2183 choice
= malloc(sizeof(ppd_choice_t
));
2185 choice
= realloc(option
->choices
,
2186 sizeof(ppd_choice_t
) * (option
->num_choices
+ 1));
2191 option
->choices
= choice
;
2192 choice
+= option
->num_choices
;
2193 option
->num_choices
++;
2195 memset(choice
, 0, sizeof(ppd_choice_t
));
2196 strlcpy(choice
->choice
, name
, sizeof(choice
->choice
));
2203 * 'ppd_add_size()' - Add a page size.
2206 static ppd_size_t
* /* O - Named size */
2207 ppd_add_size(ppd_file_t
*ppd
, /* I - PPD file */
2208 const char *name
) /* I - Name of size */
2210 ppd_size_t
*size
; /* Size */
2213 if (ppd
->num_sizes
== 0)
2214 size
= malloc(sizeof(ppd_size_t
));
2216 size
= realloc(ppd
->sizes
, sizeof(ppd_size_t
) * (ppd
->num_sizes
+ 1));
2222 size
+= ppd
->num_sizes
;
2225 memset(size
, 0, sizeof(ppd_size_t
));
2226 strlcpy(size
->name
, name
, sizeof(size
->name
));
2233 * 'ppd_compare_attrs()' - Compare two attributes.
2236 static int /* O - Result of comparison */
2237 ppd_compare_attrs(ppd_attr_t
*a
, /* I - First attribute */
2238 ppd_attr_t
*b
) /* I - Second attribute */
2240 int ret
; /* Result of comparison */
2243 if ((ret
= strcasecmp(a
->name
, b
->name
)) != 0)
2246 return (strcasecmp(a
->spec
, b
->spec
));
2251 * 'ppd_compare_choices()' - Compare two choices...
2254 static int /* O - Result of comparison */
2255 ppd_compare_choices(ppd_choice_t
*a
, /* I - First choice */
2256 ppd_choice_t
*b
) /* I - Second choice */
2258 return (a
->option
- b
->option
);
2263 * 'ppd_compare_consts()' - Compare two constraints.
2266 static int /* O - Result of comparison */
2267 ppd_compare_consts(ppd_const_t
*a
, /* I - First constraint */
2268 ppd_const_t
*b
) /* I - Second constraint */
2270 int ret
; /* Result of comparison */
2273 if ((ret
= strcmp(a
->option1
, b
->option1
)) != 0)
2275 else if ((ret
= strcmp(a
->choice1
, b
->choice1
)) != 0)
2277 else if ((ret
= strcmp(a
->option2
, b
->option2
)) != 0)
2280 return (strcmp(a
->choice2
, b
->choice2
));
2285 * 'ppd_compare_coptions()' - Compare two custom options.
2288 static int /* O - Result of comparison */
2289 ppd_compare_coptions(ppd_coption_t
*a
, /* I - First option */
2290 ppd_coption_t
*b
) /* I - Second option */
2292 return (strcasecmp(a
->keyword
, b
->keyword
));
2297 * 'ppd_compare_cparams()' - Compare two custom parameters.
2300 static int /* O - Result of comparison */
2301 ppd_compare_cparams(ppd_cparam_t
*a
, /* I - First parameter */
2302 ppd_cparam_t
*b
) /* I - Second parameter */
2304 return (strcasecmp(a
->name
, b
->name
));
2309 * 'ppd_compare_options()' - Compare two options.
2312 static int /* O - Result of comparison */
2313 ppd_compare_options(ppd_option_t
*a
, /* I - First option */
2314 ppd_option_t
*b
) /* I - Second option */
2316 return (strcasecmp(a
->keyword
, b
->keyword
));
2321 * 'ppd_decode()' - Decode a string value...
2324 static int /* O - Length of decoded string */
2325 ppd_decode(char *string
) /* I - String to decode */
2327 char *inptr
, /* Input pointer */
2328 *outptr
; /* Output pointer */
2334 while (*inptr
!= '\0')
2335 if (*inptr
== '<' && isxdigit(inptr
[1] & 255))
2338 * Convert hex to 8-bit values...
2342 while (isxdigit(*inptr
& 255))
2344 if (isalpha(*inptr
))
2345 *outptr
= (tolower(*inptr
) - 'a' + 10) << 4;
2347 *outptr
= (*inptr
- '0') << 4;
2351 if (!isxdigit(*inptr
& 255))
2354 if (isalpha(*inptr
))
2355 *outptr
|= tolower(*inptr
) - 'a' + 10;
2357 *outptr
|= *inptr
- '0';
2363 while (*inptr
!= '>' && *inptr
!= '\0')
2365 while (*inptr
== '>')
2369 *outptr
++ = *inptr
++;
2373 return ((int)(outptr
- string
));
2378 * 'ppd_free_group()' - Free a single UI group.
2382 ppd_free_group(ppd_group_t
*group
) /* I - Group to free */
2384 int i
; /* Looping var */
2385 ppd_option_t
*option
; /* Current option */
2386 ppd_group_t
*subgroup
; /* Current sub-group */
2389 if (group
->num_options
> 0)
2391 for (i
= group
->num_options
, option
= group
->options
;
2394 ppd_free_option(option
);
2396 ppd_free(group
->options
);
2399 if (group
->num_subgroups
> 0)
2401 for (i
= group
->num_subgroups
, subgroup
= group
->subgroups
;
2404 ppd_free_group(subgroup
);
2406 ppd_free(group
->subgroups
);
2412 * 'ppd_free_option()' - Free a single option.
2416 ppd_free_option(ppd_option_t
*option
) /* I - Option to free */
2418 int i
; /* Looping var */
2419 ppd_choice_t
*choice
; /* Current choice */
2422 if (option
->num_choices
> 0)
2424 for (i
= option
->num_choices
, choice
= option
->choices
;
2428 ppd_free(choice
->code
);
2431 ppd_free(option
->choices
);
2437 * 'ppd_get_coption()' - Get a custom option record.
2440 static ppd_coption_t
* /* O - Custom option... */
2441 ppd_get_coption(ppd_file_t
*ppd
, /* I - PPD file */
2442 const char *name
) /* I - Name of option */
2444 ppd_coption_t
*copt
; /* New custom option */
2448 * See if the option already exists...
2451 if ((copt
= ppdFindCustomOption(ppd
, name
)) != NULL
)
2455 * Not found, so create the custom option record...
2458 if ((copt
= calloc(1, sizeof(ppd_coption_t
))) == NULL
)
2461 strlcpy(copt
->keyword
, name
, sizeof(copt
->keyword
));
2463 copt
->params
= cupsArrayNew((cups_array_func_t
)ppd_compare_cparams
, NULL
);
2465 cupsArrayAdd(ppd
->coptions
, copt
);
2468 * Return the new record...
2476 * 'ppd_get_cparam()' - Get a custom parameter record.
2479 static ppd_cparam_t
* /* O - Extended option... */
2480 ppd_get_cparam(ppd_coption_t
*opt
, /* I - PPD file */
2481 const char *param
, /* I - Name of parameter */
2482 const char *text
) /* I - Human-readable text */
2484 ppd_cparam_t
*cparam
; /* New custom parameter */
2488 * See if the parameter already exists...
2491 if ((cparam
= ppdFindCustomParam(opt
, param
)) != NULL
)
2495 * Not found, so create the custom parameter record...
2498 if ((cparam
= calloc(1, sizeof(ppd_cparam_t
))) == NULL
)
2501 strlcpy(cparam
->name
, param
, sizeof(cparam
->name
));
2502 strlcpy(cparam
->text
, text
[0] ? text
: param
, sizeof(cparam
->text
));
2505 * Add this record to the array...
2508 cupsArrayAdd(opt
->params
, cparam
);
2511 * Return the new record...
2519 * 'ppd_get_group()' - Find or create the named group as needed.
2522 static ppd_group_t
* /* O - Named group */
2523 ppd_get_group(ppd_file_t
*ppd
, /* I - PPD file */
2524 const char *name
, /* I - Name of group */
2525 const char *text
, /* I - Text for group */
2526 _cups_globals_t
*cg
, /* I - Global data */
2527 cups_encoding_t encoding
) /* I - Encoding of text */
2529 int i
; /* Looping var */
2530 ppd_group_t
*group
; /* Group */
2533 DEBUG_printf(("ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)\n",
2534 ppd
, name
, text
, cg
));
2536 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
2537 if (!strcmp(group
->name
, name
))
2542 DEBUG_printf(("Adding group %s...\n", name
));
2544 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&& strlen(text
) >= sizeof(group
->text
))
2546 cg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
2551 if (ppd
->num_groups
== 0)
2552 group
= malloc(sizeof(ppd_group_t
));
2554 group
= realloc(ppd
->groups
,
2555 (ppd
->num_groups
+ 1) * sizeof(ppd_group_t
));
2559 cg
->ppd_status
= PPD_ALLOC_ERROR
;
2564 ppd
->groups
= group
;
2565 group
+= ppd
->num_groups
;
2568 memset(group
, 0, sizeof(ppd_group_t
));
2569 strlcpy(group
->name
, name
, sizeof(group
->name
));
2571 cupsCharsetToUTF8((cups_utf8_t
*)group
->text
, text
,
2572 sizeof(group
->text
), encoding
);
2580 * 'ppd_get_option()' - Find or create the named option as needed.
2583 static ppd_option_t
* /* O - Named option */
2584 ppd_get_option(ppd_group_t
*group
, /* I - Group */
2585 const char *name
) /* I - Name of option */
2587 int i
; /* Looping var */
2588 ppd_option_t
*option
; /* Option */
2591 DEBUG_printf(("ppd_get_option(group=%p(\"%s\"), name=\"%s\")\n",
2592 group
, group
->name
, name
));
2594 for (i
= group
->num_options
, option
= group
->options
; i
> 0; i
--, option
++)
2595 if (!strcmp(option
->keyword
, name
))
2600 if (group
->num_options
== 0)
2601 option
= malloc(sizeof(ppd_option_t
));
2603 option
= realloc(group
->options
,
2604 (group
->num_options
+ 1) * sizeof(ppd_option_t
));
2609 group
->options
= option
;
2610 option
+= group
->num_options
;
2611 group
->num_options
++;
2613 memset(option
, 0, sizeof(ppd_option_t
));
2614 strlcpy(option
->keyword
, name
, sizeof(option
->keyword
));
2622 * 'ppd_hash_option()' - Generate a hash of the option name...
2625 static int /* O - Hash index */
2626 ppd_hash_option(ppd_option_t
*option
) /* I - Option */
2628 int hash
= 0; /* Hash index */
2629 const char *k
; /* Pointer into keyword */
2632 for (hash
= option
->keyword
[0], k
= option
->keyword
+ 1; *k
;)
2633 hash
= 33 * hash
+ *k
++;
2635 return (hash
& 511);
2640 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2644 static int /* O - Bitmask of fields read */
2645 ppd_read(cups_file_t
*fp
, /* I - File to read from */
2646 char *keyword
, /* O - Keyword from line */
2647 char *option
, /* O - Option from line */
2648 char *text
, /* O - Human-readable text from line */
2649 char **string
, /* O - Code/string data */
2650 int ignoreblank
, /* I - Ignore blank lines? */
2651 _cups_globals_t
*cg
) /* I - Global data */
2653 int ch
, /* Character from file */
2654 col
, /* Column in line */
2655 colon
, /* Colon seen? */
2656 endquote
, /* Waiting for an end quote */
2657 mask
, /* Mask to be returned */
2658 startline
, /* Start line */
2659 textlen
; /* Length of text */
2660 char *keyptr
, /* Keyword pointer */
2661 *optptr
, /* Option pointer */
2662 *textptr
, /* Text pointer */
2663 *strptr
, /* Pointer into string */
2664 *lineptr
, /* Current position in line buffer */
2665 *line
; /* Line buffer */
2666 int linesize
; /* Current size of line buffer */
2669 * Range check everything...
2672 if (!fp
|| !keyword
|| !option
|| !text
|| !string
)
2676 * Now loop until we have a valid line...
2681 startline
= cg
->ppd_line
+ 1;
2683 line
= malloc(linesize
);
2698 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2700 if (lineptr
>= (line
+ linesize
- 1))
2703 * Expand the line buffer...
2706 char *temp
; /* Temporary line pointer */
2710 if (linesize
> 262144)
2713 * Don't allow lines longer than 256k!
2716 cg
->ppd_line
= startline
;
2717 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2724 temp
= realloc(line
, linesize
);
2727 cg
->ppd_line
= startline
;
2728 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2735 lineptr
= temp
+ (lineptr
- line
);
2739 if (ch
== '\r' || ch
== '\n')
2742 * Line feed or carriage return...
2751 * Check for a trailing line feed...
2754 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2761 cupsFileGetChar(fp
);
2764 if (lineptr
== line
&& ignoreblank
)
2765 continue; /* Skip blank lines */
2769 if (!endquote
) /* Continue for multi-line text */
2774 else if (ch
< ' ' && ch
!= '\t' && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2777 * Other control characters...
2780 cg
->ppd_line
= startline
;
2781 cg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
2787 else if (ch
!= 0x1a)
2790 * Any other character...
2796 if (col
> (PPD_MAX_LINE
- 1))
2799 * Line is too long...
2802 cg
->ppd_line
= startline
;
2803 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2810 if (ch
== ':' && strncmp(line
, "*%", 2) != 0)
2813 if (ch
== '\"' && colon
)
2814 endquote
= !endquote
;
2821 * Didn't finish this quoted string...
2824 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2827 else if (ch
== '\r' || ch
== '\n')
2835 * Check for a trailing line feed...
2838 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2841 cupsFileGetChar(fp
);
2846 else if (ch
< ' ' && ch
!= '\t' && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2849 * Other control characters...
2852 cg
->ppd_line
= startline
;
2853 cg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
2859 else if (ch
!= 0x1a)
2863 if (col
> (PPD_MAX_LINE
- 1))
2866 * Line is too long...
2869 cg
->ppd_line
= startline
;
2870 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2882 * Didn't finish this line...
2885 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2886 if (ch
== '\r' || ch
== '\n')
2889 * Line feed or carriage return...
2898 * Check for a trailing line feed...
2901 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2904 cupsFileGetChar(fp
);
2909 else if (ch
< ' ' && ch
!= '\t' && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2912 * Other control characters...
2915 cg
->ppd_line
= startline
;
2916 cg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
2922 else if (ch
!= 0x1a)
2926 if (col
> (PPD_MAX_LINE
- 1))
2929 * Line is too long...
2932 cg
->ppd_line
= startline
;
2933 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2942 if (lineptr
> line
&& lineptr
[-1] == '\n')
2947 DEBUG_printf(("LINE = \"%s\"\n", line
));
2950 * The dynamically created PPDs for older style Mac OS X
2951 * drivers include a large blob of data inserted as comments
2952 * at the end of the file. As an optimization we can stop
2953 * reading the PPD when we get to the start of this data.
2956 if (!strcmp(line
, "*%APLWORKSET START"))
2962 if (ch
== EOF
&& lineptr
== line
)
2980 if ((!line
[0] || /* Blank line */
2981 !strncmp(line
, "*%", 2) || /* Comment line */
2982 !strcmp(line
, "*End")) && /* End of multi-line string */
2983 ignoreblank
) /* Ignore these? */
2985 startline
= cg
->ppd_line
+ 1;
2989 if (!strcmp(line
, "*")) /* (Bad) comment line */
2991 if (cg
->ppd_conform
== PPD_CONFORM_RELAXED
)
2993 startline
= cg
->ppd_line
+ 1;
2998 cg
->ppd_line
= startline
;
2999 cg
->ppd_status
= PPD_ILLEGAL_MAIN_KEYWORD
;
3006 if (line
[0] != '*') /* All lines start with an asterisk */
3009 * Allow lines consisting of just whitespace...
3012 for (lineptr
= line
; *lineptr
; lineptr
++)
3013 if (!isspace(*lineptr
& 255))
3018 cg
->ppd_status
= PPD_MISSING_ASTERISK
;
3022 else if (ignoreblank
)
3037 while (*lineptr
!= '\0' && *lineptr
!= ':' && !isspace(*lineptr
& 255))
3039 if (*lineptr
<= ' ' || *lineptr
> 126 || *lineptr
== '/' ||
3040 (keyptr
- keyword
) >= (PPD_MAX_NAME
- 1))
3042 cg
->ppd_status
= PPD_ILLEGAL_MAIN_KEYWORD
;
3047 *keyptr
++ = *lineptr
++;
3052 if (!strcmp(keyword
, "End"))
3055 mask
|= PPD_KEYWORD
;
3057 /* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
3059 if (isspace(*lineptr
& 255))
3062 * Get an option name...
3065 while (isspace(*lineptr
& 255))
3070 while (*lineptr
!= '\0' && !isspace(*lineptr
& 255) && *lineptr
!= ':' &&
3073 if (*lineptr
<= ' ' || *lineptr
> 126 ||
3074 (optptr
- option
) >= (PPD_MAX_NAME
- 1))
3076 cg
->ppd_status
= PPD_ILLEGAL_OPTION_KEYWORD
;
3081 *optptr
++ = *lineptr
++;
3086 if (isspace(*lineptr
& 255) && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
3088 cg
->ppd_status
= PPD_ILLEGAL_WHITESPACE
;
3093 while (isspace(*lineptr
& 255))
3098 /* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
3100 if (*lineptr
== '/')
3103 * Get human-readable text...
3110 while (*lineptr
!= '\0' && *lineptr
!= '\n' && *lineptr
!= ':')
3112 if (((unsigned char)*lineptr
< ' ' && *lineptr
!= '\t') ||
3113 (textptr
- text
) >= (PPD_MAX_LINE
- 1))
3115 cg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
3120 *textptr
++ = *lineptr
++;
3124 textlen
= ppd_decode(text
);
3126 if (textlen
> PPD_MAX_TEXT
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
3128 cg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
3136 /* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
3139 if (isspace(*lineptr
& 255) && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
3141 cg
->ppd_status
= PPD_ILLEGAL_WHITESPACE
;
3146 while (isspace(*lineptr
& 255))
3149 if (*lineptr
== ':')
3152 * Get string after triming leading and trailing whitespace...
3156 while (isspace(*lineptr
& 255))
3159 strptr
= lineptr
+ strlen(lineptr
) - 1;
3160 while (strptr
>= lineptr
&& isspace(*strptr
& 255))
3163 if (*strptr
== '\"')
3166 * Quoted string by itself...
3169 *string
= malloc(strlen(lineptr
) + 1);
3173 for (; *lineptr
!= '\0'; lineptr
++)
3174 if (*lineptr
!= '\"')
3175 *strptr
++ = *lineptr
;
3180 *string
= strdup(lineptr
);
3182 /* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
3196 * End of "$Id: ppd.c 6586 2007-06-21 17:44:22Z mike $".