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