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