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