2 * "$Id: ppd.c,v 1.104 2003/06/14 16:08:20 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 *text
,
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_group_t
*ppd_get_group(ppd_file_t
*ppd
, const char *name
,
124 static ppd_option_t
*ppd_get_option(ppd_group_t
*group
, const char *name
);
125 static int ppd_read(FILE *fp
, char *keyword
, char *option
,
126 char *text
, char **string
);
130 * '_ppd_attr_compare()' - Compare two attributes.
133 int /* O - Result of comparison */
134 _ppd_attr_compare(ppd_attr_t
**a
, /* I - First attribute */
135 ppd_attr_t
**b
) /* I - Second attribute */
137 int ret
; /* Result of comparison */
140 if ((ret
= strcasecmp((*a
)->name
, (*b
)->name
)) != 0)
142 else if ((*a
)->spec
[0] && (*b
)->spec
[0])
143 return (strcasecmp((*a
)->spec
, (*b
)->spec
));
150 * 'ppdClose()' - Free all memory used by the PPD file.
154 ppdClose(ppd_file_t
*ppd
) /* I - PPD file record */
156 int i
; /* Looping var */
157 ppd_emul_t
*emul
; /* Current emulation */
158 ppd_group_t
*group
; /* Current group */
159 char **font
; /* Current font */
160 char **filter
; /* Current filter */
161 ppd_attr_t
**attr
; /* Current attribute */
165 * Range check the PPD file record...
172 * Free all strings at the top level...
175 ppd_free(ppd
->patches
);
176 ppd_free(ppd
->jcl_begin
);
177 ppd_free(ppd
->jcl_end
);
178 ppd_free(ppd
->jcl_ps
);
181 * Free any emulations...
184 if (ppd
->num_emulations
> 0)
186 for (i
= ppd
->num_emulations
, emul
= ppd
->emulations
; i
> 0; i
--, emul
++)
188 ppd_free(emul
->start
);
189 ppd_free(emul
->stop
);
192 ppd_free(ppd
->emulations
);
196 * Free any UI groups, subgroups, and options...
199 if (ppd
->num_groups
> 0)
201 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
202 ppd_free_group(group
);
204 ppd_free(ppd
->groups
);
208 * Free any page sizes...
211 if (ppd
->num_sizes
> 0)
212 ppd_free(ppd
->sizes
);
215 * Free any constraints...
218 if (ppd
->num_consts
> 0)
219 ppd_free(ppd
->consts
);
222 * Free any filters...
225 if (ppd
->num_filters
> 0)
227 for (i
= ppd
->num_filters
, filter
= ppd
->filters
; i
> 0; i
--, filter
++)
230 ppd_free(ppd
->filters
);
237 if (ppd
->num_fonts
> 0)
239 for (i
= ppd
->num_fonts
, font
= ppd
->fonts
; i
> 0; i
--, font
++)
242 ppd_free(ppd
->fonts
);
246 * Free any profiles...
249 if (ppd
->num_profiles
> 0)
250 ppd_free(ppd
->profiles
);
253 * Free any attributes...
256 if (ppd
->num_attrs
> 0)
258 for (i
= ppd
->num_attrs
, attr
= ppd
->attrs
; i
> 0; i
--, attr
++)
260 ppd_free((*attr
)->value
);
264 ppd_free(ppd
->attrs
);
268 * Free the whole record...
276 * 'ppdErrorString()' - Returns the text assocated with a status.
279 const char * /* O - Status string */
280 ppdErrorString(ppd_status_t status
) /* I - PPD status */
282 static const char * const messages
[] =/* Status messages */
285 "Unable to open PPD file",
286 "NULL PPD file pointer",
287 "Memory allocation error",
288 "Missing PPD-Adobe-4.x header",
289 "Missing value string",
292 "OpenGroup without a CloseGroup first",
293 "Bad OpenUI/JCLOpenUI",
294 "OpenUI/JCLOpenUI without a CloseUI/JCLCLoseUI first",
295 "Bad OrderDependency",
297 "Missing asterisk in column 1",
298 "Line longer than the maximum allowed (255 characters)",
299 "Illegal control character",
300 "Illegal main keyword string",
301 "Illegal option keyword string",
302 "Illegal translation string"
306 if (status
< PPD_OK
|| status
> PPD_ILLEGAL_TRANSLATION
)
309 return (messages
[status
]);
314 * 'ppdLastError()' - Return the status from the last ppdOpen*().
317 ppd_status_t
/* O - Status code */
318 ppdLastError(int *line
) /* O - Line number */
328 * 'ppdOpen()' - Read a PPD file into memory.
331 ppd_file_t
* /* O - PPD file record */
332 ppdOpen(FILE *fp
) /* I - File to read from */
334 char *oldlocale
; /* Old locale settings */
335 int i
, j
, k
, m
; /* Looping vars */
336 int count
; /* Temporary count */
337 ppd_file_t
*ppd
; /* PPD file record */
338 ppd_group_t
*group
, /* Current group */
339 *subgroup
; /* Current sub-group */
340 ppd_option_t
*option
; /* Current 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 */
361 int ui_keyword
; /* Is this line a UI keyword? */
362 static const char * const ui_keywords
[] =
364 /* Boolean keywords */
374 /* PickOne keywords */
387 "JCLFrameBufferSize",
412 * Default to "OK" status...
419 * Range check input...
424 ppd_status
= PPD_NULL_FILE
;
429 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
432 mask
= ppd_read(fp
, keyword
, name
, text
, &string
);
435 strcmp(keyword
, "PPD-Adobe") != 0 ||
436 string
== NULL
|| string
[0] != '4')
439 * Either this is not a PPD file, or it is not a 4.x PPD file.
442 if (ppd_status
!= PPD_OK
)
443 ppd_status
= PPD_MISSING_PPDADOBE4
;
450 DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword
, string
));
455 * Allocate memory for the PPD file record...
458 if ((ppd
= calloc(sizeof(ppd_file_t
), 1)) == NULL
)
460 ppd_status
= PPD_ALLOC_ERROR
;
465 ppd
->language_level
= 1;
466 ppd
->color_device
= 0;
467 ppd
->colorspace
= PPD_CS_GRAY
;
468 ppd
->landscape
= -90;
471 * Get the default language for the user...
474 language
= cupsLangDefault();
477 oldlocale
= setlocale(LC_NUMERIC
, "C");
479 oldlocale
= setlocale(LC_ALL
, "C");
480 #endif /* LC_NUMERIC */
483 * Read lines from the PPD file and add them to the file record...
492 while ((mask
= ppd_read(fp
, keyword
, name
, text
, &string
)) != 0)
495 printf("mask = %x, keyword = \"%s\"", mask
, keyword
);
498 printf(", name = \"%s\"", name
);
501 printf(", text = \"%s\"", text
);
505 if (strlen(string
) > 40)
506 printf(", string = %p", string
);
508 printf(", string = \"%s\"", string
);
514 if (strcmp(keyword
, "CloseUI") && strcmp(keyword
, "CloseGroup") &&
515 strcmp(keyword
, "CloseSubGroup") && strncmp(keyword
, "Default", 7) &&
516 strcmp(keyword
, "JCLCloseUI") && strcmp(keyword
, "JCLOpenUI") &&
517 strcmp(keyword
, "OpenUI") && strcmp(keyword
, "OpenGroup") &&
518 strcmp(keyword
, "OpenSubGroup") && string
== NULL
)
521 * Need a string value!
526 cupsLangFree(language
);
529 setlocale(LC_NUMERIC
, oldlocale
);
531 setlocale(LC_ALL
, oldlocale
);
532 #endif /* LC_NUMERIC */
534 ppd_status
= PPD_MISSING_VALUE
;
540 * Certain main keywords (as defined by the PPD spec) may be used
541 * without the usual OpenUI/CloseUI stuff. Presumably this is just
542 * so that Adobe wouldn't completely break compatibility with PPD
543 * files prior to v4.0 of the spec, but it is hopelessly
544 * inconsistent... Catch these main keywords and automatically
545 * create the corresponding option, as needed...
551 * Previous line was a UI keyword...
558 if (option
== NULL
&&
559 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
560 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
))
562 for (i
= 0; i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])); i
++)
563 if (!strcmp(keyword
, ui_keywords
[i
]))
566 if (i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])))
569 * Create the option in the appropriate group...
574 DEBUG_printf(("**** FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!\n",
579 if (strcmp(keyword
, "Collate") && strcmp(keyword
, "Duplex") &&
580 strcmp(keyword
, "InputSlot") && strcmp(keyword
, "ManualFeed") &&
581 strcmp(keyword
, "MediaType") && strcmp(keyword
, "MediaColor") &&
582 strcmp(keyword
, "MediaWeight") && strcmp(keyword
, "OutputBin") &&
583 strcmp(keyword
, "OutputMode") && strcmp(keyword
, "OutputOrder") &&
584 strcmp(keyword
, "PageSize") && strcmp(keyword
, "PageRegion"))
585 group
= ppd_get_group(ppd
, "Extra",
586 cupsLangString(language
, CUPS_MSG_EXTRA
));
588 group
= ppd_get_group(ppd
, "General",
589 cupsLangString(language
, CUPS_MSG_GENERAL
));
597 cupsLangFree(language
);
600 setlocale(LC_NUMERIC
, oldlocale
);
602 setlocale(LC_ALL
, oldlocale
);
603 #endif /* LC_NUMERIC */
605 ppd_status
= PPD_ALLOC_ERROR
;
610 DEBUG_printf(("Adding to group %s...\n", group
->text
));
611 option
= ppd_get_option(group
, keyword
);
615 option
= ppd_get_option(group
, keyword
);
623 cupsLangFree(language
);
626 setlocale(LC_NUMERIC
, oldlocale
);
628 setlocale(LC_ALL
, oldlocale
);
629 #endif /* LC_NUMERIC */
631 ppd_status
= PPD_ALLOC_ERROR
;
637 * Now fill in the initial information for the option...
640 if (!strncmp(keyword
, "JCL", 3))
641 option
->section
= PPD_ORDER_JCL
;
643 option
->section
= PPD_ORDER_ANY
;
645 option
->order
= 10.0f
;
648 option
->ui
= PPD_UI_BOOLEAN
;
650 option
->ui
= PPD_UI_PICKONE
;
652 for (j
= 0; j
< ppd
->num_attrs
; j
++)
653 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
654 !strcmp(ppd
->attrs
[j
]->name
+ 7, keyword
) &&
655 ppd
->attrs
[j
]->value
)
657 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
658 sizeof(option
->defchoice
));
662 if (strcmp(keyword
, "PageSize") == 0)
663 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_MEDIA_SIZE
),
664 sizeof(option
->text
));
665 else if (strcmp(keyword
, "MediaType") == 0)
666 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_MEDIA_TYPE
),
667 sizeof(option
->text
));
668 else if (strcmp(keyword
, "InputSlot") == 0)
669 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_MEDIA_SOURCE
),
670 sizeof(option
->text
));
671 else if (strcmp(keyword
, "ColorModel") == 0)
672 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_OUTPUT_MODE
),
673 sizeof(option
->text
));
674 else if (strcmp(keyword
, "Resolution") == 0)
675 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_RESOLUTION
),
676 sizeof(option
->text
));
678 strlcpy(option
->text
, keyword
, sizeof(option
->text
));
682 if (strcmp(keyword
, "LanguageLevel") == 0)
683 ppd
->language_level
= atoi(string
);
684 else if (strcmp(keyword
, "LanguageEncoding") == 0)
685 ppd
->lang_encoding
= string
;
686 else if (strcmp(keyword
, "LanguageVersion") == 0)
687 ppd
->lang_version
= string
;
688 else if (strcmp(keyword
, "Manufacturer") == 0)
689 ppd
->manufacturer
= string
;
690 else if (strcmp(keyword
, "ModelName") == 0)
691 ppd
->modelname
= string
;
692 else if (strcmp(keyword
, "Protocols") == 0)
693 ppd
->protocols
= string
;
694 else if (strcmp(keyword
, "PCFileName") == 0)
695 ppd
->pcfilename
= string
;
696 else if (strcmp(keyword
, "NickName") == 0)
697 ppd
->nickname
= string
;
698 else if (strcmp(keyword
, "Product") == 0)
699 ppd
->product
= string
;
700 else if (strcmp(keyword
, "ShortNickName") == 0)
701 ppd
->shortnickname
= string
;
702 else if (strcmp(keyword
, "TTRasterizer") == 0)
703 ppd
->ttrasterizer
= string
;
704 else if (strcmp(keyword
, "JCLBegin") == 0)
706 ppd
->jcl_begin
= strdup(string
);
707 ppd_decode(ppd
->jcl_begin
); /* Decode quoted string */
709 else if (strcmp(keyword
, "JCLEnd") == 0)
711 ppd
->jcl_end
= strdup(string
);
712 ppd_decode(ppd
->jcl_end
); /* Decode quoted string */
714 else if (strcmp(keyword
, "JCLToPSInterpreter") == 0)
716 ppd
->jcl_ps
= strdup(string
);
717 ppd_decode(ppd
->jcl_ps
); /* Decode quoted string */
719 else if (strcmp(keyword
, "AccurateScreensSupport") == 0)
720 ppd
->accurate_screens
= strcmp(string
, "True") == 0;
721 else if (strcmp(keyword
, "ColorDevice") == 0)
722 ppd
->color_device
= strcmp(string
, "True") == 0;
723 else if (strcmp(keyword
, "ContoneOnly") == 0)
724 ppd
->contone_only
= strcmp(string
, "True") == 0;
725 else if (strcmp(keyword
, "cupsFlipDuplex") == 0)
726 ppd
->flip_duplex
= strcmp(string
, "True") == 0;
727 else if (strcmp(keyword
, "cupsManualCopies") == 0)
728 ppd
->manual_copies
= strcmp(string
, "True") == 0;
729 else if (strcmp(keyword
, "cupsModelNumber") == 0)
730 ppd
->model_number
= atoi(string
);
731 else if (strcmp(keyword
, "cupsColorProfile") == 0)
733 if (ppd
->num_profiles
== 0)
734 profile
= malloc(sizeof(ppd_profile_t
));
736 profile
= realloc(ppd
->profiles
, sizeof(ppd_profile_t
) *
737 (ppd
->num_profiles
+ 1));
739 ppd
->profiles
= profile
;
740 profile
+= ppd
->num_profiles
;
741 ppd
->num_profiles
++;
743 memset(profile
, 0, sizeof(ppd_profile_t
));
744 strlcpy(profile
->resolution
, name
, sizeof(profile
->resolution
));
745 strlcpy(profile
->media_type
, text
, sizeof(profile
->media_type
));
746 sscanf(string
, "%f%f%f%f%f%f%f%f%f%f%f", &(profile
->density
),
748 profile
->matrix
[0] + 0, profile
->matrix
[0] + 1,
749 profile
->matrix
[0] + 2, profile
->matrix
[1] + 0,
750 profile
->matrix
[1] + 1, profile
->matrix
[1] + 2,
751 profile
->matrix
[2] + 0, profile
->matrix
[2] + 1,
752 profile
->matrix
[2] + 2);
754 else if (strcmp(keyword
, "cupsFilter") == 0)
756 if (ppd
->num_filters
== 0)
757 filter
= malloc(sizeof(char *));
759 filter
= realloc(ppd
->filters
, sizeof(char *) * (ppd
->num_filters
+ 1));
767 cupsLangFree(language
);
770 setlocale(LC_NUMERIC
, oldlocale
);
772 setlocale(LC_ALL
, oldlocale
);
773 #endif /* LC_NUMERIC */
775 ppd_status
= PPD_ALLOC_ERROR
;
780 ppd
->filters
= filter
;
781 filter
+= ppd
->num_filters
;
785 * Copy filter string and prevent it from being freed below...
791 else if (strcmp(keyword
, "Throughput") == 0)
792 ppd
->throughput
= atoi(string
);
793 else if (strcmp(keyword
, "Font") == 0)
796 * Add this font to the list of available fonts...
799 if (ppd
->num_fonts
== 0)
800 tempfonts
= (char **)malloc(sizeof(char *));
802 tempfonts
= (char **)realloc(ppd
->fonts
,
803 sizeof(char *) * (ppd
->num_fonts
+ 1));
805 if (tempfonts
== NULL
)
811 cupsLangFree(language
);
814 setlocale(LC_NUMERIC
, oldlocale
);
816 setlocale(LC_ALL
, oldlocale
);
817 #endif /* LC_NUMERIC */
819 ppd_status
= PPD_ALLOC_ERROR
;
824 ppd
->fonts
= tempfonts
;
825 ppd
->fonts
[ppd
->num_fonts
] = strdup(name
);
828 else if (strcmp(keyword
, "VariablePaperSize") == 0 &&
829 strcmp(string
, "True") == 0 &&
830 !ppd
->variable_sizes
)
832 ppd
->variable_sizes
= 1;
835 * Add a "Custom" page size entry...
838 ppd_add_size(ppd
, "Custom");
841 * Add a "Custom" page size option...
844 if ((option
= ppdFindOption(ppd
, "PageSize")) == NULL
)
849 if ((temp
= ppd_get_group(ppd
, "General",
850 cupsLangString(language
,
851 CUPS_MSG_GENERAL
))) == NULL
)
857 cupsLangFree(language
);
860 setlocale(LC_NUMERIC
, oldlocale
);
862 setlocale(LC_ALL
, oldlocale
);
863 #endif /* LC_NUMERIC */
865 ppd_status
= PPD_ALLOC_ERROR
;
870 if ((option
= ppd_get_option(temp
, "PageSize")) == NULL
)
876 cupsLangFree(language
);
879 setlocale(LC_NUMERIC
, oldlocale
);
881 setlocale(LC_ALL
, oldlocale
);
882 #endif /* LC_NUMERIC */
884 ppd_status
= PPD_ALLOC_ERROR
;
890 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
896 cupsLangFree(language
);
899 setlocale(LC_NUMERIC
, oldlocale
);
901 setlocale(LC_ALL
, oldlocale
);
902 #endif /* LC_NUMERIC */
904 ppd_status
= PPD_ALLOC_ERROR
;
909 strlcpy(choice
->text
, cupsLangString(language
, CUPS_MSG_VARIABLE
),
910 sizeof(choice
->text
));
913 else if (strcmp(keyword
, "MaxMediaWidth") == 0)
914 ppd
->custom_max
[0] = (float)atof(string
);
915 else if (strcmp(keyword
, "MaxMediaHeight") == 0)
916 ppd
->custom_max
[1] = (float)atof(string
);
917 else if (strcmp(keyword
, "ParamCustomPageSize") == 0)
919 if (strcmp(name
, "Width") == 0)
920 sscanf(string
, "%*s%*s%f%f", ppd
->custom_min
+ 0,
921 ppd
->custom_max
+ 0);
922 else if (strcmp(name
, "Height") == 0)
923 sscanf(string
, "%*s%*s%f%f", ppd
->custom_min
+ 1,
924 ppd
->custom_max
+ 1);
926 else if (strcmp(keyword
, "HWMargins") == 0)
927 sscanf(string
, "%f%f%f%f", ppd
->custom_margins
+ 0,
928 ppd
->custom_margins
+ 1, ppd
->custom_margins
+ 2,
929 ppd
->custom_margins
+ 3);
930 else if (strcmp(keyword
, "CustomPageSize") == 0 &&
931 strcmp(name
, "True") == 0)
933 if (!ppd
->variable_sizes
)
935 ppd
->variable_sizes
= 1;
938 * Add a "Custom" page size entry...
941 ppd_add_size(ppd
, "Custom");
944 * Add a "Custom" page size option...
947 if ((option
= ppdFindOption(ppd
, "PageSize")) == NULL
)
952 if ((temp
= ppd_get_group(ppd
, "General",
953 cupsLangString(language
,
954 CUPS_MSG_GENERAL
))) == NULL
)
956 DEBUG_puts("Unable to get general group!");
962 cupsLangFree(language
);
965 setlocale(LC_NUMERIC
, oldlocale
);
967 setlocale(LC_ALL
, oldlocale
);
968 #endif /* LC_NUMERIC */
970 ppd_status
= PPD_ALLOC_ERROR
;
975 if ((option
= ppd_get_option(temp
, "PageSize")) == NULL
)
977 DEBUG_puts("Unable to get PageSize option!");
983 cupsLangFree(language
);
986 setlocale(LC_NUMERIC
, oldlocale
);
988 setlocale(LC_ALL
, oldlocale
);
989 #endif /* LC_NUMERIC */
991 ppd_status
= PPD_ALLOC_ERROR
;
997 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
999 DEBUG_puts("Unable to add Custom choice!");
1005 cupsLangFree(language
);
1008 setlocale(LC_NUMERIC
, oldlocale
);
1010 setlocale(LC_ALL
, oldlocale
);
1011 #endif /* LC_NUMERIC */
1013 ppd_status
= PPD_ALLOC_ERROR
;
1018 strlcpy(choice
->text
, cupsLangString(language
, CUPS_MSG_VARIABLE
),
1019 sizeof(choice
->text
));
1023 if ((option
= ppdFindOption(ppd
, "PageSize")) == NULL
)
1025 DEBUG_puts("Unable to find PageSize option!");
1031 cupsLangFree(language
);
1034 setlocale(LC_NUMERIC
, oldlocale
);
1036 setlocale(LC_ALL
, oldlocale
);
1037 #endif /* LC_NUMERIC */
1039 ppd_status
= PPD_INTERNAL_ERROR
;
1044 if ((choice
= ppdFindChoice(option
, "Custom")) == NULL
)
1046 DEBUG_puts("Unable to find Custom choice!");
1052 cupsLangFree(language
);
1055 setlocale(LC_NUMERIC
, oldlocale
);
1057 setlocale(LC_ALL
, oldlocale
);
1058 #endif /* LC_NUMERIC */
1060 ppd_status
= PPD_INTERNAL_ERROR
;
1065 choice
->code
= string
;
1069 else if (strcmp(keyword
, "LandscapeOrientation") == 0)
1071 if (strcmp(string
, "Minus90") == 0)
1072 ppd
->landscape
= -90;
1073 else if (strcmp(string
, "Plus90") == 0)
1074 ppd
->landscape
= 90;
1076 else if (strcmp(keyword
, "Emulators") == 0)
1078 for (count
= 1, sptr
= string
; sptr
!= NULL
;)
1079 if ((sptr
= strchr(sptr
, ' ')) != NULL
)
1082 while (*sptr
== ' ')
1086 ppd
->num_emulations
= count
;
1087 ppd
->emulations
= calloc(sizeof(ppd_emul_t
), count
);
1089 for (i
= 0, sptr
= string
; i
< count
; i
++)
1091 for (nameptr
= ppd
->emulations
[i
].name
;
1092 *sptr
!= '\0' && *sptr
!= ' ';
1094 if (nameptr
< (ppd
->emulations
[i
].name
+ sizeof(ppd
->emulations
[i
].name
) - 1))
1099 while (*sptr
== ' ')
1103 else if (strncmp(keyword
, "StartEmulator_", 14) == 0)
1107 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1108 if (strcmp(keyword
+ 14, ppd
->emulations
[i
].name
) == 0)
1110 ppd
->emulations
[i
].start
= string
;
1114 else if (strncmp(keyword
, "StopEmulator_", 13) == 0)
1118 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1119 if (strcmp(keyword
+ 13, ppd
->emulations
[i
].name
) == 0)
1121 ppd
->emulations
[i
].stop
= string
;
1125 else if (strcmp(keyword
, "JobPatchFile") == 0)
1127 if (ppd
->patches
== NULL
)
1128 ppd
->patches
= strdup(string
);
1131 temp
= realloc(ppd
->patches
, strlen(ppd
->patches
) +
1132 strlen(string
) + 1);
1139 cupsLangFree(language
);
1142 setlocale(LC_NUMERIC
, oldlocale
);
1144 setlocale(LC_ALL
, oldlocale
);
1145 #endif /* LC_NUMERIC */
1147 ppd_status
= PPD_ALLOC_ERROR
;
1152 ppd
->patches
= temp
;
1154 strcpy(ppd
->patches
+ strlen(ppd
->patches
), string
);
1157 else if (strcmp(keyword
, "OpenUI") == 0)
1160 * Don't allow nesting of options...
1169 cupsLangFree(language
);
1172 setlocale(LC_NUMERIC
, oldlocale
);
1174 setlocale(LC_ALL
, oldlocale
);
1175 #endif /* LC_NUMERIC */
1177 ppd_status
= PPD_NESTED_OPEN_UI
;
1183 * Add an option record to the current sub-group, group, or file...
1187 strcpy(name
, name
+ 1); /* Eliminate leading asterisk */
1189 for (i
= strlen(name
) - 1; i
> 0 && isspace(name
[i
]); i
--)
1190 name
[i
] = '\0'; /* Eliminate trailing spaces */
1192 DEBUG_printf(("OpenUI of %s in group %s...\n", name
,
1193 group
? group
->text
: "(null)"));
1195 if (subgroup
!= NULL
)
1196 option
= ppd_get_option(subgroup
, name
);
1197 else if (group
== NULL
)
1199 if (strcmp(name
, "Collate") && strcmp(name
, "Duplex") &&
1200 strcmp(name
, "InputSlot") && strcmp(name
, "ManualFeed") &&
1201 strcmp(name
, "MediaType") && strcmp(name
, "MediaColor") &&
1202 strcmp(name
, "MediaWeight") && strcmp(name
, "OutputBin") &&
1203 strcmp(name
, "OutputMode") && strcmp(name
, "OutputOrder") &&
1204 strcmp(name
, "PageSize") && strcmp(name
, "PageRegion"))
1205 group
= ppd_get_group(ppd
, "Extra",
1206 cupsLangString(language
, CUPS_MSG_EXTRA
));
1208 group
= ppd_get_group(ppd
, "General",
1209 cupsLangString(language
, CUPS_MSG_GENERAL
));
1217 cupsLangFree(language
);
1220 setlocale(LC_NUMERIC
, oldlocale
);
1222 setlocale(LC_ALL
, oldlocale
);
1223 #endif /* LC_NUMERIC */
1225 ppd_status
= PPD_ALLOC_ERROR
;
1230 DEBUG_printf(("Adding to group %s...\n", group
->text
));
1231 option
= ppd_get_option(group
, name
);
1235 option
= ppd_get_option(group
, name
);
1243 cupsLangFree(language
);
1246 setlocale(LC_NUMERIC
, oldlocale
);
1248 setlocale(LC_ALL
, oldlocale
);
1249 #endif /* LC_NUMERIC */
1251 ppd_status
= PPD_ALLOC_ERROR
;
1257 * Now fill in the initial information for the option...
1260 if (string
&& strcmp(string
, "PickMany") == 0)
1261 option
->ui
= PPD_UI_PICKMANY
;
1262 else if (string
&& strcmp(string
, "Boolean") == 0)
1263 option
->ui
= PPD_UI_BOOLEAN
;
1264 else if (string
&& strcmp(string
, "PickOne") == 0)
1265 option
->ui
= PPD_UI_PICKONE
;
1272 cupsLangFree(language
);
1275 setlocale(LC_NUMERIC
, oldlocale
);
1277 setlocale(LC_ALL
, oldlocale
);
1278 #endif /* LC_NUMERIC */
1280 ppd_status
= PPD_BAD_OPEN_UI
;
1285 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1286 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
1287 !strcmp(ppd
->attrs
[j
]->name
+ 7, name
) &&
1288 ppd
->attrs
[j
]->value
)
1290 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
1291 sizeof(option
->defchoice
));
1297 strlcpy(option
->text
, text
, sizeof(option
->text
));
1298 ppd_fix(option
->text
);
1302 if (strcmp(name
, "PageSize") == 0)
1303 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_MEDIA_SIZE
),
1304 sizeof(option
->text
));
1305 else if (strcmp(name
, "MediaType") == 0)
1306 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_MEDIA_TYPE
),
1307 sizeof(option
->text
));
1308 else if (strcmp(name
, "InputSlot") == 0)
1309 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_MEDIA_SOURCE
),
1310 sizeof(option
->text
));
1311 else if (strcmp(name
, "ColorModel") == 0)
1312 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_OUTPUT_MODE
),
1313 sizeof(option
->text
));
1314 else if (strcmp(name
, "Resolution") == 0)
1315 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_RESOLUTION
),
1316 sizeof(option
->text
));
1318 strlcpy(option
->text
, name
, sizeof(option
->text
));
1321 option
->section
= PPD_ORDER_ANY
;
1326 else if (strcmp(keyword
, "JCLOpenUI") == 0)
1329 * Don't allow nesting of options...
1338 cupsLangFree(language
);
1341 setlocale(LC_NUMERIC
, oldlocale
);
1343 setlocale(LC_ALL
, oldlocale
);
1344 #endif /* LC_NUMERIC */
1346 ppd_status
= PPD_NESTED_OPEN_UI
;
1352 * Find the JCL group, and add if needed...
1355 group
= ppd_get_group(ppd
, "JCL", "JCL");
1363 cupsLangFree(language
);
1366 setlocale(LC_NUMERIC
, oldlocale
);
1368 setlocale(LC_ALL
, oldlocale
);
1369 #endif /* LC_NUMERIC */
1371 ppd_status
= PPD_ALLOC_ERROR
;
1377 * Add an option record to the current JCLs...
1381 strcpy(name
, name
+ 1);
1383 option
= ppd_get_option(group
, name
);
1391 cupsLangFree(language
);
1394 setlocale(LC_NUMERIC
, oldlocale
);
1396 setlocale(LC_ALL
, oldlocale
);
1397 #endif /* LC_NUMERIC */
1399 ppd_status
= PPD_ALLOC_ERROR
;
1405 * Now fill in the initial information for the option...
1408 if (string
&& strcmp(string
, "PickMany") == 0)
1409 option
->ui
= PPD_UI_PICKMANY
;
1410 else if (string
&& strcmp(string
, "Boolean") == 0)
1411 option
->ui
= PPD_UI_BOOLEAN
;
1412 else if (string
&& strcmp(string
, "PickOne") == 0)
1413 option
->ui
= PPD_UI_PICKONE
;
1420 cupsLangFree(language
);
1423 setlocale(LC_NUMERIC
, oldlocale
);
1425 setlocale(LC_ALL
, oldlocale
);
1426 #endif /* LC_NUMERIC */
1428 ppd_status
= PPD_BAD_OPEN_UI
;
1433 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1434 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
1435 !strcmp(ppd
->attrs
[j
]->name
+ 7, name
) &&
1436 ppd
->attrs
[j
]->value
)
1438 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
1439 sizeof(option
->defchoice
));
1443 strlcpy(option
->text
, text
, sizeof(option
->text
));
1445 option
->section
= PPD_ORDER_JCL
;
1451 else if (strcmp(keyword
, "CloseUI") == 0 ||
1452 strcmp(keyword
, "JCLCloseUI") == 0)
1459 else if (strcmp(keyword
, "OpenGroup") == 0)
1462 * Open a new group...
1471 cupsLangFree(language
);
1474 setlocale(LC_NUMERIC
, oldlocale
);
1476 setlocale(LC_ALL
, oldlocale
);
1477 #endif /* LC_NUMERIC */
1479 ppd_status
= PPD_NESTED_OPEN_GROUP
;
1490 cupsLangFree(language
);
1493 setlocale(LC_NUMERIC
, oldlocale
);
1495 setlocale(LC_ALL
, oldlocale
);
1496 #endif /* LC_NUMERIC */
1498 ppd_status
= PPD_BAD_OPEN_GROUP
;
1504 * Separate the group name from the text (name/text)...
1507 if ((sptr
= strchr(string
, '/')) != NULL
)
1513 * Fix up the text...
1520 * Find/add the group...
1523 group
= ppd_get_group(ppd
, string
, sptr
);
1528 else if (strcmp(keyword
, "CloseGroup") == 0)
1535 else if (strcmp(keyword
, "OrderDependency") == 0 ||
1536 strcmp(keyword
, "NonUIOrderDependency") == 0)
1538 if (sscanf(string
, "%f%40s%40s", &order
, name
, keyword
) != 3)
1544 cupsLangFree(language
);
1547 setlocale(LC_NUMERIC
, oldlocale
);
1549 setlocale(LC_ALL
, oldlocale
);
1550 #endif /* LC_NUMERIC */
1552 ppd_status
= PPD_BAD_ORDER_DEPENDENCY
;
1557 if (keyword
[0] == '*')
1558 strcpy(keyword
, keyword
+ 1);
1560 if (strcmp(name
, "ExitServer") == 0)
1561 section
= PPD_ORDER_EXIT
;
1562 else if (strcmp(name
, "Prolog") == 0)
1563 section
= PPD_ORDER_PROLOG
;
1564 else if (strcmp(name
, "DocumentSetup") == 0)
1565 section
= PPD_ORDER_DOCUMENT
;
1566 else if (strcmp(name
, "PageSetup") == 0)
1567 section
= PPD_ORDER_PAGE
;
1568 else if (strcmp(name
, "JCLSetup") == 0)
1569 section
= PPD_ORDER_JCL
;
1571 section
= PPD_ORDER_ANY
;
1579 * Only valid for Non-UI options...
1582 for (i
= ppd
->num_groups
, temp
= ppd
->groups
; i
> 0; i
--, temp
++)
1583 if (temp
->text
[0] == '\0')
1587 for (i
= 0; i
< temp
->num_options
; i
++)
1588 if (strcmp(keyword
, temp
->options
[i
].keyword
) == 0)
1590 temp
->options
[i
].section
= section
;
1591 temp
->options
[i
].order
= order
;
1597 option
->section
= section
;
1598 option
->order
= order
;
1604 else if (strncmp(keyword
, "Default", 7) == 0)
1610 * Drop UI text, if any, from value...
1613 if (strchr(string
, '/') != NULL
)
1614 *strchr(string
, '/') = '\0';
1617 * Assign the default value as appropriate...
1620 if (strcmp(keyword
, "DefaultColorSpace") == 0)
1623 * Set default colorspace...
1626 if (strcmp(string
, "CMY") == 0)
1627 ppd
->colorspace
= PPD_CS_CMY
;
1628 else if (strcmp(string
, "CMYK") == 0)
1629 ppd
->colorspace
= PPD_CS_CMYK
;
1630 else if (strcmp(string
, "RGB") == 0)
1631 ppd
->colorspace
= PPD_CS_RGB
;
1632 else if (strcmp(string
, "RGBK") == 0)
1633 ppd
->colorspace
= PPD_CS_RGBK
;
1634 else if (strcmp(string
, "N") == 0)
1635 ppd
->colorspace
= PPD_CS_N
;
1637 ppd
->colorspace
= PPD_CS_GRAY
;
1639 else if (option
&& strcmp(keyword
+ 7, option
->keyword
) == 0)
1642 * Set the default as part of the current option...
1645 strlcpy(option
->defchoice
, string
, sizeof(option
->defchoice
));
1650 * Lookup option and set if it has been defined...
1653 ppd_option_t
*toption
; /* Temporary option */
1656 if ((toption
= ppdFindOption(ppd
, keyword
+ 7)) != NULL
)
1657 strlcpy(toption
->defchoice
, string
, sizeof(toption
->defchoice
));
1660 else if (strcmp(keyword
, "UIConstraints") == 0 ||
1661 strcmp(keyword
, "NonUIConstraints") == 0)
1663 if (ppd
->num_consts
== 0)
1664 constraint
= calloc(sizeof(ppd_const_t
), 1);
1666 constraint
= realloc(ppd
->consts
,
1667 (ppd
->num_consts
+ 1) * sizeof(ppd_const_t
));
1669 if (constraint
== NULL
)
1675 cupsLangFree(language
);
1678 setlocale(LC_NUMERIC
, oldlocale
);
1680 setlocale(LC_ALL
, oldlocale
);
1681 #endif /* LC_NUMERIC */
1683 ppd_status
= PPD_ALLOC_ERROR
;
1688 ppd
->consts
= constraint
;
1689 constraint
+= ppd
->num_consts
;
1692 switch (sscanf(string
, "%40s%40s%40s%40s", constraint
->option1
,
1693 constraint
->choice1
, constraint
->option2
,
1694 constraint
->choice2
))
1696 case 0 : /* Error */
1697 case 1 : /* Error */
1700 ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1703 case 2 : /* Two options... */
1705 * The following strcpy's are safe, as optionN and
1706 * choiceN are all the same size (size defined by PPD spec...)
1709 if (constraint
->option1
[0] == '*')
1710 strcpy(constraint
->option1
, constraint
->option1
+ 1);
1712 if (constraint
->choice1
[0] == '*')
1713 strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1715 strcpy(constraint
->option2
, constraint
->choice1
);
1717 constraint
->choice1
[0] = '\0';
1718 constraint
->choice2
[0] = '\0';
1721 case 3 : /* Two options, one choice... */
1723 * The following strcpy's are safe, as optionN and
1724 * choiceN are all the same size (size defined by PPD spec...)
1727 if (constraint
->option1
[0] == '*')
1728 strcpy(constraint
->option1
, constraint
->option1
+ 1);
1730 if (constraint
->choice1
[0] == '*')
1732 strcpy(constraint
->choice2
, constraint
->option2
);
1733 strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1734 constraint
->choice1
[0] = '\0';
1738 if (constraint
->option2
[0] == '*')
1739 strcpy(constraint
->option2
, constraint
->option2
+ 1);
1741 constraint
->choice2
[0] = '\0';
1745 case 4 : /* Two options, two choices... */
1746 if (constraint
->option1
[0] == '*')
1747 strcpy(constraint
->option1
, constraint
->option1
+ 1);
1749 if (constraint
->option2
[0] == '*')
1750 strcpy(constraint
->option2
, constraint
->option2
+ 1);
1757 else if (strcmp(keyword
, "PaperDimension") == 0)
1759 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1760 size
= ppd_add_size(ppd
, name
);
1765 * Unable to add or find size!
1772 cupsLangFree(language
);
1775 setlocale(LC_NUMERIC
, oldlocale
);
1777 setlocale(LC_ALL
, oldlocale
);
1778 #endif /* LC_NUMERIC */
1780 ppd_status
= PPD_ALLOC_ERROR
;
1785 sscanf(string
, "%f%f", &(size
->width
), &(size
->length
));
1790 else if (strcmp(keyword
, "ImageableArea") == 0)
1792 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1793 size
= ppd_add_size(ppd
, name
);
1798 * Unable to add or find size!
1805 cupsLangFree(language
);
1808 setlocale(LC_NUMERIC
, oldlocale
);
1810 setlocale(LC_ALL
, oldlocale
);
1811 #endif /* LC_NUMERIC */
1813 ppd_status
= PPD_ALLOC_ERROR
;
1818 sscanf(string
, "%f%f%f%f", &(size
->left
), &(size
->bottom
),
1819 &(size
->right
), &(size
->top
));
1824 else if (option
!= NULL
&&
1825 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
1826 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
) &&
1827 strcmp(keyword
, option
->keyword
) == 0)
1829 DEBUG_printf(("group = %p, subgroup = %p\n", group
, subgroup
));
1831 if (strcmp(keyword
, "PageSize") == 0)
1834 * Add a page size...
1837 if (ppdPageSize(ppd
, name
) == NULL
)
1838 ppd_add_size(ppd
, name
);
1842 * Add the option choice...
1845 choice
= ppd_add_choice(option
, name
);
1847 if (mask
& PPD_TEXT
)
1849 strlcpy(choice
->text
, text
, sizeof(choice
->text
));
1850 ppd_fix(choice
->text
);
1852 else if (strcmp(name
, "True") == 0)
1853 strcpy(choice
->text
, "Yes");
1854 else if (strcmp(name
, "False") == 0)
1855 strcpy(choice
->text
, "No");
1857 strlcpy(choice
->text
, name
, sizeof(choice
->text
));
1859 if (option
->section
== PPD_ORDER_JCL
)
1860 ppd_decode(string
); /* Decode quoted string */
1862 choice
->code
= string
;
1863 string
= NULL
; /* Don't add as an attribute below */
1867 * Add remaining lines with keywords and string values as attributes...
1871 (mask
& (PPD_KEYWORD
| PPD_STRING
)) == (PPD_KEYWORD
| PPD_STRING
))
1872 ppd_add_attr(ppd
, keyword
, name
, text
, string
);
1878 * Reset language preferences...
1881 cupsLangFree(language
);
1884 setlocale(LC_NUMERIC
, oldlocale
);
1886 setlocale(LC_ALL
, oldlocale
);
1887 #endif /* LC_NUMERIC */
1891 printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp
));
1894 if (ppd_status
!= PPD_OK
)
1897 * Had an error reading the PPD file, cannot continue!
1907 * Make sure that all PPD files with an InputSlot option have an
1908 * "auto" choice that maps to no specific tray or media type.
1911 if ((option
= ppdFindOption(ppd
, "InputSlot")) != NULL
)
1913 for (i
= 0; i
< option
->num_choices
; i
++)
1914 if (option
->choices
[i
].code
== NULL
|| !option
->choices
[i
].code
[0])
1917 if (i
>= option
->num_choices
)
1920 * No "auto" input slot, add one...
1923 choice
= ppd_add_choice(option
, "Auto");
1925 strlcpy(choice
->text
, cupsLangString(language
, CUPS_MSG_AUTO
),
1926 sizeof(choice
->text
));
1927 choice
->code
= NULL
;
1930 #endif /* !__APPLE__ */
1933 * Set the option back-pointer for each choice...
1937 qsort(ppd
->groups
, ppd
->num_groups
, sizeof(ppd_group_t
),
1938 (int (*)(const void *, const void *))ppd_compare_groups
);
1939 #endif /* !__APPLE__ */
1941 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
1946 qsort(group
->options
, group
->num_options
, sizeof(ppd_option_t
),
1947 (int (*)(const void *, const void *))ppd_compare_options
);
1948 #endif /* !__APPLE__ */
1950 for (j
= group
->num_options
, option
= group
->options
;
1954 for (k
= 0; k
< option
->num_choices
; k
++)
1955 option
->choices
[k
].option
= (void *)option
;
1959 qsort(group
->subgroups
, group
->num_subgroups
, sizeof(ppd_group_t
),
1960 (int (*)(const void *, const void *))ppd_compare_groups
);
1961 #endif /* !__APPLE__ */
1963 for (j
= group
->num_subgroups
, subgroup
= group
->subgroups
;
1968 qsort(subgroup
->options
, subgroup
->num_options
, sizeof(ppd_option_t
),
1969 (int (*)(const void *, const void *))ppd_compare_options
);
1970 #endif /* !__APPLE__ */
1972 for (k
= group
->num_options
, option
= group
->options
;
1976 for (m
= 0; m
< option
->num_choices
; m
++)
1977 option
->choices
[m
].option
= (void *)option
;
1983 * Sort the attributes...
1986 if (ppd
->num_attrs
> 1)
1987 qsort(ppd
->attrs
, ppd
->num_attrs
, sizeof(ppd_attr_t
*),
1988 (int (*)(const void *, const void *))_ppd_attr_compare
);
1991 * Return the PPD file structure...
1999 * 'ppdOpenFd()' - Read a PPD file into memory.
2002 ppd_file_t
* /* O - PPD file record */
2003 ppdOpenFd(int fd
) /* I - File to read from */
2005 FILE *fp
; /* File pointer */
2006 ppd_file_t
*ppd
; /* PPD file record */
2010 * Set the line number to 0...
2016 * Range check input...
2021 ppd_status
= PPD_NULL_FILE
;
2027 * Try to open the file and parse it...
2030 if ((fp
= fdopen(fd
, "r")) != NULL
)
2040 ppd_status
= PPD_FILE_OPEN_ERROR
;
2049 * 'ppdOpenFile()' - Read a PPD file into memory.
2052 ppd_file_t
* /* O - PPD file record */
2053 ppdOpenFile(const char *filename
) /* I - File to read from */
2055 FILE *fp
; /* File pointer */
2056 ppd_file_t
*ppd
; /* PPD file record */
2060 * Set the line number to 0...
2066 * Range check input...
2069 if (filename
== NULL
)
2071 ppd_status
= PPD_NULL_FILE
;
2077 * Try to open the file and parse it...
2080 if ((fp
= fopen(filename
, "r")) != NULL
)
2088 ppd_status
= PPD_FILE_OPEN_ERROR
;
2097 * 'ppd_add_attr()' - Add an attribute to the PPD data.
2100 static ppd_attr_t
* /* O - New attribute */
2101 ppd_add_attr(ppd_file_t
*ppd
, /* I - PPD file data */
2102 const char *name
, /* I - Attribute name */
2103 const char *spec
, /* I - Specifier string, if any */
2104 const char *text
, /* I - Text string, if any */
2105 const char *value
) /* I - Value of attribute */
2107 ppd_attr_t
**ptr
, /* New array */
2108 *temp
; /* New attribute */
2112 * Range check input...
2115 if (ppd
== NULL
|| name
== NULL
|| spec
== NULL
)
2119 * Allocate memory for the new attribute...
2122 if (ppd
->num_attrs
== 0)
2123 ptr
= malloc(sizeof(ppd_attr_t
*));
2125 ptr
= realloc(ppd
->attrs
, (ppd
->num_attrs
+ 1) * sizeof(ppd_attr_t
*));
2131 ptr
+= ppd
->num_attrs
;
2133 if ((temp
= calloc(1, sizeof(ppd_attr_t
))) == NULL
)
2144 strlcpy(temp
->name
, name
, sizeof(temp
->name
));
2145 strlcpy(temp
->spec
, spec
, sizeof(temp
->spec
));
2146 strlcpy(temp
->text
, text
, sizeof(temp
->text
));
2147 temp
->value
= (char *)value
;
2150 * Return the attribute...
2158 * 'ppd_add_choice()' - Add a choice to an option.
2161 static ppd_choice_t
* /* O - Named choice */
2162 ppd_add_choice(ppd_option_t
*option
, /* I - Option */
2163 const char *name
) /* I - Name of choice */
2165 ppd_choice_t
*choice
; /* Choice */
2168 if (option
->num_choices
== 0)
2169 choice
= malloc(sizeof(ppd_choice_t
));
2171 choice
= realloc(option
->choices
,
2172 sizeof(ppd_choice_t
) * (option
->num_choices
+ 1));
2177 option
->choices
= choice
;
2178 choice
+= option
->num_choices
;
2179 option
->num_choices
++;
2181 memset(choice
, 0, sizeof(ppd_choice_t
));
2182 strlcpy(choice
->choice
, name
, sizeof(choice
->choice
));
2189 * 'ppd_add_size()' - Add a page size.
2192 static ppd_size_t
* /* O - Named size */
2193 ppd_add_size(ppd_file_t
*ppd
, /* I - PPD file */
2194 const char *name
) /* I - Name of size */
2196 ppd_size_t
*size
; /* Size */
2199 if (ppd
->num_sizes
== 0)
2200 size
= malloc(sizeof(ppd_size_t
));
2202 size
= realloc(ppd
->sizes
, sizeof(ppd_size_t
) * (ppd
->num_sizes
+ 1));
2208 size
+= ppd
->num_sizes
;
2211 memset(size
, 0, sizeof(ppd_size_t
));
2212 strlcpy(size
->name
, name
, sizeof(size
->name
));
2220 * 'ppd_compare_groups()' - Compare two groups.
2223 static int /* O - Result of comparison */
2224 ppd_compare_groups(ppd_group_t
*g0
, /* I - First group */
2225 ppd_group_t
*g1
) /* I - Second group */
2227 return (strcasecmp(g0
->text
, g1
->text
));
2232 * 'ppd_compare_options()' - Compare two options.
2235 static int /* O - Result of comparison */
2236 ppd_compare_options(ppd_option_t
*o0
, /* I - First option */
2237 ppd_option_t
*o1
) /* I - Second option */
2239 return (strcasecmp(o0
->text
, o1
->text
));
2241 #endif /* !__APPLE__ */
2245 * 'ppd_decode()' - Decode a string value...
2249 ppd_decode(char *string
) /* I - String to decode */
2251 char *inptr
, /* Input pointer */
2252 *outptr
; /* Output pointer */
2258 while (*inptr
!= '\0')
2259 if (*inptr
== '<' && isxdigit(inptr
[1]))
2262 * Convert hex to 8-bit values...
2266 while (isxdigit(*inptr
))
2268 if (isalpha(*inptr
))
2269 *outptr
= (tolower(*inptr
) - 'a' + 10) << 4;
2271 *outptr
= (*inptr
- '0') << 4;
2275 if (isalpha(*inptr
))
2276 *outptr
|= tolower(*inptr
) - 'a' + 10;
2278 *outptr
|= *inptr
- '0';
2284 while (*inptr
!= '>' && *inptr
!= '\0')
2286 while (*inptr
== '>')
2290 *outptr
++ = *inptr
++;
2298 * 'ppd_fix()' - Fix WinANSI characters in the range 0x80 to 0x9f to be
2299 * valid ISO-8859-1 characters...
2303 ppd_fix(char *string
) /* IO - String to fix */
2305 unsigned char *p
; /* Pointer into string */
2306 static const unsigned char lut
[32] = /* Lookup table for characters */
2330 0x20, /* circumflex */
2332 0x20, /* double dot */
2337 '\"', /* should be right quotes */
2343 for (p
= (unsigned char *)string
; *p
; p
++)
2344 if (*p
>= 0x80 && *p
< 0xa0)
2345 *p
= lut
[*p
- 0x80];
2347 #endif /* !__APPLE__ */
2351 * 'ppd_free_group()' - Free a single UI group.
2355 ppd_free_group(ppd_group_t
*group
) /* I - Group to free */
2357 int i
; /* Looping var */
2358 ppd_option_t
*option
; /* Current option */
2359 ppd_group_t
*subgroup
; /* Current sub-group */
2362 if (group
->num_options
> 0)
2364 for (i
= group
->num_options
, option
= group
->options
;
2367 ppd_free_option(option
);
2369 ppd_free(group
->options
);
2372 if (group
->num_subgroups
> 0)
2374 for (i
= group
->num_subgroups
, subgroup
= group
->subgroups
;
2377 ppd_free_group(subgroup
);
2379 ppd_free(group
->subgroups
);
2385 * 'ppd_free_option()' - Free a single option.
2389 ppd_free_option(ppd_option_t
*option
) /* I - Option to free */
2391 int i
; /* Looping var */
2392 ppd_choice_t
*choice
; /* Current choice */
2395 if (option
->num_choices
> 0)
2397 for (i
= option
->num_choices
, choice
= option
->choices
;
2400 ppd_free(choice
->code
);
2402 ppd_free(option
->choices
);
2408 * 'ppd_get_group()' - Find or create the named group as needed.
2411 static ppd_group_t
* /* O - Named group */
2412 ppd_get_group(ppd_file_t
*ppd
, /* I - PPD file */
2413 const char *name
, /* I - Name of group */
2414 const char *text
) /* I - Text for group */
2416 int i
; /* Looping var */
2417 ppd_group_t
*group
; /* Group */
2420 DEBUG_printf(("ppd_get_group(%p, \"%s\")\n", ppd
, name
));
2422 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
2423 if (strcmp(group
->name
, name
) == 0)
2428 DEBUG_printf(("Adding group %s...\n", name
));
2430 if (ppd
->num_groups
== 0)
2431 group
= malloc(sizeof(ppd_group_t
));
2433 group
= realloc(ppd
->groups
,
2434 (ppd
->num_groups
+ 1) * sizeof(ppd_group_t
));
2439 ppd
->groups
= group
;
2440 group
+= ppd
->num_groups
;
2443 memset(group
, 0, sizeof(ppd_group_t
));
2444 strlcpy(group
->name
, name
, sizeof(group
->name
));
2445 strlcpy(group
->text
, text
, sizeof(group
->text
));
2453 * 'ppd_get_option()' - Find or create the named option as needed.
2456 static ppd_option_t
* /* O - Named option */
2457 ppd_get_option(ppd_group_t
*group
, /* I - Group */
2458 const char *name
) /* I - Name of option */
2460 int i
; /* Looping var */
2461 ppd_option_t
*option
; /* Option */
2464 for (i
= group
->num_options
, option
= group
->options
; i
> 0; i
--, option
++)
2465 if (strcmp(option
->keyword
, name
) == 0)
2470 if (group
->num_options
== 0)
2471 option
= malloc(sizeof(ppd_option_t
));
2473 option
= realloc(group
->options
,
2474 (group
->num_options
+ 1) * sizeof(ppd_option_t
));
2479 group
->options
= option
;
2480 option
+= group
->num_options
;
2481 group
->num_options
++;
2483 memset(option
, 0, sizeof(ppd_option_t
));
2484 strlcpy(option
->keyword
, name
, sizeof(option
->keyword
));
2492 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2496 static int /* O - Bitmask of fields read */
2497 ppd_read(FILE *fp
, /* I - File to read from */
2498 char *keyword
, /* O - Keyword from line */
2499 char *option
, /* O - Option from line */
2500 char *text
, /* O - Human-readable text from line */
2501 char **string
) /* O - Code/string data */
2503 int ch
, /* Character from file */
2504 col
, /* Column in line */
2505 colon
, /* Colon seen? */
2506 endquote
, /* Waiting for an end quote */
2507 mask
, /* Mask to be returned */
2508 startline
; /* Start line */
2509 char *keyptr
, /* Keyword pointer */
2510 *optptr
, /* Option pointer */
2511 *textptr
, /* Text pointer */
2512 *strptr
, /* Pointer into string */
2513 *lineptr
, /* Current position in line buffer */
2514 line
[65536]; /* Line buffer (64k) */
2518 * Range check everything...
2521 if (fp
== NULL
|| keyword
== NULL
|| option
== NULL
|| text
== NULL
||
2526 * Now loop until we have a valid line...
2531 startline
= ppd_line
+ 1;
2543 while ((ch
= getc(fp
)) != EOF
&&
2544 (lineptr
- line
) < (sizeof(line
) - 1))
2546 if (ch
== '\r' || ch
== '\n')
2549 * Line feed or carriage return...
2558 * Check for a trailing line feed...
2561 if ((ch
= getc(fp
)) == EOF
)
2567 if (lineptr
== line
) /* Skip blank lines */
2572 if (!endquote
) /* Continue for multi-line text */
2577 else if (ch
< ' ' && ch
!= '\t' && ch
!= 0x1a)
2580 * Other control characters...
2583 ppd_line
= startline
;
2584 ppd_status
= PPD_ILLEGAL_CHARACTER
;
2588 else if (ch
!= 0x1a)
2591 * Any other character...
2597 if (col
> (PPD_MAX_LINE
- 1))
2600 * Line is too long...
2603 ppd_line
= startline
;
2604 ppd_status
= PPD_LINE_TOO_LONG
;
2609 if (ch
== ':' && strncmp(line
, "*%", 2) != 0)
2612 if (ch
== '\"' && colon
)
2613 endquote
= !endquote
;
2620 * Didn't finish this quoted string...
2623 while ((ch
= getc(fp
)) != EOF
)
2626 else if (ch
== '\r' || ch
== '\n')
2634 * Check for a trailing line feed...
2637 if ((ch
= getc(fp
)) == EOF
)
2645 else if (ch
< ' ' && ch
!= '\t' && ch
!= 0x1a)
2648 * Other control characters...
2651 ppd_line
= startline
;
2652 ppd_status
= PPD_ILLEGAL_CHARACTER
;
2656 else if (ch
!= 0x1a)
2660 if (col
> (PPD_MAX_LINE
- 1))
2663 * Line is too long...
2666 ppd_line
= startline
;
2667 ppd_status
= PPD_LINE_TOO_LONG
;
2677 * Didn't finish this line...
2680 while ((ch
= getc(fp
)) != EOF
)
2681 if (ch
== '\r' || ch
== '\n')
2684 * Line feed or carriage return...
2693 * Check for a trailing line feed...
2696 if ((ch
= getc(fp
)) == EOF
)
2704 else if (ch
< ' ' && ch
!= '\t' && ch
!= 0x1a)
2707 * Other control characters...
2710 ppd_line
= startline
;
2711 ppd_status
= PPD_ILLEGAL_CHARACTER
;
2715 else if (ch
!= 0x1a)
2719 if (col
> (PPD_MAX_LINE
- 1))
2722 * Line is too long...
2725 ppd_line
= startline
;
2726 ppd_status
= PPD_LINE_TOO_LONG
;
2733 if (lineptr
> line
&& lineptr
[-1] == '\n')
2738 /* DEBUG_printf(("LINE = \"%s\"\n", line));*/
2740 if (ch
== EOF
&& lineptr
== line
)
2755 if (!line
[0] || /* Blank line */
2756 strcmp(line
, "*") == 0 || /* (Bad) comment line */
2757 strncmp(line
, "*%", 2) == 0 || /* Comment line */
2758 strcmp(line
, "*End") == 0) /* End of multi-line string */
2760 startline
= ppd_line
+ 1;
2764 if (line
[0] != '*') /* All lines start with an asterisk */
2767 * Allow lines consisting of just whitespace...
2770 for (lineptr
= line
; *lineptr
; lineptr
++)
2771 if (!isspace(*lineptr
))
2776 ppd_status
= PPD_MISSING_ASTERISK
;
2789 while (*lineptr
!= '\0' && *lineptr
!= ':' && !isspace(*lineptr
))
2791 if (*lineptr
<= ' ' || *lineptr
> 126 || *lineptr
== '/' ||
2792 (keyptr
- keyword
) >= (PPD_MAX_NAME
- 1))
2794 ppd_status
= PPD_ILLEGAL_MAIN_KEYWORD
;
2798 *keyptr
++ = *lineptr
++;
2803 if (strcmp(keyword
, "End") == 0)
2806 mask
|= PPD_KEYWORD
;
2808 /* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
2810 if (isspace(*lineptr
))
2813 * Get an option name...
2816 while (isspace(*lineptr
))
2821 while (*lineptr
!= '\0' && *lineptr
!= '\n' && *lineptr
!= ':' &&
2824 if (*lineptr
<= ' ' || *lineptr
> 126 ||
2825 (optptr
- option
) >= (PPD_MAX_NAME
- 1))
2827 ppd_status
= PPD_ILLEGAL_OPTION_KEYWORD
;
2831 *optptr
++ = *lineptr
++;
2837 /* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
2839 if (*lineptr
== '/')
2842 * Get human-readable text...
2849 while (*lineptr
!= '\0' && *lineptr
!= '\n' && *lineptr
!= ':')
2851 if (((unsigned char)*lineptr
< ' ' && *lineptr
!= '\t') ||
2852 (textptr
- text
) >= (PPD_MAX_LINE
- 1))
2854 ppd_status
= PPD_ILLEGAL_TRANSLATION
;
2858 *textptr
++ = *lineptr
++;
2867 /* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
2870 if (*lineptr
== ':')
2873 * Get string after triming leading and trailing whitespace...
2876 while (*lineptr
== ':' || isspace(*lineptr
))
2879 strptr
= lineptr
+ strlen(lineptr
) - 1;
2880 while (strptr
>= lineptr
&& isspace(*strptr
))
2883 if (*strptr
== '\"')
2886 * Quoted string by itself...
2889 *string
= malloc(strlen(lineptr
) + 1);
2893 for (; *lineptr
!= '\0'; lineptr
++)
2894 if (*lineptr
!= '\"')
2895 *strptr
++ = *lineptr
;
2900 *string
= strdup(lineptr
);
2902 /* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
2914 * End of "$Id: ppd.c,v 1.104 2003/06/14 16:08:20 mike Exp $".