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