]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/ppd.c
Import CUPS trunk (1.4svn) r7116.
[thirdparty/cups.git] / cups / ppd.c
1 /*
2 * "$Id: ppd.c 6937 2007-09-10 21:13:31Z mike $"
3 *
4 * PPD file routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * PostScript is a trademark of Adobe Systems, Inc.
16 *
17 * This code and any derivative of it may be used and distributed
18 * freely under the terms of the GNU General Public License when
19 * used with GNU Ghostscript or its derivatives. Use of the code
20 * (or any derivative of it) with software other than GNU
21 * GhostScript (or its derivatives) is governed by the CUPS license
22 * agreement.
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * ppdClose() - Free all memory used by the PPD file.
29 * ppdErrorString() - Returns the text assocated with a status.
30 * _ppdGetEncoding() - Get the CUPS encoding value for the given
31 * LanguageEncoding.
32 * ppdLastError() - Return the status from the last ppdOpen*().
33 * ppdOpen() - Read a PPD file into memory.
34 * ppdOpen2() - Read a PPD file into memory.
35 * ppdOpenFd() - Read a PPD file into memory.
36 * ppdOpenFile() - Read a PPD file into memory.
37 * ppdSetConformance() - Set the conformance level for PPD files.
38 * ppd_add_attr() - Add an attribute to the PPD data.
39 * ppd_add_choice() - Add a choice to an option.
40 * ppd_add_size() - Add a page size.
41 * ppd_compare_attrs() - Compare two attributes.
42 * ppd_compare_choices() - Compare two choices...
43 * ppd_compare_consts() - Compare two constraints.
44 * ppd_compare_coptions() - Compare two custom options.
45 * ppd_compare_cparams() - Compare two custom parameters.
46 * ppd_compare_options() - Compare two options.
47 * ppd_decode() - Decode a string value...
48 * ppd_free_group() - Free a single UI group.
49 * ppd_free_option() - Free a single option.
50 * ppd_get_coption() - Get a custom option record.
51 * ppd_get_cparam() - Get a custom parameter record.
52 * ppd_get_group() - Find or create the named group as needed.
53 * ppd_get_option() - Find or create the named option as needed.
54 * ppd_hash_option() - Generate a hash of the option name...
55 * ppd_read() - Read a line from a PPD file, skipping comment
56 * lines as necessary.
57 */
58
59 /*
60 * Include necessary headers.
61 */
62
63 #include "globals.h"
64 #include "debug.h"
65 #include <stdlib.h>
66
67
68 /*
69 * Definitions...
70 */
71
72 #if defined(WIN32) || defined(__EMX__)
73 # define READ_BINARY "rb" /* Open a binary file for reading */
74 # define WRITE_BINARY "wb" /* Open a binary file for writing */
75 #else
76 # define READ_BINARY "r" /* Open a binary file for reading */
77 # define WRITE_BINARY "w" /* Open a binary file for writing */
78 #endif /* WIN32 || __EMX__ */
79
80 #define ppd_free(p) if (p) free(p) /* Safe free macro */
81
82 #define PPD_KEYWORD 1 /* Line contained a keyword */
83 #define PPD_OPTION 2 /* Line contained an option name */
84 #define PPD_TEXT 4 /* Line contained human-readable text */
85 #define PPD_STRING 8 /* Line contained a string or code */
86
87 #define PPD_HASHSIZE 512 /* Size of hash */
88
89
90 /*
91 * Line buffer structure...
92 */
93
94 typedef struct _ppd_line_s
95 {
96 char *buffer; /* Pointer to buffer */
97 size_t bufsize; /* Size of the buffer */
98 } _ppd_line_t;
99
100
101 /*
102 * Local functions...
103 */
104
105 static ppd_attr_t *ppd_add_attr(ppd_file_t *ppd, const char *name,
106 const char *spec, const char *text,
107 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);
110 static int ppd_compare_attrs(ppd_attr_t *a, ppd_attr_t *b);
111 static int ppd_compare_choices(ppd_choice_t *a, ppd_choice_t *b);
112 static int ppd_compare_consts(ppd_const_t *a, ppd_const_t *b);
113 static int ppd_compare_coptions(ppd_coption_t *a,
114 ppd_coption_t *b);
115 static int ppd_compare_cparams(ppd_cparam_t *a, ppd_cparam_t *b);
116 static int ppd_compare_options(ppd_option_t *a, ppd_option_t *b);
117 static int ppd_decode(char *string);
118 static void ppd_free_group(ppd_group_t *group);
119 static void ppd_free_option(ppd_option_t *option);
120 static ppd_coption_t *ppd_get_coption(ppd_file_t *ppd, const char *name);
121 static ppd_cparam_t *ppd_get_cparam(ppd_coption_t *opt,
122 const char *param,
123 const char *text);
124 static ppd_group_t *ppd_get_group(ppd_file_t *ppd, const char *name,
125 const char *text, _cups_globals_t *cg,
126 cups_encoding_t encoding);
127 static ppd_option_t *ppd_get_option(ppd_group_t *group, const char *name);
128 static int ppd_hash_option(ppd_option_t *option);
129 static int ppd_read(cups_file_t *fp, _ppd_line_t *line,
130 char *keyword, char *option, char *text,
131 char **string, int ignoreblank,
132 _cups_globals_t *cg);
133
134
135 /*
136 * 'ppdClose()' - Free all memory used by the PPD file.
137 */
138
139 void
140 ppdClose(ppd_file_t *ppd) /* I - PPD file record */
141 {
142 int i; /* Looping var */
143 ppd_emul_t *emul; /* Current emulation */
144 ppd_group_t *group; /* Current group */
145 char **font; /* Current font */
146 char **filter; /* Current filter */
147 ppd_attr_t **attr; /* Current attribute */
148 ppd_coption_t *coption; /* Current custom option */
149 ppd_cparam_t *cparam; /* Current custom parameter */
150
151
152 /*
153 * Range check arguments...
154 */
155
156 if (!ppd)
157 return;
158
159 /*
160 * Free all strings at the top level...
161 */
162
163 _cupsStrFree(ppd->lang_encoding);
164 _cupsStrFree(ppd->nickname);
165 _cupsStrFree(ppd->patches);
166 _cupsStrFree(ppd->jcl_begin);
167 _cupsStrFree(ppd->jcl_end);
168 _cupsStrFree(ppd->jcl_ps);
169
170 /*
171 * Free any emulations...
172 */
173
174 if (ppd->num_emulations > 0)
175 {
176 for (i = ppd->num_emulations, emul = ppd->emulations; i > 0; i --, emul ++)
177 {
178 _cupsStrFree(emul->start);
179 _cupsStrFree(emul->stop);
180 }
181
182 ppd_free(ppd->emulations);
183 }
184
185 /*
186 * Free any UI groups, subgroups, and options...
187 */
188
189 if (ppd->num_groups > 0)
190 {
191 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
192 ppd_free_group(group);
193
194 ppd_free(ppd->groups);
195 }
196
197 cupsArrayDelete(ppd->options);
198 cupsArrayDelete(ppd->marked);
199
200 /*
201 * Free any page sizes...
202 */
203
204 if (ppd->num_sizes > 0)
205 ppd_free(ppd->sizes);
206
207 /*
208 * Free any constraints...
209 */
210
211 if (ppd->num_consts > 0)
212 ppd_free(ppd->consts);
213
214 /*
215 * Free any filters...
216 */
217
218 if (ppd->num_filters > 0)
219 {
220 for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++)
221 _cupsStrFree(*filter);
222
223 ppd_free(ppd->filters);
224 }
225
226 /*
227 * Free any fonts...
228 */
229
230 if (ppd->num_fonts > 0)
231 {
232 for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++)
233 _cupsStrFree(*font);
234
235 ppd_free(ppd->fonts);
236 }
237
238 /*
239 * Free any profiles...
240 */
241
242 if (ppd->num_profiles > 0)
243 ppd_free(ppd->profiles);
244
245 /*
246 * Free any attributes...
247 */
248
249 if (ppd->num_attrs > 0)
250 {
251 for (i = ppd->num_attrs, attr = ppd->attrs; i > 0; i --, attr ++)
252 {
253 _cupsStrFree((*attr)->value);
254 ppd_free(*attr);
255 }
256
257 ppd_free(ppd->attrs);
258 }
259
260 cupsArrayDelete(ppd->sorted_attrs);
261
262 /*
263 * Free custom options...
264 */
265
266 for (coption = (ppd_coption_t *)cupsArrayFirst(ppd->coptions);
267 coption;
268 coption = (ppd_coption_t *)cupsArrayNext(ppd->coptions))
269 {
270 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
271 cparam;
272 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
273 {
274 switch (cparam->type)
275 {
276 case PPD_CUSTOM_PASSCODE :
277 case PPD_CUSTOM_PASSWORD :
278 case PPD_CUSTOM_STRING :
279 _cupsStrFree(cparam->current.custom_string);
280 break;
281
282 default :
283 break;
284 }
285
286 free(cparam);
287 }
288
289 cupsArrayDelete(coption->params);
290
291 free(coption);
292 }
293
294 cupsArrayDelete(ppd->coptions);
295
296 /*
297 * Free the whole record...
298 */
299
300 ppd_free(ppd);
301 }
302
303
304 /*
305 * 'ppdErrorString()' - Returns the text assocated with a status.
306 *
307 * @since CUPS 1.1.19@
308 */
309
310 const char * /* O - Status string */
311 ppdErrorString(ppd_status_t status) /* I - PPD status */
312 {
313 static const char * const messages[] =/* Status messages */
314 {
315 _("OK"),
316 _("Unable to open PPD file"),
317 _("NULL PPD file pointer"),
318 _("Memory allocation error"),
319 _("Missing PPD-Adobe-4.x header"),
320 _("Missing value string"),
321 _("Internal error"),
322 _("Bad OpenGroup"),
323 _("OpenGroup without a CloseGroup first"),
324 _("Bad OpenUI/JCLOpenUI"),
325 _("OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"),
326 _("Bad OrderDependency"),
327 _("Bad UIConstraints"),
328 _("Missing asterisk in column 1"),
329 _("Line longer than the maximum allowed (255 characters)"),
330 _("Illegal control character"),
331 _("Illegal main keyword string"),
332 _("Illegal option keyword string"),
333 _("Illegal translation string"),
334 _("Illegal whitespace character"),
335 _("Bad custom parameter")
336 };
337
338
339 if (status < PPD_OK || status > PPD_ILLEGAL_WHITESPACE)
340 return (_cupsLangString(cupsLangDefault(), _("Unknown")));
341 else
342 return (_cupsLangString(cupsLangDefault(), messages[status]));
343 }
344
345
346 /*
347 * '_ppdGetEncoding()' - Get the CUPS encoding value for the given
348 * LanguageEncoding.
349 */
350
351 cups_encoding_t /* O - CUPS encoding value */
352 _ppdGetEncoding(const char *name) /* I - LanguageEncoding string */
353 {
354 if (!strcasecmp(name, "ISOLatin1"))
355 return (CUPS_ISO8859_1);
356 else if (!strcasecmp(name, "ISOLatin2"))
357 return (CUPS_ISO8859_2);
358 else if (!strcasecmp(name, "ISOLatin5"))
359 return (CUPS_ISO8859_5);
360 else if (!strcasecmp(name, "JIS83-RKSJ"))
361 return (CUPS_WINDOWS_932);
362 else if (!strcasecmp(name, "MacStandard"))
363 return (CUPS_MAC_ROMAN);
364 else if (!strcasecmp(name, "WindowsANSI"))
365 return (CUPS_WINDOWS_1252);
366 else
367 return (CUPS_UTF8);
368 }
369
370
371 /*
372 * 'ppdLastError()' - Return the status from the last ppdOpen*().
373 *
374 * @since CUPS 1.1.19@
375 */
376
377 ppd_status_t /* O - Status code */
378 ppdLastError(int *line) /* O - Line number */
379 {
380 _cups_globals_t *cg = _cupsGlobals();
381 /* Global data */
382
383
384 if (line)
385 *line = cg->ppd_line;
386
387 return (cg->ppd_status);
388 }
389
390
391 /*
392 * 'ppdOpen()' - Read a PPD file into memory.
393 */
394
395 ppd_file_t * /* O - PPD file record */
396 ppdOpen(FILE *fp) /* I - File to read from */
397 {
398 ppd_file_t *ppd; /* PPD file record */
399 cups_file_t *cf; /* CUPS file */
400
401
402 /*
403 * Reopen the stdio file as a CUPS file...
404 */
405
406 if ((cf = cupsFileOpenFd(fileno(fp), "r")) == NULL)
407 return (NULL);
408
409 /*
410 * Load the PPD file using the newer API...
411 */
412
413 ppd = ppdOpen2(cf);
414
415 /*
416 * Close the CUPS file and return the PPD...
417 */
418
419 cupsFileClose(cf);
420
421 return (ppd);
422 }
423
424
425 /*
426 * 'ppdOpen2()' - Read a PPD file into memory.
427 *
428 * @since CUPS 1.2@
429 */
430
431 ppd_file_t * /* O - PPD file record */
432 ppdOpen2(cups_file_t *fp) /* I - File to read from */
433 {
434 int i, j, k; /* Looping vars */
435 int count; /* Temporary count */
436 _ppd_line_t line; /* Line buffer */
437 ppd_file_t *ppd; /* PPD file record */
438 ppd_group_t *group, /* Current group */
439 *subgroup; /* Current sub-group */
440 ppd_option_t *option; /* Current option */
441 ppd_choice_t *choice; /* Current choice */
442 ppd_const_t *constraint; /* Current constraint */
443 ppd_size_t *size; /* Current page size */
444 int mask; /* Line data mask */
445 char keyword[PPD_MAX_NAME],
446 /* Keyword from file */
447 name[PPD_MAX_NAME],
448 /* Option from file */
449 text[PPD_MAX_LINE],
450 /* Human-readable text from file */
451 *string, /* Code/text from file */
452 *sptr, /* Pointer into string */
453 *nameptr, /* Pointer into name */
454 *temp, /* Temporary string pointer */
455 **tempfonts; /* Temporary fonts pointer */
456 float order; /* Order dependency number */
457 ppd_section_t section; /* Order dependency section */
458 ppd_profile_t *profile; /* Pointer to color profile */
459 char **filter; /* Pointer to filter */
460 cups_lang_t *language; /* Default language */
461 struct lconv *loc; /* Locale data */
462 int ui_keyword; /* Is this line a UI keyword? */
463 cups_encoding_t encoding; /* Encoding of PPD file */
464 _cups_globals_t *cg = _cupsGlobals();
465 /* Global data */
466 char custom_name[PPD_MAX_NAME];
467 /* CustomFoo attribute name */
468 ppd_attr_t *custom_attr; /* CustomFoo attribute */
469 static const char * const ui_keywords[] =
470 {
471 #ifdef CUPS_USE_FULL_UI_KEYWORDS_LIST
472 /*
473 * Adobe defines some 41 keywords as "UI", meaning that they are
474 * user interface elements and that they should be treated as such
475 * even if the PPD creator doesn't use Open/CloseUI around them.
476 *
477 * Since this can cause previously invisible options to appear and
478 * confuse users, the default is to only treat the PageSize and
479 * PageRegion keywords this way.
480 */
481 /* Boolean keywords */
482 "BlackSubstitution",
483 "Booklet",
484 "Collate",
485 "ManualFeed",
486 "MirrorPrint",
487 "NegativePrint",
488 "Sorter",
489 "TraySwitch",
490
491 /* PickOne keywords */
492 "AdvanceMedia",
493 "BindColor",
494 "BindEdge",
495 "BindType",
496 "BindWhen",
497 "BitsPerPixel",
498 "ColorModel",
499 "CutMedia",
500 "Duplex",
501 "FoldType",
502 "FoldWhen",
503 "InputSlot",
504 "JCLFrameBufferSize",
505 "JCLResolution",
506 "Jog",
507 "MediaColor",
508 "MediaType",
509 "MediaWeight",
510 "OutputBin",
511 "OutputMode",
512 "OutputOrder",
513 "PageRegion",
514 "PageSize",
515 "Resolution",
516 "Separations",
517 "Signature",
518 "Slipsheet",
519 "Smoothing",
520 "StapleLocation",
521 "StapleOrientation",
522 "StapleWhen",
523 "StapleX",
524 "StapleY"
525 #else /* !CUPS_USE_FULL_UI_KEYWORDS_LIST */
526 "PageRegion",
527 "PageSize"
528 #endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */
529 };
530
531
532 /*
533 * Default to "OK" status...
534 */
535
536 cg->ppd_status = PPD_OK;
537 cg->ppd_line = 0;
538
539 /*
540 * Range check input...
541 */
542
543 if (fp == NULL)
544 {
545 cg->ppd_status = PPD_NULL_FILE;
546 return (NULL);
547 }
548
549 /*
550 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
551 */
552
553 line.buffer = NULL;
554 line.bufsize = 0;
555
556 mask = ppd_read(fp, &line, keyword, name, text, &string, 0, cg);
557
558 DEBUG_printf(("mask=%x, keyword=\"%s\"...\n", mask, keyword));
559
560 if (mask == 0 ||
561 strcmp(keyword, "PPD-Adobe") ||
562 string == NULL || string[0] != '4')
563 {
564 /*
565 * Either this is not a PPD file, or it is not a 4.x PPD file.
566 */
567
568 if (cg->ppd_status == PPD_OK)
569 cg->ppd_status = PPD_MISSING_PPDADOBE4;
570
571 _cupsStrFree(string);
572
573 return (NULL);
574 }
575
576 DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword, string));
577
578 _cupsStrFree(string);
579
580 /*
581 * Allocate memory for the PPD file record...
582 */
583
584 if ((ppd = calloc(1, sizeof(ppd_file_t))) == NULL)
585 {
586 cg->ppd_status = PPD_ALLOC_ERROR;
587
588 return (NULL);
589 }
590
591 ppd->language_level = 2;
592 ppd->color_device = 0;
593 ppd->colorspace = PPD_CS_GRAY;
594 ppd->landscape = -90;
595 ppd->coptions = cupsArrayNew((cups_array_func_t)ppd_compare_coptions,
596 NULL);
597
598 /*
599 * Get the default language for the user...
600 */
601
602 language = cupsLangDefault();
603 loc = localeconv();
604
605 /*
606 * Read lines from the PPD file and add them to the file record...
607 */
608
609 group = NULL;
610 subgroup = NULL;
611 option = NULL;
612 choice = NULL;
613 ui_keyword = 0;
614 encoding = CUPS_ISO8859_1;
615
616 while ((mask = ppd_read(fp, &line, keyword, name, text, &string, 1, cg)) != 0)
617 {
618 #ifdef DEBUG
619 printf("mask = %x, keyword = \"%s\"", mask, keyword);
620
621 if (name[0] != '\0')
622 printf(", name = \"%s\"", name);
623
624 if (text[0] != '\0')
625 printf(", text = \"%s\"", text);
626
627 if (string != NULL)
628 {
629 if (strlen(string) > 40)
630 printf(", string = %p", string);
631 else
632 printf(", string = \"%s\"", string);
633 }
634
635 puts("");
636 #endif /* DEBUG */
637
638 if (strcmp(keyword, "CloseUI") && strcmp(keyword, "CloseGroup") &&
639 strcmp(keyword, "CloseSubGroup") && strncmp(keyword, "Default", 7) &&
640 strcmp(keyword, "JCLCloseUI") && strcmp(keyword, "JCLOpenUI") &&
641 strcmp(keyword, "OpenUI") && strcmp(keyword, "OpenGroup") &&
642 strcmp(keyword, "OpenSubGroup") && string == NULL)
643 {
644 /*
645 * Need a string value!
646 */
647
648 cg->ppd_status = PPD_MISSING_VALUE;
649
650 goto error;
651 }
652
653 /*
654 * Certain main keywords (as defined by the PPD spec) may be used
655 * without the usual OpenUI/CloseUI stuff. Presumably this is just
656 * so that Adobe wouldn't completely break compatibility with PPD
657 * files prior to v4.0 of the spec, but it is hopelessly
658 * inconsistent... Catch these main keywords and automatically
659 * create the corresponding option, as needed...
660 */
661
662 if (ui_keyword)
663 {
664 /*
665 * Previous line was a UI keyword...
666 */
667
668 option = NULL;
669 ui_keyword = 0;
670 }
671
672 if (option == NULL &&
673 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
674 (PPD_KEYWORD | PPD_OPTION | PPD_STRING))
675 {
676 for (i = 0; i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])); i ++)
677 if (!strcmp(keyword, ui_keywords[i]))
678 break;
679
680 if (i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])))
681 {
682 /*
683 * Create the option in the appropriate group...
684 */
685
686 ui_keyword = 1;
687
688 DEBUG_printf(("**** FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!\n",
689 keyword));
690
691 if (!group)
692 {
693 if ((group = ppd_get_group(ppd, "General", _("General"), cg,
694 encoding)) == NULL)
695 goto error;
696
697 DEBUG_printf(("Adding to group %s...\n", group->text));
698 option = ppd_get_option(group, keyword);
699 group = NULL;
700 }
701 else
702 option = ppd_get_option(group, keyword);
703
704 if (option == NULL)
705 {
706 cg->ppd_status = PPD_ALLOC_ERROR;
707
708 goto error;
709 }
710
711 /*
712 * Now fill in the initial information for the option...
713 */
714
715 if (!strncmp(keyword, "JCL", 3))
716 option->section = PPD_ORDER_JCL;
717 else
718 option->section = PPD_ORDER_ANY;
719
720 option->order = 10.0f;
721
722 if (i < 8)
723 option->ui = PPD_UI_BOOLEAN;
724 else
725 option->ui = PPD_UI_PICKONE;
726
727 for (j = 0; j < ppd->num_attrs; j ++)
728 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
729 !strcmp(ppd->attrs[j]->name + 7, keyword) &&
730 ppd->attrs[j]->value)
731 {
732 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
733 option->keyword, ppd->attrs[j]->value));
734 strlcpy(option->defchoice, ppd->attrs[j]->value,
735 sizeof(option->defchoice));
736 break;
737 }
738
739 if (!strcmp(keyword, "PageSize"))
740 strlcpy(option->text, _("Media Size"), sizeof(option->text));
741 else if (!strcmp(keyword, "MediaType"))
742 strlcpy(option->text, _("Media Type"), sizeof(option->text));
743 else if (!strcmp(keyword, "InputSlot"))
744 strlcpy(option->text, _("Media Source"), sizeof(option->text));
745 else if (!strcmp(keyword, "ColorModel"))
746 strlcpy(option->text, _("Output Mode"), sizeof(option->text));
747 else if (!strcmp(keyword, "Resolution"))
748 strlcpy(option->text, _("Resolution"), sizeof(option->text));
749 else
750 strlcpy(option->text, keyword, sizeof(option->text));
751 }
752 }
753
754 if (!strcmp(keyword, "LanguageLevel"))
755 ppd->language_level = atoi(string);
756 else if (!strcmp(keyword, "LanguageEncoding"))
757 {
758 /*
759 * Say all PPD files are UTF-8, since we convert to UTF-8...
760 */
761
762 ppd->lang_encoding = _cupsStrAlloc("UTF-8");
763 encoding = _ppdGetEncoding(string);
764 }
765 else if (!strcmp(keyword, "LanguageVersion"))
766 ppd->lang_version = string;
767 else if (!strcmp(keyword, "Manufacturer"))
768 ppd->manufacturer = string;
769 else if (!strcmp(keyword, "ModelName"))
770 ppd->modelname = string;
771 else if (!strcmp(keyword, "Protocols"))
772 ppd->protocols = string;
773 else if (!strcmp(keyword, "PCFileName"))
774 ppd->pcfilename = string;
775 else if (!strcmp(keyword, "NickName"))
776 {
777 if (encoding != CUPS_UTF8)
778 {
779 cups_utf8_t utf8[256]; /* UTF-8 version of NickName */
780
781
782 cupsCharsetToUTF8(utf8, string, sizeof(utf8), encoding);
783 ppd->nickname = _cupsStrAlloc((char *)utf8);
784 }
785 else
786 ppd->nickname = _cupsStrAlloc(string);
787 }
788 else if (!strcmp(keyword, "Product"))
789 ppd->product = string;
790 else if (!strcmp(keyword, "ShortNickName"))
791 ppd->shortnickname = string;
792 else if (!strcmp(keyword, "TTRasterizer"))
793 ppd->ttrasterizer = string;
794 else if (!strcmp(keyword, "JCLBegin"))
795 {
796 ppd->jcl_begin = _cupsStrAlloc(string);
797 ppd_decode(ppd->jcl_begin); /* Decode quoted string */
798 }
799 else if (!strcmp(keyword, "JCLEnd"))
800 {
801 ppd->jcl_end = _cupsStrAlloc(string);
802 ppd_decode(ppd->jcl_end); /* Decode quoted string */
803 }
804 else if (!strcmp(keyword, "JCLToPSInterpreter"))
805 {
806 ppd->jcl_ps = _cupsStrAlloc(string);
807 ppd_decode(ppd->jcl_ps); /* Decode quoted string */
808 }
809 else if (!strcmp(keyword, "AccurateScreensSupport"))
810 ppd->accurate_screens = !strcmp(string, "True");
811 else if (!strcmp(keyword, "ColorDevice"))
812 ppd->color_device = !strcmp(string, "True");
813 else if (!strcmp(keyword, "ContoneOnly"))
814 ppd->contone_only = !strcmp(string, "True");
815 else if (!strcmp(keyword, "cupsFlipDuplex"))
816 ppd->flip_duplex = !strcmp(string, "True");
817 else if (!strcmp(keyword, "cupsManualCopies"))
818 ppd->manual_copies = !strcmp(string, "True");
819 else if (!strcmp(keyword, "cupsModelNumber"))
820 ppd->model_number = atoi(string);
821 else if (!strcmp(keyword, "cupsColorProfile"))
822 {
823 if (ppd->num_profiles == 0)
824 profile = malloc(sizeof(ppd_profile_t));
825 else
826 profile = realloc(ppd->profiles, sizeof(ppd_profile_t) *
827 (ppd->num_profiles + 1));
828
829 ppd->profiles = profile;
830 profile += ppd->num_profiles;
831 ppd->num_profiles ++;
832
833 memset(profile, 0, sizeof(ppd_profile_t));
834 strlcpy(profile->resolution, name, sizeof(profile->resolution));
835 strlcpy(profile->media_type, text, sizeof(profile->media_type));
836
837 profile->density = (float)_cupsStrScand(string, &sptr, loc);
838 profile->gamma = (float)_cupsStrScand(sptr, &sptr, loc);
839 profile->matrix[0][0] = (float)_cupsStrScand(sptr, &sptr, loc);
840 profile->matrix[0][1] = (float)_cupsStrScand(sptr, &sptr, loc);
841 profile->matrix[0][2] = (float)_cupsStrScand(sptr, &sptr, loc);
842 profile->matrix[1][0] = (float)_cupsStrScand(sptr, &sptr, loc);
843 profile->matrix[1][1] = (float)_cupsStrScand(sptr, &sptr, loc);
844 profile->matrix[1][2] = (float)_cupsStrScand(sptr, &sptr, loc);
845 profile->matrix[2][0] = (float)_cupsStrScand(sptr, &sptr, loc);
846 profile->matrix[2][1] = (float)_cupsStrScand(sptr, &sptr, loc);
847 profile->matrix[2][2] = (float)_cupsStrScand(sptr, &sptr, loc);
848 }
849 else if (!strcmp(keyword, "cupsFilter"))
850 {
851 if (ppd->num_filters == 0)
852 filter = malloc(sizeof(char *));
853 else
854 filter = realloc(ppd->filters, sizeof(char *) * (ppd->num_filters + 1));
855
856 if (filter == NULL)
857 {
858 cg->ppd_status = PPD_ALLOC_ERROR;
859
860 goto error;
861 }
862
863 ppd->filters = filter;
864 filter += ppd->num_filters;
865 ppd->num_filters ++;
866
867 /*
868 * Copy filter string and prevent it from being freed below...
869 */
870
871 *filter = string;
872 string = NULL;
873 }
874 else if (!strcmp(keyword, "Throughput"))
875 ppd->throughput = atoi(string);
876 else if (!strcmp(keyword, "Font"))
877 {
878 /*
879 * Add this font to the list of available fonts...
880 */
881
882 if (ppd->num_fonts == 0)
883 tempfonts = (char **)malloc(sizeof(char *));
884 else
885 tempfonts = (char **)realloc(ppd->fonts,
886 sizeof(char *) * (ppd->num_fonts + 1));
887
888 if (tempfonts == NULL)
889 {
890 cg->ppd_status = PPD_ALLOC_ERROR;
891
892 goto error;
893 }
894
895 ppd->fonts = tempfonts;
896 ppd->fonts[ppd->num_fonts] = _cupsStrAlloc(name);
897 ppd->num_fonts ++;
898 }
899 else if (!strncmp(keyword, "ParamCustom", 11))
900 {
901 ppd_coption_t *coption; /* Custom option */
902 ppd_cparam_t *cparam; /* Custom parameter */
903 int corder; /* Order number */
904 char ctype[33], /* Data type */
905 cminimum[65], /* Minimum value */
906 cmaximum[65]; /* Maximum value */
907
908
909 /*
910 * Get the custom option and parameter...
911 */
912
913 if ((coption = ppd_get_coption(ppd, keyword + 11)) == NULL)
914 {
915 cg->ppd_status = PPD_ALLOC_ERROR;
916
917 goto error;
918 }
919
920 if ((cparam = ppd_get_cparam(coption, name, text)) == NULL)
921 {
922 cg->ppd_status = PPD_ALLOC_ERROR;
923
924 goto error;
925 }
926
927 /*
928 * Get the parameter data...
929 */
930
931 if (sscanf(string, "%d%32s%64s%64s", &corder, ctype, cminimum,
932 cmaximum) != 4)
933 {
934 cg->ppd_status = PPD_BAD_CUSTOM_PARAM;
935
936 goto error;
937 }
938
939 cparam->order = corder;
940
941 if (!strcmp(ctype, "curve"))
942 {
943 cparam->type = PPD_CUSTOM_CURVE;
944 cparam->minimum.custom_curve = (float)_cupsStrScand(cminimum, NULL, loc);
945 cparam->maximum.custom_curve = (float)_cupsStrScand(cmaximum, NULL, loc);
946 }
947 else if (!strcmp(ctype, "int"))
948 {
949 cparam->type = PPD_CUSTOM_INT;
950 cparam->minimum.custom_int = atoi(cminimum);
951 cparam->maximum.custom_int = atoi(cmaximum);
952 }
953 else if (!strcmp(ctype, "invcurve"))
954 {
955 cparam->type = PPD_CUSTOM_INVCURVE;
956 cparam->minimum.custom_invcurve = (float)_cupsStrScand(cminimum, NULL, loc);
957 cparam->maximum.custom_invcurve = (float)_cupsStrScand(cmaximum, NULL, loc);
958 }
959 else if (!strcmp(ctype, "passcode"))
960 {
961 cparam->type = PPD_CUSTOM_PASSCODE;
962 cparam->minimum.custom_passcode = atoi(cminimum);
963 cparam->maximum.custom_passcode = atoi(cmaximum);
964 }
965 else if (!strcmp(ctype, "password"))
966 {
967 cparam->type = PPD_CUSTOM_PASSWORD;
968 cparam->minimum.custom_password = atoi(cminimum);
969 cparam->maximum.custom_password = atoi(cmaximum);
970 }
971 else if (!strcmp(ctype, "points"))
972 {
973 cparam->type = PPD_CUSTOM_POINTS;
974 cparam->minimum.custom_points = (float)_cupsStrScand(cminimum, NULL, loc);
975 cparam->maximum.custom_points = (float)_cupsStrScand(cmaximum, NULL, loc);
976 }
977 else if (!strcmp(ctype, "real"))
978 {
979 cparam->type = PPD_CUSTOM_REAL;
980 cparam->minimum.custom_real = (float)_cupsStrScand(cminimum, NULL, loc);
981 cparam->maximum.custom_real = (float)_cupsStrScand(cmaximum, NULL, loc);
982 }
983 else if (!strcmp(ctype, "string"))
984 {
985 cparam->type = PPD_CUSTOM_STRING;
986 cparam->minimum.custom_string = atoi(cminimum);
987 cparam->maximum.custom_string = atoi(cmaximum);
988 }
989 else
990 {
991 cg->ppd_status = PPD_BAD_CUSTOM_PARAM;
992
993 goto error;
994 }
995
996 /*
997 * Now special-case for CustomPageSize...
998 */
999
1000 if (!strcmp(coption->keyword, "PageSize"))
1001 {
1002 if (!strcmp(name, "Width"))
1003 {
1004 ppd->custom_min[0] = cparam->minimum.custom_points;
1005 ppd->custom_max[0] = cparam->maximum.custom_points;
1006 }
1007 else if (!strcmp(name, "Height"))
1008 {
1009 ppd->custom_min[1] = cparam->minimum.custom_points;
1010 ppd->custom_max[1] = cparam->maximum.custom_points;
1011 }
1012 }
1013 }
1014 else if (!strcmp(keyword, "HWMargins"))
1015 {
1016 for (i = 0, sptr = string; i < 4; i ++)
1017 ppd->custom_margins[i] = (float)_cupsStrScand(sptr, &sptr, loc);
1018 }
1019 else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True") && !option)
1020 {
1021 ppd_option_t *custom_option; /* Custom option */
1022
1023 DEBUG_puts("Processing Custom option...");
1024
1025 /*
1026 * Get the option and custom option...
1027 */
1028
1029 if (!ppd_get_coption(ppd, keyword + 6))
1030 {
1031 cg->ppd_status = PPD_ALLOC_ERROR;
1032
1033 goto error;
1034 }
1035
1036 if (option && !strcasecmp(option->keyword, keyword + 6))
1037 custom_option = option;
1038 else
1039 custom_option = ppdFindOption(ppd, keyword + 6);
1040
1041 if (custom_option)
1042 {
1043 /*
1044 * Add the "custom" option...
1045 */
1046
1047 if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
1048 {
1049 DEBUG_puts("Unable to add Custom choice!");
1050
1051 cg->ppd_status = PPD_ALLOC_ERROR;
1052
1053 goto error;
1054 }
1055
1056 strlcpy(choice->text, text[0] ? text : _("Custom"),
1057 sizeof(choice->text));
1058
1059 choice->code = _cupsStrAlloc(string);
1060 }
1061
1062 /*
1063 * Now process custom page sizes specially...
1064 */
1065
1066 if (!strcmp(keyword, "CustomPageSize"))
1067 {
1068 /*
1069 * Add a "Custom" page size entry...
1070 */
1071
1072 ppd->variable_sizes = 1;
1073
1074 ppd_add_size(ppd, "Custom");
1075
1076 if (option && !strcasecmp(option->keyword, "PageRegion"))
1077 custom_option = option;
1078 else
1079 custom_option = ppdFindOption(ppd, "PageRegion");
1080
1081 if (custom_option)
1082 {
1083 if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
1084 {
1085 DEBUG_puts("Unable to add Custom choice!");
1086
1087 cg->ppd_status = PPD_ALLOC_ERROR;
1088
1089 goto error;
1090 }
1091
1092 strlcpy(choice->text, text[0] ? text : _("Custom"),
1093 sizeof(choice->text));
1094 }
1095 }
1096 }
1097 else if (!strcmp(keyword, "LandscapeOrientation"))
1098 {
1099 if (!strcmp(string, "Minus90"))
1100 ppd->landscape = -90;
1101 else if (!strcmp(string, "Plus90"))
1102 ppd->landscape = 90;
1103 }
1104 else if (!strcmp(keyword, "Emulators"))
1105 {
1106 for (count = 1, sptr = string; sptr != NULL;)
1107 if ((sptr = strchr(sptr, ' ')) != NULL)
1108 {
1109 count ++;
1110 while (*sptr == ' ')
1111 sptr ++;
1112 }
1113
1114 ppd->num_emulations = count;
1115 ppd->emulations = calloc(count, sizeof(ppd_emul_t));
1116
1117 for (i = 0, sptr = string; i < count; i ++)
1118 {
1119 for (nameptr = ppd->emulations[i].name;
1120 *sptr != '\0' && *sptr != ' ';
1121 sptr ++)
1122 if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1))
1123 *nameptr++ = *sptr;
1124
1125 *nameptr = '\0';
1126
1127 while (*sptr == ' ')
1128 sptr ++;
1129 }
1130 }
1131 else if (!strncmp(keyword, "StartEmulator_", 14))
1132 {
1133 ppd_decode(string);
1134
1135 for (i = 0; i < ppd->num_emulations; i ++)
1136 if (!strcmp(keyword + 14, ppd->emulations[i].name))
1137 {
1138 ppd->emulations[i].start = string;
1139 string = NULL;
1140 }
1141 }
1142 else if (!strncmp(keyword, "StopEmulator_", 13))
1143 {
1144 ppd_decode(string);
1145
1146 for (i = 0; i < ppd->num_emulations; i ++)
1147 if (!strcmp(keyword + 13, ppd->emulations[i].name))
1148 {
1149 ppd->emulations[i].stop = string;
1150 string = NULL;
1151 }
1152 }
1153 else if (!strcmp(keyword, "JobPatchFile"))
1154 {
1155 if (ppd->patches == NULL)
1156 ppd->patches = _cupsStrAlloc(string);
1157 else
1158 {
1159 temp = realloc(ppd->patches, strlen(ppd->patches) +
1160 strlen(string) + 1);
1161 if (temp == NULL)
1162 {
1163 cg->ppd_status = PPD_ALLOC_ERROR;
1164
1165 goto error;
1166 }
1167
1168 ppd->patches = temp;
1169
1170 strcpy(ppd->patches + strlen(ppd->patches), string);
1171 }
1172 }
1173 else if (!strcmp(keyword, "OpenUI"))
1174 {
1175 /*
1176 * Don't allow nesting of options...
1177 */
1178
1179 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
1180 {
1181 cg->ppd_status = PPD_NESTED_OPEN_UI;
1182
1183 goto error;
1184 }
1185
1186 /*
1187 * Add an option record to the current sub-group, group, or file...
1188 */
1189
1190 DEBUG_printf(("name=\"%s\" (%d)\n", name, strlen(name)));
1191
1192 if (name[0] == '*')
1193 _cups_strcpy(name, name + 1); /* Eliminate leading asterisk */
1194
1195 for (i = (int)strlen(name) - 1; i > 0 && isspace(name[i] & 255); i --)
1196 name[i] = '\0'; /* Eliminate trailing spaces */
1197
1198 DEBUG_printf(("OpenUI of %s in group %s...\n", name,
1199 group ? group->text : "(null)"));
1200
1201 if (subgroup != NULL)
1202 option = ppd_get_option(subgroup, name);
1203 else if (group == NULL)
1204 {
1205 if ((group = ppd_get_group(ppd, "General", _("General"), cg,
1206 encoding)) == NULL)
1207 goto error;
1208
1209 DEBUG_printf(("Adding to group %s...\n", group->text));
1210 option = ppd_get_option(group, name);
1211 group = NULL;
1212 }
1213 else
1214 option = ppd_get_option(group, name);
1215
1216 if (option == NULL)
1217 {
1218 cg->ppd_status = PPD_ALLOC_ERROR;
1219
1220 goto error;
1221 }
1222
1223 /*
1224 * Now fill in the initial information for the option...
1225 */
1226
1227 if (string && !strcmp(string, "PickMany"))
1228 option->ui = PPD_UI_PICKMANY;
1229 else if (string && !strcmp(string, "Boolean"))
1230 option->ui = PPD_UI_BOOLEAN;
1231 else if (string && !strcmp(string, "PickOne"))
1232 option->ui = PPD_UI_PICKONE;
1233 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1234 {
1235 cg->ppd_status = PPD_BAD_OPEN_UI;
1236
1237 goto error;
1238 }
1239 else
1240 option->ui = PPD_UI_PICKONE;
1241
1242 for (j = 0; j < ppd->num_attrs; j ++)
1243 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
1244 !strcmp(ppd->attrs[j]->name + 7, name) &&
1245 ppd->attrs[j]->value)
1246 {
1247 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
1248 option->keyword, ppd->attrs[j]->value));
1249 strlcpy(option->defchoice, ppd->attrs[j]->value,
1250 sizeof(option->defchoice));
1251 break;
1252 }
1253
1254 if (text[0])
1255 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1256 sizeof(option->text), encoding);
1257 else
1258 {
1259 if (!strcmp(name, "PageSize"))
1260 strlcpy(option->text, _("Media Size"), sizeof(option->text));
1261 else if (!strcmp(name, "MediaType"))
1262 strlcpy(option->text, _("Media Type"), sizeof(option->text));
1263 else if (!strcmp(name, "InputSlot"))
1264 strlcpy(option->text, _("Media Source"), sizeof(option->text));
1265 else if (!strcmp(name, "ColorModel"))
1266 strlcpy(option->text, _("Output Mode"), sizeof(option->text));
1267 else if (!strcmp(name, "Resolution"))
1268 strlcpy(option->text, _("Resolution"), sizeof(option->text));
1269 else
1270 strlcpy(option->text, name, sizeof(option->text));
1271 }
1272
1273 option->section = PPD_ORDER_ANY;
1274
1275 _cupsStrFree(string);
1276 string = NULL;
1277
1278 /*
1279 * Add a custom option choice if we have already seen a CustomFoo
1280 * attribute...
1281 */
1282
1283 if (!strcasecmp(name, "PageRegion"))
1284 strcpy(custom_name, "CustomPageSize");
1285 else
1286 snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
1287
1288 if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
1289 {
1290 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
1291 {
1292 DEBUG_puts("Unable to add Custom choice!");
1293
1294 cg->ppd_status = PPD_ALLOC_ERROR;
1295
1296 goto error;
1297 }
1298
1299 strlcpy(choice->text,
1300 custom_attr->text[0] ? custom_attr->text : _("Custom"),
1301 sizeof(choice->text));
1302 choice->code = _cupsStrAlloc(custom_attr->value);
1303 }
1304 }
1305 else if (!strcmp(keyword, "JCLOpenUI"))
1306 {
1307 /*
1308 * Don't allow nesting of options...
1309 */
1310
1311 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
1312 {
1313 cg->ppd_status = PPD_NESTED_OPEN_UI;
1314
1315 goto error;
1316 }
1317
1318 /*
1319 * Find the JCL group, and add if needed...
1320 */
1321
1322 group = ppd_get_group(ppd, "JCL", _("JCL"), cg, encoding);
1323
1324 if (group == NULL)
1325 goto error;
1326
1327 /*
1328 * Add an option record to the current JCLs...
1329 */
1330
1331 if (name[0] == '*')
1332 _cups_strcpy(name, name + 1);
1333
1334 option = ppd_get_option(group, name);
1335
1336 if (option == NULL)
1337 {
1338 cg->ppd_status = PPD_ALLOC_ERROR;
1339
1340 goto error;
1341 }
1342
1343 /*
1344 * Now fill in the initial information for the option...
1345 */
1346
1347 if (string && !strcmp(string, "PickMany"))
1348 option->ui = PPD_UI_PICKMANY;
1349 else if (string && !strcmp(string, "Boolean"))
1350 option->ui = PPD_UI_BOOLEAN;
1351 else if (string && !strcmp(string, "PickOne"))
1352 option->ui = PPD_UI_PICKONE;
1353 else
1354 {
1355 cg->ppd_status = PPD_BAD_OPEN_UI;
1356
1357 goto error;
1358 }
1359
1360 for (j = 0; j < ppd->num_attrs; j ++)
1361 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
1362 !strcmp(ppd->attrs[j]->name + 7, name) &&
1363 ppd->attrs[j]->value)
1364 {
1365 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
1366 option->keyword, ppd->attrs[j]->value));
1367 strlcpy(option->defchoice, ppd->attrs[j]->value,
1368 sizeof(option->defchoice));
1369 break;
1370 }
1371
1372 if (text[0])
1373 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1374 sizeof(option->text), encoding);
1375 else
1376 strlcpy(option->text, name, sizeof(option->text));
1377
1378 option->section = PPD_ORDER_JCL;
1379 group = NULL;
1380
1381 _cupsStrFree(string);
1382 string = NULL;
1383
1384 /*
1385 * Add a custom option choice if we have already seen a CustomFoo
1386 * attribute...
1387 */
1388
1389 snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
1390
1391 if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
1392 {
1393 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
1394 {
1395 DEBUG_puts("Unable to add Custom choice!");
1396
1397 cg->ppd_status = PPD_ALLOC_ERROR;
1398
1399 goto error;
1400 }
1401
1402 strlcpy(choice->text,
1403 custom_attr->text[0] ? custom_attr->text : _("Custom"),
1404 sizeof(choice->text));
1405 choice->code = _cupsStrAlloc(custom_attr->value);
1406 }
1407 }
1408 else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI"))
1409 {
1410 option = NULL;
1411
1412 _cupsStrFree(string);
1413 string = NULL;
1414 }
1415 else if (!strcmp(keyword, "OpenGroup"))
1416 {
1417 /*
1418 * Open a new group...
1419 */
1420
1421 if (group != NULL)
1422 {
1423 cg->ppd_status = PPD_NESTED_OPEN_GROUP;
1424
1425 goto error;
1426 }
1427
1428 if (!string)
1429 {
1430 cg->ppd_status = PPD_BAD_OPEN_GROUP;
1431
1432 goto error;
1433 }
1434
1435 /*
1436 * Separate the group name from the text (name/text)...
1437 */
1438
1439 if ((sptr = strchr(string, '/')) != NULL)
1440 *sptr++ = '\0';
1441 else
1442 sptr = string;
1443
1444 /*
1445 * Fix up the text...
1446 */
1447
1448 ppd_decode(sptr);
1449
1450 /*
1451 * Find/add the group...
1452 */
1453
1454 group = ppd_get_group(ppd, string, sptr, cg, encoding);
1455
1456 if (group == NULL)
1457 goto error;
1458
1459 _cupsStrFree(string);
1460 string = NULL;
1461 }
1462 else if (!strcmp(keyword, "CloseGroup"))
1463 {
1464 group = NULL;
1465
1466 _cupsStrFree(string);
1467 string = NULL;
1468 }
1469 else if (!strcmp(keyword, "OrderDependency"))
1470 {
1471 order = (float)_cupsStrScand(string, &sptr, loc);
1472
1473 if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2)
1474 {
1475 cg->ppd_status = PPD_BAD_ORDER_DEPENDENCY;
1476
1477 goto error;
1478 }
1479
1480 if (keyword[0] == '*')
1481 _cups_strcpy(keyword, keyword + 1);
1482
1483 if (!strcmp(name, "ExitServer"))
1484 section = PPD_ORDER_EXIT;
1485 else if (!strcmp(name, "Prolog"))
1486 section = PPD_ORDER_PROLOG;
1487 else if (!strcmp(name, "DocumentSetup"))
1488 section = PPD_ORDER_DOCUMENT;
1489 else if (!strcmp(name, "PageSetup"))
1490 section = PPD_ORDER_PAGE;
1491 else if (!strcmp(name, "JCLSetup"))
1492 section = PPD_ORDER_JCL;
1493 else
1494 section = PPD_ORDER_ANY;
1495
1496 if (option == NULL)
1497 {
1498 ppd_group_t *gtemp;
1499
1500
1501 /*
1502 * Only valid for Non-UI options...
1503 */
1504
1505 for (i = ppd->num_groups, gtemp = ppd->groups; i > 0; i --, gtemp ++)
1506 if (gtemp->text[0] == '\0')
1507 break;
1508
1509 if (i > 0)
1510 for (i = 0; i < gtemp->num_options; i ++)
1511 if (!strcmp(keyword, gtemp->options[i].keyword))
1512 {
1513 gtemp->options[i].section = section;
1514 gtemp->options[i].order = order;
1515 break;
1516 }
1517 }
1518 else
1519 {
1520 option->section = section;
1521 option->order = order;
1522 }
1523
1524 _cupsStrFree(string);
1525 string = NULL;
1526 }
1527 else if (!strncmp(keyword, "Default", 7))
1528 {
1529 if (string == NULL)
1530 continue;
1531
1532 /*
1533 * Drop UI text, if any, from value...
1534 */
1535
1536 if (strchr(string, '/') != NULL)
1537 *strchr(string, '/') = '\0';
1538
1539 /*
1540 * Assign the default value as appropriate...
1541 */
1542
1543 if (!strcmp(keyword, "DefaultColorSpace"))
1544 {
1545 /*
1546 * Set default colorspace...
1547 */
1548
1549 if (!strcmp(string, "CMY"))
1550 ppd->colorspace = PPD_CS_CMY;
1551 else if (!strcmp(string, "CMYK"))
1552 ppd->colorspace = PPD_CS_CMYK;
1553 else if (!strcmp(string, "RGB"))
1554 ppd->colorspace = PPD_CS_RGB;
1555 else if (!strcmp(string, "RGBK"))
1556 ppd->colorspace = PPD_CS_RGBK;
1557 else if (!strcmp(string, "N"))
1558 ppd->colorspace = PPD_CS_N;
1559 else
1560 ppd->colorspace = PPD_CS_GRAY;
1561 }
1562 else if (option && !strcmp(keyword + 7, option->keyword))
1563 {
1564 /*
1565 * Set the default as part of the current option...
1566 */
1567
1568 DEBUG_printf(("Setting %s to %s...\n", keyword, string));
1569
1570 strlcpy(option->defchoice, string, sizeof(option->defchoice));
1571
1572 DEBUG_printf(("%s is now %s...\n", keyword, option->defchoice));
1573 }
1574 else
1575 {
1576 /*
1577 * Lookup option and set if it has been defined...
1578 */
1579
1580 ppd_option_t *toption; /* Temporary option */
1581
1582
1583 if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL)
1584 {
1585 DEBUG_printf(("Setting %s to %s...\n", keyword, string));
1586 strlcpy(toption->defchoice, string, sizeof(toption->defchoice));
1587 }
1588 }
1589 }
1590 else if (!strcmp(keyword, "UIConstraints") ||
1591 !strcmp(keyword, "NonUIConstraints"))
1592 {
1593 if (ppd->num_consts == 0)
1594 constraint = calloc(2, sizeof(ppd_const_t));
1595 else
1596 constraint = realloc(ppd->consts,
1597 (ppd->num_consts + 2) * sizeof(ppd_const_t));
1598
1599 if (constraint == NULL)
1600 {
1601 cg->ppd_status = PPD_ALLOC_ERROR;
1602
1603 goto error;
1604 }
1605
1606 ppd->consts = constraint;
1607 constraint += ppd->num_consts;
1608 ppd->num_consts ++;
1609
1610 switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1,
1611 constraint->choice1, constraint->option2,
1612 constraint->choice2))
1613 {
1614 case 0 : /* Error */
1615 case 1 : /* Error */
1616 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1617 goto error;
1618
1619 case 2 : /* Two options... */
1620 /*
1621 * Check for broken constraints like "* Option"...
1622 */
1623
1624 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1625 (!strcmp(constraint->option1, "*") ||
1626 !strcmp(constraint->choice1, "*")))
1627 {
1628 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1629 goto error;
1630 }
1631
1632 /*
1633 * The following strcpy's are safe, as optionN and
1634 * choiceN are all the same size (size defined by PPD spec...)
1635 */
1636
1637 if (constraint->option1[0] == '*')
1638 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1639 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1640 {
1641 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1642 goto error;
1643 }
1644
1645 if (constraint->choice1[0] == '*')
1646 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1647 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1648 {
1649 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1650 goto error;
1651 }
1652
1653 constraint->choice1[0] = '\0';
1654 constraint->choice2[0] = '\0';
1655 break;
1656
1657 case 3 : /* Two options, one choice... */
1658 /*
1659 * Check for broken constraints like "* Option"...
1660 */
1661
1662 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1663 (!strcmp(constraint->option1, "*") ||
1664 !strcmp(constraint->choice1, "*") ||
1665 !strcmp(constraint->option2, "*")))
1666 {
1667 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1668 goto error;
1669 }
1670
1671 /*
1672 * The following _cups_strcpy's are safe, as optionN and
1673 * choiceN are all the same size (size defined by PPD spec...)
1674 */
1675
1676 if (constraint->option1[0] == '*')
1677 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1678 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1679 {
1680 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1681 goto error;
1682 }
1683
1684 if (constraint->choice1[0] == '*')
1685 {
1686 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1687 constraint->option2[0] == '*')
1688 {
1689 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1690 goto error;
1691 }
1692
1693 _cups_strcpy(constraint->choice2, constraint->option2);
1694 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1695 constraint->choice1[0] = '\0';
1696 }
1697 else
1698 {
1699 if (constraint->option2[0] == '*')
1700 _cups_strcpy(constraint->option2, constraint->option2 + 1);
1701 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1702 {
1703 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1704 goto error;
1705 }
1706
1707 constraint->choice2[0] = '\0';
1708 }
1709 break;
1710
1711 case 4 : /* Two options, two choices... */
1712 /*
1713 * Check for broken constraints like "* Option"...
1714 */
1715
1716 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1717 (!strcmp(constraint->option1, "*") ||
1718 !strcmp(constraint->choice1, "*") ||
1719 !strcmp(constraint->option2, "*") ||
1720 !strcmp(constraint->choice2, "*")))
1721 {
1722 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1723 goto error;
1724 }
1725
1726 if (constraint->option1[0] == '*')
1727 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1728 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1729 {
1730 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1731 goto error;
1732 }
1733
1734 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1735 constraint->choice1[0] == '*')
1736 {
1737 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1738 goto error;
1739 }
1740
1741 if (constraint->option2[0] == '*')
1742 _cups_strcpy(constraint->option2, constraint->option2 + 1);
1743 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1744 {
1745 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1746 goto error;
1747 }
1748
1749 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1750 constraint->choice2[0] == '*')
1751 {
1752 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1753 goto error;
1754 }
1755 break;
1756 }
1757
1758 /*
1759 * For CustomPageSize and InputSlot/ManualFeed, create a duplicate
1760 * constraint for PageRegion...
1761 */
1762
1763 if (!strcasecmp(constraint->option1, "CustomPageSize") &&
1764 (!strcasecmp(constraint->option2, "InputSlot") ||
1765 !strcasecmp(constraint->option2, "ManualFeed")))
1766 {
1767 ppd->num_consts ++;
1768
1769 strcpy(constraint[1].option1, "PageRegion");
1770 strcpy(constraint[1].choice1, "Custom");
1771 strcpy(constraint[1].option2, constraint->option2);
1772 strcpy(constraint[1].choice2, constraint->choice2);
1773 }
1774 else if (!strcasecmp(constraint->option2, "CustomPageSize") &&
1775 (!strcasecmp(constraint->option1, "InputSlot") ||
1776 !strcasecmp(constraint->option1, "ManualFeed")))
1777 {
1778 ppd->num_consts ++;
1779
1780 strcpy(constraint[1].option1, constraint->option1);
1781 strcpy(constraint[1].choice1, constraint->choice1);
1782 strcpy(constraint[1].option2, "PageRegion");
1783 strcpy(constraint[1].choice2, "Custom");
1784 }
1785
1786 /*
1787 * Handle CustomFoo option constraints...
1788 */
1789
1790 if (!strncasecmp(constraint->option1, "Custom", 6) &&
1791 !strcasecmp(constraint->choice1, "True"))
1792 {
1793 _cups_strcpy(constraint->option1, constraint->option1 + 6);
1794 strcpy(constraint->choice1, "Custom");
1795 }
1796
1797 if (!strncasecmp(constraint->option2, "Custom", 6) &&
1798 !strcasecmp(constraint->choice2, "True"))
1799 {
1800 _cups_strcpy(constraint->option2, constraint->option2 + 6);
1801 strcpy(constraint->choice2, "Custom");
1802 }
1803
1804 /*
1805 * Don't add this one as an attribute...
1806 */
1807
1808 _cupsStrFree(string);
1809 string = NULL;
1810 }
1811 else if (!strcmp(keyword, "PaperDimension"))
1812 {
1813 if ((size = ppdPageSize(ppd, name)) == NULL)
1814 size = ppd_add_size(ppd, name);
1815
1816 if (size == NULL)
1817 {
1818 /*
1819 * Unable to add or find size!
1820 */
1821
1822 cg->ppd_status = PPD_ALLOC_ERROR;
1823
1824 goto error;
1825 }
1826
1827 size->width = (float)_cupsStrScand(string, &sptr, loc);
1828 size->length = (float)_cupsStrScand(sptr, NULL, loc);
1829
1830 _cupsStrFree(string);
1831 string = NULL;
1832 }
1833 else if (!strcmp(keyword, "ImageableArea"))
1834 {
1835 if ((size = ppdPageSize(ppd, name)) == NULL)
1836 size = ppd_add_size(ppd, name);
1837
1838 if (size == NULL)
1839 {
1840 /*
1841 * Unable to add or find size!
1842 */
1843
1844 cg->ppd_status = PPD_ALLOC_ERROR;
1845
1846 goto error;
1847 }
1848
1849 size->left = (float)_cupsStrScand(string, &sptr, loc);
1850 size->bottom = (float)_cupsStrScand(sptr, &sptr, loc);
1851 size->right = (float)_cupsStrScand(sptr, &sptr, loc);
1852 size->top = (float)_cupsStrScand(sptr, NULL, loc);
1853
1854 _cupsStrFree(string);
1855 string = NULL;
1856 }
1857 else if (option != NULL &&
1858 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
1859 (PPD_KEYWORD | PPD_OPTION | PPD_STRING) &&
1860 !strcmp(keyword, option->keyword))
1861 {
1862 DEBUG_printf(("group = %p, subgroup = %p\n", group, subgroup));
1863
1864 if (!strcmp(keyword, "PageSize"))
1865 {
1866 /*
1867 * Add a page size...
1868 */
1869
1870 if (ppdPageSize(ppd, name) == NULL)
1871 ppd_add_size(ppd, name);
1872 }
1873
1874 /*
1875 * Add the option choice...
1876 */
1877
1878 choice = ppd_add_choice(option, name);
1879
1880 if (text[0])
1881 cupsCharsetToUTF8((cups_utf8_t *)choice->text, text,
1882 sizeof(choice->text), encoding);
1883 else if (!strcmp(name, "True"))
1884 strcpy(choice->text, _("Yes"));
1885 else if (!strcmp(name, "False"))
1886 strcpy(choice->text, _("No"));
1887 else
1888 strlcpy(choice->text, name, sizeof(choice->text));
1889
1890 if (option->section == PPD_ORDER_JCL)
1891 ppd_decode(string); /* Decode quoted string */
1892
1893 choice->code = string;
1894 string = NULL; /* Don't add as an attribute below */
1895 }
1896
1897 /*
1898 * Add remaining lines with keywords and string values as attributes...
1899 */
1900
1901 if (string &&
1902 (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
1903 ppd_add_attr(ppd, keyword, name, text, string);
1904 else
1905 _cupsStrFree(string);
1906 }
1907
1908 if (line.buffer)
1909 free(line.buffer);
1910
1911 /*
1912 * Reset language preferences...
1913 */
1914
1915 cupsLangFree(language);
1916
1917 #ifdef DEBUG
1918 if (!cupsFileEOF(fp))
1919 printf("Premature EOF at %lu...\n", (unsigned long)cupsFileTell(fp));
1920 #endif /* DEBUG */
1921
1922 if (cg->ppd_status != PPD_OK)
1923 {
1924 /*
1925 * Had an error reading the PPD file, cannot continue!
1926 */
1927
1928 ppdClose(ppd);
1929
1930 return (NULL);
1931 }
1932
1933 /*
1934 * Create the sorted options array and set the option back-pointer for
1935 * each choice and custom option...
1936 */
1937
1938 ppd->options = cupsArrayNew2((cups_array_func_t)ppd_compare_options, NULL,
1939 (cups_ahash_func_t)ppd_hash_option,
1940 PPD_HASHSIZE);
1941
1942 for (i = ppd->num_groups, group = ppd->groups;
1943 i > 0;
1944 i --, group ++)
1945 {
1946 for (j = group->num_options, option = group->options;
1947 j > 0;
1948 j --, option ++)
1949 {
1950 ppd_coption_t *coption; /* Custom option */
1951
1952
1953 cupsArrayAdd(ppd->options, option);
1954
1955 for (k = 0; k < option->num_choices; k ++)
1956 option->choices[k].option = option;
1957
1958 if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
1959 coption->option = option;
1960 }
1961 }
1962
1963 /*
1964 * Sort the constraints...
1965 */
1966
1967 if (ppd->num_consts > 1)
1968 qsort(ppd->consts, ppd->num_consts, sizeof(ppd_const_t),
1969 (int (*)(const void *, const void *))ppd_compare_consts);
1970
1971 /*
1972 * Create an array to track the marked choices...
1973 */
1974
1975 ppd->marked = cupsArrayNew((cups_array_func_t)ppd_compare_choices, NULL);
1976
1977 /*
1978 * Return the PPD file structure...
1979 */
1980
1981 return (ppd);
1982
1983 /*
1984 * Common exit point for errors to save code size...
1985 */
1986
1987 error:
1988
1989 if (line.buffer)
1990 free(line.buffer);
1991
1992 _cupsStrFree(string);
1993
1994 ppdClose(ppd);
1995
1996 cupsLangFree(language);
1997
1998 return (NULL);
1999 }
2000
2001
2002 /*
2003 * 'ppdOpenFd()' - Read a PPD file into memory.
2004 */
2005
2006 ppd_file_t * /* O - PPD file record */
2007 ppdOpenFd(int fd) /* I - File to read from */
2008 {
2009 cups_file_t *fp; /* CUPS file pointer */
2010 ppd_file_t *ppd; /* PPD file record */
2011 _cups_globals_t *cg = _cupsGlobals();
2012 /* Global data */
2013
2014
2015 /*
2016 * Set the line number to 0...
2017 */
2018
2019 cg->ppd_line = 0;
2020
2021 /*
2022 * Range check input...
2023 */
2024
2025 if (fd < 0)
2026 {
2027 cg->ppd_status = PPD_NULL_FILE;
2028
2029 return (NULL);
2030 }
2031
2032 /*
2033 * Try to open the file and parse it...
2034 */
2035
2036 if ((fp = cupsFileOpenFd(fd, "r")) != NULL)
2037 {
2038 ppd = ppdOpen2(fp);
2039
2040 cupsFileClose(fp);
2041 }
2042 else
2043 {
2044 cg->ppd_status = PPD_FILE_OPEN_ERROR;
2045 ppd = NULL;
2046 }
2047
2048 return (ppd);
2049 }
2050
2051
2052 /*
2053 * 'ppdOpenFile()' - Read a PPD file into memory.
2054 */
2055
2056 ppd_file_t * /* O - PPD file record */
2057 ppdOpenFile(const char *filename) /* I - File to read from */
2058 {
2059 cups_file_t *fp; /* File pointer */
2060 ppd_file_t *ppd; /* PPD file record */
2061 _cups_globals_t *cg = _cupsGlobals();
2062 /* Global data */
2063
2064
2065 /*
2066 * Set the line number to 0...
2067 */
2068
2069 cg->ppd_line = 0;
2070
2071 /*
2072 * Range check input...
2073 */
2074
2075 if (filename == NULL)
2076 {
2077 cg->ppd_status = PPD_NULL_FILE;
2078
2079 return (NULL);
2080 }
2081
2082 /*
2083 * Try to open the file and parse it...
2084 */
2085
2086 if ((fp = cupsFileOpen(filename, "r")) != NULL)
2087 {
2088 ppd = ppdOpen2(fp);
2089
2090 cupsFileClose(fp);
2091 }
2092 else
2093 {
2094 cg->ppd_status = PPD_FILE_OPEN_ERROR;
2095 ppd = NULL;
2096 }
2097
2098 return (ppd);
2099 }
2100
2101
2102 /*
2103 * 'ppdSetConformance()' - Set the conformance level for PPD files.
2104 *
2105 * @since CUPS 1.1.20@
2106 */
2107
2108 void
2109 ppdSetConformance(ppd_conform_t c) /* I - Conformance level */
2110 {
2111 _cups_globals_t *cg = _cupsGlobals();
2112 /* Global data */
2113
2114
2115 cg->ppd_conform = c;
2116 }
2117
2118
2119 /*
2120 * 'ppd_add_attr()' - Add an attribute to the PPD data.
2121 */
2122
2123 static ppd_attr_t * /* O - New attribute */
2124 ppd_add_attr(ppd_file_t *ppd, /* I - PPD file data */
2125 const char *name, /* I - Attribute name */
2126 const char *spec, /* I - Specifier string, if any */
2127 const char *text, /* I - Text string, if any */
2128 const char *value) /* I - Value of attribute */
2129 {
2130 ppd_attr_t **ptr, /* New array */
2131 *temp; /* New attribute */
2132
2133
2134 /*
2135 * Range check input...
2136 */
2137
2138 if (ppd == NULL || name == NULL || spec == NULL)
2139 return (NULL);
2140
2141 /*
2142 * Create the array as needed...
2143 */
2144
2145 if (!ppd->sorted_attrs)
2146 ppd->sorted_attrs = cupsArrayNew((cups_array_func_t)ppd_compare_attrs,
2147 NULL);
2148
2149 /*
2150 * Allocate memory for the new attribute...
2151 */
2152
2153 if (ppd->num_attrs == 0)
2154 ptr = malloc(sizeof(ppd_attr_t *));
2155 else
2156 ptr = realloc(ppd->attrs, (ppd->num_attrs + 1) * sizeof(ppd_attr_t *));
2157
2158 if (ptr == NULL)
2159 return (NULL);
2160
2161 ppd->attrs = ptr;
2162 ptr += ppd->num_attrs;
2163
2164 if ((temp = calloc(1, sizeof(ppd_attr_t))) == NULL)
2165 return (NULL);
2166
2167 *ptr = temp;
2168
2169 ppd->num_attrs ++;
2170
2171 /*
2172 * Copy data over...
2173 */
2174
2175 strlcpy(temp->name, name, sizeof(temp->name));
2176 strlcpy(temp->spec, spec, sizeof(temp->spec));
2177 strlcpy(temp->text, text, sizeof(temp->text));
2178 temp->value = (char *)value;
2179
2180 /*
2181 * Add the attribute to the sorted array...
2182 */
2183
2184 cupsArrayAdd(ppd->sorted_attrs, temp);
2185
2186 /*
2187 * Return the attribute...
2188 */
2189
2190 return (temp);
2191 }
2192
2193
2194 /*
2195 * 'ppd_add_choice()' - Add a choice to an option.
2196 */
2197
2198 static ppd_choice_t * /* O - Named choice */
2199 ppd_add_choice(ppd_option_t *option, /* I - Option */
2200 const char *name) /* I - Name of choice */
2201 {
2202 ppd_choice_t *choice; /* Choice */
2203
2204
2205 if (option->num_choices == 0)
2206 choice = malloc(sizeof(ppd_choice_t));
2207 else
2208 choice = realloc(option->choices,
2209 sizeof(ppd_choice_t) * (option->num_choices + 1));
2210
2211 if (choice == NULL)
2212 return (NULL);
2213
2214 option->choices = choice;
2215 choice += option->num_choices;
2216 option->num_choices ++;
2217
2218 memset(choice, 0, sizeof(ppd_choice_t));
2219 strlcpy(choice->choice, name, sizeof(choice->choice));
2220
2221 return (choice);
2222 }
2223
2224
2225 /*
2226 * 'ppd_add_size()' - Add a page size.
2227 */
2228
2229 static ppd_size_t * /* O - Named size */
2230 ppd_add_size(ppd_file_t *ppd, /* I - PPD file */
2231 const char *name) /* I - Name of size */
2232 {
2233 ppd_size_t *size; /* Size */
2234
2235
2236 if (ppd->num_sizes == 0)
2237 size = malloc(sizeof(ppd_size_t));
2238 else
2239 size = realloc(ppd->sizes, sizeof(ppd_size_t) * (ppd->num_sizes + 1));
2240
2241 if (size == NULL)
2242 return (NULL);
2243
2244 ppd->sizes = size;
2245 size += ppd->num_sizes;
2246 ppd->num_sizes ++;
2247
2248 memset(size, 0, sizeof(ppd_size_t));
2249 strlcpy(size->name, name, sizeof(size->name));
2250
2251 return (size);
2252 }
2253
2254
2255 /*
2256 * 'ppd_compare_attrs()' - Compare two attributes.
2257 */
2258
2259 static int /* O - Result of comparison */
2260 ppd_compare_attrs(ppd_attr_t *a, /* I - First attribute */
2261 ppd_attr_t *b) /* I - Second attribute */
2262 {
2263 int ret; /* Result of comparison */
2264
2265
2266 if ((ret = strcasecmp(a->name, b->name)) != 0)
2267 return (ret);
2268 else
2269 return (strcasecmp(a->spec, b->spec));
2270 }
2271
2272
2273 /*
2274 * 'ppd_compare_choices()' - Compare two choices...
2275 */
2276
2277 static int /* O - Result of comparison */
2278 ppd_compare_choices(ppd_choice_t *a, /* I - First choice */
2279 ppd_choice_t *b) /* I - Second choice */
2280 {
2281 return (strcmp(a->option->keyword, b->option->keyword));
2282 }
2283
2284
2285 /*
2286 * 'ppd_compare_consts()' - Compare two constraints.
2287 */
2288
2289 static int /* O - Result of comparison */
2290 ppd_compare_consts(ppd_const_t *a, /* I - First constraint */
2291 ppd_const_t *b) /* I - Second constraint */
2292 {
2293 int ret; /* Result of comparison */
2294
2295
2296 if ((ret = strcmp(a->option1, b->option1)) != 0)
2297 return (ret);
2298 else if ((ret = strcmp(a->choice1, b->choice1)) != 0)
2299 return (ret);
2300 else if ((ret = strcmp(a->option2, b->option2)) != 0)
2301 return (ret);
2302 else
2303 return (strcmp(a->choice2, b->choice2));
2304 }
2305
2306
2307 /*
2308 * 'ppd_compare_coptions()' - Compare two custom options.
2309 */
2310
2311 static int /* O - Result of comparison */
2312 ppd_compare_coptions(ppd_coption_t *a, /* I - First option */
2313 ppd_coption_t *b) /* I - Second option */
2314 {
2315 return (strcasecmp(a->keyword, b->keyword));
2316 }
2317
2318
2319 /*
2320 * 'ppd_compare_cparams()' - Compare two custom parameters.
2321 */
2322
2323 static int /* O - Result of comparison */
2324 ppd_compare_cparams(ppd_cparam_t *a, /* I - First parameter */
2325 ppd_cparam_t *b) /* I - Second parameter */
2326 {
2327 return (strcasecmp(a->name, b->name));
2328 }
2329
2330
2331 /*
2332 * 'ppd_compare_options()' - Compare two options.
2333 */
2334
2335 static int /* O - Result of comparison */
2336 ppd_compare_options(ppd_option_t *a, /* I - First option */
2337 ppd_option_t *b) /* I - Second option */
2338 {
2339 return (strcasecmp(a->keyword, b->keyword));
2340 }
2341
2342
2343 /*
2344 * 'ppd_decode()' - Decode a string value...
2345 */
2346
2347 static int /* O - Length of decoded string */
2348 ppd_decode(char *string) /* I - String to decode */
2349 {
2350 char *inptr, /* Input pointer */
2351 *outptr; /* Output pointer */
2352
2353
2354 inptr = string;
2355 outptr = string;
2356
2357 while (*inptr != '\0')
2358 if (*inptr == '<' && isxdigit(inptr[1] & 255))
2359 {
2360 /*
2361 * Convert hex to 8-bit values...
2362 */
2363
2364 inptr ++;
2365 while (isxdigit(*inptr & 255))
2366 {
2367 if (isalpha(*inptr))
2368 *outptr = (tolower(*inptr) - 'a' + 10) << 4;
2369 else
2370 *outptr = (*inptr - '0') << 4;
2371
2372 inptr ++;
2373
2374 if (!isxdigit(*inptr & 255))
2375 break;
2376
2377 if (isalpha(*inptr))
2378 *outptr |= tolower(*inptr) - 'a' + 10;
2379 else
2380 *outptr |= *inptr - '0';
2381
2382 inptr ++;
2383 outptr ++;
2384 }
2385
2386 while (*inptr != '>' && *inptr != '\0')
2387 inptr ++;
2388 while (*inptr == '>')
2389 inptr ++;
2390 }
2391 else
2392 *outptr++ = *inptr++;
2393
2394 *outptr = '\0';
2395
2396 return ((int)(outptr - string));
2397 }
2398
2399
2400 /*
2401 * 'ppd_free_group()' - Free a single UI group.
2402 */
2403
2404 static void
2405 ppd_free_group(ppd_group_t *group) /* I - Group to free */
2406 {
2407 int i; /* Looping var */
2408 ppd_option_t *option; /* Current option */
2409 ppd_group_t *subgroup; /* Current sub-group */
2410
2411
2412 if (group->num_options > 0)
2413 {
2414 for (i = group->num_options, option = group->options;
2415 i > 0;
2416 i --, option ++)
2417 ppd_free_option(option);
2418
2419 ppd_free(group->options);
2420 }
2421
2422 if (group->num_subgroups > 0)
2423 {
2424 for (i = group->num_subgroups, subgroup = group->subgroups;
2425 i > 0;
2426 i --, subgroup ++)
2427 ppd_free_group(subgroup);
2428
2429 ppd_free(group->subgroups);
2430 }
2431 }
2432
2433
2434 /*
2435 * 'ppd_free_option()' - Free a single option.
2436 */
2437
2438 static void
2439 ppd_free_option(ppd_option_t *option) /* I - Option to free */
2440 {
2441 int i; /* Looping var */
2442 ppd_choice_t *choice; /* Current choice */
2443
2444
2445 if (option->num_choices > 0)
2446 {
2447 for (i = option->num_choices, choice = option->choices;
2448 i > 0;
2449 i --, choice ++)
2450 {
2451 _cupsStrFree(choice->code);
2452 }
2453
2454 ppd_free(option->choices);
2455 }
2456 }
2457
2458
2459 /*
2460 * 'ppd_get_coption()' - Get a custom option record.
2461 */
2462
2463 static ppd_coption_t * /* O - Custom option... */
2464 ppd_get_coption(ppd_file_t *ppd, /* I - PPD file */
2465 const char *name) /* I - Name of option */
2466 {
2467 ppd_coption_t *copt; /* New custom option */
2468
2469
2470 /*
2471 * See if the option already exists...
2472 */
2473
2474 if ((copt = ppdFindCustomOption(ppd, name)) != NULL)
2475 return (copt);
2476
2477 /*
2478 * Not found, so create the custom option record...
2479 */
2480
2481 if ((copt = calloc(1, sizeof(ppd_coption_t))) == NULL)
2482 return (NULL);
2483
2484 strlcpy(copt->keyword, name, sizeof(copt->keyword));
2485
2486 copt->params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL);
2487
2488 cupsArrayAdd(ppd->coptions, copt);
2489
2490 /*
2491 * Return the new record...
2492 */
2493
2494 return (copt);
2495 }
2496
2497
2498 /*
2499 * 'ppd_get_cparam()' - Get a custom parameter record.
2500 */
2501
2502 static ppd_cparam_t * /* O - Extended option... */
2503 ppd_get_cparam(ppd_coption_t *opt, /* I - PPD file */
2504 const char *param, /* I - Name of parameter */
2505 const char *text) /* I - Human-readable text */
2506 {
2507 ppd_cparam_t *cparam; /* New custom parameter */
2508
2509
2510 /*
2511 * See if the parameter already exists...
2512 */
2513
2514 if ((cparam = ppdFindCustomParam(opt, param)) != NULL)
2515 return (cparam);
2516
2517 /*
2518 * Not found, so create the custom parameter record...
2519 */
2520
2521 if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL)
2522 return (NULL);
2523
2524 strlcpy(cparam->name, param, sizeof(cparam->name));
2525 strlcpy(cparam->text, text[0] ? text : param, sizeof(cparam->text));
2526
2527 /*
2528 * Add this record to the array...
2529 */
2530
2531 cupsArrayAdd(opt->params, cparam);
2532
2533 /*
2534 * Return the new record...
2535 */
2536
2537 return (cparam);
2538 }
2539
2540
2541 /*
2542 * 'ppd_get_group()' - Find or create the named group as needed.
2543 */
2544
2545 static ppd_group_t * /* O - Named group */
2546 ppd_get_group(ppd_file_t *ppd, /* I - PPD file */
2547 const char *name, /* I - Name of group */
2548 const char *text, /* I - Text for group */
2549 _cups_globals_t *cg, /* I - Global data */
2550 cups_encoding_t encoding) /* I - Encoding of text */
2551 {
2552 int i; /* Looping var */
2553 ppd_group_t *group; /* Group */
2554
2555
2556 DEBUG_printf(("ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)\n",
2557 ppd, name, text, cg));
2558
2559 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
2560 if (!strcmp(group->name, name))
2561 break;
2562
2563 if (i == 0)
2564 {
2565 DEBUG_printf(("Adding group %s...\n", name));
2566
2567 if (cg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
2568 {
2569 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2570
2571 return (NULL);
2572 }
2573
2574 if (ppd->num_groups == 0)
2575 group = malloc(sizeof(ppd_group_t));
2576 else
2577 group = realloc(ppd->groups,
2578 (ppd->num_groups + 1) * sizeof(ppd_group_t));
2579
2580 if (group == NULL)
2581 {
2582 cg->ppd_status = PPD_ALLOC_ERROR;
2583
2584 return (NULL);
2585 }
2586
2587 ppd->groups = group;
2588 group += ppd->num_groups;
2589 ppd->num_groups ++;
2590
2591 memset(group, 0, sizeof(ppd_group_t));
2592 strlcpy(group->name, name, sizeof(group->name));
2593
2594 cupsCharsetToUTF8((cups_utf8_t *)group->text, text,
2595 sizeof(group->text), encoding);
2596 }
2597
2598 return (group);
2599 }
2600
2601
2602 /*
2603 * 'ppd_get_option()' - Find or create the named option as needed.
2604 */
2605
2606 static ppd_option_t * /* O - Named option */
2607 ppd_get_option(ppd_group_t *group, /* I - Group */
2608 const char *name) /* I - Name of option */
2609 {
2610 int i; /* Looping var */
2611 ppd_option_t *option; /* Option */
2612
2613
2614 DEBUG_printf(("ppd_get_option(group=%p(\"%s\"), name=\"%s\")\n",
2615 group, group->name, name));
2616
2617 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
2618 if (!strcmp(option->keyword, name))
2619 break;
2620
2621 if (i == 0)
2622 {
2623 if (group->num_options == 0)
2624 option = malloc(sizeof(ppd_option_t));
2625 else
2626 option = realloc(group->options,
2627 (group->num_options + 1) * sizeof(ppd_option_t));
2628
2629 if (option == NULL)
2630 return (NULL);
2631
2632 group->options = option;
2633 option += group->num_options;
2634 group->num_options ++;
2635
2636 memset(option, 0, sizeof(ppd_option_t));
2637 strlcpy(option->keyword, name, sizeof(option->keyword));
2638 }
2639
2640 return (option);
2641 }
2642
2643
2644 /*
2645 * 'ppd_hash_option()' - Generate a hash of the option name...
2646 */
2647
2648 static int /* O - Hash index */
2649 ppd_hash_option(ppd_option_t *option) /* I - Option */
2650 {
2651 int hash = 0; /* Hash index */
2652 const char *k; /* Pointer into keyword */
2653
2654
2655 for (hash = option->keyword[0], k = option->keyword + 1; *k;)
2656 hash = 33 * hash + *k++;
2657
2658 return (hash & 511);
2659 }
2660
2661
2662 /*
2663 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2664 * necessary.
2665 */
2666
2667 static int /* O - Bitmask of fields read */
2668 ppd_read(cups_file_t *fp, /* I - File to read from */
2669 _ppd_line_t *line, /* I - Line buffer */
2670 char *keyword, /* O - Keyword from line */
2671 char *option, /* O - Option from line */
2672 char *text, /* O - Human-readable text from line */
2673 char **string, /* O - Code/string data */
2674 int ignoreblank, /* I - Ignore blank lines? */
2675 _cups_globals_t *cg) /* I - Global data */
2676 {
2677 int ch, /* Character from file */
2678 col, /* Column in line */
2679 colon, /* Colon seen? */
2680 endquote, /* Waiting for an end quote */
2681 mask, /* Mask to be returned */
2682 startline, /* Start line */
2683 textlen; /* Length of text */
2684 char *keyptr, /* Keyword pointer */
2685 *optptr, /* Option pointer */
2686 *textptr, /* Text pointer */
2687 *strptr, /* Pointer into string */
2688 *lineptr; /* Current position in line buffer */
2689
2690
2691 /*
2692 * Now loop until we have a valid line...
2693 */
2694
2695 *string = NULL;
2696 col = 0;
2697 startline = cg->ppd_line + 1;
2698
2699 if (!line->buffer)
2700 {
2701 line->bufsize = 1024;
2702 line->buffer = malloc(1024);
2703
2704 if (!line->buffer)
2705 return (0);
2706 }
2707
2708 do
2709 {
2710 /*
2711 * Read the line...
2712 */
2713
2714 lineptr = line->buffer;
2715 endquote = 0;
2716 colon = 0;
2717
2718 while ((ch = cupsFileGetChar(fp)) != EOF)
2719 {
2720 if (lineptr >= (line->buffer + line->bufsize - 1))
2721 {
2722 /*
2723 * Expand the line buffer...
2724 */
2725
2726 char *temp; /* Temporary line pointer */
2727
2728
2729 line->bufsize += 1024;
2730 if (line->bufsize > 262144)
2731 {
2732 /*
2733 * Don't allow lines longer than 256k!
2734 */
2735
2736 cg->ppd_line = startline;
2737 cg->ppd_status = PPD_LINE_TOO_LONG;
2738
2739 return (0);
2740 }
2741
2742 temp = realloc(line->buffer, line->bufsize);
2743 if (!temp)
2744 {
2745 cg->ppd_line = startline;
2746 cg->ppd_status = PPD_LINE_TOO_LONG;
2747
2748 return (0);
2749 }
2750
2751 lineptr = temp + (lineptr - line->buffer);
2752 line->buffer = temp;
2753 }
2754
2755 if (ch == '\r' || ch == '\n')
2756 {
2757 /*
2758 * Line feed or carriage return...
2759 */
2760
2761 cg->ppd_line ++;
2762 col = 0;
2763
2764 if (ch == '\r')
2765 {
2766 /*
2767 * Check for a trailing line feed...
2768 */
2769
2770 if ((ch = cupsFilePeekChar(fp)) == EOF)
2771 {
2772 ch = '\n';
2773 break;
2774 }
2775
2776 if (ch == 0x0a)
2777 cupsFileGetChar(fp);
2778 }
2779
2780 if (lineptr == line->buffer && ignoreblank)
2781 continue; /* Skip blank lines */
2782
2783 ch = '\n';
2784
2785 if (!endquote) /* Continue for multi-line text */
2786 break;
2787
2788 *lineptr++ = '\n';
2789 }
2790 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2791 {
2792 /*
2793 * Other control characters...
2794 */
2795
2796 cg->ppd_line = startline;
2797 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2798
2799 return (0);
2800 }
2801 else if (ch != 0x1a)
2802 {
2803 /*
2804 * Any other character...
2805 */
2806
2807 *lineptr++ = ch;
2808 col ++;
2809
2810 if (col > (PPD_MAX_LINE - 1))
2811 {
2812 /*
2813 * Line is too long...
2814 */
2815
2816 cg->ppd_line = startline;
2817 cg->ppd_status = PPD_LINE_TOO_LONG;
2818
2819 return (0);
2820 }
2821
2822 if (ch == ':' && strncmp(line->buffer, "*%", 2) != 0)
2823 colon = 1;
2824
2825 if (ch == '\"' && colon)
2826 endquote = !endquote;
2827 }
2828 }
2829
2830 if (endquote)
2831 {
2832 /*
2833 * Didn't finish this quoted string...
2834 */
2835
2836 while ((ch = cupsFileGetChar(fp)) != EOF)
2837 if (ch == '\"')
2838 break;
2839 else if (ch == '\r' || ch == '\n')
2840 {
2841 cg->ppd_line ++;
2842 col = 0;
2843
2844 if (ch == '\r')
2845 {
2846 /*
2847 * Check for a trailing line feed...
2848 */
2849
2850 if ((ch = cupsFilePeekChar(fp)) == EOF)
2851 break;
2852 if (ch == 0x0a)
2853 cupsFileGetChar(fp);
2854 }
2855
2856 ch = '\n';
2857 }
2858 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2859 {
2860 /*
2861 * Other control characters...
2862 */
2863
2864 cg->ppd_line = startline;
2865 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2866
2867 return (0);
2868 }
2869 else if (ch != 0x1a)
2870 {
2871 col ++;
2872
2873 if (col > (PPD_MAX_LINE - 1))
2874 {
2875 /*
2876 * Line is too long...
2877 */
2878
2879 cg->ppd_line = startline;
2880 cg->ppd_status = PPD_LINE_TOO_LONG;
2881
2882 return (0);
2883 }
2884 }
2885 }
2886
2887 if (ch != '\n')
2888 {
2889 /*
2890 * Didn't finish this line...
2891 */
2892
2893 while ((ch = cupsFileGetChar(fp)) != EOF)
2894 if (ch == '\r' || ch == '\n')
2895 {
2896 /*
2897 * Line feed or carriage return...
2898 */
2899
2900 cg->ppd_line ++;
2901 col = 0;
2902
2903 if (ch == '\r')
2904 {
2905 /*
2906 * Check for a trailing line feed...
2907 */
2908
2909 if ((ch = cupsFilePeekChar(fp)) == EOF)
2910 break;
2911 if (ch == 0x0a)
2912 cupsFileGetChar(fp);
2913 }
2914
2915 break;
2916 }
2917 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2918 {
2919 /*
2920 * Other control characters...
2921 */
2922
2923 cg->ppd_line = startline;
2924 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2925
2926 return (0);
2927 }
2928 else if (ch != 0x1a)
2929 {
2930 col ++;
2931
2932 if (col > (PPD_MAX_LINE - 1))
2933 {
2934 /*
2935 * Line is too long...
2936 */
2937
2938 cg->ppd_line = startline;
2939 cg->ppd_status = PPD_LINE_TOO_LONG;
2940
2941 return (0);
2942 }
2943 }
2944 }
2945
2946 if (lineptr > line->buffer && lineptr[-1] == '\n')
2947 lineptr --;
2948
2949 *lineptr = '\0';
2950
2951 DEBUG_printf(("LINE = \"%s\"\n", line));
2952
2953 /*
2954 * The dynamically created PPDs for older style Mac OS X
2955 * drivers include a large blob of data inserted as comments
2956 * at the end of the file. As an optimization we can stop
2957 * reading the PPD when we get to the start of this data.
2958 */
2959
2960 if (!strcmp(line->buffer, "*%APLWORKSET START"))
2961 return (0);
2962
2963 if (ch == EOF && lineptr == line->buffer)
2964 return (0);
2965
2966 /*
2967 * Now parse it...
2968 */
2969
2970 mask = 0;
2971 lineptr = line->buffer + 1;
2972
2973 keyword[0] = '\0';
2974 option[0] = '\0';
2975 text[0] = '\0';
2976 *string = NULL;
2977
2978 if ((!line->buffer[0] || /* Blank line */
2979 !strncmp(line->buffer, "*%", 2) || /* Comment line */
2980 !strcmp(line->buffer, "*End")) && /* End of multi-line string */
2981 ignoreblank) /* Ignore these? */
2982 {
2983 startline = cg->ppd_line + 1;
2984 continue;
2985 }
2986
2987 if (!strcmp(line->buffer, "*")) /* (Bad) comment line */
2988 {
2989 if (cg->ppd_conform == PPD_CONFORM_RELAXED)
2990 {
2991 startline = cg->ppd_line + 1;
2992 continue;
2993 }
2994 else
2995 {
2996 cg->ppd_line = startline;
2997 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
2998
2999 return (0);
3000 }
3001 }
3002
3003 if (line->buffer[0] != '*') /* All lines start with an asterisk */
3004 {
3005 /*
3006 * Allow lines consisting of just whitespace...
3007 */
3008
3009 for (lineptr = line->buffer; *lineptr; lineptr ++)
3010 if (!isspace(*lineptr & 255))
3011 break;
3012
3013 if (*lineptr)
3014 {
3015 cg->ppd_status = PPD_MISSING_ASTERISK;
3016 return (0);
3017 }
3018 else if (ignoreblank)
3019 continue;
3020 else
3021 return (0);
3022 }
3023
3024 /*
3025 * Get a keyword...
3026 */
3027
3028 keyptr = keyword;
3029
3030 while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr & 255))
3031 {
3032 if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
3033 (keyptr - keyword) >= (PPD_MAX_NAME - 1))
3034 {
3035 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
3036 return (0);
3037 }
3038
3039 *keyptr++ = *lineptr++;
3040 }
3041
3042 *keyptr = '\0';
3043
3044 if (!strcmp(keyword, "End"))
3045 continue;
3046
3047 mask |= PPD_KEYWORD;
3048
3049 /* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
3050
3051 if (isspace(*lineptr & 255))
3052 {
3053 /*
3054 * Get an option name...
3055 */
3056
3057 while (isspace(*lineptr & 255))
3058 lineptr ++;
3059
3060 optptr = option;
3061
3062 while (*lineptr != '\0' && !isspace(*lineptr & 255) && *lineptr != ':' &&
3063 *lineptr != '/')
3064 {
3065 if (*lineptr <= ' ' || *lineptr > 126 ||
3066 (optptr - option) >= (PPD_MAX_NAME - 1))
3067 {
3068 cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
3069 return (0);
3070 }
3071
3072 *optptr++ = *lineptr++;
3073 }
3074
3075 *optptr = '\0';
3076
3077 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
3078 {
3079 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
3080 return (0);
3081 }
3082
3083 while (isspace(*lineptr & 255))
3084 lineptr ++;
3085
3086 mask |= PPD_OPTION;
3087
3088 /* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
3089
3090 if (*lineptr == '/')
3091 {
3092 /*
3093 * Get human-readable text...
3094 */
3095
3096 lineptr ++;
3097
3098 textptr = text;
3099
3100 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
3101 {
3102 if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
3103 (textptr - text) >= (PPD_MAX_LINE - 1))
3104 {
3105 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
3106 return (0);
3107 }
3108
3109 *textptr++ = *lineptr++;
3110 }
3111
3112 *textptr = '\0';
3113 textlen = ppd_decode(text);
3114
3115 if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT)
3116 {
3117 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
3118 return (0);
3119 }
3120
3121 mask |= PPD_TEXT;
3122 }
3123
3124 /* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
3125 }
3126
3127 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
3128 {
3129 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
3130 return (0);
3131 }
3132
3133 while (isspace(*lineptr & 255))
3134 lineptr ++;
3135
3136 if (*lineptr == ':')
3137 {
3138 /*
3139 * Get string after triming leading and trailing whitespace...
3140 */
3141
3142 lineptr ++;
3143 while (isspace(*lineptr & 255))
3144 lineptr ++;
3145
3146 strptr = lineptr + strlen(lineptr) - 1;
3147 while (strptr >= lineptr && isspace(*strptr & 255))
3148 *strptr-- = '\0';
3149
3150 if (*strptr == '\"')
3151 {
3152 /*
3153 * Quoted string by itself, remove quotes...
3154 */
3155
3156 *strptr = '\0';
3157 lineptr ++;
3158 }
3159
3160 *string = _cupsStrAlloc(lineptr);
3161
3162 /* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
3163
3164 mask |= PPD_STRING;
3165 }
3166 }
3167 while (mask == 0);
3168
3169 return (mask);
3170 }
3171
3172
3173 /*
3174 * End of "$Id: ppd.c 6937 2007-09-10 21:13:31Z mike $".
3175 */