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