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