2 * "$Id: ppd.c,v 1.51.2.31 2003/01/29 17:04:33 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_extopt() - Get an extended option record.
55 * ppd_get_group() - Find or create the named group as needed.
56 * ppd_get_option() - Find or create the named option as needed.
57 * ppd_read() - Read a line from a PPD file, skipping comment
62 * Include necessary headers.
77 #if defined(WIN32) || defined(__EMX__)
78 # define READ_BINARY "rb" /* Open a binary file for reading */
79 # define WRITE_BINARY "wb" /* Open a binary file for writing */
81 # define READ_BINARY "r" /* Open a binary file for reading */
82 # define WRITE_BINARY "w" /* Open a binary file for writing */
83 #endif /* WIN32 || __EMX__ */
85 #define ppd_free(p) if (p) free(p) /* Safe free macro */
87 #define PPD_KEYWORD 1 /* Line contained a keyword */
88 #define PPD_OPTION 2 /* Line contained an option name */
89 #define PPD_TEXT 4 /* Line contained human-readable text */
90 #define PPD_STRING 8 /* Line contained a string or code */
97 static ppd_status_t ppd_status
= PPD_OK
;
98 /* Status of last ppdOpen*() */
99 static int ppd_line
= 1; /* Current line number */
106 static ppd_attr_t
*ppd_add_attr(ppd_file_t
*ppd
, const char *name
,
107 const char *spec
, const char *value
);
108 static ppd_choice_t
*ppd_add_choice(ppd_option_t
*option
, const char *name
);
109 static ppd_size_t
*ppd_add_size(ppd_file_t
*ppd
, const char *name
);
111 static int ppd_compare_groups(ppd_group_t
*g0
, ppd_group_t
*g1
);
112 static int ppd_compare_options(ppd_option_t
*o0
, ppd_option_t
*o1
);
113 #endif /* !__APPLE__ */
114 static void ppd_decode(char *string
);
116 static void ppd_fix(char *string
);
119 #endif /* !__APPLE__ */
120 static void ppd_free_group(ppd_group_t
*group
);
121 static void ppd_free_option(ppd_option_t
*option
);
122 static ppd_ext_option_t
*ppd_get_extopt(ppd_file_t
*ppd
, const char *name
);
123 static ppd_group_t
*ppd_get_group(ppd_file_t
*ppd
, const char *name
,
125 static ppd_option_t
*ppd_get_option(ppd_group_t
*group
, const char *name
);
126 static int ppd_read(FILE *fp
, char *keyword
, char *option
,
127 char *text
, char **string
);
131 * '_ppd_attr_compare()' - Compare two attributes.
134 int /* O - Result of comparison */
135 _ppd_attr_compare(ppd_attr_t
**a
, /* I - First attribute */
136 ppd_attr_t
**b
) /* I - Second attribute */
138 int ret
; /* Result of comparison */
141 if ((ret
= strcasecmp((*a
)->name
, (*b
)->name
)) != 0)
143 else if ((*a
)->spec
[0] && (*b
)->spec
[0])
144 return (strcasecmp((*a
)->spec
, (*b
)->spec
));
151 * 'ppdClose()' - Free all memory used by the PPD file.
155 ppdClose(ppd_file_t
*ppd
) /* I - PPD file record */
157 int i
; /* Looping var */
158 ppd_emul_t
*emul
; /* Current emulation */
159 ppd_group_t
*group
; /* Current group */
160 char **font
; /* Current font */
161 char **filter
; /* Current filter */
162 ppd_attr_t
**attr
; /* Current attribute */
166 * Range check the PPD file record...
173 * Free all strings at the top level...
176 ppd_free(ppd
->patches
);
177 ppd_free(ppd
->jcl_begin
);
178 ppd_free(ppd
->jcl_ps
);
179 ppd_free(ppd
->jcl_end
);
180 ppd_free(ppd
->lang_encoding
);
181 ppd_free(ppd
->lang_version
);
182 ppd_free(ppd
->modelname
);
183 ppd_free(ppd
->ttrasterizer
);
184 ppd_free(ppd
->manufacturer
);
185 ppd_free(ppd
->nickname
);
186 ppd_free(ppd
->shortnickname
);
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 "Missing PPD-Adobe-4.x header",
296 "Memory allocation error",
297 "Missing value string",
299 "OpenGroup without a CloseGroup first",
300 "Bad OrderDependency",
305 if (status
< PPD_OK
|| status
> PPD_BAD_UI_CONSTRAINTS
)
308 return (messages
[status
]);
313 * 'ppdLastError()' - Return the status from the last ppdOpen*().
316 ppd_status_t
/* O - Status code */
317 ppdLastError(int *line
) /* O - Line number */
327 * 'ppdOpen()' - Read a PPD file into memory.
330 ppd_file_t
* /* O - PPD file record */
331 ppdOpen(FILE *fp
) /* I - File to read from */
333 char *oldlocale
; /* Old locale settings */
334 int i
, j
, k
, m
; /* Looping vars */
335 int count
; /* Temporary count */
336 ppd_file_t
*ppd
; /* PPD file record */
337 ppd_group_t
*group
, /* Current group */
338 *subgroup
; /* Current sub-group */
339 ppd_option_t
*option
; /* Current option */
340 ppd_ext_option_t
*extopt
; /* Current extended option */
341 ppd_choice_t
*choice
; /* Current choice */
342 ppd_const_t
*constraint
; /* Current constraint */
343 ppd_size_t
*size
; /* Current page size */
344 int mask
; /* Line data mask */
345 char keyword
[PPD_MAX_NAME
],
346 /* Keyword from file */
348 /* Option from file */
350 /* Human-readable text from file */
351 *string
, /* Code/text from file */
352 *sptr
, /* Pointer into string */
353 *nameptr
, /* Pointer into name */
354 *temp
, /* Temporary string pointer */
355 **tempfonts
; /* Temporary fonts pointer */
356 float order
; /* Order dependency number */
357 ppd_section_t section
; /* Order dependency section */
358 ppd_profile_t
*profile
; /* Pointer to color profile */
359 char **filter
; /* Pointer to filter */
360 cups_lang_t
*language
; /* Default language */
364 * Default to "OK" status...
371 * Range check input...
376 ppd_status
= PPD_NULL_FILE
;
381 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
384 mask
= ppd_read(fp
, keyword
, name
, text
, &string
);
387 strcmp(keyword
, "PPD-Adobe") != 0 ||
388 string
== NULL
|| string
[0] != '4')
391 * Either this is not a PPD file, or it is not a 4.x PPD file.
394 ppd_status
= PPD_MISSING_PPDADOBE4
;
401 DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword
, string
));
406 * Allocate memory for the PPD file record...
409 if ((ppd
= calloc(sizeof(ppd_file_t
), 1)) == NULL
)
411 ppd_status
= PPD_ALLOC_ERROR
;
416 ppd
->language_level
= 1;
417 ppd
->color_device
= 0;
418 ppd
->colorspace
= PPD_CS_GRAY
;
419 ppd
->landscape
= -90;
422 * Get the default language for the user...
425 language
= cupsLangDefault();
428 oldlocale
= setlocale(LC_NUMERIC
, "C");
430 oldlocale
= setlocale(LC_ALL
, "C");
431 #endif /* LC_NUMERIC */
434 * Read lines from the PPD file and add them to the file record...
442 while ((mask
= ppd_read(fp
, keyword
, name
, text
, &string
)) != 0)
445 printf("mask = %x, keyword = \"%s\"", mask
, keyword
);
448 printf(", name = \"%s\"", name
);
451 printf(", text = \"%s\"", text
);
455 if (strlen(string
) > 40)
456 printf(", string = %p", string
);
458 printf(", string = \"%s\"", string
);
464 if (strcmp(keyword
, "CloseUI") != 0 &&
465 strcmp(keyword
, "JCLCloseUI") != 0 &&
466 strcmp(keyword
, "CloseGroup") != 0 &&
467 strcmp(keyword
, "CloseSubGroup") != 0 &&
468 strncmp(keyword
, "Default", 7) != 0 &&
472 * Need a string value!
477 cupsLangFree(language
);
480 setlocale(LC_NUMERIC
, oldlocale
);
482 setlocale(LC_ALL
, oldlocale
);
483 #endif /* LC_NUMERIC */
485 ppd_status
= PPD_MISSING_VALUE
;
490 if (strcmp(keyword
, "LanguageLevel") == 0)
491 ppd
->language_level
= atoi(string
);
492 else if (strcmp(keyword
, "LanguageEncoding") == 0)
494 ppd_free(ppd
->lang_encoding
);
495 ppd
->lang_encoding
= string
;
496 string
= NULL
; /* Don't free this string below */
498 else if (strcmp(keyword
, "LanguageVersion") == 0)
500 ppd_free(ppd
->lang_version
);
501 ppd
->lang_version
= string
;
502 string
= NULL
; /* Don't free this string below */
504 else if (strcmp(keyword
, "Manufacturer") == 0)
506 ppd_free(ppd
->manufacturer
);
507 ppd
->manufacturer
= string
;
508 string
= NULL
; /* Don't free this string below */
510 else if (strcmp(keyword
, "ModelName") == 0)
512 ppd_free(ppd
->modelname
);
513 ppd
->modelname
= string
;
514 string
= NULL
; /* Don't free this string below */
516 else if (strcmp(keyword
, "Protocols") == 0)
518 ppd_free(ppd
->protocols
);
519 ppd
->protocols
= string
;
520 string
= NULL
; /* Don't free this string below */
522 else if (strcmp(keyword
, "PCFileName") == 0)
524 ppd_free(ppd
->pcfilename
);
525 ppd
->pcfilename
= string
;
526 string
= NULL
; /* Don't free this string below */
528 else if (strcmp(keyword
, "NickName") == 0)
530 ppd_free(ppd
->nickname
);
531 ppd
->nickname
= string
;
532 string
= NULL
; /* Don't free this string below */
534 else if (strcmp(keyword
, "Product") == 0)
537 * Add each Product keyword as an attribute...
540 ppd_add_attr(ppd
, keyword
, "", string
);
543 * Save the last one in the product element...
546 ppd
->product
= string
;
547 string
= NULL
; /* Don't free this string below */
549 else if (strcmp(keyword
, "ShortNickName") == 0)
551 ppd_free(ppd
->shortnickname
);
552 ppd
->shortnickname
= string
;
553 string
= NULL
; /* Don't free this string below */
555 else if (strcmp(keyword
, "TTRasterizer") == 0)
557 ppd_free(ppd
->ttrasterizer
);
558 ppd
->ttrasterizer
= string
;
559 string
= NULL
; /* Don't free this string below */
561 else if (strcmp(keyword
, "JCLBegin") == 0)
563 ppd_free(ppd
->jcl_begin
);
564 ppd_decode(string
); /* Decode quoted string */
565 ppd
->jcl_begin
= string
;
566 string
= NULL
; /* Don't free this string below */
568 else if (strcmp(keyword
, "JCLEnd") == 0)
570 ppd_free(ppd
->jcl_end
);
571 ppd_decode(string
); /* Decode quoted string */
572 ppd
->jcl_end
= string
;
573 string
= NULL
; /* Don't free this string below */
575 else if (strcmp(keyword
, "JCLToPSInterpreter") == 0)
577 ppd_free(ppd
->jcl_ps
);
578 ppd_decode(string
); /* Decode quoted string */
579 ppd
->jcl_ps
= string
;
580 string
= NULL
; /* Don't free this string below */
582 else if (strcmp(keyword
, "AccurateScreensSupport") == 0)
583 ppd
->accurate_screens
= strcmp(string
, "True") == 0;
584 else if (strcmp(keyword
, "ColorDevice") == 0)
585 ppd
->color_device
= strcmp(string
, "True") == 0;
586 else if (strcmp(keyword
, "ContoneOnly") == 0)
587 ppd
->contone_only
= strcmp(string
, "True") == 0;
588 else if (strcmp(keyword
, "DefaultColorSpace") == 0)
590 if (strcmp(string
, "CMY") == 0)
591 ppd
->colorspace
= PPD_CS_CMY
;
592 else if (strcmp(string
, "CMYK") == 0)
593 ppd
->colorspace
= PPD_CS_CMYK
;
594 else if (strcmp(string
, "RGB") == 0)
595 ppd
->colorspace
= PPD_CS_RGB
;
596 else if (strcmp(string
, "RGBK") == 0)
597 ppd
->colorspace
= PPD_CS_RGBK
;
598 else if (strcmp(string
, "N") == 0)
599 ppd
->colorspace
= PPD_CS_N
;
601 ppd
->colorspace
= PPD_CS_GRAY
;
603 else if (strcmp(keyword
, "cupsFlipDuplex") == 0)
604 ppd
->flip_duplex
= strcmp(string
, "True") == 0;
605 else if (strcmp(keyword
, "cupsManualCopies") == 0)
606 ppd
->manual_copies
= strcmp(string
, "True") == 0;
607 else if (strcmp(keyword
, "cupsModelNumber") == 0)
608 ppd
->model_number
= atoi(string
);
609 else if (strcmp(keyword
, "cupsColorProfile") == 0)
611 if (ppd
->num_profiles
== 0)
612 profile
= malloc(sizeof(ppd_profile_t
));
614 profile
= realloc(ppd
->profiles
, sizeof(ppd_profile_t
) *
615 (ppd
->num_profiles
+ 1));
617 ppd
->profiles
= profile
;
618 profile
+= ppd
->num_profiles
;
619 ppd
->num_profiles
++;
621 memset(profile
, 0, sizeof(ppd_profile_t
));
622 strlcpy(profile
->resolution
, name
, sizeof(profile
->resolution
));
623 strlcpy(profile
->media_type
, text
, sizeof(profile
->media_type
));
624 sscanf(string
, "%f%f%f%f%f%f%f%f%f%f%f", &(profile
->density
),
626 profile
->matrix
[0] + 0, profile
->matrix
[0] + 1,
627 profile
->matrix
[0] + 2, profile
->matrix
[1] + 0,
628 profile
->matrix
[1] + 1, profile
->matrix
[1] + 2,
629 profile
->matrix
[2] + 0, profile
->matrix
[2] + 1,
630 profile
->matrix
[2] + 2);
632 else if (strcmp(keyword
, "cupsFilter") == 0)
634 if (ppd
->num_filters
== 0)
635 filter
= malloc(sizeof(char *));
637 filter
= realloc(ppd
->filters
, sizeof(char *) * (ppd
->num_filters
+ 1));
645 cupsLangFree(language
);
648 setlocale(LC_NUMERIC
, oldlocale
);
650 setlocale(LC_ALL
, oldlocale
);
651 #endif /* LC_NUMERIC */
653 ppd_status
= PPD_ALLOC_ERROR
;
658 ppd
->filters
= filter
;
659 filter
+= ppd
->num_filters
;
663 * Copy filter string and prevent it from being freed below...
669 else if (strcmp(keyword
, "Throughput") == 0)
670 ppd
->throughput
= atoi(string
);
671 else if (strcmp(keyword
, "Font") == 0)
674 * Add this font to the list of available fonts...
677 if (ppd
->num_fonts
== 0)
678 tempfonts
= (char **)malloc(sizeof(char *));
680 tempfonts
= (char **)realloc(ppd
->fonts
,
681 sizeof(char *) * (ppd
->num_fonts
+ 1));
683 if (tempfonts
== NULL
)
689 cupsLangFree(language
);
692 setlocale(LC_NUMERIC
, oldlocale
);
694 setlocale(LC_ALL
, oldlocale
);
695 #endif /* LC_NUMERIC */
697 ppd_status
= PPD_ALLOC_ERROR
;
702 ppd
->fonts
= tempfonts
;
703 ppd
->fonts
[ppd
->num_fonts
] = strdup(name
);
706 else if (strcmp(keyword
, "VariablePaperSize") == 0 &&
707 strcmp(string
, "True") == 0 &&
708 !ppd
->variable_sizes
)
710 ppd
->variable_sizes
= 1;
713 * Add a "Custom" page size entry...
716 ppd_add_size(ppd
, "Custom");
719 * Add a "Custom" page size option...
722 if ((option
= ppdFindOption(ppd
, "PageSize")) == NULL
)
727 if ((temp
= ppd_get_group(ppd
, "General",
728 cupsLangString(language
,
729 CUPS_MSG_GENERAL
))) == NULL
)
735 cupsLangFree(language
);
738 setlocale(LC_NUMERIC
, oldlocale
);
740 setlocale(LC_ALL
, oldlocale
);
741 #endif /* LC_NUMERIC */
743 ppd_status
= PPD_ALLOC_ERROR
;
748 if ((option
= ppd_get_option(temp
, "PageSize")) == NULL
)
754 cupsLangFree(language
);
757 setlocale(LC_NUMERIC
, oldlocale
);
759 setlocale(LC_ALL
, oldlocale
);
760 #endif /* LC_NUMERIC */
762 ppd_status
= PPD_ALLOC_ERROR
;
768 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
774 cupsLangFree(language
);
777 setlocale(LC_NUMERIC
, oldlocale
);
779 setlocale(LC_ALL
, oldlocale
);
780 #endif /* LC_NUMERIC */
782 ppd_status
= PPD_ALLOC_ERROR
;
787 strlcpy(choice
->text
, cupsLangString(language
, CUPS_MSG_VARIABLE
),
788 sizeof(choice
->text
));
791 else if (strcmp(keyword
, "MaxMediaWidth") == 0)
792 ppd
->custom_max
[0] = (float)atof(string
);
793 else if (strcmp(keyword
, "MaxMediaHeight") == 0)
794 ppd
->custom_max
[1] = (float)atof(string
);
795 else if (strcmp(keyword
, "ParamCustomPageSize") == 0)
797 if (strcmp(name
, "Width") == 0)
798 sscanf(string
, "%*s%*s%f%f", ppd
->custom_min
+ 0,
799 ppd
->custom_max
+ 0);
800 else if (strcmp(name
, "Height") == 0)
801 sscanf(string
, "%*s%*s%f%f", ppd
->custom_min
+ 1,
802 ppd
->custom_max
+ 1);
804 else if (strcmp(keyword
, "HWMargins") == 0)
805 sscanf(string
, "%f%f%f%f", ppd
->custom_margins
+ 0,
806 ppd
->custom_margins
+ 1, ppd
->custom_margins
+ 2,
807 ppd
->custom_margins
+ 3);
808 else if (strcmp(keyword
, "CustomPageSize") == 0 &&
809 strcmp(name
, "True") == 0)
811 if (!ppd
->variable_sizes
)
813 ppd
->variable_sizes
= 1;
816 * Add a "Custom" page size entry...
819 ppd_add_size(ppd
, "Custom");
822 * Add a "Custom" page size option...
825 if ((option
= ppdFindOption(ppd
, "PageSize")) == NULL
)
830 if ((temp
= ppd_get_group(ppd
, "General",
831 cupsLangString(language
,
832 CUPS_MSG_GENERAL
))) == NULL
)
834 DEBUG_puts("Unable to get general group!");
840 cupsLangFree(language
);
843 setlocale(LC_NUMERIC
, oldlocale
);
845 setlocale(LC_ALL
, oldlocale
);
846 #endif /* LC_NUMERIC */
848 ppd_status
= PPD_ALLOC_ERROR
;
853 if ((option
= ppd_get_option(temp
, "PageSize")) == NULL
)
855 DEBUG_puts("Unable to get PageSize option!");
861 cupsLangFree(language
);
864 setlocale(LC_NUMERIC
, oldlocale
);
866 setlocale(LC_ALL
, oldlocale
);
867 #endif /* LC_NUMERIC */
869 ppd_status
= PPD_ALLOC_ERROR
;
875 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
877 DEBUG_puts("Unable to add Custom choice!");
883 cupsLangFree(language
);
886 setlocale(LC_NUMERIC
, oldlocale
);
888 setlocale(LC_ALL
, oldlocale
);
889 #endif /* LC_NUMERIC */
891 ppd_status
= PPD_ALLOC_ERROR
;
896 strlcpy(choice
->text
, cupsLangString(language
, CUPS_MSG_VARIABLE
),
897 sizeof(choice
->text
));
901 if ((option
= ppdFindOption(ppd
, "PageSize")) == NULL
)
903 DEBUG_puts("Unable to find PageSize option!");
909 cupsLangFree(language
);
912 setlocale(LC_NUMERIC
, oldlocale
);
914 setlocale(LC_ALL
, oldlocale
);
915 #endif /* LC_NUMERIC */
917 ppd_status
= PPD_INTERNAL_ERROR
;
922 if ((choice
= ppdFindChoice(option
, "Custom")) == NULL
)
924 DEBUG_puts("Unable to find Custom choice!");
930 cupsLangFree(language
);
933 setlocale(LC_NUMERIC
, oldlocale
);
935 setlocale(LC_ALL
, oldlocale
);
936 #endif /* LC_NUMERIC */
938 ppd_status
= PPD_INTERNAL_ERROR
;
943 choice
->code
= string
;
947 else if (strcmp(keyword
, "LandscapeOrientation") == 0)
949 if (strcmp(string
, "Minus90") == 0)
950 ppd
->landscape
= -90;
951 else if (strcmp(string
, "Plus90") == 0)
954 else if (strcmp(keyword
, "Emulators") == 0)
956 for (count
= 1, sptr
= string
; sptr
!= NULL
;)
957 if ((sptr
= strchr(sptr
, ' ')) != NULL
)
964 ppd
->num_emulations
= count
;
965 ppd
->emulations
= calloc(sizeof(ppd_emul_t
), count
);
967 for (i
= 0, sptr
= string
; i
< count
; i
++)
969 for (nameptr
= ppd
->emulations
[i
].name
;
970 *sptr
!= '\0' && *sptr
!= ' ';
972 if (nameptr
< (ppd
->emulations
[i
].name
+ sizeof(ppd
->emulations
[i
].name
) - 1))
981 else if (strncmp(keyword
, "StartEmulator_", 14) == 0)
985 for (i
= 0; i
< ppd
->num_emulations
; i
++)
986 if (strcmp(keyword
+ 14, ppd
->emulations
[i
].name
) == 0)
988 ppd
->emulations
[i
].start
= string
;
992 else if (strncmp(keyword
, "StopEmulator_", 13) == 0)
996 for (i
= 0; i
< ppd
->num_emulations
; i
++)
997 if (strcmp(keyword
+ 13, ppd
->emulations
[i
].name
) == 0)
999 ppd
->emulations
[i
].stop
= string
;
1003 else if (strcmp(keyword
, "JobPatchFile") == 0)
1005 if (ppd
->patches
== NULL
)
1007 ppd
->patches
= string
;
1012 temp
= realloc(ppd
->patches
, strlen(ppd
->patches
) +
1013 strlen(string
) + 1);
1020 cupsLangFree(language
);
1023 setlocale(LC_NUMERIC
, oldlocale
);
1025 setlocale(LC_ALL
, oldlocale
);
1026 #endif /* LC_NUMERIC */
1028 ppd_status
= PPD_ALLOC_ERROR
;
1033 ppd
->patches
= temp
;
1035 strcpy(ppd
->patches
+ strlen(ppd
->patches
), string
);
1038 else if (strcmp(keyword
, "OpenUI") == 0)
1041 * Add an option record to the current sub-group, group, or file...
1045 strcpy(name
, name
+ 1); /* Eliminate leading asterisk */
1047 for (i
= strlen(name
) - 1; i
> 0 && isspace(name
[i
]); i
--)
1048 name
[i
] = '\0'; /* Eliminate trailing spaces */
1050 DEBUG_printf(("OpenUI of %s in group %s...\n", name
,
1051 group
? group
->text
: "(null)"));
1053 if (subgroup
!= NULL
)
1054 option
= ppd_get_option(subgroup
, name
);
1055 else if (group
== NULL
)
1057 if (strcmp(name
, "Collate") != 0 &&
1058 strcmp(name
, "Duplex") != 0 &&
1059 strcmp(name
, "InputSlot") != 0 &&
1060 strcmp(name
, "ManualFeed") != 0 &&
1061 strcmp(name
, "MediaType") != 0 &&
1062 strcmp(name
, "MediaColor") != 0 &&
1063 strcmp(name
, "MediaWeight") != 0 &&
1064 strcmp(name
, "OutputBin") != 0 &&
1065 strcmp(name
, "OutputMode") != 0 &&
1066 strcmp(name
, "OutputOrder") != 0 &&
1067 strcmp(name
, "PageSize") != 0 &&
1068 strcmp(name
, "PageRegion") != 0)
1069 group
= ppd_get_group(ppd
, "Extra",
1070 cupsLangString(language
, CUPS_MSG_EXTRA
));
1072 group
= ppd_get_group(ppd
, "General",
1073 cupsLangString(language
, CUPS_MSG_GENERAL
));
1081 cupsLangFree(language
);
1084 setlocale(LC_NUMERIC
, oldlocale
);
1086 setlocale(LC_ALL
, oldlocale
);
1087 #endif /* LC_NUMERIC */
1089 ppd_status
= PPD_ALLOC_ERROR
;
1094 DEBUG_printf(("Adding to group %s...\n", group
->text
));
1095 option
= ppd_get_option(group
, name
);
1099 option
= ppd_get_option(group
, name
);
1107 cupsLangFree(language
);
1110 setlocale(LC_NUMERIC
, oldlocale
);
1112 setlocale(LC_ALL
, oldlocale
);
1113 #endif /* LC_NUMERIC */
1115 ppd_status
= PPD_ALLOC_ERROR
;
1121 * Now fill in the initial information for the option...
1124 if (strcmp(string
, "PickMany") == 0)
1125 option
->ui
= PPD_UI_PICKMANY
;
1126 else if (strcmp(string
, "Boolean") == 0)
1127 option
->ui
= PPD_UI_BOOLEAN
;
1129 option
->ui
= PPD_UI_PICKONE
;
1133 strlcpy(option
->text
, text
, sizeof(option
->text
));
1134 ppd_fix(option
->text
);
1138 if (strcmp(name
, "PageSize") == 0)
1139 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_MEDIA_SIZE
),
1140 sizeof(option
->text
));
1141 else if (strcmp(name
, "MediaType") == 0)
1142 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_MEDIA_TYPE
),
1143 sizeof(option
->text
));
1144 else if (strcmp(name
, "InputSlot") == 0)
1145 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_MEDIA_SOURCE
),
1146 sizeof(option
->text
));
1147 else if (strcmp(name
, "ColorModel") == 0)
1148 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_OUTPUT_MODE
),
1149 sizeof(option
->text
));
1150 else if (strcmp(name
, "Resolution") == 0)
1151 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_RESOLUTION
),
1152 sizeof(option
->text
));
1154 strlcpy(option
->text
, name
, sizeof(option
->text
));
1157 option
->section
= PPD_ORDER_ANY
;
1159 else if (strcmp(keyword
, "JCLOpenUI") == 0)
1162 * Find the JCL group, and add if needed...
1165 group
= ppd_get_group(ppd
, "JCL", "JCL");
1173 cupsLangFree(language
);
1176 setlocale(LC_NUMERIC
, oldlocale
);
1178 setlocale(LC_ALL
, oldlocale
);
1179 #endif /* LC_NUMERIC */
1181 ppd_status
= PPD_ALLOC_ERROR
;
1187 * Add an option record to the current JCLs...
1191 strcpy(name
, name
+ 1);
1193 option
= ppd_get_option(group
, name
);
1201 cupsLangFree(language
);
1204 setlocale(LC_NUMERIC
, oldlocale
);
1206 setlocale(LC_ALL
, oldlocale
);
1207 #endif /* LC_NUMERIC */
1209 ppd_status
= PPD_ALLOC_ERROR
;
1215 * Now fill in the initial information for the option...
1218 if (strcmp(string
, "PickMany") == 0)
1219 option
->ui
= PPD_UI_PICKMANY
;
1220 else if (strcmp(string
, "Boolean") == 0)
1221 option
->ui
= PPD_UI_BOOLEAN
;
1223 option
->ui
= PPD_UI_PICKONE
;
1225 strlcpy(option
->text
, text
, sizeof(option
->text
));
1227 option
->section
= PPD_ORDER_JCL
;
1230 else if (strcmp(keyword
, "CloseUI") == 0 ||
1231 strcmp(keyword
, "JCLCloseUI") == 0)
1233 else if (strcmp(keyword
, "OpenGroup") == 0)
1236 * Open a new group...
1245 cupsLangFree(language
);
1248 setlocale(LC_NUMERIC
, oldlocale
);
1250 setlocale(LC_ALL
, oldlocale
);
1251 #endif /* LC_NUMERIC */
1253 ppd_status
= PPD_NESTED_OPEN_GROUP
;
1259 * Separate the group name from the text (name/text)...
1262 if ((sptr
= strchr(string
, '/')) != NULL
)
1268 * Fix up the text...
1275 * Find/add the group...
1278 group
= ppd_get_group(ppd
, string
, sptr
);
1280 else if (strcmp(keyword
, "CloseGroup") == 0)
1282 else if (strcmp(keyword
, "OrderDependency") == 0 ||
1283 strcmp(keyword
, "NonUIOrderDependency") == 0)
1285 if (sscanf(string
, "%f%40s%40s", &order
, name
, keyword
) != 3)
1291 cupsLangFree(language
);
1294 setlocale(LC_NUMERIC
, oldlocale
);
1296 setlocale(LC_ALL
, oldlocale
);
1297 #endif /* LC_NUMERIC */
1299 ppd_status
= PPD_BAD_ORDER_DEPENDENCY
;
1304 if (keyword
[0] == '*')
1305 strcpy(keyword
, keyword
+ 1);
1307 if (strcmp(name
, "ExitServer") == 0)
1308 section
= PPD_ORDER_EXIT
;
1309 else if (strcmp(name
, "Prolog") == 0)
1310 section
= PPD_ORDER_PROLOG
;
1311 else if (strcmp(name
, "DocumentSetup") == 0)
1312 section
= PPD_ORDER_DOCUMENT
;
1313 else if (strcmp(name
, "PageSetup") == 0)
1314 section
= PPD_ORDER_PAGE
;
1315 else if (strcmp(name
, "JCLSetup") == 0)
1316 section
= PPD_ORDER_JCL
;
1318 section
= PPD_ORDER_ANY
;
1326 * Only valid for Non-UI options...
1329 for (i
= ppd
->num_groups
, temp
= ppd
->groups
; i
> 0; i
--, temp
++)
1330 if (temp
->text
[0] == '\0')
1334 for (i
= 0; i
< temp
->num_options
; i
++)
1335 if (strcmp(keyword
, temp
->options
[i
].keyword
) == 0)
1337 temp
->options
[i
].section
= section
;
1338 temp
->options
[i
].order
= order
;
1344 option
->section
= section
;
1345 option
->order
= order
;
1348 else if (strncmp(keyword
, "Default", 7) == 0)
1353 if (strchr(string
, '/') != NULL
)
1354 *strchr(string
, '/') = '\0';
1362 * Only valid for Non-UI options...
1365 for (i
= ppd
->num_groups
, temp
= ppd
->groups
; i
> 0; i
--, temp
++)
1366 if (temp
->text
[0] == '\0')
1370 for (i
= 0; i
< temp
->num_options
; i
++)
1371 if (strcmp(keyword
, temp
->options
[i
].keyword
) == 0)
1373 strlcpy(temp
->options
[i
].defchoice
, string
,
1374 sizeof(temp
->options
[i
].defchoice
));
1378 else if (strcmp(keyword
+ 7, option
->keyword
) == 0)
1379 strlcpy(option
->defchoice
, string
, sizeof(option
->defchoice
));
1381 else if (strcmp(keyword
, "UIConstraints") == 0 ||
1382 strcmp(keyword
, "NonUIConstraints") == 0)
1384 if (ppd
->num_consts
== 0)
1385 constraint
= calloc(sizeof(ppd_const_t
), 1);
1387 constraint
= realloc(ppd
->consts
,
1388 (ppd
->num_consts
+ 1) * sizeof(ppd_const_t
));
1390 if (constraint
== NULL
)
1396 cupsLangFree(language
);
1399 setlocale(LC_NUMERIC
, oldlocale
);
1401 setlocale(LC_ALL
, oldlocale
);
1402 #endif /* LC_NUMERIC */
1404 ppd_status
= PPD_ALLOC_ERROR
;
1409 ppd
->consts
= constraint
;
1410 constraint
+= ppd
->num_consts
;
1413 switch (sscanf(string
, "%40s%40s%40s%40s", constraint
->option1
,
1414 constraint
->choice1
, constraint
->option2
,
1415 constraint
->choice2
))
1417 case 0 : /* Error */
1418 case 1 : /* Error */
1421 ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1424 case 2 : /* Two options... */
1426 * The following strcpy's are safe, as optionN and
1427 * choiceN are all the same size (size defined by PPD spec...)
1430 if (constraint
->option1
[0] == '*')
1431 strcpy(constraint
->option1
, constraint
->option1
+ 1);
1433 if (constraint
->choice1
[0] == '*')
1434 strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1436 strcpy(constraint
->option2
, constraint
->choice1
);
1438 constraint
->choice1
[0] = '\0';
1439 constraint
->choice2
[0] = '\0';
1442 case 3 : /* Two options, one choice... */
1444 * The following strcpy's are safe, as optionN and
1445 * choiceN are all the same size (size defined by PPD spec...)
1448 if (constraint
->option1
[0] == '*')
1449 strcpy(constraint
->option1
, constraint
->option1
+ 1);
1451 if (constraint
->choice1
[0] == '*')
1453 strcpy(constraint
->choice2
, constraint
->option2
);
1454 strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1455 constraint
->choice1
[0] = '\0';
1459 if (constraint
->option2
[0] == '*')
1460 strcpy(constraint
->option2
, constraint
->option2
+ 1);
1462 constraint
->choice2
[0] = '\0';
1466 case 4 : /* Two options, two choices... */
1467 if (constraint
->option1
[0] == '*')
1468 strcpy(constraint
->option1
, constraint
->option1
+ 1);
1470 if (constraint
->option2
[0] == '*')
1471 strcpy(constraint
->option2
, constraint
->option2
+ 1);
1475 else if (strcmp(keyword
, "PaperDimension") == 0)
1477 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1478 size
= ppd_add_size(ppd
, name
);
1483 * Unable to add or find size!
1490 cupsLangFree(language
);
1493 setlocale(LC_NUMERIC
, oldlocale
);
1495 setlocale(LC_ALL
, oldlocale
);
1496 #endif /* LC_NUMERIC */
1498 ppd_status
= PPD_ALLOC_ERROR
;
1503 sscanf(string
, "%f%f", &(size
->width
), &(size
->length
));
1505 else if (strcmp(keyword
, "ImageableArea") == 0)
1507 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1508 size
= ppd_add_size(ppd
, name
);
1513 * Unable to add or find size!
1520 cupsLangFree(language
);
1523 setlocale(LC_NUMERIC
, oldlocale
);
1525 setlocale(LC_ALL
, oldlocale
);
1526 #endif /* LC_NUMERIC */
1528 ppd_status
= PPD_ALLOC_ERROR
;
1533 sscanf(string
, "%f%f%f%f", &(size
->left
), &(size
->bottom
),
1534 &(size
->right
), &(size
->top
));
1536 else if (option
!= NULL
&&
1537 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
1538 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
) &&
1539 strcmp(keyword
, option
->keyword
) == 0)
1541 DEBUG_printf(("group = %p, subgroup = %p\n", group
, subgroup
));
1543 if (strcmp(keyword
, "PageSize") == 0)
1546 * Add a page size...
1549 if (ppdPageSize(ppd
, name
) == NULL
)
1550 ppd_add_size(ppd
, name
);
1554 * Add the option choice...
1557 choice
= ppd_add_choice(option
, name
);
1559 if (mask
& PPD_TEXT
)
1561 strlcpy(choice
->text
, text
, sizeof(choice
->text
));
1562 ppd_fix(choice
->text
);
1564 else if (strcmp(name
, "True") == 0)
1565 strcpy(choice
->text
, "Yes");
1566 else if (strcmp(name
, "False") == 0)
1567 strcpy(choice
->text
, "No");
1569 strlcpy(choice
->text
, name
, sizeof(choice
->text
));
1571 if (option
->section
== PPD_ORDER_JCL
)
1572 ppd_decode(string
); /* Decode quoted string */
1574 choice
->code
= string
;
1575 string
= NULL
; /* Don't free this string below */
1577 else if (strcmp(keyword
, "cupsUIType") == 0 &&
1578 (mask
& (PPD_KEYWORD
| PPD_STRING
)) == (PPD_KEYWORD
| PPD_STRING
) &&
1582 * Define an extended option value type...
1585 extopt
= ppd_get_extopt(ppd
, name
);
1587 if (strcmp(string
, "Text") == 0)
1588 option
->ui
= PPD_UI_CUPS_TEXT
;
1589 else if (strcmp(string
, "Integer") == 0)
1591 option
->ui
= PPD_UI_CUPS_INTEGER
;
1592 extopt
->defval
.integer
= 0;
1593 extopt
->minval
.integer
= 0;
1594 extopt
->maxval
.integer
= 100;
1596 else if (strcmp(string
, "Real") == 0)
1598 option
->ui
= PPD_UI_CUPS_REAL
;
1599 extopt
->defval
.real
= 0.0;
1600 extopt
->minval
.real
= 0.0;
1601 extopt
->maxval
.real
= 1.0;
1603 else if (strcmp(string
, "Gamma") == 0)
1605 option
->ui
= PPD_UI_CUPS_GAMMA
;
1606 extopt
->defval
.gamma
= 1.0;
1607 extopt
->minval
.gamma
= 1.0;
1608 extopt
->maxval
.gamma
= 10.0;
1610 else if (strcmp(string
, "Curve") == 0)
1612 option
->ui
= PPD_UI_CUPS_CURVE
;
1613 extopt
->defval
.curve
.start
= 0.0;
1614 extopt
->defval
.curve
.end
= 0.0;
1615 extopt
->defval
.curve
.gamma
= 1.0;
1616 extopt
->minval
.curve
.start
= 0.0;
1617 extopt
->minval
.curve
.end
= 0.0;
1618 extopt
->minval
.curve
.gamma
= 1.0;
1619 extopt
->maxval
.curve
.start
= 1.0;
1620 extopt
->maxval
.curve
.end
= 1.0;
1621 extopt
->maxval
.curve
.gamma
= 10.0;
1623 else if (strcmp(string
, "IntegerArray") == 0)
1625 option
->ui
= PPD_UI_CUPS_INTEGER_ARRAY
;
1626 extopt
->defval
.integer_array
.num_elements
= 2;
1627 extopt
->minval
.integer_array
.num_elements
= 2;
1628 extopt
->maxval
.integer_array
.num_elements
= 16;
1630 else if (strcmp(string
, "RealArray") == 0)
1632 option
->ui
= PPD_UI_CUPS_REAL_ARRAY
;
1633 extopt
->defval
.real_array
.num_elements
= 2;
1634 extopt
->minval
.real_array
.num_elements
= 2;
1635 extopt
->maxval
.real_array
.num_elements
= 16;
1638 else if (strcmp(keyword
, "cupsUIDefault") == 0 &&
1639 (mask
& (PPD_KEYWORD
| PPD_STRING
)) == (PPD_KEYWORD
| PPD_STRING
) &&
1643 * Define an extended option minimum value...
1646 extopt
= ppd_get_extopt(ppd
, name
);
1650 case PPD_UI_CUPS_INTEGER
:
1651 sscanf(string
, "%d", &(extopt
->defval
.integer
));
1654 case PPD_UI_CUPS_REAL
:
1655 sscanf(string
, "%f", &(extopt
->defval
.real
));
1658 case PPD_UI_CUPS_GAMMA
:
1659 sscanf(string
, "%f", &(extopt
->defval
.gamma
));
1662 case PPD_UI_CUPS_CURVE
:
1663 sscanf(string
, "%f%f%f", &(extopt
->defval
.curve
.start
),
1664 &(extopt
->defval
.curve
.end
),
1665 &(extopt
->defval
.curve
.gamma
));
1668 case PPD_UI_CUPS_INTEGER_ARRAY
:
1669 extopt
->defval
.integer_array
.elements
= calloc(1, sizeof(int));
1670 sscanf(string
, "%d%d", &(extopt
->defval
.integer_array
.num_elements
),
1671 extopt
->defval
.integer_array
.elements
);
1674 case PPD_UI_CUPS_REAL_ARRAY
:
1675 extopt
->defval
.real_array
.elements
= calloc(1, sizeof(float));
1676 sscanf(string
, "%d%f", &(extopt
->defval
.real_array
.num_elements
),
1677 extopt
->defval
.real_array
.elements
);
1684 else if (strcmp(keyword
, "cupsUIMinimum") == 0 &&
1685 (mask
& (PPD_KEYWORD
| PPD_STRING
)) == (PPD_KEYWORD
| PPD_STRING
) &&
1689 * Define an extended option minimum value...
1692 extopt
= ppd_get_extopt(ppd
, name
);
1696 case PPD_UI_CUPS_INTEGER
:
1697 sscanf(string
, "%d", &(extopt
->minval
.integer
));
1700 case PPD_UI_CUPS_REAL
:
1701 sscanf(string
, "%f", &(extopt
->minval
.real
));
1704 case PPD_UI_CUPS_GAMMA
:
1705 sscanf(string
, "%f", &(extopt
->minval
.gamma
));
1708 case PPD_UI_CUPS_CURVE
:
1709 sscanf(string
, "%f%f%f", &(extopt
->minval
.curve
.start
),
1710 &(extopt
->minval
.curve
.end
),
1711 &(extopt
->minval
.curve
.gamma
));
1714 case PPD_UI_CUPS_INTEGER_ARRAY
:
1715 extopt
->minval
.integer_array
.elements
= calloc(1, sizeof(int));
1716 sscanf(string
, "%d%d", &(extopt
->minval
.integer_array
.num_elements
),
1717 extopt
->minval
.integer_array
.elements
);
1720 case PPD_UI_CUPS_REAL_ARRAY
:
1721 extopt
->minval
.real_array
.elements
= calloc(1, sizeof(float));
1722 sscanf(string
, "%d%f", &(extopt
->minval
.real_array
.num_elements
),
1723 extopt
->minval
.real_array
.elements
);
1730 else if (strcmp(keyword
, "cupsUIMaximum") == 0 &&
1731 (mask
& (PPD_KEYWORD
| PPD_STRING
)) == (PPD_KEYWORD
| PPD_STRING
) &&
1735 * Define an extended option maximum value...
1738 extopt
= ppd_get_extopt(ppd
, name
);
1742 case PPD_UI_CUPS_INTEGER
:
1743 sscanf(string
, "%d", &(extopt
->maxval
.integer
));
1746 case PPD_UI_CUPS_REAL
:
1747 sscanf(string
, "%f", &(extopt
->maxval
.real
));
1750 case PPD_UI_CUPS_GAMMA
:
1751 sscanf(string
, "%f", &(extopt
->maxval
.gamma
));
1754 case PPD_UI_CUPS_CURVE
:
1755 sscanf(string
, "%f%f%f", &(extopt
->maxval
.curve
.start
),
1756 &(extopt
->maxval
.curve
.end
),
1757 &(extopt
->maxval
.curve
.gamma
));
1760 case PPD_UI_CUPS_INTEGER_ARRAY
:
1761 extopt
->maxval
.integer_array
.elements
= calloc(1, sizeof(int));
1762 sscanf(string
, "%d%d", &(extopt
->maxval
.integer_array
.num_elements
),
1763 extopt
->maxval
.integer_array
.elements
);
1766 case PPD_UI_CUPS_REAL_ARRAY
:
1767 extopt
->maxval
.real_array
.elements
= calloc(1, sizeof(float));
1768 sscanf(string
, "%d%f", &(extopt
->maxval
.real_array
.num_elements
),
1769 extopt
->maxval
.real_array
.elements
);
1776 else if (strcmp(keyword
, "cupsUICommand") == 0 &&
1777 (mask
& (PPD_KEYWORD
| PPD_STRING
)) == (PPD_KEYWORD
| PPD_STRING
) &&
1781 * Define an extended option command...
1784 extopt
= ppd_get_extopt(ppd
, name
);
1786 extopt
->command
= string
;
1789 else if (strcmp(keyword
, "OpenSubGroup") != 0 &&
1790 strcmp(keyword
, "CloseSubGroup") != 0)
1792 char spec
[PPD_MAX_NAME
+ PPD_MAX_TEXT
];
1794 snprintf(spec
, sizeof(spec
), "%s/%s", name
, text
);
1795 ppd_add_attr(ppd
, keyword
, spec
, string
);
1797 string
= NULL
; /* Don't free this string below */
1804 * Reset language preferences...
1807 cupsLangFree(language
);
1810 setlocale(LC_NUMERIC
, oldlocale
);
1812 setlocale(LC_ALL
, oldlocale
);
1813 #endif /* LC_NUMERIC */
1817 printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp
));
1822 * Make sure that all PPD files with an InputSlot option have an
1823 * "auto" choice that maps to no specific tray or media type.
1826 if ((option
= ppdFindOption(ppd
, "InputSlot")) != NULL
)
1828 for (i
= 0; i
< option
->num_choices
; i
++)
1829 if (option
->choices
[i
].code
== NULL
|| !option
->choices
[i
].code
[0])
1832 if (i
>= option
->num_choices
)
1835 * No "auto" input slot, add one...
1838 choice
= ppd_add_choice(option
, "Auto");
1840 strlcpy(choice
->text
, cupsLangString(language
, CUPS_MSG_AUTO
),
1841 sizeof(choice
->text
));
1842 choice
->code
= NULL
;
1845 #endif /* !__APPLE__ */
1848 * Set the option back-pointer for each choice...
1852 qsort(ppd
->groups
, ppd
->num_groups
, sizeof(ppd_group_t
),
1853 (int (*)(const void *, const void *))ppd_compare_groups
);
1854 #endif /* !__APPLE__ */
1856 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
1861 qsort(group
->options
, group
->num_options
, sizeof(ppd_option_t
),
1862 (int (*)(const void *, const void *))ppd_compare_options
);
1863 #endif /* !__APPLE__ */
1865 for (j
= group
->num_options
, option
= group
->options
;
1869 for (k
= 0; k
< option
->num_choices
; k
++)
1870 option
->choices
[k
].option
= (void *)option
;
1874 qsort(group
->subgroups
, group
->num_subgroups
, sizeof(ppd_group_t
),
1875 (int (*)(const void *, const void *))ppd_compare_groups
);
1876 #endif /* !__APPLE__ */
1878 for (j
= group
->num_subgroups
, subgroup
= group
->subgroups
;
1883 qsort(subgroup
->options
, subgroup
->num_options
, sizeof(ppd_option_t
),
1884 (int (*)(const void *, const void *))ppd_compare_options
);
1885 #endif /* !__APPLE__ */
1887 for (k
= group
->num_options
, option
= group
->options
;
1891 for (m
= 0; m
< option
->num_choices
; m
++)
1892 option
->choices
[m
].option
= (void *)option
;
1898 * Set the option pointers for all extended options...
1901 for (i
= 0; i
< ppd
->num_extended
; i
++)
1902 ppd
->extended
[i
]->option
= ppdFindOption(ppd
, ppd
->extended
[i
]->keyword
);
1905 * Sort the attributes...
1908 if (ppd
->num_attrs
> 1)
1909 qsort(ppd
->attrs
, ppd
->num_attrs
, sizeof(ppd_attr_t
*),
1910 (int (*)(const void *, const void *))_ppd_attr_compare
);
1913 * Return the PPD file structure...
1921 * 'ppdOpenFd()' - Read a PPD file into memory.
1924 ppd_file_t
* /* O - PPD file record */
1925 ppdOpenFd(int fd
) /* I - File to read from */
1927 FILE *fp
; /* File pointer */
1928 ppd_file_t
*ppd
; /* PPD file record */
1932 * Set the line number to 1...
1938 * Range check input...
1943 ppd_status
= PPD_NULL_FILE
;
1949 * Try to open the file and parse it...
1952 if ((fp
= fdopen(fd
, "r")) != NULL
)
1962 ppd_status
= PPD_FILE_OPEN_ERROR
;
1971 * 'ppdOpenFile()' - Read a PPD file into memory.
1974 ppd_file_t
* /* O - PPD file record */
1975 ppdOpenFile(const char *filename
) /* I - File to read from */
1977 FILE *fp
; /* File pointer */
1978 ppd_file_t
*ppd
; /* PPD file record */
1982 * Set the line number to 1...
1988 * Range check input...
1991 if (filename
== NULL
)
1993 ppd_status
= PPD_NULL_FILE
;
1999 * Try to open the file and parse it...
2002 if ((fp
= fopen(filename
, "r")) != NULL
)
2010 ppd_status
= PPD_FILE_OPEN_ERROR
;
2019 * 'ppd_add_attr()' - Add an attribute to the PPD data.
2022 static ppd_attr_t
* /* O - New attribute */
2023 ppd_add_attr(ppd_file_t
*ppd
, /* I - PPD file data */
2024 const char *name
, /* I - Attribute name */
2025 const char *spec
, /* I - Specifier string, if any */
2026 const char *value
) /* I - Value of attribute */
2028 ppd_attr_t
**ptr
, /* New array */
2029 *temp
; /* New attribute */
2033 * Range check input...
2036 if (ppd
== NULL
|| name
== NULL
|| spec
== NULL
)
2040 * Allocate memory for the new attribute...
2043 if (ppd
->num_attrs
== 0)
2044 ptr
= malloc(sizeof(ppd_attr_t
*));
2046 ptr
= realloc(ppd
->attrs
, (ppd
->num_attrs
+ 1) * sizeof(ppd_attr_t
*));
2052 ptr
+= ppd
->num_attrs
;
2054 if ((temp
= calloc(1, sizeof(ppd_attr_t
))) == NULL
)
2065 strlcpy(temp
->name
, name
, sizeof(temp
->name
));
2066 strlcpy(temp
->spec
, spec
, sizeof(temp
->spec
));
2067 temp
->value
= (char *)value
;
2070 * Return the attribute...
2078 * 'ppd_add_choice()' - Add a choice to an option.
2081 static ppd_choice_t
* /* O - Named choice */
2082 ppd_add_choice(ppd_option_t
*option
, /* I - Option */
2083 const char *name
) /* I - Name of choice */
2085 ppd_choice_t
*choice
; /* Choice */
2088 if (option
->num_choices
== 0)
2089 choice
= malloc(sizeof(ppd_choice_t
));
2091 choice
= realloc(option
->choices
,
2092 sizeof(ppd_choice_t
) * (option
->num_choices
+ 1));
2097 option
->choices
= choice
;
2098 choice
+= option
->num_choices
;
2099 option
->num_choices
++;
2101 memset(choice
, 0, sizeof(ppd_choice_t
));
2102 strlcpy(choice
->choice
, name
, sizeof(choice
->choice
));
2109 * 'ppd_add_size()' - Add a page size.
2112 static ppd_size_t
* /* O - Named size */
2113 ppd_add_size(ppd_file_t
*ppd
, /* I - PPD file */
2114 const char *name
) /* I - Name of size */
2116 ppd_size_t
*size
; /* Size */
2119 if (ppd
->num_sizes
== 0)
2120 size
= malloc(sizeof(ppd_size_t
));
2122 size
= realloc(ppd
->sizes
, sizeof(ppd_size_t
) * (ppd
->num_sizes
+ 1));
2128 size
+= ppd
->num_sizes
;
2131 memset(size
, 0, sizeof(ppd_size_t
));
2132 strlcpy(size
->name
, name
, sizeof(size
->name
));
2140 * 'ppd_compare_groups()' - Compare two groups.
2143 static int /* O - Result of comparison */
2144 ppd_compare_groups(ppd_group_t
*g0
, /* I - First group */
2145 ppd_group_t
*g1
) /* I - Second group */
2147 return (strcasecmp(g0
->text
, g1
->text
));
2152 * 'ppd_compare_options()' - Compare two options.
2155 static int /* O - Result of comparison */
2156 ppd_compare_options(ppd_option_t
*o0
, /* I - First option */
2157 ppd_option_t
*o1
) /* I - Second option */
2159 return (strcasecmp(o0
->text
, o1
->text
));
2161 #endif /* !__APPLE__ */
2165 * 'ppd_decode()' - Decode a string value...
2169 ppd_decode(char *string
) /* I - String to decode */
2171 char *inptr
, /* Input pointer */
2172 *outptr
; /* Output pointer */
2178 while (*inptr
!= '\0')
2179 if (*inptr
== '<' && isxdigit(inptr
[1]))
2182 * Convert hex to 8-bit values...
2186 while (isxdigit(*inptr
))
2188 if (isalpha(*inptr
))
2189 *outptr
= (tolower(*inptr
) - 'a' + 10) << 4;
2191 *outptr
= (*inptr
- '0') << 4;
2195 if (isalpha(*inptr
))
2196 *outptr
|= tolower(*inptr
) - 'a' + 10;
2198 *outptr
|= *inptr
- '0';
2204 while (*inptr
!= '>' && *inptr
!= '\0')
2206 while (*inptr
== '>')
2210 *outptr
++ = *inptr
++;
2218 * 'ppd_fix()' - Fix WinANSI characters in the range 0x80 to 0x9f to be
2219 * valid ISO-8859-1 characters...
2223 ppd_fix(char *string
) /* IO - String to fix */
2225 unsigned char *p
; /* Pointer into string */
2226 static const unsigned char lut
[32] = /* Lookup table for characters */
2250 0x20, /* circumflex */
2252 0x20, /* double dot */
2257 '\"', /* should be right quotes */
2263 for (p
= (unsigned char *)string
; *p
; p
++)
2264 if (*p
>= 0x80 && *p
< 0xa0)
2265 *p
= lut
[*p
- 0x80];
2267 #endif /* !__APPLE__ */
2271 * 'ppd_free_group()' - Free a single UI group.
2275 ppd_free_group(ppd_group_t
*group
) /* I - Group to free */
2277 int i
; /* Looping var */
2278 ppd_option_t
*option
; /* Current option */
2279 ppd_group_t
*subgroup
; /* Current sub-group */
2282 if (group
->num_options
> 0)
2284 for (i
= group
->num_options
, option
= group
->options
;
2287 ppd_free_option(option
);
2289 ppd_free(group
->options
);
2292 if (group
->num_subgroups
> 0)
2294 for (i
= group
->num_subgroups
, subgroup
= group
->subgroups
;
2297 ppd_free_group(subgroup
);
2299 ppd_free(group
->subgroups
);
2305 * 'ppd_free_option()' - Free a single option.
2309 ppd_free_option(ppd_option_t
*option
) /* I - Option to free */
2311 int i
; /* Looping var */
2312 ppd_choice_t
*choice
; /* Current choice */
2315 if (option
->num_choices
> 0)
2317 for (i
= option
->num_choices
, choice
= option
->choices
;
2320 ppd_free(choice
->code
);
2322 ppd_free(option
->choices
);
2328 * 'ppd_get_extopt()' - Get an extended option record.
2331 static ppd_ext_option_t
* /* O - Extended option... */
2332 ppd_get_extopt(ppd_file_t
*ppd
, /* I - PPD file */
2333 const char *name
) /* I - Name of option */
2335 ppd_ext_option_t
**temp
, /* New array pointer */
2336 *extopt
; /* New extended option */
2340 * See if the option already exists...
2343 if ((extopt
= ppdFindExtOption(ppd
, name
)) != NULL
)
2347 * Not found, so create the extended option record...
2350 if ((extopt
= calloc(sizeof(ppd_ext_option_t
), 1)) == NULL
)
2353 strlcpy(extopt
->keyword
, name
, sizeof(extopt
->keyword
));
2356 * Add this record to the end of the array...
2359 if (ppd
->num_extended
== 0)
2360 temp
= malloc(sizeof(ppd_ext_option_t
*));
2362 temp
= realloc(ppd
->extended
, sizeof(ppd_ext_option_t
*) *
2363 (ppd
->num_extended
+ 1));
2371 ppd
->extended
= temp
;
2372 temp
[ppd
->num_extended
] = extopt
;
2374 ppd
->num_extended
++;
2377 * Return the new record...
2385 * 'ppd_get_group()' - Find or create the named group as needed.
2388 static ppd_group_t
* /* O - Named group */
2389 ppd_get_group(ppd_file_t
*ppd
, /* I - PPD file */
2390 const char *name
, /* I - Name of group */
2391 const char *text
) /* I - Text for group */
2393 int i
; /* Looping var */
2394 ppd_group_t
*group
; /* Group */
2397 DEBUG_printf(("ppd_get_group(%p, \"%s\")\n", ppd
, name
));
2399 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
2400 if (strcmp(group
->name
, name
) == 0)
2405 DEBUG_printf(("Adding group %s...\n", name
));
2407 if (ppd
->num_groups
== 0)
2408 group
= malloc(sizeof(ppd_group_t
));
2410 group
= realloc(ppd
->groups
,
2411 (ppd
->num_groups
+ 1) * sizeof(ppd_group_t
));
2416 ppd
->groups
= group
;
2417 group
+= ppd
->num_groups
;
2420 memset(group
, 0, sizeof(ppd_group_t
));
2421 strlcpy(group
->name
, name
, sizeof(group
->name
));
2422 strlcpy(group
->text
, text
, sizeof(group
->text
));
2430 * 'ppd_get_option()' - Find or create the named option as needed.
2433 static ppd_option_t
* /* O - Named option */
2434 ppd_get_option(ppd_group_t
*group
, /* I - Group */
2435 const char *name
) /* I - Name of option */
2437 int i
; /* Looping var */
2438 ppd_option_t
*option
; /* Option */
2441 for (i
= group
->num_options
, option
= group
->options
; i
> 0; i
--, option
++)
2442 if (strcmp(option
->keyword
, name
) == 0)
2447 if (group
->num_options
== 0)
2448 option
= malloc(sizeof(ppd_option_t
));
2450 option
= realloc(group
->options
,
2451 (group
->num_options
+ 1) * sizeof(ppd_option_t
));
2456 group
->options
= option
;
2457 option
+= group
->num_options
;
2458 group
->num_options
++;
2460 memset(option
, 0, sizeof(ppd_option_t
));
2461 strlcpy(option
->keyword
, name
, sizeof(option
->keyword
));
2469 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2473 static int /* O - Bitmask of fields read */
2474 ppd_read(FILE *fp
, /* I - File to read from */
2475 char *keyword
, /* O - Keyword from line */
2476 char *option
, /* O - Option from line */
2477 char *text
, /* O - Human-readable text from line */
2478 char **string
) /* O - Code/string data */
2480 int ch
, /* Character from file */
2481 colon
, /* Colon seen? */
2482 endquote
, /* Waiting for an end quote */
2483 mask
; /* Mask to be returned */
2484 char *keyptr
, /* Keyword pointer */
2485 *optptr
, /* Option pointer */
2486 *textptr
, /* Text pointer */
2487 *strptr
, /* Pointer into string */
2488 *lineptr
, /* Current position in line buffer */
2489 line
[65536]; /* Line buffer (64k) */
2493 * Range check everything...
2496 if (fp
== NULL
|| keyword
== NULL
|| option
== NULL
|| text
== NULL
||
2501 * Now loop until we have a valid line...
2516 while ((ch
= getc(fp
)) != EOF
&&
2517 (lineptr
- line
) < (sizeof(line
) - 1))
2519 if (ch
== '\r' || ch
== '\n')
2522 * Line feed or carriage return...
2527 if (lineptr
== line
) /* Skip blank lines */
2533 * Check for a trailing line feed...
2536 if ((ch
= getc(fp
)) == EOF
)
2544 if (!endquote
) /* Continue for multi-line text */
2552 * Any other character...
2557 if (ch
== ':' && strncmp(line
, "*%", 2) != 0)
2560 if (ch
== '\"' && colon
)
2562 endquote
= !endquote
;
2567 * End of quoted string; ignore trailing characters...
2570 while ((ch
= getc(fp
)) != EOF
)
2573 else if (ch
== '\r')
2592 * Didn't finish this quoted string...
2595 while ((ch
= getc(fp
)) != EOF
)
2603 * Didn't finish this line...
2606 while ((ch
= getc(fp
)) != EOF
)
2607 if (ch
== '\r' || ch
== '\n')
2610 * Line feed or carriage return...
2616 * Check for a trailing line feed...
2619 if ((ch
= getc(fp
)) == EOF
)
2629 if (lineptr
> line
&& lineptr
[-1] == '\n')
2634 /* DEBUG_printf(("LINE = \"%s\"\n", line));*/
2636 if (ch
== EOF
&& lineptr
== line
)
2651 if (line
[0] != '*') /* All lines start with an asterisk */
2654 if (strcmp(line
, "*") == 0 || /* (Bad) comment line */
2655 strncmp(line
, "*%", 2) == 0 || /* Comment line */
2656 strncmp(line
, "*?", 2) == 0 || /* Query line */
2657 strcmp(line
, "*End") == 0) /* End of multi-line string */
2666 for (; *lineptr
!= '\0' && *lineptr
!= ':' && !isspace(*lineptr
);
2668 if ((keyptr
- keyword
) < (PPD_MAX_NAME
- 1))
2669 *keyptr
++ = *lineptr
;
2673 if (strcmp(keyword
, "End") == 0)
2676 mask
|= PPD_KEYWORD
;
2678 /* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
2680 if (isspace(*lineptr
))
2683 * Get an option name...
2686 while (isspace(*lineptr
))
2691 for (; *lineptr
!= '\0' && *lineptr
!= '\n' && *lineptr
!= ':' &&
2692 *lineptr
!= '/'; lineptr
++)
2693 if ((optptr
- option
) < (PPD_MAX_NAME
- 1))
2694 *optptr
++ = *lineptr
;
2699 /* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
2701 if (*lineptr
== '/')
2704 * Get human-readable text...
2711 for (; *lineptr
!= '\0' && *lineptr
!= '\n' && *lineptr
!= ':';
2713 if ((textptr
- text
) < (PPD_MAX_LINE
- 1))
2714 *textptr
++ = *lineptr
;
2722 /* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
2725 if (*lineptr
== ':')
2731 *string
= malloc(strlen(lineptr
) + 1);
2733 while (*lineptr
== ':' || isspace(*lineptr
))
2738 for (; *lineptr
!= '\0'; lineptr
++)
2739 if (*lineptr
!= '\"')
2740 *strptr
++ = *lineptr
;
2744 /* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
2756 * End of "$Id: ppd.c,v 1.51.2.31 2003/01/29 17:04:33 mike Exp $".