2 * "$Id: ppd.c,v 1.93 2003/02/19 14:46:10 mike Exp $"
4 * PPD file routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2003 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-3111 USA
20 * Voice: (301) 373-9603
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 * _ppd_attr_compare() - Compare two attributes.
38 * ppdClose() - Free all memory used by the PPD file.
39 * ppdErrorString() - Returns the text assocated with a status.
40 * ppdLastError() - Return the status from the last ppdOpen*().
41 * ppdOpen() - Read a PPD file into memory.
42 * ppdOpenFd() - Read a PPD file into memory.
43 * ppdOpenFile() - Read a PPD file into memory.
44 * ppd_add_attr() - Add an attribute to the PPD data.
45 * ppd_add_choice() - Add a choice to an option.
46 * ppd_add_size() - Add a page size.
47 * ppd_compare_groups() - Compare two groups.
48 * ppd_compare_options() - Compare two options.
49 * ppd_decode() - Decode a string value...
50 * ppd_fix() - Fix WinANSI characters in the range 0x80 to
51 * 0x9f to be valid ISO-8859-1 characters...
52 * ppd_free_group() - Free a single UI group.
53 * ppd_free_option() - Free a single option.
54 * ppd_get_group() - Find or create the named group as needed.
55 * ppd_get_option() - Find or create the named option as needed.
56 * ppd_read() - Read a line from a PPD file, skipping comment
61 * 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_status_t ppd_status
= PPD_OK
;
97 /* Status of last ppdOpen*() */
98 static int ppd_line
= 0; /* Current line number */
105 static ppd_attr_t
*ppd_add_attr(ppd_file_t
*ppd
, const char *name
,
106 const char *spec
, const char *value
);
107 static ppd_choice_t
*ppd_add_choice(ppd_option_t
*option
, const char *name
);
108 static ppd_size_t
*ppd_add_size(ppd_file_t
*ppd
, const char *name
);
110 static int ppd_compare_groups(ppd_group_t
*g0
, ppd_group_t
*g1
);
111 static int ppd_compare_options(ppd_option_t
*o0
, ppd_option_t
*o1
);
112 #endif /* !__APPLE__ */
113 static void ppd_decode(char *string
);
115 static void ppd_fix(char *string
);
118 #endif /* !__APPLE__ */
119 static void ppd_free_group(ppd_group_t
*group
);
120 static void ppd_free_option(ppd_option_t
*option
);
121 static ppd_group_t
*ppd_get_group(ppd_file_t
*ppd
, const char *name
,
123 static ppd_option_t
*ppd_get_option(ppd_group_t
*group
, const char *name
);
124 static int ppd_read(FILE *fp
, char *keyword
, char *option
,
125 char *text
, char **string
);
129 * '_ppd_attr_compare()' - Compare two attributes.
132 int /* O - Result of comparison */
133 _ppd_attr_compare(ppd_attr_t
**a
, /* I - First attribute */
134 ppd_attr_t
**b
) /* I - Second attribute */
136 int ret
; /* Result of comparison */
139 if ((ret
= strcasecmp((*a
)->name
, (*b
)->name
)) != 0)
141 else if ((*a
)->spec
[0] && (*b
)->spec
[0])
142 return (strcasecmp((*a
)->spec
, (*b
)->spec
));
149 * 'ppdClose()' - Free all memory used by the PPD file.
153 ppdClose(ppd_file_t
*ppd
) /* I - PPD file record */
155 int i
; /* Looping var */
156 ppd_emul_t
*emul
; /* Current emulation */
157 ppd_group_t
*group
; /* Current group */
158 char **font
; /* Current font */
159 char **filter
; /* Current filter */
160 ppd_attr_t
**attr
; /* Current attribute */
164 * Range check the PPD file record...
171 * Free all strings at the top level...
174 ppd_free(ppd
->patches
);
175 ppd_free(ppd
->jcl_begin
);
176 ppd_free(ppd
->jcl_ps
);
177 ppd_free(ppd
->jcl_end
);
178 ppd_free(ppd
->lang_encoding
);
179 ppd_free(ppd
->lang_version
);
180 ppd_free(ppd
->modelname
);
181 ppd_free(ppd
->ttrasterizer
);
182 ppd_free(ppd
->manufacturer
);
183 ppd_free(ppd
->nickname
);
184 ppd_free(ppd
->shortnickname
);
185 ppd_free(ppd
->protocols
);
186 ppd_free(ppd
->pcfilename
);
189 * Free any emulations...
192 if (ppd
->num_emulations
> 0)
194 for (i
= ppd
->num_emulations
, emul
= ppd
->emulations
; i
> 0; i
--, emul
++)
196 ppd_free(emul
->start
);
197 ppd_free(emul
->stop
);
200 ppd_free(ppd
->emulations
);
204 * Free any UI groups, subgroups, and options...
207 if (ppd
->num_groups
> 0)
209 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
210 ppd_free_group(group
);
212 ppd_free(ppd
->groups
);
216 * Free any page sizes...
219 if (ppd
->num_sizes
> 0)
220 ppd_free(ppd
->sizes
);
223 * Free any constraints...
226 if (ppd
->num_consts
> 0)
227 ppd_free(ppd
->consts
);
230 * Free any filters...
233 if (ppd
->num_filters
> 0)
235 for (i
= ppd
->num_filters
, filter
= ppd
->filters
; i
> 0; i
--, filter
++)
238 ppd_free(ppd
->filters
);
245 if (ppd
->num_fonts
> 0)
247 for (i
= ppd
->num_fonts
, font
= ppd
->fonts
; i
> 0; i
--, font
++)
250 ppd_free(ppd
->fonts
);
254 * Free any profiles...
257 if (ppd
->num_profiles
> 0)
258 ppd_free(ppd
->profiles
);
261 * Free any attributes...
264 if (ppd
->num_attrs
> 0)
266 for (i
= ppd
->num_attrs
, attr
= ppd
->attrs
; i
> 0; i
--, attr
++)
268 ppd_free((*attr
)->value
);
272 ppd_free(ppd
->attrs
);
276 * Free the whole record...
284 * 'ppdErrorString()' - Returns the text assocated with a status.
287 const char * /* O - Status string */
288 ppdErrorString(ppd_status_t status
) /* I - PPD status */
290 static const char * const messages
[] =/* Status messages */
293 "Unable to open PPD file",
294 "NULL PPD file pointer",
295 "Memory allocation error",
296 "Missing PPD-Adobe-4.x header",
297 "Missing value string",
300 "OpenGroup without a CloseGroup first",
301 "Bad OpenUI/JCLOpenUI",
302 "OpenUI/JCLOpenUI without a CloseUI/JCLCLoseUI first",
303 "Bad OrderDependency",
305 "Missing asterisk in column 1",
306 "Line longer than the maximum allowed (255 characters)",
307 "Illegal control character",
308 "Illegal main keyword string",
309 "Illegal option keyword string",
310 "Illegal translation string"
314 if (status
< PPD_OK
|| status
> PPD_ILLEGAL_TRANSLATION
)
317 return (messages
[status
]);
322 * 'ppdLastError()' - Return the status from the last ppdOpen*().
325 ppd_status_t
/* O - Status code */
326 ppdLastError(int *line
) /* O - Line number */
336 * 'ppdOpen()' - Read a PPD file into memory.
339 ppd_file_t
* /* O - PPD file record */
340 ppdOpen(FILE *fp
) /* I - File to read from */
342 char *oldlocale
; /* Old locale settings */
343 int i
, j
, k
, m
; /* Looping vars */
344 int count
; /* Temporary count */
345 ppd_file_t
*ppd
; /* PPD file record */
346 ppd_group_t
*group
, /* Current group */
347 *subgroup
; /* Current sub-group */
348 ppd_option_t
*option
; /* Current option */
349 ppd_choice_t
*choice
; /* Current choice */
350 ppd_const_t
*constraint
; /* Current constraint */
351 ppd_size_t
*size
; /* Current page size */
352 int mask
; /* Line data mask */
353 char keyword
[PPD_MAX_NAME
],
354 /* Keyword from file */
356 /* Option from file */
358 /* Human-readable text from file */
359 *string
, /* Code/text from file */
360 *sptr
, /* Pointer into string */
361 *nameptr
, /* Pointer into name */
362 *temp
, /* Temporary string pointer */
363 **tempfonts
; /* Temporary fonts pointer */
364 float order
; /* Order dependency number */
365 ppd_section_t section
; /* Order dependency section */
366 ppd_profile_t
*profile
; /* Pointer to color profile */
367 char **filter
; /* Pointer to filter */
368 cups_lang_t
*language
; /* Default language */
369 static const char * const ui_keywords
[] =
371 /* Boolean keywords */
381 /* PickOne keywords */
394 "JCLFrameBufferSize",
419 * Default to "OK" status...
426 * Range check input...
431 ppd_status
= PPD_NULL_FILE
;
436 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
439 mask
= ppd_read(fp
, keyword
, name
, text
, &string
);
442 strcmp(keyword
, "PPD-Adobe") != 0 ||
443 string
== NULL
|| string
[0] != '4')
446 * Either this is not a PPD file, or it is not a 4.x PPD file.
449 if (ppd_status
!= PPD_OK
)
450 ppd_status
= PPD_MISSING_PPDADOBE4
;
457 DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword
, string
));
462 * Allocate memory for the PPD file record...
465 if ((ppd
= calloc(sizeof(ppd_file_t
), 1)) == NULL
)
467 ppd_status
= PPD_ALLOC_ERROR
;
472 ppd
->language_level
= 1;
473 ppd
->color_device
= 0;
474 ppd
->colorspace
= PPD_CS_GRAY
;
475 ppd
->landscape
= -90;
478 * Get the default language for the user...
481 language
= cupsLangDefault();
484 oldlocale
= setlocale(LC_NUMERIC
, "C");
486 oldlocale
= setlocale(LC_ALL
, "C");
487 #endif /* LC_NUMERIC */
490 * Read lines from the PPD file and add them to the file record...
498 while ((mask
= ppd_read(fp
, keyword
, name
, text
, &string
)) != 0)
501 printf("mask = %x, keyword = \"%s\"", mask
, keyword
);
504 printf(", name = \"%s\"", name
);
507 printf(", text = \"%s\"", text
);
511 if (strlen(string
) > 40)
512 printf(", string = %p", string
);
514 printf(", string = \"%s\"", string
);
520 if (strcmp(keyword
, "CloseUI") && strcmp(keyword
, "CloseGroup") &&
521 strcmp(keyword
, "CloseSubGroup") && strncmp(keyword
, "Default", 7) &&
522 strcmp(keyword
, "JCLCloseUI") && strcmp(keyword
, "JCLOpenUI") &&
523 strcmp(keyword
, "OpenUI") && strcmp(keyword
, "OpenGroup") &&
524 strcmp(keyword
, "OpenSubGroup") && string
== NULL
)
527 * Need a string value!
532 cupsLangFree(language
);
535 setlocale(LC_NUMERIC
, oldlocale
);
537 setlocale(LC_ALL
, oldlocale
);
538 #endif /* LC_NUMERIC */
540 ppd_status
= PPD_MISSING_VALUE
;
546 * Certain main keywords (as defined by the PPD spec) may be used
547 * without the usual OpenUI/CloseUI stuff. Presumably this is just
548 * so that Adobe wouldn't completely break compatibility with PPD
549 * files prior to v4.0 of the spec, but it is hopelessly
550 * inconsistent... Catch these main keywords and automatically
551 * create the corresponding option, as needed...
556 for (i
= 0; i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])); i
++)
557 if (!strcmp(name
, ui_keywords
[i
]))
560 if (i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])))
563 * Create the option in the appropriate group...
568 if (strcmp(name
, "Collate") && strcmp(name
, "Duplex") &&
569 strcmp(name
, "InputSlot") && strcmp(name
, "ManualFeed") &&
570 strcmp(name
, "MediaType") && strcmp(name
, "MediaColor") &&
571 strcmp(name
, "MediaWeight") && strcmp(name
, "OutputBin") &&
572 strcmp(name
, "OutputMode") && strcmp(name
, "OutputOrder") &&
573 strcmp(name
, "PageSize") && strcmp(name
, "PageRegion"))
574 group
= ppd_get_group(ppd
, "Extra",
575 cupsLangString(language
, CUPS_MSG_EXTRA
));
577 group
= ppd_get_group(ppd
, "General",
578 cupsLangString(language
, CUPS_MSG_GENERAL
));
586 cupsLangFree(language
);
589 setlocale(LC_NUMERIC
, oldlocale
);
591 setlocale(LC_ALL
, oldlocale
);
592 #endif /* LC_NUMERIC */
594 ppd_status
= PPD_ALLOC_ERROR
;
599 DEBUG_printf(("Adding to group %s...\n", group
->text
));
600 option
= ppd_get_option(group
, name
);
604 option
= ppd_get_option(group
, name
);
612 cupsLangFree(language
);
615 setlocale(LC_NUMERIC
, oldlocale
);
617 setlocale(LC_ALL
, oldlocale
);
618 #endif /* LC_NUMERIC */
620 ppd_status
= PPD_ALLOC_ERROR
;
626 * Now fill in the initial information for the option...
629 if (!strncmp(name
, "JCL", 3))
630 option
->section
= PPD_ORDER_JCL
;
632 option
->section
= PPD_ORDER_ANY
;
634 option
->order
= 10.0f
;
637 option
->ui
= PPD_UI_BOOLEAN
;
639 option
->ui
= PPD_UI_PICKONE
;
643 if (strcmp(keyword
, "LanguageLevel") == 0)
644 ppd
->language_level
= atoi(string
);
645 else if (strcmp(keyword
, "LanguageEncoding") == 0)
647 ppd_free(ppd
->lang_encoding
);
648 ppd
->lang_encoding
= string
;
649 string
= NULL
; /* Don't free this string below */
651 else if (strcmp(keyword
, "LanguageVersion") == 0)
653 ppd_free(ppd
->lang_version
);
654 ppd
->lang_version
= string
;
655 string
= NULL
; /* Don't free this string below */
657 else if (strcmp(keyword
, "Manufacturer") == 0)
659 ppd_free(ppd
->manufacturer
);
660 ppd
->manufacturer
= string
;
661 string
= NULL
; /* Don't free this string below */
663 else if (strcmp(keyword
, "ModelName") == 0)
665 ppd_free(ppd
->modelname
);
666 ppd
->modelname
= string
;
667 string
= NULL
; /* Don't free this string below */
669 else if (strcmp(keyword
, "Protocols") == 0)
671 ppd_free(ppd
->protocols
);
672 ppd
->protocols
= string
;
673 string
= NULL
; /* Don't free this string below */
675 else if (strcmp(keyword
, "PCFileName") == 0)
677 ppd_free(ppd
->pcfilename
);
678 ppd
->pcfilename
= string
;
679 string
= NULL
; /* Don't free this string below */
681 else if (strcmp(keyword
, "NickName") == 0)
683 ppd_free(ppd
->nickname
);
684 ppd
->nickname
= string
;
685 string
= NULL
; /* Don't free this string below */
687 else if (strcmp(keyword
, "Product") == 0)
690 * Add each Product keyword as an attribute...
693 ppd_add_attr(ppd
, keyword
, "", string
);
696 * Save the last one in the product element...
699 ppd
->product
= string
;
700 string
= NULL
; /* Don't free this string below */
702 else if (strcmp(keyword
, "ShortNickName") == 0)
704 ppd_free(ppd
->shortnickname
);
705 ppd
->shortnickname
= string
;
706 string
= NULL
; /* Don't free this string below */
708 else if (strcmp(keyword
, "TTRasterizer") == 0)
710 ppd_free(ppd
->ttrasterizer
);
711 ppd
->ttrasterizer
= string
;
712 string
= NULL
; /* Don't free this string below */
714 else if (strcmp(keyword
, "JCLBegin") == 0)
716 ppd_free(ppd
->jcl_begin
);
717 ppd_decode(string
); /* Decode quoted string */
718 ppd
->jcl_begin
= string
;
719 string
= NULL
; /* Don't free this string below */
721 else if (strcmp(keyword
, "JCLEnd") == 0)
723 ppd_free(ppd
->jcl_end
);
724 ppd_decode(string
); /* Decode quoted string */
725 ppd
->jcl_end
= string
;
726 string
= NULL
; /* Don't free this string below */
728 else if (strcmp(keyword
, "JCLToPSInterpreter") == 0)
730 ppd_free(ppd
->jcl_ps
);
731 ppd_decode(string
); /* Decode quoted string */
732 ppd
->jcl_ps
= string
;
733 string
= NULL
; /* Don't free this string below */
735 else if (strcmp(keyword
, "AccurateScreensSupport") == 0)
736 ppd
->accurate_screens
= strcmp(string
, "True") == 0;
737 else if (strcmp(keyword
, "ColorDevice") == 0)
738 ppd
->color_device
= strcmp(string
, "True") == 0;
739 else if (strcmp(keyword
, "ContoneOnly") == 0)
740 ppd
->contone_only
= strcmp(string
, "True") == 0;
741 else if (strcmp(keyword
, "DefaultColorSpace") == 0)
743 if (strcmp(string
, "CMY") == 0)
744 ppd
->colorspace
= PPD_CS_CMY
;
745 else if (strcmp(string
, "CMYK") == 0)
746 ppd
->colorspace
= PPD_CS_CMYK
;
747 else if (strcmp(string
, "RGB") == 0)
748 ppd
->colorspace
= PPD_CS_RGB
;
749 else if (strcmp(string
, "RGBK") == 0)
750 ppd
->colorspace
= PPD_CS_RGBK
;
751 else if (strcmp(string
, "N") == 0)
752 ppd
->colorspace
= PPD_CS_N
;
754 ppd
->colorspace
= PPD_CS_GRAY
;
756 else if (strcmp(keyword
, "cupsFlipDuplex") == 0)
757 ppd
->flip_duplex
= strcmp(string
, "True") == 0;
758 else if (strcmp(keyword
, "cupsManualCopies") == 0)
759 ppd
->manual_copies
= strcmp(string
, "True") == 0;
760 else if (strcmp(keyword
, "cupsModelNumber") == 0)
761 ppd
->model_number
= atoi(string
);
762 else if (strcmp(keyword
, "cupsColorProfile") == 0)
764 if (ppd
->num_profiles
== 0)
765 profile
= malloc(sizeof(ppd_profile_t
));
767 profile
= realloc(ppd
->profiles
, sizeof(ppd_profile_t
) *
768 (ppd
->num_profiles
+ 1));
770 ppd
->profiles
= profile
;
771 profile
+= ppd
->num_profiles
;
772 ppd
->num_profiles
++;
774 memset(profile
, 0, sizeof(ppd_profile_t
));
775 strlcpy(profile
->resolution
, name
, sizeof(profile
->resolution
));
776 strlcpy(profile
->media_type
, text
, sizeof(profile
->media_type
));
777 sscanf(string
, "%f%f%f%f%f%f%f%f%f%f%f", &(profile
->density
),
779 profile
->matrix
[0] + 0, profile
->matrix
[0] + 1,
780 profile
->matrix
[0] + 2, profile
->matrix
[1] + 0,
781 profile
->matrix
[1] + 1, profile
->matrix
[1] + 2,
782 profile
->matrix
[2] + 0, profile
->matrix
[2] + 1,
783 profile
->matrix
[2] + 2);
785 else if (strcmp(keyword
, "cupsFilter") == 0)
787 if (ppd
->num_filters
== 0)
788 filter
= malloc(sizeof(char *));
790 filter
= realloc(ppd
->filters
, sizeof(char *) * (ppd
->num_filters
+ 1));
798 cupsLangFree(language
);
801 setlocale(LC_NUMERIC
, oldlocale
);
803 setlocale(LC_ALL
, oldlocale
);
804 #endif /* LC_NUMERIC */
806 ppd_status
= PPD_ALLOC_ERROR
;
811 ppd
->filters
= filter
;
812 filter
+= ppd
->num_filters
;
816 * Copy filter string and prevent it from being freed below...
822 else if (strcmp(keyword
, "Throughput") == 0)
823 ppd
->throughput
= atoi(string
);
824 else if (strcmp(keyword
, "Font") == 0)
827 * Add this font to the list of available fonts...
830 if (ppd
->num_fonts
== 0)
831 tempfonts
= (char **)malloc(sizeof(char *));
833 tempfonts
= (char **)realloc(ppd
->fonts
,
834 sizeof(char *) * (ppd
->num_fonts
+ 1));
836 if (tempfonts
== NULL
)
842 cupsLangFree(language
);
845 setlocale(LC_NUMERIC
, oldlocale
);
847 setlocale(LC_ALL
, oldlocale
);
848 #endif /* LC_NUMERIC */
850 ppd_status
= PPD_ALLOC_ERROR
;
855 ppd
->fonts
= tempfonts
;
856 ppd
->fonts
[ppd
->num_fonts
] = strdup(name
);
859 else if (strcmp(keyword
, "VariablePaperSize") == 0 &&
860 strcmp(string
, "True") == 0 &&
861 !ppd
->variable_sizes
)
863 ppd
->variable_sizes
= 1;
866 * Add a "Custom" page size entry...
869 ppd_add_size(ppd
, "Custom");
872 * Add a "Custom" page size option...
875 if ((option
= ppdFindOption(ppd
, "PageSize")) == NULL
)
880 if ((temp
= ppd_get_group(ppd
, "General",
881 cupsLangString(language
,
882 CUPS_MSG_GENERAL
))) == NULL
)
888 cupsLangFree(language
);
891 setlocale(LC_NUMERIC
, oldlocale
);
893 setlocale(LC_ALL
, oldlocale
);
894 #endif /* LC_NUMERIC */
896 ppd_status
= PPD_ALLOC_ERROR
;
901 if ((option
= ppd_get_option(temp
, "PageSize")) == NULL
)
907 cupsLangFree(language
);
910 setlocale(LC_NUMERIC
, oldlocale
);
912 setlocale(LC_ALL
, oldlocale
);
913 #endif /* LC_NUMERIC */
915 ppd_status
= PPD_ALLOC_ERROR
;
921 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
927 cupsLangFree(language
);
930 setlocale(LC_NUMERIC
, oldlocale
);
932 setlocale(LC_ALL
, oldlocale
);
933 #endif /* LC_NUMERIC */
935 ppd_status
= PPD_ALLOC_ERROR
;
940 strlcpy(choice
->text
, cupsLangString(language
, CUPS_MSG_VARIABLE
),
941 sizeof(choice
->text
));
944 else if (strcmp(keyword
, "MaxMediaWidth") == 0)
945 ppd
->custom_max
[0] = (float)atof(string
);
946 else if (strcmp(keyword
, "MaxMediaHeight") == 0)
947 ppd
->custom_max
[1] = (float)atof(string
);
948 else if (strcmp(keyword
, "ParamCustomPageSize") == 0)
950 if (strcmp(name
, "Width") == 0)
951 sscanf(string
, "%*s%*s%f%f", ppd
->custom_min
+ 0,
952 ppd
->custom_max
+ 0);
953 else if (strcmp(name
, "Height") == 0)
954 sscanf(string
, "%*s%*s%f%f", ppd
->custom_min
+ 1,
955 ppd
->custom_max
+ 1);
957 else if (strcmp(keyword
, "HWMargins") == 0)
958 sscanf(string
, "%f%f%f%f", ppd
->custom_margins
+ 0,
959 ppd
->custom_margins
+ 1, ppd
->custom_margins
+ 2,
960 ppd
->custom_margins
+ 3);
961 else if (strcmp(keyword
, "CustomPageSize") == 0 &&
962 strcmp(name
, "True") == 0)
964 if (!ppd
->variable_sizes
)
966 ppd
->variable_sizes
= 1;
969 * Add a "Custom" page size entry...
972 ppd_add_size(ppd
, "Custom");
975 * Add a "Custom" page size option...
978 if ((option
= ppdFindOption(ppd
, "PageSize")) == NULL
)
983 if ((temp
= ppd_get_group(ppd
, "General",
984 cupsLangString(language
,
985 CUPS_MSG_GENERAL
))) == NULL
)
987 DEBUG_puts("Unable to get general group!");
993 cupsLangFree(language
);
996 setlocale(LC_NUMERIC
, oldlocale
);
998 setlocale(LC_ALL
, oldlocale
);
999 #endif /* LC_NUMERIC */
1001 ppd_status
= PPD_ALLOC_ERROR
;
1006 if ((option
= ppd_get_option(temp
, "PageSize")) == NULL
)
1008 DEBUG_puts("Unable to get PageSize option!");
1014 cupsLangFree(language
);
1017 setlocale(LC_NUMERIC
, oldlocale
);
1019 setlocale(LC_ALL
, oldlocale
);
1020 #endif /* LC_NUMERIC */
1022 ppd_status
= PPD_ALLOC_ERROR
;
1028 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
1030 DEBUG_puts("Unable to add Custom choice!");
1036 cupsLangFree(language
);
1039 setlocale(LC_NUMERIC
, oldlocale
);
1041 setlocale(LC_ALL
, oldlocale
);
1042 #endif /* LC_NUMERIC */
1044 ppd_status
= PPD_ALLOC_ERROR
;
1049 strlcpy(choice
->text
, cupsLangString(language
, CUPS_MSG_VARIABLE
),
1050 sizeof(choice
->text
));
1054 if ((option
= ppdFindOption(ppd
, "PageSize")) == NULL
)
1056 DEBUG_puts("Unable to find PageSize option!");
1062 cupsLangFree(language
);
1065 setlocale(LC_NUMERIC
, oldlocale
);
1067 setlocale(LC_ALL
, oldlocale
);
1068 #endif /* LC_NUMERIC */
1070 ppd_status
= PPD_INTERNAL_ERROR
;
1075 if ((choice
= ppdFindChoice(option
, "Custom")) == NULL
)
1077 DEBUG_puts("Unable to find Custom choice!");
1083 cupsLangFree(language
);
1086 setlocale(LC_NUMERIC
, oldlocale
);
1088 setlocale(LC_ALL
, oldlocale
);
1089 #endif /* LC_NUMERIC */
1091 ppd_status
= PPD_INTERNAL_ERROR
;
1096 choice
->code
= string
;
1100 else if (strcmp(keyword
, "LandscapeOrientation") == 0)
1102 if (strcmp(string
, "Minus90") == 0)
1103 ppd
->landscape
= -90;
1104 else if (strcmp(string
, "Plus90") == 0)
1105 ppd
->landscape
= 90;
1107 else if (strcmp(keyword
, "Emulators") == 0)
1109 for (count
= 1, sptr
= string
; sptr
!= NULL
;)
1110 if ((sptr
= strchr(sptr
, ' ')) != NULL
)
1113 while (*sptr
== ' ')
1117 ppd
->num_emulations
= count
;
1118 ppd
->emulations
= calloc(sizeof(ppd_emul_t
), count
);
1120 for (i
= 0, sptr
= string
; i
< count
; i
++)
1122 for (nameptr
= ppd
->emulations
[i
].name
;
1123 *sptr
!= '\0' && *sptr
!= ' ';
1125 if (nameptr
< (ppd
->emulations
[i
].name
+ sizeof(ppd
->emulations
[i
].name
) - 1))
1130 while (*sptr
== ' ')
1134 else if (strncmp(keyword
, "StartEmulator_", 14) == 0)
1138 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1139 if (strcmp(keyword
+ 14, ppd
->emulations
[i
].name
) == 0)
1141 ppd
->emulations
[i
].start
= string
;
1145 else if (strncmp(keyword
, "StopEmulator_", 13) == 0)
1149 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1150 if (strcmp(keyword
+ 13, ppd
->emulations
[i
].name
) == 0)
1152 ppd
->emulations
[i
].stop
= string
;
1156 else if (strcmp(keyword
, "JobPatchFile") == 0)
1158 if (ppd
->patches
== NULL
)
1160 ppd
->patches
= string
;
1165 temp
= realloc(ppd
->patches
, strlen(ppd
->patches
) +
1166 strlen(string
) + 1);
1173 cupsLangFree(language
);
1176 setlocale(LC_NUMERIC
, oldlocale
);
1178 setlocale(LC_ALL
, oldlocale
);
1179 #endif /* LC_NUMERIC */
1181 ppd_status
= PPD_ALLOC_ERROR
;
1186 ppd
->patches
= temp
;
1188 strcpy(ppd
->patches
+ strlen(ppd
->patches
), string
);
1191 else if (strcmp(keyword
, "OpenUI") == 0)
1194 * Don't allow nesting of options...
1203 cupsLangFree(language
);
1206 setlocale(LC_NUMERIC
, oldlocale
);
1208 setlocale(LC_ALL
, oldlocale
);
1209 #endif /* LC_NUMERIC */
1211 ppd_status
= PPD_NESTED_OPEN_UI
;
1217 * Add an option record to the current sub-group, group, or file...
1221 strcpy(name
, name
+ 1); /* Eliminate leading asterisk */
1223 for (i
= strlen(name
) - 1; i
> 0 && isspace(name
[i
]); i
--)
1224 name
[i
] = '\0'; /* Eliminate trailing spaces */
1226 DEBUG_printf(("OpenUI of %s in group %s...\n", name
,
1227 group
? group
->text
: "(null)"));
1229 if (subgroup
!= NULL
)
1230 option
= ppd_get_option(subgroup
, name
);
1231 else if (group
== NULL
)
1233 if (strcmp(name
, "Collate") && strcmp(name
, "Duplex") &&
1234 strcmp(name
, "InputSlot") && strcmp(name
, "ManualFeed") &&
1235 strcmp(name
, "MediaType") && strcmp(name
, "MediaColor") &&
1236 strcmp(name
, "MediaWeight") && strcmp(name
, "OutputBin") &&
1237 strcmp(name
, "OutputMode") && strcmp(name
, "OutputOrder") &&
1238 strcmp(name
, "PageSize") && strcmp(name
, "PageRegion"))
1239 group
= ppd_get_group(ppd
, "Extra",
1240 cupsLangString(language
, CUPS_MSG_EXTRA
));
1242 group
= ppd_get_group(ppd
, "General",
1243 cupsLangString(language
, CUPS_MSG_GENERAL
));
1251 cupsLangFree(language
);
1254 setlocale(LC_NUMERIC
, oldlocale
);
1256 setlocale(LC_ALL
, oldlocale
);
1257 #endif /* LC_NUMERIC */
1259 ppd_status
= PPD_ALLOC_ERROR
;
1264 DEBUG_printf(("Adding to group %s...\n", group
->text
));
1265 option
= ppd_get_option(group
, name
);
1269 option
= ppd_get_option(group
, name
);
1277 cupsLangFree(language
);
1280 setlocale(LC_NUMERIC
, oldlocale
);
1282 setlocale(LC_ALL
, oldlocale
);
1283 #endif /* LC_NUMERIC */
1285 ppd_status
= PPD_ALLOC_ERROR
;
1291 * Now fill in the initial information for the option...
1294 if (string
&& strcmp(string
, "PickMany") == 0)
1295 option
->ui
= PPD_UI_PICKMANY
;
1296 else if (string
&& strcmp(string
, "Boolean") == 0)
1297 option
->ui
= PPD_UI_BOOLEAN
;
1298 else if (string
&& strcmp(string
, "PickOne") == 0)
1299 option
->ui
= PPD_UI_PICKONE
;
1306 cupsLangFree(language
);
1309 setlocale(LC_NUMERIC
, oldlocale
);
1311 setlocale(LC_ALL
, oldlocale
);
1312 #endif /* LC_NUMERIC */
1314 ppd_status
= PPD_BAD_OPEN_UI
;
1321 strlcpy(option
->text
, text
, sizeof(option
->text
));
1322 ppd_fix(option
->text
);
1326 if (strcmp(name
, "PageSize") == 0)
1327 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_MEDIA_SIZE
),
1328 sizeof(option
->text
));
1329 else if (strcmp(name
, "MediaType") == 0)
1330 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_MEDIA_TYPE
),
1331 sizeof(option
->text
));
1332 else if (strcmp(name
, "InputSlot") == 0)
1333 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_MEDIA_SOURCE
),
1334 sizeof(option
->text
));
1335 else if (strcmp(name
, "ColorModel") == 0)
1336 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_OUTPUT_MODE
),
1337 sizeof(option
->text
));
1338 else if (strcmp(name
, "Resolution") == 0)
1339 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_RESOLUTION
),
1340 sizeof(option
->text
));
1342 strlcpy(option
->text
, name
, sizeof(option
->text
));
1345 option
->section
= PPD_ORDER_ANY
;
1347 else if (strcmp(keyword
, "JCLOpenUI") == 0)
1350 * Don't allow nesting of options...
1359 cupsLangFree(language
);
1362 setlocale(LC_NUMERIC
, oldlocale
);
1364 setlocale(LC_ALL
, oldlocale
);
1365 #endif /* LC_NUMERIC */
1367 ppd_status
= PPD_NESTED_OPEN_UI
;
1373 * Find the JCL group, and add if needed...
1376 group
= ppd_get_group(ppd
, "JCL", "JCL");
1384 cupsLangFree(language
);
1387 setlocale(LC_NUMERIC
, oldlocale
);
1389 setlocale(LC_ALL
, oldlocale
);
1390 #endif /* LC_NUMERIC */
1392 ppd_status
= PPD_ALLOC_ERROR
;
1398 * Add an option record to the current JCLs...
1402 strcpy(name
, name
+ 1);
1404 option
= ppd_get_option(group
, name
);
1412 cupsLangFree(language
);
1415 setlocale(LC_NUMERIC
, oldlocale
);
1417 setlocale(LC_ALL
, oldlocale
);
1418 #endif /* LC_NUMERIC */
1420 ppd_status
= PPD_ALLOC_ERROR
;
1426 * Now fill in the initial information for the option...
1429 if (string
&& strcmp(string
, "PickMany") == 0)
1430 option
->ui
= PPD_UI_PICKMANY
;
1431 else if (string
&& strcmp(string
, "Boolean") == 0)
1432 option
->ui
= PPD_UI_BOOLEAN
;
1433 else if (string
&& strcmp(string
, "PickOne") == 0)
1434 option
->ui
= PPD_UI_PICKONE
;
1441 cupsLangFree(language
);
1444 setlocale(LC_NUMERIC
, oldlocale
);
1446 setlocale(LC_ALL
, oldlocale
);
1447 #endif /* LC_NUMERIC */
1449 ppd_status
= PPD_BAD_OPEN_UI
;
1454 strlcpy(option
->text
, text
, sizeof(option
->text
));
1456 option
->section
= PPD_ORDER_JCL
;
1459 else if (strcmp(keyword
, "CloseUI") == 0 ||
1460 strcmp(keyword
, "JCLCloseUI") == 0)
1462 else if (strcmp(keyword
, "OpenGroup") == 0)
1465 * Open a new group...
1474 cupsLangFree(language
);
1477 setlocale(LC_NUMERIC
, oldlocale
);
1479 setlocale(LC_ALL
, oldlocale
);
1480 #endif /* LC_NUMERIC */
1482 ppd_status
= PPD_NESTED_OPEN_GROUP
;
1493 cupsLangFree(language
);
1496 setlocale(LC_NUMERIC
, oldlocale
);
1498 setlocale(LC_ALL
, oldlocale
);
1499 #endif /* LC_NUMERIC */
1501 ppd_status
= PPD_BAD_OPEN_GROUP
;
1507 * Separate the group name from the text (name/text)...
1510 if ((sptr
= strchr(string
, '/')) != NULL
)
1516 * Fix up the text...
1523 * Find/add the group...
1526 group
= ppd_get_group(ppd
, string
, sptr
);
1528 else if (strcmp(keyword
, "CloseGroup") == 0)
1530 else if (strcmp(keyword
, "OrderDependency") == 0 ||
1531 strcmp(keyword
, "NonUIOrderDependency") == 0)
1533 if (sscanf(string
, "%f%40s%40s", &order
, name
, keyword
) != 3)
1539 cupsLangFree(language
);
1542 setlocale(LC_NUMERIC
, oldlocale
);
1544 setlocale(LC_ALL
, oldlocale
);
1545 #endif /* LC_NUMERIC */
1547 ppd_status
= PPD_BAD_ORDER_DEPENDENCY
;
1552 if (keyword
[0] == '*')
1553 strcpy(keyword
, keyword
+ 1);
1555 if (strcmp(name
, "ExitServer") == 0)
1556 section
= PPD_ORDER_EXIT
;
1557 else if (strcmp(name
, "Prolog") == 0)
1558 section
= PPD_ORDER_PROLOG
;
1559 else if (strcmp(name
, "DocumentSetup") == 0)
1560 section
= PPD_ORDER_DOCUMENT
;
1561 else if (strcmp(name
, "PageSetup") == 0)
1562 section
= PPD_ORDER_PAGE
;
1563 else if (strcmp(name
, "JCLSetup") == 0)
1564 section
= PPD_ORDER_JCL
;
1566 section
= PPD_ORDER_ANY
;
1574 * Only valid for Non-UI options...
1577 for (i
= ppd
->num_groups
, temp
= ppd
->groups
; i
> 0; i
--, temp
++)
1578 if (temp
->text
[0] == '\0')
1582 for (i
= 0; i
< temp
->num_options
; i
++)
1583 if (strcmp(keyword
, temp
->options
[i
].keyword
) == 0)
1585 temp
->options
[i
].section
= section
;
1586 temp
->options
[i
].order
= order
;
1592 option
->section
= section
;
1593 option
->order
= order
;
1596 else if (strncmp(keyword
, "Default", 7) == 0)
1601 if (strchr(string
, '/') != NULL
)
1602 *strchr(string
, '/') = '\0';
1610 * Only valid for Non-UI options...
1613 for (i
= ppd
->num_groups
, temp
= ppd
->groups
; i
> 0; i
--, temp
++)
1614 if (temp
->text
[0] == '\0')
1619 for (i
= 0; i
< temp
->num_options
; i
++)
1620 if (strcmp(keyword
+ 7, temp
->options
[i
].keyword
) == 0)
1622 strlcpy(temp
->options
[i
].defchoice
, string
,
1623 sizeof(temp
->options
[i
].defchoice
));
1627 if (i
>= temp
->num_options
)
1630 * Option not found; add this as an attribute...
1633 ppd_add_attr(ppd
, keyword
, "", string
);
1635 string
= NULL
; /* Don't free this string below */
1641 * Default group not found; add this as an attribute...
1644 ppd_add_attr(ppd
, keyword
, "", string
);
1646 string
= NULL
; /* Don't free this string below */
1649 else if (strcmp(keyword
+ 7, option
->keyword
) == 0)
1650 strlcpy(option
->defchoice
, string
, sizeof(option
->defchoice
));
1654 * Default doesn't match this option; add as an attribute...
1657 ppd_add_attr(ppd
, keyword
, "", string
);
1659 string
= NULL
; /* Don't free this string below */
1662 else if (strcmp(keyword
, "UIConstraints") == 0 ||
1663 strcmp(keyword
, "NonUIConstraints") == 0)
1665 if (ppd
->num_consts
== 0)
1666 constraint
= calloc(sizeof(ppd_const_t
), 1);
1668 constraint
= realloc(ppd
->consts
,
1669 (ppd
->num_consts
+ 1) * sizeof(ppd_const_t
));
1671 if (constraint
== NULL
)
1677 cupsLangFree(language
);
1680 setlocale(LC_NUMERIC
, oldlocale
);
1682 setlocale(LC_ALL
, oldlocale
);
1683 #endif /* LC_NUMERIC */
1685 ppd_status
= PPD_ALLOC_ERROR
;
1690 ppd
->consts
= constraint
;
1691 constraint
+= ppd
->num_consts
;
1694 switch (sscanf(string
, "%40s%40s%40s%40s", constraint
->option1
,
1695 constraint
->choice1
, constraint
->option2
,
1696 constraint
->choice2
))
1698 case 0 : /* Error */
1699 case 1 : /* Error */
1702 ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1705 case 2 : /* Two options... */
1707 * The following strcpy's are safe, as optionN and
1708 * choiceN are all the same size (size defined by PPD spec...)
1711 if (constraint
->option1
[0] == '*')
1712 strcpy(constraint
->option1
, constraint
->option1
+ 1);
1714 if (constraint
->choice1
[0] == '*')
1715 strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1717 strcpy(constraint
->option2
, constraint
->choice1
);
1719 constraint
->choice1
[0] = '\0';
1720 constraint
->choice2
[0] = '\0';
1723 case 3 : /* Two options, one choice... */
1725 * The following strcpy's are safe, as optionN and
1726 * choiceN are all the same size (size defined by PPD spec...)
1729 if (constraint
->option1
[0] == '*')
1730 strcpy(constraint
->option1
, constraint
->option1
+ 1);
1732 if (constraint
->choice1
[0] == '*')
1734 strcpy(constraint
->choice2
, constraint
->option2
);
1735 strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1736 constraint
->choice1
[0] = '\0';
1740 if (constraint
->option2
[0] == '*')
1741 strcpy(constraint
->option2
, constraint
->option2
+ 1);
1743 constraint
->choice2
[0] = '\0';
1747 case 4 : /* Two options, two choices... */
1748 if (constraint
->option1
[0] == '*')
1749 strcpy(constraint
->option1
, constraint
->option1
+ 1);
1751 if (constraint
->option2
[0] == '*')
1752 strcpy(constraint
->option2
, constraint
->option2
+ 1);
1756 else if (strcmp(keyword
, "PaperDimension") == 0)
1758 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1759 size
= ppd_add_size(ppd
, name
);
1764 * Unable to add or find size!
1771 cupsLangFree(language
);
1774 setlocale(LC_NUMERIC
, oldlocale
);
1776 setlocale(LC_ALL
, oldlocale
);
1777 #endif /* LC_NUMERIC */
1779 ppd_status
= PPD_ALLOC_ERROR
;
1784 sscanf(string
, "%f%f", &(size
->width
), &(size
->length
));
1786 else if (strcmp(keyword
, "ImageableArea") == 0)
1788 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1789 size
= ppd_add_size(ppd
, name
);
1794 * Unable to add or find size!
1801 cupsLangFree(language
);
1804 setlocale(LC_NUMERIC
, oldlocale
);
1806 setlocale(LC_ALL
, oldlocale
);
1807 #endif /* LC_NUMERIC */
1809 ppd_status
= PPD_ALLOC_ERROR
;
1814 sscanf(string
, "%f%f%f%f", &(size
->left
), &(size
->bottom
),
1815 &(size
->right
), &(size
->top
));
1817 else if (option
!= NULL
&&
1818 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
1819 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
) &&
1820 strcmp(keyword
, option
->keyword
) == 0)
1822 DEBUG_printf(("group = %p, subgroup = %p\n", group
, subgroup
));
1824 if (strcmp(keyword
, "PageSize") == 0)
1827 * Add a page size...
1830 if (ppdPageSize(ppd
, name
) == NULL
)
1831 ppd_add_size(ppd
, name
);
1835 * Add the option choice...
1838 choice
= ppd_add_choice(option
, name
);
1840 if (mask
& PPD_TEXT
)
1842 strlcpy(choice
->text
, text
, sizeof(choice
->text
));
1843 ppd_fix(choice
->text
);
1845 else if (strcmp(name
, "True") == 0)
1846 strcpy(choice
->text
, "Yes");
1847 else if (strcmp(name
, "False") == 0)
1848 strcpy(choice
->text
, "No");
1850 strlcpy(choice
->text
, name
, sizeof(choice
->text
));
1852 if (option
->section
== PPD_ORDER_JCL
)
1853 ppd_decode(string
); /* Decode quoted string */
1855 choice
->code
= string
;
1856 string
= NULL
; /* Don't free this string below */
1858 else if (strcmp(keyword
, "OpenSubGroup") != 0 &&
1859 strcmp(keyword
, "CloseSubGroup") != 0)
1861 char spec
[PPD_MAX_NAME
+ PPD_MAX_TEXT
];
1863 snprintf(spec
, sizeof(spec
), "%s/%s", name
, text
);
1864 ppd_add_attr(ppd
, keyword
, spec
, string
);
1866 string
= NULL
; /* Don't free this string below */
1873 * Reset language preferences...
1876 cupsLangFree(language
);
1879 setlocale(LC_NUMERIC
, oldlocale
);
1881 setlocale(LC_ALL
, oldlocale
);
1882 #endif /* LC_NUMERIC */
1886 printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp
));
1889 if (ppd_status
!= PPD_OK
)
1892 * Had an error reading the PPD file, cannot continue!
1902 * Make sure that all PPD files with an InputSlot option have an
1903 * "auto" choice that maps to no specific tray or media type.
1906 if ((option
= ppdFindOption(ppd
, "InputSlot")) != NULL
)
1908 for (i
= 0; i
< option
->num_choices
; i
++)
1909 if (option
->choices
[i
].code
== NULL
|| !option
->choices
[i
].code
[0])
1912 if (i
>= option
->num_choices
)
1915 * No "auto" input slot, add one...
1918 choice
= ppd_add_choice(option
, "Auto");
1920 strlcpy(choice
->text
, cupsLangString(language
, CUPS_MSG_AUTO
),
1921 sizeof(choice
->text
));
1922 choice
->code
= NULL
;
1925 #endif /* !__APPLE__ */
1928 * Set the option back-pointer for each choice...
1932 qsort(ppd
->groups
, ppd
->num_groups
, sizeof(ppd_group_t
),
1933 (int (*)(const void *, const void *))ppd_compare_groups
);
1934 #endif /* !__APPLE__ */
1936 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
1941 qsort(group
->options
, group
->num_options
, sizeof(ppd_option_t
),
1942 (int (*)(const void *, const void *))ppd_compare_options
);
1943 #endif /* !__APPLE__ */
1945 for (j
= group
->num_options
, option
= group
->options
;
1949 for (k
= 0; k
< option
->num_choices
; k
++)
1950 option
->choices
[k
].option
= (void *)option
;
1954 qsort(group
->subgroups
, group
->num_subgroups
, sizeof(ppd_group_t
),
1955 (int (*)(const void *, const void *))ppd_compare_groups
);
1956 #endif /* !__APPLE__ */
1958 for (j
= group
->num_subgroups
, subgroup
= group
->subgroups
;
1963 qsort(subgroup
->options
, subgroup
->num_options
, sizeof(ppd_option_t
),
1964 (int (*)(const void *, const void *))ppd_compare_options
);
1965 #endif /* !__APPLE__ */
1967 for (k
= group
->num_options
, option
= group
->options
;
1971 for (m
= 0; m
< option
->num_choices
; m
++)
1972 option
->choices
[m
].option
= (void *)option
;
1978 * Sort the attributes...
1981 if (ppd
->num_attrs
> 1)
1982 qsort(ppd
->attrs
, ppd
->num_attrs
, sizeof(ppd_attr_t
*),
1983 (int (*)(const void *, const void *))_ppd_attr_compare
);
1986 * Return the PPD file structure...
1994 * 'ppdOpenFd()' - Read a PPD file into memory.
1997 ppd_file_t
* /* O - PPD file record */
1998 ppdOpenFd(int fd
) /* I - File to read from */
2000 FILE *fp
; /* File pointer */
2001 ppd_file_t
*ppd
; /* PPD file record */
2005 * Set the line number to 0...
2011 * Range check input...
2016 ppd_status
= PPD_NULL_FILE
;
2022 * Try to open the file and parse it...
2025 if ((fp
= fdopen(fd
, "r")) != NULL
)
2035 ppd_status
= PPD_FILE_OPEN_ERROR
;
2044 * 'ppdOpenFile()' - Read a PPD file into memory.
2047 ppd_file_t
* /* O - PPD file record */
2048 ppdOpenFile(const char *filename
) /* I - File to read from */
2050 FILE *fp
; /* File pointer */
2051 ppd_file_t
*ppd
; /* PPD file record */
2055 * Set the line number to 0...
2061 * Range check input...
2064 if (filename
== NULL
)
2066 ppd_status
= PPD_NULL_FILE
;
2072 * Try to open the file and parse it...
2075 if ((fp
= fopen(filename
, "r")) != NULL
)
2083 ppd_status
= PPD_FILE_OPEN_ERROR
;
2092 * 'ppd_add_attr()' - Add an attribute to the PPD data.
2095 static ppd_attr_t
* /* O - New attribute */
2096 ppd_add_attr(ppd_file_t
*ppd
, /* I - PPD file data */
2097 const char *name
, /* I - Attribute name */
2098 const char *spec
, /* I - Specifier string, if any */
2099 const char *value
) /* I - Value of attribute */
2101 ppd_attr_t
**ptr
, /* New array */
2102 *temp
; /* New attribute */
2106 * Range check input...
2109 if (ppd
== NULL
|| name
== NULL
|| spec
== NULL
)
2113 * Allocate memory for the new attribute...
2116 if (ppd
->num_attrs
== 0)
2117 ptr
= malloc(sizeof(ppd_attr_t
*));
2119 ptr
= realloc(ppd
->attrs
, (ppd
->num_attrs
+ 1) * sizeof(ppd_attr_t
*));
2125 ptr
+= ppd
->num_attrs
;
2127 if ((temp
= calloc(1, sizeof(ppd_attr_t
))) == NULL
)
2138 strlcpy(temp
->name
, name
, sizeof(temp
->name
));
2139 strlcpy(temp
->spec
, spec
, sizeof(temp
->spec
));
2140 temp
->value
= (char *)value
;
2143 * Return the attribute...
2151 * 'ppd_add_choice()' - Add a choice to an option.
2154 static ppd_choice_t
* /* O - Named choice */
2155 ppd_add_choice(ppd_option_t
*option
, /* I - Option */
2156 const char *name
) /* I - Name of choice */
2158 ppd_choice_t
*choice
; /* Choice */
2161 if (option
->num_choices
== 0)
2162 choice
= malloc(sizeof(ppd_choice_t
));
2164 choice
= realloc(option
->choices
,
2165 sizeof(ppd_choice_t
) * (option
->num_choices
+ 1));
2170 option
->choices
= choice
;
2171 choice
+= option
->num_choices
;
2172 option
->num_choices
++;
2174 memset(choice
, 0, sizeof(ppd_choice_t
));
2175 strlcpy(choice
->choice
, name
, sizeof(choice
->choice
));
2182 * 'ppd_add_size()' - Add a page size.
2185 static ppd_size_t
* /* O - Named size */
2186 ppd_add_size(ppd_file_t
*ppd
, /* I - PPD file */
2187 const char *name
) /* I - Name of size */
2189 ppd_size_t
*size
; /* Size */
2192 if (ppd
->num_sizes
== 0)
2193 size
= malloc(sizeof(ppd_size_t
));
2195 size
= realloc(ppd
->sizes
, sizeof(ppd_size_t
) * (ppd
->num_sizes
+ 1));
2201 size
+= ppd
->num_sizes
;
2204 memset(size
, 0, sizeof(ppd_size_t
));
2205 strlcpy(size
->name
, name
, sizeof(size
->name
));
2213 * 'ppd_compare_groups()' - Compare two groups.
2216 static int /* O - Result of comparison */
2217 ppd_compare_groups(ppd_group_t
*g0
, /* I - First group */
2218 ppd_group_t
*g1
) /* I - Second group */
2220 return (strcasecmp(g0
->text
, g1
->text
));
2225 * 'ppd_compare_options()' - Compare two options.
2228 static int /* O - Result of comparison */
2229 ppd_compare_options(ppd_option_t
*o0
, /* I - First option */
2230 ppd_option_t
*o1
) /* I - Second option */
2232 return (strcasecmp(o0
->text
, o1
->text
));
2234 #endif /* !__APPLE__ */
2238 * 'ppd_decode()' - Decode a string value...
2242 ppd_decode(char *string
) /* I - String to decode */
2244 char *inptr
, /* Input pointer */
2245 *outptr
; /* Output pointer */
2251 while (*inptr
!= '\0')
2252 if (*inptr
== '<' && isxdigit(inptr
[1]))
2255 * Convert hex to 8-bit values...
2259 while (isxdigit(*inptr
))
2261 if (isalpha(*inptr
))
2262 *outptr
= (tolower(*inptr
) - 'a' + 10) << 4;
2264 *outptr
= (*inptr
- '0') << 4;
2268 if (isalpha(*inptr
))
2269 *outptr
|= tolower(*inptr
) - 'a' + 10;
2271 *outptr
|= *inptr
- '0';
2277 while (*inptr
!= '>' && *inptr
!= '\0')
2279 while (*inptr
== '>')
2283 *outptr
++ = *inptr
++;
2291 * 'ppd_fix()' - Fix WinANSI characters in the range 0x80 to 0x9f to be
2292 * valid ISO-8859-1 characters...
2296 ppd_fix(char *string
) /* IO - String to fix */
2298 unsigned char *p
; /* Pointer into string */
2299 static const unsigned char lut
[32] = /* Lookup table for characters */
2323 0x20, /* circumflex */
2325 0x20, /* double dot */
2330 '\"', /* should be right quotes */
2336 for (p
= (unsigned char *)string
; *p
; p
++)
2337 if (*p
>= 0x80 && *p
< 0xa0)
2338 *p
= lut
[*p
- 0x80];
2340 #endif /* !__APPLE__ */
2344 * 'ppd_free_group()' - Free a single UI group.
2348 ppd_free_group(ppd_group_t
*group
) /* I - Group to free */
2350 int i
; /* Looping var */
2351 ppd_option_t
*option
; /* Current option */
2352 ppd_group_t
*subgroup
; /* Current sub-group */
2355 if (group
->num_options
> 0)
2357 for (i
= group
->num_options
, option
= group
->options
;
2360 ppd_free_option(option
);
2362 ppd_free(group
->options
);
2365 if (group
->num_subgroups
> 0)
2367 for (i
= group
->num_subgroups
, subgroup
= group
->subgroups
;
2370 ppd_free_group(subgroup
);
2372 ppd_free(group
->subgroups
);
2378 * 'ppd_free_option()' - Free a single option.
2382 ppd_free_option(ppd_option_t
*option
) /* I - Option to free */
2384 int i
; /* Looping var */
2385 ppd_choice_t
*choice
; /* Current choice */
2388 if (option
->num_choices
> 0)
2390 for (i
= option
->num_choices
, choice
= option
->choices
;
2393 ppd_free(choice
->code
);
2395 ppd_free(option
->choices
);
2401 * 'ppd_get_group()' - Find or create the named group as needed.
2404 static ppd_group_t
* /* O - Named group */
2405 ppd_get_group(ppd_file_t
*ppd
, /* I - PPD file */
2406 const char *name
, /* I - Name of group */
2407 const char *text
) /* I - Text for group */
2409 int i
; /* Looping var */
2410 ppd_group_t
*group
; /* Group */
2413 DEBUG_printf(("ppd_get_group(%p, \"%s\")\n", ppd
, name
));
2415 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
2416 if (strcmp(group
->name
, name
) == 0)
2421 DEBUG_printf(("Adding group %s...\n", name
));
2423 if (ppd
->num_groups
== 0)
2424 group
= malloc(sizeof(ppd_group_t
));
2426 group
= realloc(ppd
->groups
,
2427 (ppd
->num_groups
+ 1) * sizeof(ppd_group_t
));
2432 ppd
->groups
= group
;
2433 group
+= ppd
->num_groups
;
2436 memset(group
, 0, sizeof(ppd_group_t
));
2437 strlcpy(group
->name
, name
, sizeof(group
->name
));
2438 strlcpy(group
->text
, text
, sizeof(group
->text
));
2446 * 'ppd_get_option()' - Find or create the named option as needed.
2449 static ppd_option_t
* /* O - Named option */
2450 ppd_get_option(ppd_group_t
*group
, /* I - Group */
2451 const char *name
) /* I - Name of option */
2453 int i
; /* Looping var */
2454 ppd_option_t
*option
; /* Option */
2457 for (i
= group
->num_options
, option
= group
->options
; i
> 0; i
--, option
++)
2458 if (strcmp(option
->keyword
, name
) == 0)
2463 if (group
->num_options
== 0)
2464 option
= malloc(sizeof(ppd_option_t
));
2466 option
= realloc(group
->options
,
2467 (group
->num_options
+ 1) * sizeof(ppd_option_t
));
2472 group
->options
= option
;
2473 option
+= group
->num_options
;
2474 group
->num_options
++;
2476 memset(option
, 0, sizeof(ppd_option_t
));
2477 strlcpy(option
->keyword
, name
, sizeof(option
->keyword
));
2485 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2489 static int /* O - Bitmask of fields read */
2490 ppd_read(FILE *fp
, /* I - File to read from */
2491 char *keyword
, /* O - Keyword from line */
2492 char *option
, /* O - Option from line */
2493 char *text
, /* O - Human-readable text from line */
2494 char **string
) /* O - Code/string data */
2496 int ch
, /* Character from file */
2497 col
, /* Column in line */
2498 colon
, /* Colon seen? */
2499 endquote
, /* Waiting for an end quote */
2500 mask
; /* Mask to be returned */
2501 char *keyptr
, /* Keyword pointer */
2502 *optptr
, /* Option pointer */
2503 *textptr
, /* Text pointer */
2504 *strptr
, /* Pointer into string */
2505 *lineptr
, /* Current position in line buffer */
2506 line
[65536]; /* Line buffer (64k) */
2510 * Range check everything...
2513 if (fp
== NULL
|| keyword
== NULL
|| option
== NULL
|| text
== NULL
||
2518 * Now loop until we have a valid line...
2534 while ((ch
= getc(fp
)) != EOF
&&
2535 (lineptr
- line
) < (sizeof(line
) - 1))
2537 if (ch
== '\r' || ch
== '\n')
2540 * Line feed or carriage return...
2546 if (lineptr
== line
) /* Skip blank lines */
2552 * Check for a trailing line feed...
2555 if ((ch
= getc(fp
)) == EOF
)
2563 if (!endquote
) /* Continue for multi-line text */
2568 else if (ch
< ' ' && ch
!= '\t' && ch
!= 0x1a)
2571 * Other control characters...
2574 ppd_status
= PPD_ILLEGAL_CHARACTER
;
2578 else if (ch
!= 0x1a)
2581 * Any other character...
2587 if (col
> (PPD_MAX_LINE
- 1))
2590 * Line is too long...
2593 ppd_status
= PPD_LINE_TOO_LONG
;
2598 if (ch
== ':' && strncmp(line
, "*%", 2) != 0)
2601 if (ch
== '\"' && colon
)
2603 endquote
= !endquote
;
2608 * End of quoted string; ignore trailing characters...
2611 while ((ch
= getc(fp
)) != EOF
)
2612 if (ch
== '\r' || ch
== '\n')
2628 else if (ch
< ' ' && ch
!= '\t' && ch
!= 0x1a)
2631 * Other control characters...
2634 ppd_status
= PPD_ILLEGAL_CHARACTER
;
2638 else if (ch
!= 0x1a)
2642 if (col
> (PPD_MAX_LINE
- 1))
2645 * Line is too long...
2648 ppd_status
= PPD_LINE_TOO_LONG
;
2663 * Didn't finish this quoted string...
2666 while ((ch
= getc(fp
)) != EOF
)
2669 else if (ch
== '\r' || ch
== '\n')
2677 * Check for a trailing line feed...
2680 if ((ch
= getc(fp
)) == EOF
)
2688 else if (ch
< ' ' && ch
!= '\t' && ch
!= 0x1a)
2691 * Other control characters...
2694 ppd_status
= PPD_ILLEGAL_CHARACTER
;
2698 else if (ch
!= 0x1a)
2702 if (col
> (PPD_MAX_LINE
- 1))
2705 * Line is too long...
2708 ppd_status
= PPD_LINE_TOO_LONG
;
2718 * Didn't finish this line...
2721 while ((ch
= getc(fp
)) != EOF
)
2722 if (ch
== '\r' || ch
== '\n')
2725 * Line feed or carriage return...
2734 * Check for a trailing line feed...
2737 if ((ch
= getc(fp
)) == EOF
)
2745 else if (ch
< ' ' && ch
!= '\t' && ch
!= 0x1a)
2748 * Other control characters...
2751 ppd_status
= PPD_ILLEGAL_CHARACTER
;
2755 else if (ch
!= 0x1a)
2759 if (col
> (PPD_MAX_LINE
- 1))
2762 * Line is too long...
2765 ppd_status
= PPD_LINE_TOO_LONG
;
2772 if (lineptr
> line
&& lineptr
[-1] == '\n')
2777 /* DEBUG_printf(("LINE = \"%s\"\n", line));*/
2779 if (ch
== EOF
&& lineptr
== line
)
2794 if (!line
[0] || /* Blank line */
2795 strcmp(line
, "*") == 0 || /* (Bad) comment line */
2796 strncmp(line
, "*%", 2) == 0 || /* Comment line */
2797 strncmp(line
, "*?", 2) == 0 || /* Query line */
2798 strcmp(line
, "*End") == 0) /* End of multi-line string */
2801 if (line
[0] != '*') /* All lines start with an asterisk */
2804 * Allow lines consisting of just whitespace...
2807 for (lineptr
= line
; *lineptr
; lineptr
++)
2808 if (!isspace(*lineptr
))
2813 ppd_status
= PPD_MISSING_ASTERISK
;
2826 while (*lineptr
!= '\0' && *lineptr
!= ':' && !isspace(*lineptr
))
2828 if (*lineptr
<= ' ' || *lineptr
> 126 || *lineptr
== '/' ||
2829 (keyptr
- keyword
) >= (PPD_MAX_NAME
- 1))
2831 ppd_status
= PPD_ILLEGAL_MAIN_KEYWORD
;
2835 *keyptr
++ = *lineptr
++;
2840 if (strcmp(keyword
, "End") == 0)
2843 mask
|= PPD_KEYWORD
;
2845 /* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
2847 if (isspace(*lineptr
))
2850 * Get an option name...
2853 while (isspace(*lineptr
))
2858 while (*lineptr
!= '\0' && *lineptr
!= '\n' && *lineptr
!= ':' &&
2861 if (*lineptr
<= ' ' || *lineptr
> 126 ||
2862 (optptr
- option
) >= (PPD_MAX_NAME
- 1))
2864 ppd_status
= PPD_ILLEGAL_OPTION_KEYWORD
;
2868 *optptr
++ = *lineptr
++;
2874 /* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
2876 if (*lineptr
== '/')
2879 * Get human-readable text...
2886 while (*lineptr
!= '\0' && *lineptr
!= '\n' && *lineptr
!= ':')
2888 if (((unsigned char)*lineptr
< ' ' && *lineptr
!= '\t') ||
2889 (textptr
- text
) >= (PPD_MAX_LINE
- 1))
2891 ppd_status
= PPD_ILLEGAL_TRANSLATION
;
2895 *textptr
++ = *lineptr
++;
2904 /* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
2907 if (*lineptr
== ':')
2913 *string
= malloc(strlen(lineptr
) + 1);
2915 while (*lineptr
== ':' || isspace(*lineptr
))
2920 for (; *lineptr
!= '\0'; lineptr
++)
2921 if (*lineptr
!= '\"')
2922 *strptr
++ = *lineptr
;
2926 /* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
2938 * End of "$Id: ppd.c,v 1.93 2003/02/19 14:46:10 mike Exp $".