2 * "$Id: ppd.c 5119 2006-02-16 15:52:06Z mike $"
4 * PPD file routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2006 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 * ppdLastError() - Return the status from the last ppdOpen*().
40 * ppdOpen() - Read a PPD file into memory.
41 * ppdOpen2() - Read a PPD file into memory.
42 * ppdOpenFd() - Read a PPD file into memory.
43 * ppdOpenFile() - Read a PPD file into memory.
44 * ppdSetConformance() - Set the conformance level for PPD files.
45 * ppd_add_attr() - Add an attribute to the PPD data.
46 * ppd_add_choice() - Add a choice to an option.
47 * ppd_add_size() - Add a page size.
48 * ppd_compare_attrs() - Compare two attributes.
49 * ppd_compare_coptions() - Compare two custom options.
50 * ppd_compare_cparams() - Compare two custom parameters.
51 * ppd_compare_options() - Compare two options.
52 * ppd_decode() - Decode a string value...
53 * ppd_free_group() - Free a single UI group.
54 * ppd_free_option() - Free a single option.
55 * ppd_get_coption() - Get a custom option record.
56 * ppd_get_cparam() - Get a custom parameter record.
57 * ppd_get_group() - Find or create the named group as needed.
58 * ppd_get_option() - Find or create the named option as needed.
59 * ppd_read() - Read a line from a PPD file, skipping comment
64 * Include necessary headers.
76 #if defined(WIN32) || defined(__EMX__)
77 # define READ_BINARY "rb" /* Open a binary file for reading */
78 # define WRITE_BINARY "wb" /* Open a binary file for writing */
80 # define READ_BINARY "r" /* Open a binary file for reading */
81 # define WRITE_BINARY "w" /* Open a binary file for writing */
82 #endif /* WIN32 || __EMX__ */
84 #define ppd_free(p) if (p) free(p) /* Safe free macro */
86 #define PPD_KEYWORD 1 /* Line contained a keyword */
87 #define PPD_OPTION 2 /* Line contained an option name */
88 #define PPD_TEXT 4 /* Line contained human-readable text */
89 #define PPD_STRING 8 /* Line contained a string or code */
96 static ppd_attr_t
*ppd_add_attr(ppd_file_t
*ppd
, const char *name
,
97 const char *spec
, const char *text
,
99 static ppd_choice_t
*ppd_add_choice(ppd_option_t
*option
, const char *name
);
100 static ppd_size_t
*ppd_add_size(ppd_file_t
*ppd
, const char *name
);
101 static int ppd_compare_attrs(ppd_attr_t
*a
, ppd_attr_t
*b
);
102 static int ppd_compare_coptions(ppd_coption_t
*a
,
104 static int ppd_compare_cparams(ppd_cparam_t
*a
, ppd_cparam_t
*b
);
105 static int ppd_compare_options(ppd_option_t
*a
, ppd_option_t
*b
);
106 static int ppd_decode(char *string
);
107 static void ppd_free_group(ppd_group_t
*group
);
108 static void ppd_free_option(ppd_option_t
*option
);
109 static ppd_coption_t
*ppd_get_coption(ppd_file_t
*ppd
, const char *name
);
110 static ppd_cparam_t
*ppd_get_cparam(ppd_coption_t
*opt
,
113 static ppd_group_t
*ppd_get_group(ppd_file_t
*ppd
, const char *name
,
114 const char *text
, _cups_globals_t
*cg
);
115 static ppd_option_t
*ppd_get_option(ppd_group_t
*group
, const char *name
);
116 static int ppd_read(cups_file_t
*fp
, char *keyword
, char *option
,
117 char *text
, char **string
, int ignoreblank
,
118 _cups_globals_t
*cg
);
122 * 'ppdClose()' - Free all memory used by the PPD file.
126 ppdClose(ppd_file_t
*ppd
) /* I - PPD file record */
128 int i
; /* Looping var */
129 ppd_emul_t
*emul
; /* Current emulation */
130 ppd_group_t
*group
; /* Current group */
131 char **font
; /* Current font */
132 char **filter
; /* Current filter */
133 ppd_attr_t
**attr
; /* Current attribute */
134 ppd_coption_t
*coption
; /* Current custom option */
135 ppd_cparam_t
*cparam
; /* Current custom parameter */
139 * Range check arguments...
146 * Free all strings at the top level...
149 ppd_free(ppd
->patches
);
150 ppd_free(ppd
->jcl_begin
);
151 ppd_free(ppd
->jcl_end
);
152 ppd_free(ppd
->jcl_ps
);
155 * Free any emulations...
158 if (ppd
->num_emulations
> 0)
160 for (i
= ppd
->num_emulations
, emul
= ppd
->emulations
; i
> 0; i
--, emul
++)
162 ppd_free(emul
->start
);
163 ppd_free(emul
->stop
);
166 ppd_free(ppd
->emulations
);
170 * Free any UI groups, subgroups, and options...
173 if (ppd
->num_groups
> 0)
175 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
176 ppd_free_group(group
);
178 ppd_free(ppd
->groups
);
181 cupsArrayDelete(ppd
->options
);
184 * Free any page sizes...
187 if (ppd
->num_sizes
> 0)
188 ppd_free(ppd
->sizes
);
191 * Free any constraints...
194 if (ppd
->num_consts
> 0)
195 ppd_free(ppd
->consts
);
198 * Free any filters...
201 if (ppd
->num_filters
> 0)
203 for (i
= ppd
->num_filters
, filter
= ppd
->filters
; i
> 0; i
--, filter
++)
208 ppd_free(ppd
->filters
);
215 if (ppd
->num_fonts
> 0)
217 for (i
= ppd
->num_fonts
, font
= ppd
->fonts
; i
> 0; i
--, font
++)
222 ppd_free(ppd
->fonts
);
226 * Free any profiles...
229 if (ppd
->num_profiles
> 0)
230 ppd_free(ppd
->profiles
);
233 * Free any attributes...
236 if (ppd
->num_attrs
> 0)
238 for (i
= ppd
->num_attrs
, attr
= ppd
->attrs
; i
> 0; i
--, attr
++)
240 ppd_free((*attr
)->value
);
244 ppd_free(ppd
->attrs
);
248 * Free custom options...
251 for (coption
= (ppd_coption_t
*)cupsArrayFirst(ppd
->coptions
);
253 coption
= (ppd_coption_t
*)cupsArrayNext(ppd
->coptions
))
255 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
257 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
259 switch (cparam
->type
)
261 case PPD_CUSTOM_PASSCODE
:
262 case PPD_CUSTOM_PASSWORD
:
263 case PPD_CUSTOM_STRING
:
264 ppd_free(cparam
->current
.custom_string
);
265 ppd_free(cparam
->minimum
.custom_string
);
266 ppd_free(cparam
->maximum
.custom_string
);
276 cupsArrayDelete(coption
->params
);
281 cupsArrayDelete(ppd
->coptions
);
284 * Free the whole record...
292 * 'ppdErrorString()' - Returns the text assocated with a status.
294 * @since CUPS 1.1.19@
297 const char * /* O - Status string */
298 ppdErrorString(ppd_status_t status
) /* I - PPD status */
300 static const char * const messages
[] =/* Status messages */
303 _("Unable to open PPD file"),
304 _("NULL PPD file pointer"),
305 _("Memory allocation error"),
306 _("Missing PPD-Adobe-4.x header"),
307 _("Missing value string"),
310 _("OpenGroup without a CloseGroup first"),
311 _("Bad OpenUI/JCLOpenUI"),
312 _("OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"),
313 _("Bad OrderDependency"),
314 _("Bad UIConstraints"),
315 _("Missing asterisk in column 1"),
316 _("Line longer than the maximum allowed (255 characters)"),
317 _("Illegal control character"),
318 _("Illegal main keyword string"),
319 _("Illegal option keyword string"),
320 _("Illegal translation string"),
321 _("Illegal whitespace character"),
322 _("Bad custom parameter")
326 if (status
< PPD_OK
|| status
> PPD_ILLEGAL_WHITESPACE
)
327 return (_cupsLangString(cupsLangDefault(), _("Unknown")));
329 return (_cupsLangString(cupsLangDefault(), messages
[status
]));
334 * 'ppdLastError()' - Return the status from the last ppdOpen*().
336 * @since CUPS 1.1.19@
339 ppd_status_t
/* O - Status code */
340 ppdLastError(int *line
) /* O - Line number */
342 _cups_globals_t
*cg
= _cupsGlobals();
347 *line
= cg
->ppd_line
;
349 return (cg
->ppd_status
);
354 * 'ppdOpen()' - Read a PPD file into memory.
357 ppd_file_t
* /* O - PPD file record */
358 ppdOpen(FILE *fp
) /* I - File to read from */
360 ppd_file_t
*ppd
; /* PPD file record */
361 cups_file_t
*cf
; /* CUPS file */
365 * Reopen the stdio file as a CUPS file...
368 if ((cf
= cupsFileOpenFd(fileno(fp
), "r")) == NULL
)
372 * Load the PPD file using the newer API...
378 * Close the CUPS file and return the PPD...
388 * 'ppdOpen2()' - Read a PPD file into memory.
393 ppd_file_t
* /* O - PPD file record */
394 ppdOpen2(cups_file_t
*fp
) /* I - File to read from */
396 char *oldlocale
; /* Old locale settings */
397 int i
, j
, k
; /* Looping vars */
398 int count
; /* Temporary count */
399 ppd_file_t
*ppd
; /* PPD file record */
400 ppd_group_t
*group
, /* Current group */
401 *subgroup
; /* Current sub-group */
402 ppd_option_t
*option
; /* Current option */
403 ppd_choice_t
*choice
; /* Current choice */
404 ppd_const_t
*constraint
; /* Current constraint */
405 ppd_size_t
*size
; /* Current page size */
406 int mask
; /* Line data mask */
407 char keyword
[PPD_MAX_NAME
],
408 /* Keyword from file */
410 /* Option from file */
412 /* Human-readable text from file */
413 *string
, /* Code/text from file */
414 *sptr
, /* Pointer into string */
415 *nameptr
, /* Pointer into name */
416 *temp
, /* Temporary string pointer */
417 **tempfonts
; /* Temporary fonts pointer */
418 float order
; /* Order dependency number */
419 ppd_section_t section
; /* Order dependency section */
420 ppd_profile_t
*profile
; /* Pointer to color profile */
421 char **filter
; /* Pointer to filter */
422 cups_lang_t
*language
; /* Default language */
423 int ui_keyword
; /* Is this line a UI keyword? */
424 _cups_globals_t
*cg
= _cupsGlobals();
426 static const char * const ui_keywords
[] =
428 #ifdef CUPS_USE_FULL_UI_KEYWORDS_LIST
430 * Adobe defines some 41 keywords as "UI", meaning that they are
431 * user interface elements and that they should be treated as such
432 * even if the PPD creator doesn't use Open/CloseUI around them.
434 * Since this can cause previously invisible options to appear and
435 * confuse users, the default is to only treat the PageSize and
436 * PageRegion keywords this way.
438 /* Boolean keywords */
448 /* PickOne keywords */
461 "JCLFrameBufferSize",
482 #else /* !CUPS_USE_FULL_UI_KEYWORDS_LIST */
485 #endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */
490 * Default to "OK" status...
493 cg
->ppd_status
= PPD_OK
;
497 * Range check input...
502 cg
->ppd_status
= PPD_NULL_FILE
;
507 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
510 mask
= ppd_read(fp
, keyword
, name
, text
, &string
, 0, cg
);
512 DEBUG_printf(("mask=%x, keyword=\"%s\"...\n", mask
, keyword
));
515 strcmp(keyword
, "PPD-Adobe") ||
516 string
== NULL
|| string
[0] != '4')
519 * Either this is not a PPD file, or it is not a 4.x PPD file.
522 if (cg
->ppd_status
== PPD_OK
)
523 cg
->ppd_status
= PPD_MISSING_PPDADOBE4
;
530 DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword
, string
));
535 * Allocate memory for the PPD file record...
538 if ((ppd
= calloc(1, sizeof(ppd_file_t
))) == NULL
)
540 cg
->ppd_status
= PPD_ALLOC_ERROR
;
545 ppd
->language_level
= 1;
546 ppd
->color_device
= 0;
547 ppd
->colorspace
= PPD_CS_GRAY
;
548 ppd
->landscape
= -90;
549 ppd
->coptions
= cupsArrayNew((cups_array_func_t
)ppd_compare_coptions
,
553 * Get the default language for the user...
556 language
= cupsLangDefault();
559 oldlocale
= _cupsSaveLocale(LC_NUMERIC
, "C");
561 oldlocale
= _cupsSaveLocale(LC_ALL
, "C");
562 #endif /* LC_NUMERIC */
565 * Read lines from the PPD file and add them to the file record...
574 while ((mask
= ppd_read(fp
, keyword
, name
, text
, &string
, 1, cg
)) != 0)
577 printf("mask = %x, keyword = \"%s\"", mask
, keyword
);
580 printf(", name = \"%s\"", name
);
583 printf(", text = \"%s\"", text
);
587 if (strlen(string
) > 40)
588 printf(", string = %p", string
);
590 printf(", string = \"%s\"", string
);
596 if (strcmp(keyword
, "CloseUI") && strcmp(keyword
, "CloseGroup") &&
597 strcmp(keyword
, "CloseSubGroup") && strncmp(keyword
, "Default", 7) &&
598 strcmp(keyword
, "JCLCloseUI") && strcmp(keyword
, "JCLOpenUI") &&
599 strcmp(keyword
, "OpenUI") && strcmp(keyword
, "OpenGroup") &&
600 strcmp(keyword
, "OpenSubGroup") && string
== NULL
)
603 * Need a string value!
606 cg
->ppd_status
= PPD_MISSING_VALUE
;
612 * Certain main keywords (as defined by the PPD spec) may be used
613 * without the usual OpenUI/CloseUI stuff. Presumably this is just
614 * so that Adobe wouldn't completely break compatibility with PPD
615 * files prior to v4.0 of the spec, but it is hopelessly
616 * inconsistent... Catch these main keywords and automatically
617 * create the corresponding option, as needed...
623 * Previous line was a UI keyword...
630 if (option
== NULL
&&
631 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
632 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
))
634 for (i
= 0; i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])); i
++)
635 if (!strcmp(keyword
, ui_keywords
[i
]))
638 if (i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])))
641 * Create the option in the appropriate group...
646 DEBUG_printf(("**** FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!\n",
651 if ((group
= ppd_get_group(ppd
, "General", _("General"), cg
)) == NULL
)
654 DEBUG_printf(("Adding to group %s...\n", group
->text
));
655 option
= ppd_get_option(group
, keyword
);
659 option
= ppd_get_option(group
, keyword
);
663 cg
->ppd_status
= PPD_ALLOC_ERROR
;
669 * Now fill in the initial information for the option...
672 if (!strncmp(keyword
, "JCL", 3))
673 option
->section
= PPD_ORDER_JCL
;
675 option
->section
= PPD_ORDER_ANY
;
677 option
->order
= 10.0f
;
680 option
->ui
= PPD_UI_BOOLEAN
;
682 option
->ui
= PPD_UI_PICKONE
;
684 for (j
= 0; j
< ppd
->num_attrs
; j
++)
685 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
686 !strcmp(ppd
->attrs
[j
]->name
+ 7, keyword
) &&
687 ppd
->attrs
[j
]->value
)
689 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
690 option
->keyword
, ppd
->attrs
[j
]->value
));
691 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
692 sizeof(option
->defchoice
));
696 if (!strcmp(keyword
, "PageSize"))
697 strlcpy(option
->text
, _("Media Size"), sizeof(option
->text
));
698 else if (!strcmp(keyword
, "MediaType"))
699 strlcpy(option
->text
, _("Media Type"), sizeof(option
->text
));
700 else if (!strcmp(keyword
, "InputSlot"))
701 strlcpy(option
->text
, _("Media Source"), sizeof(option
->text
));
702 else if (!strcmp(keyword
, "ColorModel"))
703 strlcpy(option
->text
, _("Output Mode"), sizeof(option
->text
));
704 else if (!strcmp(keyword
, "Resolution"))
705 strlcpy(option
->text
, _("Resolution"), sizeof(option
->text
));
707 strlcpy(option
->text
, keyword
, sizeof(option
->text
));
711 if (!strcmp(keyword
, "LanguageLevel"))
712 ppd
->language_level
= atoi(string
);
713 else if (!strcmp(keyword
, "LanguageEncoding"))
714 ppd
->lang_encoding
= string
;
715 else if (!strcmp(keyword
, "LanguageVersion"))
716 ppd
->lang_version
= string
;
717 else if (!strcmp(keyword
, "Manufacturer"))
718 ppd
->manufacturer
= string
;
719 else if (!strcmp(keyword
, "ModelName"))
720 ppd
->modelname
= string
;
721 else if (!strcmp(keyword
, "Protocols"))
722 ppd
->protocols
= string
;
723 else if (!strcmp(keyword
, "PCFileName"))
724 ppd
->pcfilename
= string
;
725 else if (!strcmp(keyword
, "NickName"))
726 ppd
->nickname
= string
;
727 else if (!strcmp(keyword
, "Product"))
728 ppd
->product
= string
;
729 else if (!strcmp(keyword
, "ShortNickName"))
730 ppd
->shortnickname
= string
;
731 else if (!strcmp(keyword
, "TTRasterizer"))
732 ppd
->ttrasterizer
= string
;
733 else if (!strcmp(keyword
, "JCLBegin"))
735 ppd
->jcl_begin
= strdup(string
);
736 ppd_decode(ppd
->jcl_begin
); /* Decode quoted string */
738 else if (!strcmp(keyword
, "JCLEnd"))
740 ppd
->jcl_end
= strdup(string
);
741 ppd_decode(ppd
->jcl_end
); /* Decode quoted string */
743 else if (!strcmp(keyword
, "JCLToPSInterpreter"))
745 ppd
->jcl_ps
= strdup(string
);
746 ppd_decode(ppd
->jcl_ps
); /* Decode quoted string */
748 else if (!strcmp(keyword
, "AccurateScreensSupport"))
749 ppd
->accurate_screens
= !strcmp(string
, "True");
750 else if (!strcmp(keyword
, "ColorDevice"))
751 ppd
->color_device
= !strcmp(string
, "True");
752 else if (!strcmp(keyword
, "ContoneOnly"))
753 ppd
->contone_only
= !strcmp(string
, "True");
754 else if (!strcmp(keyword
, "cupsFlipDuplex"))
755 ppd
->flip_duplex
= !strcmp(string
, "True");
756 else if (!strcmp(keyword
, "cupsManualCopies"))
757 ppd
->manual_copies
= !strcmp(string
, "True");
758 else if (!strcmp(keyword
, "cupsModelNumber"))
759 ppd
->model_number
= atoi(string
);
760 else if (!strcmp(keyword
, "cupsColorProfile"))
762 if (ppd
->num_profiles
== 0)
763 profile
= malloc(sizeof(ppd_profile_t
));
765 profile
= realloc(ppd
->profiles
, sizeof(ppd_profile_t
) *
766 (ppd
->num_profiles
+ 1));
768 ppd
->profiles
= profile
;
769 profile
+= ppd
->num_profiles
;
770 ppd
->num_profiles
++;
772 memset(profile
, 0, sizeof(ppd_profile_t
));
773 strlcpy(profile
->resolution
, name
, sizeof(profile
->resolution
));
774 strlcpy(profile
->media_type
, text
, sizeof(profile
->media_type
));
775 sscanf(string
, "%f%f%f%f%f%f%f%f%f%f%f", &(profile
->density
),
777 profile
->matrix
[0] + 0, profile
->matrix
[0] + 1,
778 profile
->matrix
[0] + 2, profile
->matrix
[1] + 0,
779 profile
->matrix
[1] + 1, profile
->matrix
[1] + 2,
780 profile
->matrix
[2] + 0, profile
->matrix
[2] + 1,
781 profile
->matrix
[2] + 2);
783 else if (!strcmp(keyword
, "cupsFilter"))
785 if (ppd
->num_filters
== 0)
786 filter
= malloc(sizeof(char *));
788 filter
= realloc(ppd
->filters
, sizeof(char *) * (ppd
->num_filters
+ 1));
794 cg
->ppd_status
= PPD_ALLOC_ERROR
;
799 ppd
->filters
= filter
;
800 filter
+= ppd
->num_filters
;
804 * Copy filter string and prevent it from being freed below...
810 else if (!strcmp(keyword
, "Throughput"))
811 ppd
->throughput
= atoi(string
);
812 else if (!strcmp(keyword
, "Font"))
815 * Add this font to the list of available fonts...
818 if (ppd
->num_fonts
== 0)
819 tempfonts
= (char **)malloc(sizeof(char *));
821 tempfonts
= (char **)realloc(ppd
->fonts
,
822 sizeof(char *) * (ppd
->num_fonts
+ 1));
824 if (tempfonts
== NULL
)
826 cg
->ppd_status
= PPD_ALLOC_ERROR
;
831 ppd
->fonts
= tempfonts
;
832 ppd
->fonts
[ppd
->num_fonts
] = strdup(name
);
836 else if (!strcmp(keyword
, "ParamCustomPageSize"))
838 if (!strcmp(name
, "Width"))
839 sscanf(string
, "%*s%*s%f%f", ppd
->custom_min
+ 0,
840 ppd
->custom_max
+ 0);
841 else if (!strcmp(name
, "Height"))
842 sscanf(string
, "%*s%*s%f%f", ppd
->custom_min
+ 1,
843 ppd
->custom_max
+ 1);
846 else if (!strncmp(keyword
, "ParamCustom", 11))
848 ppd_coption_t
*coption
; /* Custom option */
849 ppd_cparam_t
*cparam
; /* Custom parameter */
850 int corder
; /* Order number */
851 char ctype
[33], /* Data type */
852 cminimum
[65], /* Minimum value */
853 cmaximum
[65]; /* Maximum value */
857 * Get the custom option and parameter...
860 if ((coption
= ppd_get_coption(ppd
, keyword
+ 11)) == NULL
)
862 cg
->ppd_status
= PPD_ALLOC_ERROR
;
867 if ((cparam
= ppd_get_cparam(coption
, name
, text
)) == NULL
)
869 cg
->ppd_status
= PPD_ALLOC_ERROR
;
875 * Get the parameter data...
878 if (sscanf(string
, "%d%32s%64s%64s", &corder
, ctype
, cminimum
,
881 cg
->ppd_status
= PPD_BAD_CUSTOM_PARAM
;
886 cparam
->order
= corder
;
888 if (!strcmp(ctype
, "curve"))
890 cparam
->type
= PPD_CUSTOM_CURVE
;
891 cparam
->minimum
.custom_curve
= atof(cminimum
);
892 cparam
->maximum
.custom_curve
= atof(cmaximum
);
894 else if (!strcmp(ctype
, "int"))
896 cparam
->type
= PPD_CUSTOM_INT
;
897 cparam
->minimum
.custom_int
= atoi(cminimum
);
898 cparam
->maximum
.custom_int
= atoi(cmaximum
);
900 else if (!strcmp(ctype
, "invcurve"))
902 cparam
->type
= PPD_CUSTOM_INVCURVE
;
903 cparam
->minimum
.custom_invcurve
= atof(cminimum
);
904 cparam
->maximum
.custom_invcurve
= atof(cmaximum
);
906 else if (!strcmp(ctype
, "passcode"))
908 cparam
->type
= PPD_CUSTOM_PASSCODE
;
909 cparam
->minimum
.custom_passcode
= strdup(cminimum
);
910 cparam
->maximum
.custom_passcode
= strdup(cmaximum
);
912 else if (!strcmp(ctype
, "password"))
914 cparam
->type
= PPD_CUSTOM_PASSWORD
;
915 cparam
->minimum
.custom_password
= strdup(cminimum
);
916 cparam
->maximum
.custom_password
= strdup(cmaximum
);
918 else if (!strcmp(ctype
, "points"))
920 cparam
->type
= PPD_CUSTOM_POINTS
;
921 cparam
->minimum
.custom_points
= atof(cminimum
);
922 cparam
->maximum
.custom_points
= atof(cmaximum
);
924 else if (!strcmp(ctype
, "real"))
926 cparam
->type
= PPD_CUSTOM_REAL
;
927 cparam
->minimum
.custom_real
= atof(cminimum
);
928 cparam
->maximum
.custom_real
= atof(cmaximum
);
930 else if (!strcmp(ctype
, "string"))
932 cparam
->type
= PPD_CUSTOM_STRING
;
933 cparam
->minimum
.custom_string
= strdup(cminimum
);
934 cparam
->maximum
.custom_string
= strdup(cmaximum
);
938 cg
->ppd_status
= PPD_BAD_CUSTOM_PARAM
;
944 * Now special-case for CustomPageSize...
947 if (!strcmp(coption
->keyword
, "PageSize"))
949 if (!strcmp(name
, "Width"))
951 ppd
->custom_min
[0] = cparam
->minimum
.custom_points
;
952 ppd
->custom_max
[0] = cparam
->maximum
.custom_points
;
954 else if (!strcmp(name
, "Height"))
956 ppd
->custom_min
[1] = cparam
->minimum
.custom_points
;
957 ppd
->custom_max
[1] = cparam
->maximum
.custom_points
;
961 else if (!strcmp(keyword
, "HWMargins"))
962 sscanf(string
, "%f%f%f%f", ppd
->custom_margins
+ 0,
963 ppd
->custom_margins
+ 1, ppd
->custom_margins
+ 2,
964 ppd
->custom_margins
+ 3);
965 else if (!strncmp(keyword
, "Custom", 6) && !strcmp(name
, "True"))
967 ppd_coption_t
*coption
; /* Custom option */
970 DEBUG_puts("Processing Custom option...");
973 * Get the option and custom option...
976 if ((option
= ppdFindOption(ppd
, keyword
+ 6)) == NULL
)
978 ppd_group_t
*gtemp
; /* Temporary group */
981 DEBUG_printf(("%s option not found for %s...\n", keyword
+ 6, keyword
));
983 if ((gtemp
= ppd_get_group(ppd
, "General", _("General"), cg
)) == NULL
)
985 DEBUG_puts("Unable to get general group!");
990 if ((option
= ppd_get_option(gtemp
, keyword
+ 6)) == NULL
)
992 DEBUG_printf(("Unable to get %s option!\n", keyword
+ 6));
994 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1000 if ((coption
= ppd_get_coption(ppd
, keyword
+ 6)) == NULL
)
1002 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1008 * Add the "custom" option...
1011 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
1013 DEBUG_puts("Unable to add Custom choice!");
1015 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1020 strlcpy(choice
->text
, text
[0] ? text
: _("Custom"),
1021 sizeof(choice
->text
));
1023 choice
->code
= string
;
1024 string
= NULL
; /* Don't add as an attribute below */
1028 * Now process custom page sizes specially...
1031 if (!strcmp(keyword
, "CustomPageSize"))
1033 ppd
->variable_sizes
= 1;
1036 * Add a "Custom" page size entry...
1039 ppd_add_size(ppd
, "Custom");
1042 else if (!strcmp(keyword
, "LandscapeOrientation"))
1044 if (!strcmp(string
, "Minus90"))
1045 ppd
->landscape
= -90;
1046 else if (!strcmp(string
, "Plus90"))
1047 ppd
->landscape
= 90;
1049 else if (!strcmp(keyword
, "Emulators"))
1051 for (count
= 1, sptr
= string
; sptr
!= NULL
;)
1052 if ((sptr
= strchr(sptr
, ' ')) != NULL
)
1055 while (*sptr
== ' ')
1059 ppd
->num_emulations
= count
;
1060 ppd
->emulations
= calloc(count
, sizeof(ppd_emul_t
));
1062 for (i
= 0, sptr
= string
; i
< count
; i
++)
1064 for (nameptr
= ppd
->emulations
[i
].name
;
1065 *sptr
!= '\0' && *sptr
!= ' ';
1067 if (nameptr
< (ppd
->emulations
[i
].name
+ sizeof(ppd
->emulations
[i
].name
) - 1))
1072 while (*sptr
== ' ')
1076 else if (!strncmp(keyword
, "StartEmulator_", 14))
1080 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1081 if (!strcmp(keyword
+ 14, ppd
->emulations
[i
].name
))
1083 ppd
->emulations
[i
].start
= string
;
1087 else if (!strncmp(keyword
, "StopEmulator_", 13))
1091 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1092 if (!strcmp(keyword
+ 13, ppd
->emulations
[i
].name
))
1094 ppd
->emulations
[i
].stop
= string
;
1098 else if (!strcmp(keyword
, "JobPatchFile"))
1100 if (ppd
->patches
== NULL
)
1101 ppd
->patches
= strdup(string
);
1104 temp
= realloc(ppd
->patches
, strlen(ppd
->patches
) +
1105 strlen(string
) + 1);
1108 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1113 ppd
->patches
= temp
;
1115 strcpy(ppd
->patches
+ strlen(ppd
->patches
), string
);
1118 else if (!strcmp(keyword
, "OpenUI"))
1121 * Don't allow nesting of options...
1124 if (option
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1126 cg
->ppd_status
= PPD_NESTED_OPEN_UI
;
1132 * Add an option record to the current sub-group, group, or file...
1136 _cups_strcpy(name
, name
+ 1); /* Eliminate leading asterisk */
1138 for (i
= (int)strlen(name
) - 1; i
> 0 && isspace(name
[i
] & 255); i
--)
1139 name
[i
] = '\0'; /* Eliminate trailing spaces */
1141 DEBUG_printf(("OpenUI of %s in group %s...\n", name
,
1142 group
? group
->text
: "(null)"));
1144 if (subgroup
!= NULL
)
1145 option
= ppd_get_option(subgroup
, name
);
1146 else if (group
== NULL
)
1148 if ((group
= ppd_get_group(ppd
, "General", _("General"), cg
)) == NULL
)
1151 DEBUG_printf(("Adding to group %s...\n", group
->text
));
1152 option
= ppd_get_option(group
, name
);
1156 option
= ppd_get_option(group
, name
);
1160 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1166 * Now fill in the initial information for the option...
1169 if (string
&& !strcmp(string
, "PickMany"))
1170 option
->ui
= PPD_UI_PICKMANY
;
1171 else if (string
&& !strcmp(string
, "Boolean"))
1172 option
->ui
= PPD_UI_BOOLEAN
;
1173 else if (string
&& !strcmp(string
, "PickOne"))
1174 option
->ui
= PPD_UI_PICKONE
;
1175 else if (cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1177 cg
->ppd_status
= PPD_BAD_OPEN_UI
;
1182 option
->ui
= PPD_UI_PICKONE
;
1184 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1185 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
1186 !strcmp(ppd
->attrs
[j
]->name
+ 7, name
) &&
1187 ppd
->attrs
[j
]->value
)
1189 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
1190 option
->keyword
, ppd
->attrs
[j
]->value
));
1191 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
1192 sizeof(option
->defchoice
));
1197 strlcpy(option
->text
, text
, sizeof(option
->text
));
1200 if (!strcmp(name
, "PageSize"))
1201 strlcpy(option
->text
, _("Media Size"), sizeof(option
->text
));
1202 else if (!strcmp(name
, "MediaType"))
1203 strlcpy(option
->text
, _("Media Type"), sizeof(option
->text
));
1204 else if (!strcmp(name
, "InputSlot"))
1205 strlcpy(option
->text
, _("Media Source"), sizeof(option
->text
));
1206 else if (!strcmp(name
, "ColorModel"))
1207 strlcpy(option
->text
, _("Output Mode"), sizeof(option
->text
));
1208 else if (!strcmp(name
, "Resolution"))
1209 strlcpy(option
->text
, _("Resolution"), sizeof(option
->text
));
1211 strlcpy(option
->text
, name
, sizeof(option
->text
));
1214 option
->section
= PPD_ORDER_ANY
;
1219 else if (!strcmp(keyword
, "JCLOpenUI"))
1222 * Don't allow nesting of options...
1225 if (option
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
1227 cg
->ppd_status
= PPD_NESTED_OPEN_UI
;
1233 * Find the JCL group, and add if needed...
1236 group
= ppd_get_group(ppd
, "JCL", _("JCL"), cg
);
1242 * Add an option record to the current JCLs...
1246 _cups_strcpy(name
, name
+ 1);
1248 option
= ppd_get_option(group
, name
);
1252 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1258 * Now fill in the initial information for the option...
1261 if (string
&& !strcmp(string
, "PickMany"))
1262 option
->ui
= PPD_UI_PICKMANY
;
1263 else if (string
&& !strcmp(string
, "Boolean"))
1264 option
->ui
= PPD_UI_BOOLEAN
;
1265 else if (string
&& !strcmp(string
, "PickOne"))
1266 option
->ui
= PPD_UI_PICKONE
;
1269 cg
->ppd_status
= PPD_BAD_OPEN_UI
;
1274 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1275 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
1276 !strcmp(ppd
->attrs
[j
]->name
+ 7, name
) &&
1277 ppd
->attrs
[j
]->value
)
1279 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
1280 option
->keyword
, ppd
->attrs
[j
]->value
));
1281 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
1282 sizeof(option
->defchoice
));
1286 strlcpy(option
->text
, text
, sizeof(option
->text
));
1288 option
->section
= PPD_ORDER_JCL
;
1294 else if (!strcmp(keyword
, "CloseUI") || !strcmp(keyword
, "JCLCloseUI"))
1301 else if (!strcmp(keyword
, "OpenGroup"))
1304 * Open a new group...
1309 cg
->ppd_status
= PPD_NESTED_OPEN_GROUP
;
1316 cg
->ppd_status
= PPD_BAD_OPEN_GROUP
;
1322 * Separate the group name from the text (name/text)...
1325 if ((sptr
= strchr(string
, '/')) != NULL
)
1331 * Fix up the text...
1337 * Find/add the group...
1340 group
= ppd_get_group(ppd
, string
, sptr
, cg
);
1348 else if (!strcmp(keyword
, "CloseGroup"))
1355 else if (!strcmp(keyword
, "OrderDependency") ||
1356 !strcmp(keyword
, "NonUIOrderDependency"))
1358 if (sscanf(string
, "%f%40s%40s", &order
, name
, keyword
) != 3)
1360 cg
->ppd_status
= PPD_BAD_ORDER_DEPENDENCY
;
1365 if (keyword
[0] == '*')
1366 _cups_strcpy(keyword
, keyword
+ 1);
1368 if (!strcmp(name
, "ExitServer"))
1369 section
= PPD_ORDER_EXIT
;
1370 else if (!strcmp(name
, "Prolog"))
1371 section
= PPD_ORDER_PROLOG
;
1372 else if (!strcmp(name
, "DocumentSetup"))
1373 section
= PPD_ORDER_DOCUMENT
;
1374 else if (!strcmp(name
, "PageSetup"))
1375 section
= PPD_ORDER_PAGE
;
1376 else if (!strcmp(name
, "JCLSetup"))
1377 section
= PPD_ORDER_JCL
;
1379 section
= PPD_ORDER_ANY
;
1387 * Only valid for Non-UI options...
1390 for (i
= ppd
->num_groups
, gtemp
= ppd
->groups
; i
> 0; i
--, gtemp
++)
1391 if (gtemp
->text
[0] == '\0')
1395 for (i
= 0; i
< gtemp
->num_options
; i
++)
1396 if (!strcmp(keyword
, gtemp
->options
[i
].keyword
))
1398 gtemp
->options
[i
].section
= section
;
1399 gtemp
->options
[i
].order
= order
;
1405 option
->section
= section
;
1406 option
->order
= order
;
1412 else if (!strncmp(keyword
, "Default", 7))
1418 * Drop UI text, if any, from value...
1421 if (strchr(string
, '/') != NULL
)
1422 *strchr(string
, '/') = '\0';
1425 * Assign the default value as appropriate...
1428 if (!strcmp(keyword
, "DefaultColorSpace"))
1431 * Set default colorspace...
1434 if (!strcmp(string
, "CMY"))
1435 ppd
->colorspace
= PPD_CS_CMY
;
1436 else if (!strcmp(string
, "CMYK"))
1437 ppd
->colorspace
= PPD_CS_CMYK
;
1438 else if (!strcmp(string
, "RGB"))
1439 ppd
->colorspace
= PPD_CS_RGB
;
1440 else if (!strcmp(string
, "RGBK"))
1441 ppd
->colorspace
= PPD_CS_RGBK
;
1442 else if (!strcmp(string
, "N"))
1443 ppd
->colorspace
= PPD_CS_N
;
1445 ppd
->colorspace
= PPD_CS_GRAY
;
1447 else if (option
&& !strcmp(keyword
+ 7, option
->keyword
))
1450 * Set the default as part of the current option...
1453 DEBUG_printf(("Setting %s to %s...\n", keyword
, string
));
1455 strlcpy(option
->defchoice
, string
, sizeof(option
->defchoice
));
1457 DEBUG_printf(("%s is now %s...\n", keyword
, option
->defchoice
));
1462 * Lookup option and set if it has been defined...
1465 ppd_option_t
*toption
; /* Temporary option */
1468 if ((toption
= ppdFindOption(ppd
, keyword
+ 7)) != NULL
)
1470 DEBUG_printf(("Setting %s to %s...\n", keyword
, string
));
1471 strlcpy(toption
->defchoice
, string
, sizeof(toption
->defchoice
));
1475 else if (!strcmp(keyword
, "UIConstraints") ||
1476 !strcmp(keyword
, "NonUIConstraints"))
1478 if (ppd
->num_consts
== 0)
1479 constraint
= calloc(1, sizeof(ppd_const_t
));
1481 constraint
= realloc(ppd
->consts
,
1482 (ppd
->num_consts
+ 1) * sizeof(ppd_const_t
));
1484 if (constraint
== NULL
)
1486 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1491 ppd
->consts
= constraint
;
1492 constraint
+= ppd
->num_consts
;
1495 switch (sscanf(string
, "%40s%40s%40s%40s", constraint
->option1
,
1496 constraint
->choice1
, constraint
->option2
,
1497 constraint
->choice2
))
1499 case 0 : /* Error */
1500 case 1 : /* Error */
1501 cg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1504 case 2 : /* Two options... */
1506 * The following strcpy's are safe, as optionN and
1507 * choiceN are all the same size (size defined by PPD spec...)
1510 if (constraint
->option1
[0] == '*')
1511 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1513 if (constraint
->choice1
[0] == '*')
1514 _cups_strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1516 _cups_strcpy(constraint
->option2
, constraint
->choice1
);
1518 constraint
->choice1
[0] = '\0';
1519 constraint
->choice2
[0] = '\0';
1522 case 3 : /* Two options, one choice... */
1524 * The following _cups_strcpy's are safe, as optionN and
1525 * choiceN are all the same size (size defined by PPD spec...)
1528 if (constraint
->option1
[0] == '*')
1529 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1531 if (constraint
->choice1
[0] == '*')
1533 _cups_strcpy(constraint
->choice2
, constraint
->option2
);
1534 _cups_strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1535 constraint
->choice1
[0] = '\0';
1539 if (constraint
->option2
[0] == '*')
1540 _cups_strcpy(constraint
->option2
, constraint
->option2
+ 1);
1542 constraint
->choice2
[0] = '\0';
1546 case 4 : /* Two options, two choices... */
1547 if (constraint
->option1
[0] == '*')
1548 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1550 if (constraint
->option2
[0] == '*')
1551 _cups_strcpy(constraint
->option2
, constraint
->option2
+ 1);
1558 else if (!strcmp(keyword
, "PaperDimension"))
1560 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1561 size
= ppd_add_size(ppd
, name
);
1566 * Unable to add or find size!
1569 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1574 sscanf(string
, "%f%f", &(size
->width
), &(size
->length
));
1579 else if (!strcmp(keyword
, "ImageableArea"))
1581 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1582 size
= ppd_add_size(ppd
, name
);
1587 * Unable to add or find size!
1590 cg
->ppd_status
= PPD_ALLOC_ERROR
;
1595 sscanf(string
, "%f%f%f%f", &(size
->left
), &(size
->bottom
),
1596 &(size
->right
), &(size
->top
));
1601 else if (option
!= NULL
&&
1602 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
1603 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
) &&
1604 !strcmp(keyword
, option
->keyword
))
1606 DEBUG_printf(("group = %p, subgroup = %p\n", group
, subgroup
));
1608 if (!strcmp(keyword
, "PageSize"))
1611 * Add a page size...
1614 if (ppdPageSize(ppd
, name
) == NULL
)
1615 ppd_add_size(ppd
, name
);
1619 * Add the option choice...
1622 choice
= ppd_add_choice(option
, name
);
1624 if (mask
& PPD_TEXT
)
1625 strlcpy(choice
->text
, text
, sizeof(choice
->text
));
1626 else if (!strcmp(name
, "True"))
1627 strcpy(choice
->text
, _("Yes"));
1628 else if (!strcmp(name
, "False"))
1629 strcpy(choice
->text
, _("No"));
1631 strlcpy(choice
->text
, name
, sizeof(choice
->text
));
1633 if (option
->section
== PPD_ORDER_JCL
)
1634 ppd_decode(string
); /* Decode quoted string */
1636 choice
->code
= string
;
1637 string
= NULL
; /* Don't add as an attribute below */
1641 * Add remaining lines with keywords and string values as attributes...
1645 (mask
& (PPD_KEYWORD
| PPD_STRING
)) == (PPD_KEYWORD
| PPD_STRING
))
1646 ppd_add_attr(ppd
, keyword
, name
, text
, string
);
1652 * Reset language preferences...
1655 cupsLangFree(language
);
1658 _cupsRestoreLocale(LC_NUMERIC
, oldlocale
);
1660 _cupsRestoreLocale(LC_ALL
, oldlocale
);
1661 #endif /* LC_NUMERIC */
1665 printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp
));
1668 if (cg
->ppd_status
!= PPD_OK
)
1671 * Had an error reading the PPD file, cannot continue!
1680 * Create the sorted options array and set the option back-pointer for
1681 * each choice and custom option...
1684 ppd
->options
= cupsArrayNew((cups_array_func_t
)ppd_compare_options
, NULL
);
1686 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
1690 for (j
= group
->num_options
, option
= group
->options
;
1694 ppd_coption_t
*coption
; /* Custom option */
1697 cupsArrayAdd(ppd
->options
, option
);
1699 for (k
= 0; k
< option
->num_choices
; k
++)
1700 option
->choices
[k
].option
= option
;
1702 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)) != NULL
)
1703 coption
->option
= option
;
1708 * Return the PPD file structure...
1714 * Common exit point for errors to save code size...
1723 cupsLangFree(language
);
1726 _cupsRestoreLocale(LC_NUMERIC
, oldlocale
);
1728 _cupsRestoreLocale(LC_ALL
, oldlocale
);
1729 #endif /* LC_NUMERIC */
1736 * 'ppdOpenFd()' - Read a PPD file into memory.
1739 ppd_file_t
* /* O - PPD file record */
1740 ppdOpenFd(int fd
) /* I - File to read from */
1742 cups_file_t
*fp
; /* CUPS file pointer */
1743 ppd_file_t
*ppd
; /* PPD file record */
1744 _cups_globals_t
*cg
= _cupsGlobals();
1749 * Set the line number to 0...
1755 * Range check input...
1760 cg
->ppd_status
= PPD_NULL_FILE
;
1766 * Try to open the file and parse it...
1769 if ((fp
= cupsFileOpenFd(fd
, "r")) != NULL
)
1777 cg
->ppd_status
= PPD_FILE_OPEN_ERROR
;
1786 * 'ppdOpenFile()' - Read a PPD file into memory.
1789 ppd_file_t
* /* O - PPD file record */
1790 ppdOpenFile(const char *filename
) /* I - File to read from */
1792 cups_file_t
*fp
; /* File pointer */
1793 ppd_file_t
*ppd
; /* PPD file record */
1794 _cups_globals_t
*cg
= _cupsGlobals();
1799 * Set the line number to 0...
1805 * Range check input...
1808 if (filename
== NULL
)
1810 cg
->ppd_status
= PPD_NULL_FILE
;
1816 * Try to open the file and parse it...
1819 if ((fp
= cupsFileOpen(filename
, "r")) != NULL
)
1827 cg
->ppd_status
= PPD_FILE_OPEN_ERROR
;
1836 * 'ppdSetConformance()' - Set the conformance level for PPD files.
1838 * @since CUPS 1.1.20@
1842 ppdSetConformance(ppd_conform_t c
) /* I - Conformance level */
1844 _cups_globals_t
*cg
= _cupsGlobals();
1848 cg
->ppd_conform
= c
;
1853 * 'ppd_add_attr()' - Add an attribute to the PPD data.
1856 static ppd_attr_t
* /* O - New attribute */
1857 ppd_add_attr(ppd_file_t
*ppd
, /* I - PPD file data */
1858 const char *name
, /* I - Attribute name */
1859 const char *spec
, /* I - Specifier string, if any */
1860 const char *text
, /* I - Text string, if any */
1861 const char *value
) /* I - Value of attribute */
1863 ppd_attr_t
**ptr
, /* New array */
1864 *temp
; /* New attribute */
1868 * Range check input...
1871 if (ppd
== NULL
|| name
== NULL
|| spec
== NULL
)
1875 * Create the array as needed...
1878 if (!ppd
->sorted_attrs
)
1879 ppd
->sorted_attrs
= cupsArrayNew((cups_array_func_t
)ppd_compare_attrs
,
1883 * Allocate memory for the new attribute...
1886 if (ppd
->num_attrs
== 0)
1887 ptr
= malloc(sizeof(ppd_attr_t
*));
1889 ptr
= realloc(ppd
->attrs
, (ppd
->num_attrs
+ 1) * sizeof(ppd_attr_t
*));
1895 ptr
+= ppd
->num_attrs
;
1897 if ((temp
= calloc(1, sizeof(ppd_attr_t
))) == NULL
)
1908 strlcpy(temp
->name
, name
, sizeof(temp
->name
));
1909 strlcpy(temp
->spec
, spec
, sizeof(temp
->spec
));
1910 strlcpy(temp
->text
, text
, sizeof(temp
->text
));
1911 temp
->value
= (char *)value
;
1914 * Add the attribute to the sorted array...
1917 cupsArrayAdd(ppd
->sorted_attrs
, temp
);
1920 * Return the attribute...
1928 * 'ppd_add_choice()' - Add a choice to an option.
1931 static ppd_choice_t
* /* O - Named choice */
1932 ppd_add_choice(ppd_option_t
*option
, /* I - Option */
1933 const char *name
) /* I - Name of choice */
1935 ppd_choice_t
*choice
; /* Choice */
1938 if (option
->num_choices
== 0)
1939 choice
= malloc(sizeof(ppd_choice_t
));
1941 choice
= realloc(option
->choices
,
1942 sizeof(ppd_choice_t
) * (option
->num_choices
+ 1));
1947 option
->choices
= choice
;
1948 choice
+= option
->num_choices
;
1949 option
->num_choices
++;
1951 memset(choice
, 0, sizeof(ppd_choice_t
));
1952 strlcpy(choice
->choice
, name
, sizeof(choice
->choice
));
1959 * 'ppd_add_size()' - Add a page size.
1962 static ppd_size_t
* /* O - Named size */
1963 ppd_add_size(ppd_file_t
*ppd
, /* I - PPD file */
1964 const char *name
) /* I - Name of size */
1966 ppd_size_t
*size
; /* Size */
1969 if (ppd
->num_sizes
== 0)
1970 size
= malloc(sizeof(ppd_size_t
));
1972 size
= realloc(ppd
->sizes
, sizeof(ppd_size_t
) * (ppd
->num_sizes
+ 1));
1978 size
+= ppd
->num_sizes
;
1981 memset(size
, 0, sizeof(ppd_size_t
));
1982 strlcpy(size
->name
, name
, sizeof(size
->name
));
1989 * 'ppd_compare_attrs()' - Compare two attributes.
1992 static int /* O - Result of comparison */
1993 ppd_compare_attrs(ppd_attr_t
*a
, /* I - First attribute */
1994 ppd_attr_t
*b
) /* I - Second attribute */
1996 int ret
; /* Result of comparison */
1999 if ((ret
= strcasecmp(a
->name
, b
->name
)) != 0)
2001 else if (a
->spec
[0] && b
->spec
[0])
2002 return (strcasecmp(a
->spec
, b
->spec
));
2009 * 'ppd_compare_coptions()' - Compare two custom options.
2012 static int /* O - Result of comparison */
2013 ppd_compare_coptions(ppd_coption_t
*a
, /* I - First option */
2014 ppd_coption_t
*b
) /* I - Second option */
2016 return (strcasecmp(a
->keyword
, b
->keyword
));
2021 * 'ppd_compare_cparams()' - Compare two custom parameters.
2024 static int /* O - Result of comparison */
2025 ppd_compare_cparams(ppd_cparam_t
*a
, /* I - First parameter */
2026 ppd_cparam_t
*b
) /* I - Second parameter */
2028 return (strcasecmp(a
->name
, b
->name
));
2033 * 'ppd_compare_options()' - Compare two options.
2036 static int /* O - Result of comparison */
2037 ppd_compare_options(ppd_option_t
*a
, /* I - First option */
2038 ppd_option_t
*b
) /* I - Second option */
2040 return (strcasecmp(a
->keyword
, b
->keyword
));
2045 * 'ppd_decode()' - Decode a string value...
2048 static int /* O - Length of decoded string */
2049 ppd_decode(char *string
) /* I - String to decode */
2051 char *inptr
, /* Input pointer */
2052 *outptr
; /* Output pointer */
2058 while (*inptr
!= '\0')
2059 if (*inptr
== '<' && isxdigit(inptr
[1] & 255))
2062 * Convert hex to 8-bit values...
2066 while (isxdigit(*inptr
& 255))
2068 if (isalpha(*inptr
))
2069 *outptr
= (tolower(*inptr
) - 'a' + 10) << 4;
2071 *outptr
= (*inptr
- '0') << 4;
2075 if (!isxdigit(*inptr
& 255))
2078 if (isalpha(*inptr
))
2079 *outptr
|= tolower(*inptr
) - 'a' + 10;
2081 *outptr
|= *inptr
- '0';
2087 while (*inptr
!= '>' && *inptr
!= '\0')
2089 while (*inptr
== '>')
2093 *outptr
++ = *inptr
++;
2097 return ((int)(outptr
- string
));
2102 * 'ppd_free_group()' - Free a single UI group.
2106 ppd_free_group(ppd_group_t
*group
) /* I - Group to free */
2108 int i
; /* Looping var */
2109 ppd_option_t
*option
; /* Current option */
2110 ppd_group_t
*subgroup
; /* Current sub-group */
2113 if (group
->num_options
> 0)
2115 for (i
= group
->num_options
, option
= group
->options
;
2118 ppd_free_option(option
);
2120 ppd_free(group
->options
);
2123 if (group
->num_subgroups
> 0)
2125 for (i
= group
->num_subgroups
, subgroup
= group
->subgroups
;
2128 ppd_free_group(subgroup
);
2130 ppd_free(group
->subgroups
);
2136 * 'ppd_free_option()' - Free a single option.
2140 ppd_free_option(ppd_option_t
*option
) /* I - Option to free */
2142 int i
; /* Looping var */
2143 ppd_choice_t
*choice
; /* Current choice */
2146 if (option
->num_choices
> 0)
2148 for (i
= option
->num_choices
, choice
= option
->choices
;
2152 ppd_free(choice
->code
);
2155 ppd_free(option
->choices
);
2161 * 'ppd_get_coption()' - Get a custom option record.
2164 static ppd_coption_t
* /* O - Custom option... */
2165 ppd_get_coption(ppd_file_t
*ppd
, /* I - PPD file */
2166 const char *name
) /* I - Name of option */
2168 ppd_coption_t
*copt
; /* New custom option */
2172 * See if the option already exists...
2175 if ((copt
= ppdFindCustomOption(ppd
, name
)) != NULL
)
2179 * Not found, so create the custom option record...
2182 if ((copt
= calloc(1, sizeof(ppd_coption_t
))) == NULL
)
2185 strlcpy(copt
->keyword
, name
, sizeof(copt
->keyword
));
2187 copt
->params
= cupsArrayNew((cups_array_func_t
)ppd_compare_cparams
, NULL
);
2189 cupsArrayAdd(ppd
->coptions
, copt
);
2192 * Return the new record...
2200 * 'ppd_get_cparam()' - Get a custom parameter record.
2203 static ppd_cparam_t
* /* O - Extended option... */
2204 ppd_get_cparam(ppd_coption_t
*opt
, /* I - PPD file */
2205 const char *param
, /* I - Name of parameter */
2206 const char *text
) /* I - Human-readable text */
2208 ppd_cparam_t
*cparam
; /* New custom parameter */
2212 * See if the parameter already exists...
2215 if ((cparam
= ppdFindCustomParam(opt
, param
)) != NULL
)
2219 * Not found, so create the custom parameter record...
2222 if ((cparam
= calloc(1, sizeof(ppd_cparam_t
))) == NULL
)
2225 strlcpy(cparam
->name
, param
, sizeof(cparam
->name
));
2226 strlcpy(cparam
->text
, text
, sizeof(cparam
->text
));
2229 * Add this record to the array...
2232 cupsArrayAdd(opt
->params
, cparam
);
2235 * Return the new record...
2243 * 'ppd_get_group()' - Find or create the named group as needed.
2246 static ppd_group_t
* /* O - Named group */
2247 ppd_get_group(ppd_file_t
*ppd
, /* I - PPD file */
2248 const char *name
, /* I - Name of group */
2249 const char *text
, /* I - Text for group */
2250 _cups_globals_t
*cg
) /* I - Global data */
2252 int i
; /* Looping var */
2253 ppd_group_t
*group
; /* Group */
2256 DEBUG_printf(("ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)\n",
2257 ppd
, name
, text
, cg
));
2259 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
2260 if (!strcmp(group
->name
, name
))
2265 DEBUG_printf(("Adding group %s...\n", name
));
2267 if (cg
->ppd_conform
== PPD_CONFORM_STRICT
&& strlen(text
) >= sizeof(group
->text
))
2269 cg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
2274 if (ppd
->num_groups
== 0)
2275 group
= malloc(sizeof(ppd_group_t
));
2277 group
= realloc(ppd
->groups
,
2278 (ppd
->num_groups
+ 1) * sizeof(ppd_group_t
));
2282 cg
->ppd_status
= PPD_ALLOC_ERROR
;
2287 ppd
->groups
= group
;
2288 group
+= ppd
->num_groups
;
2291 memset(group
, 0, sizeof(ppd_group_t
));
2292 strlcpy(group
->name
, name
, sizeof(group
->name
));
2293 strlcpy(group
->text
, text
, sizeof(group
->text
));
2301 * 'ppd_get_option()' - Find or create the named option as needed.
2304 static ppd_option_t
* /* O - Named option */
2305 ppd_get_option(ppd_group_t
*group
, /* I - Group */
2306 const char *name
) /* I - Name of option */
2308 int i
; /* Looping var */
2309 ppd_option_t
*option
; /* Option */
2312 DEBUG_printf(("ppd_get_option(group=%p(\"%s\"), name=\"%s\")\n",
2313 group
, group
->name
, name
));
2315 for (i
= group
->num_options
, option
= group
->options
; i
> 0; i
--, option
++)
2316 if (!strcmp(option
->keyword
, name
))
2321 if (group
->num_options
== 0)
2322 option
= malloc(sizeof(ppd_option_t
));
2324 option
= realloc(group
->options
,
2325 (group
->num_options
+ 1) * sizeof(ppd_option_t
));
2330 group
->options
= option
;
2331 option
+= group
->num_options
;
2332 group
->num_options
++;
2334 memset(option
, 0, sizeof(ppd_option_t
));
2335 strlcpy(option
->keyword
, name
, sizeof(option
->keyword
));
2343 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2347 static int /* O - Bitmask of fields read */
2348 ppd_read(cups_file_t
*fp
, /* I - File to read from */
2349 char *keyword
, /* O - Keyword from line */
2350 char *option
, /* O - Option from line */
2351 char *text
, /* O - Human-readable text from line */
2352 char **string
, /* O - Code/string data */
2353 int ignoreblank
, /* I - Ignore blank lines? */
2354 _cups_globals_t
*cg
) /* I - Global data */
2356 int ch
, /* Character from file */
2357 col
, /* Column in line */
2358 colon
, /* Colon seen? */
2359 endquote
, /* Waiting for an end quote */
2360 mask
, /* Mask to be returned */
2361 startline
, /* Start line */
2362 textlen
; /* Length of text */
2363 char *keyptr
, /* Keyword pointer */
2364 *optptr
, /* Option pointer */
2365 *textptr
, /* Text pointer */
2366 *strptr
, /* Pointer into string */
2367 *lineptr
, /* Current position in line buffer */
2368 *line
; /* Line buffer */
2369 int linesize
; /* Current size of line buffer */
2372 * Range check everything...
2375 if (!fp
|| !keyword
|| !option
|| !text
|| !string
)
2379 * Now loop until we have a valid line...
2384 startline
= cg
->ppd_line
+ 1;
2386 line
= malloc(linesize
);
2401 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2403 if (lineptr
>= (line
+ linesize
- 1))
2406 * Expand the line buffer...
2409 char *temp
; /* Temporary line pointer */
2413 if (linesize
> 262144)
2416 * Don't allow lines longer than 256k!
2419 cg
->ppd_line
= startline
;
2420 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2427 temp
= realloc(line
, linesize
);
2430 cg
->ppd_line
= startline
;
2431 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2438 lineptr
= temp
+ (lineptr
- line
);
2442 if (ch
== '\r' || ch
== '\n')
2445 * Line feed or carriage return...
2454 * Check for a trailing line feed...
2457 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2464 cupsFileGetChar(fp
);
2467 if (lineptr
== line
&& ignoreblank
)
2468 continue; /* Skip blank lines */
2472 if (!endquote
) /* Continue for multi-line text */
2477 else if (ch
< ' ' && ch
!= '\t' && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2480 * Other control characters...
2483 cg
->ppd_line
= startline
;
2484 cg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
2490 else if (ch
!= 0x1a)
2493 * Any other character...
2499 if (col
> (PPD_MAX_LINE
- 1))
2502 * Line is too long...
2505 cg
->ppd_line
= startline
;
2506 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2513 if (ch
== ':' && strncmp(line
, "*%", 2) != 0)
2516 if (ch
== '\"' && colon
)
2517 endquote
= !endquote
;
2524 * Didn't finish this quoted string...
2527 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2530 else if (ch
== '\r' || ch
== '\n')
2538 * Check for a trailing line feed...
2541 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2544 cupsFileGetChar(fp
);
2549 else if (ch
< ' ' && ch
!= '\t' && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2552 * Other control characters...
2555 cg
->ppd_line
= startline
;
2556 cg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
2562 else if (ch
!= 0x1a)
2566 if (col
> (PPD_MAX_LINE
- 1))
2569 * Line is too long...
2572 cg
->ppd_line
= startline
;
2573 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2585 * Didn't finish this line...
2588 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2589 if (ch
== '\r' || ch
== '\n')
2592 * Line feed or carriage return...
2601 * Check for a trailing line feed...
2604 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2607 cupsFileGetChar(fp
);
2612 else if (ch
< ' ' && ch
!= '\t' && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2615 * Other control characters...
2618 cg
->ppd_line
= startline
;
2619 cg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
2625 else if (ch
!= 0x1a)
2629 if (col
> (PPD_MAX_LINE
- 1))
2632 * Line is too long...
2635 cg
->ppd_line
= startline
;
2636 cg
->ppd_status
= PPD_LINE_TOO_LONG
;
2645 if (lineptr
> line
&& lineptr
[-1] == '\n')
2650 DEBUG_printf(("LINE = \"%s\"\n", line
));
2653 * The dynamically created PPDs for older style Mac OS X
2654 * drivers include a large blob of data inserted as comments
2655 * at the end of the file. As an optimization we can stop
2656 * reading the PPD when we get to the start of this data.
2659 if (!strcmp(line
, "*%APLWORKSET START"))
2665 if (ch
== EOF
&& lineptr
== line
)
2683 if ((!line
[0] || /* Blank line */
2684 !strncmp(line
, "*%", 2) || /* Comment line */
2685 !strcmp(line
, "*End")) && /* End of multi-line string */
2686 ignoreblank
) /* Ignore these? */
2688 startline
= cg
->ppd_line
+ 1;
2692 if (!strcmp(line
, "*")) /* (Bad) comment line */
2694 if (cg
->ppd_conform
== PPD_CONFORM_RELAXED
)
2696 startline
= cg
->ppd_line
+ 1;
2701 cg
->ppd_line
= startline
;
2702 cg
->ppd_status
= PPD_ILLEGAL_MAIN_KEYWORD
;
2709 if (line
[0] != '*') /* All lines start with an asterisk */
2712 * Allow lines consisting of just whitespace...
2715 for (lineptr
= line
; *lineptr
; lineptr
++)
2716 if (!isspace(*lineptr
& 255))
2721 cg
->ppd_status
= PPD_MISSING_ASTERISK
;
2725 else if (ignoreblank
)
2740 while (*lineptr
!= '\0' && *lineptr
!= ':' && !isspace(*lineptr
& 255))
2742 if (*lineptr
<= ' ' || *lineptr
> 126 || *lineptr
== '/' ||
2743 (keyptr
- keyword
) >= (PPD_MAX_NAME
- 1))
2745 cg
->ppd_status
= PPD_ILLEGAL_MAIN_KEYWORD
;
2750 *keyptr
++ = *lineptr
++;
2755 if (!strcmp(keyword
, "End"))
2758 mask
|= PPD_KEYWORD
;
2760 /* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
2762 if (isspace(*lineptr
& 255))
2765 * Get an option name...
2768 while (isspace(*lineptr
& 255))
2773 while (*lineptr
!= '\0' && !isspace(*lineptr
& 255) && *lineptr
!= ':' &&
2776 if (*lineptr
<= ' ' || *lineptr
> 126 ||
2777 (optptr
- option
) >= (PPD_MAX_NAME
- 1))
2779 cg
->ppd_status
= PPD_ILLEGAL_OPTION_KEYWORD
;
2784 *optptr
++ = *lineptr
++;
2789 if (isspace(*lineptr
& 255) && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2791 cg
->ppd_status
= PPD_ILLEGAL_WHITESPACE
;
2796 while (isspace(*lineptr
& 255))
2801 /* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
2803 if (*lineptr
== '/')
2806 * Get human-readable text...
2813 while (*lineptr
!= '\0' && *lineptr
!= '\n' && *lineptr
!= ':')
2815 if (((unsigned char)*lineptr
< ' ' && *lineptr
!= '\t') ||
2816 (textptr
- text
) >= (PPD_MAX_LINE
- 1))
2818 cg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
2823 *textptr
++ = *lineptr
++;
2827 textlen
= ppd_decode(text
);
2829 if (textlen
> PPD_MAX_TEXT
&& cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2831 cg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
2839 /* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
2842 if (isspace(*lineptr
& 255) && cg
->ppd_conform
== PPD_CONFORM_STRICT
)
2844 cg
->ppd_status
= PPD_ILLEGAL_WHITESPACE
;
2849 while (isspace(*lineptr
& 255))
2852 if (*lineptr
== ':')
2855 * Get string after triming leading and trailing whitespace...
2859 while (isspace(*lineptr
& 255))
2862 strptr
= lineptr
+ strlen(lineptr
) - 1;
2863 while (strptr
>= lineptr
&& isspace(*strptr
& 255))
2866 if (*strptr
== '\"')
2869 * Quoted string by itself...
2872 *string
= malloc(strlen(lineptr
) + 1);
2876 for (; *lineptr
!= '\0'; lineptr
++)
2877 if (*lineptr
!= '\"')
2878 *strptr
++ = *lineptr
;
2883 *string
= strdup(lineptr
);
2885 /* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
2899 * End of "$Id: ppd.c 5119 2006-02-16 15:52:06Z mike $".