]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/ppd.c
Merge changes from CUPS 1.4svn-r7961.
[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{
2234 int ret; /* Result of comparison */
2235
2236
2237 if ((ret = strcasecmp(a->name, b->name)) != 0)
2238 return (ret);
bd7854cb 2239 else
d09495fa 2240 return (strcasecmp(a->spec, b->spec));
bd7854cb 2241}
2242
2243
b94498cf 2244/*
2245 * 'ppd_compare_choices()' - Compare two choices...
2246 */
2247
2248static int /* O - Result of comparison */
2249ppd_compare_choices(ppd_choice_t *a, /* I - First choice */
2250 ppd_choice_t *b) /* I - Second choice */
2251{
355e94dc 2252 return (strcmp(a->option->keyword, b->option->keyword));
b94498cf 2253}
2254
2255
ef416fc2 2256/*
fa73b229 2257 * 'ppd_compare_coptions()' - Compare two custom options.
ef416fc2 2258 */
2259
2260static int /* O - Result of comparison */
fa73b229 2261ppd_compare_coptions(ppd_coption_t *a, /* I - First option */
2262 ppd_coption_t *b) /* I - Second option */
ef416fc2 2263{
fa73b229 2264 return (strcasecmp(a->keyword, b->keyword));
2265}
2266
2267
2268/*
2269 * 'ppd_compare_cparams()' - Compare two custom parameters.
2270 */
2271
2272static int /* O - Result of comparison */
2273ppd_compare_cparams(ppd_cparam_t *a, /* I - First parameter */
2274 ppd_cparam_t *b) /* I - Second parameter */
2275{
2276 return (strcasecmp(a->name, b->name));
ef416fc2 2277}
2278
2279
2280/*
2281 * 'ppd_compare_options()' - Compare two options.
2282 */
2283
2284static int /* O - Result of comparison */
fa73b229 2285ppd_compare_options(ppd_option_t *a, /* I - First option */
2286 ppd_option_t *b) /* I - Second option */
ef416fc2 2287{
fa73b229 2288 return (strcasecmp(a->keyword, b->keyword));
ef416fc2 2289}
ef416fc2 2290
2291
2292/*
2293 * 'ppd_decode()' - Decode a string value...
2294 */
2295
2296static int /* O - Length of decoded string */
2297ppd_decode(char *string) /* I - String to decode */
2298{
2299 char *inptr, /* Input pointer */
2300 *outptr; /* Output pointer */
2301
2302
2303 inptr = string;
2304 outptr = string;
2305
2306 while (*inptr != '\0')
2307 if (*inptr == '<' && isxdigit(inptr[1] & 255))
2308 {
2309 /*
2310 * Convert hex to 8-bit values...
2311 */
2312
2313 inptr ++;
2314 while (isxdigit(*inptr & 255))
2315 {
2316 if (isalpha(*inptr))
2317 *outptr = (tolower(*inptr) - 'a' + 10) << 4;
2318 else
2319 *outptr = (*inptr - '0') << 4;
2320
2321 inptr ++;
2322
2323 if (!isxdigit(*inptr & 255))
2324 break;
2325
2326 if (isalpha(*inptr))
2327 *outptr |= tolower(*inptr) - 'a' + 10;
2328 else
2329 *outptr |= *inptr - '0';
2330
2331 inptr ++;
2332 outptr ++;
2333 }
2334
2335 while (*inptr != '>' && *inptr != '\0')
2336 inptr ++;
2337 while (*inptr == '>')
2338 inptr ++;
2339 }
2340 else
2341 *outptr++ = *inptr++;
2342
2343 *outptr = '\0';
2344
2345 return ((int)(outptr - string));
2346}
2347
2348
2349/*
2350 * 'ppd_free_group()' - Free a single UI group.
2351 */
2352
2353static void
2354ppd_free_group(ppd_group_t *group) /* I - Group to free */
2355{
2356 int i; /* Looping var */
2357 ppd_option_t *option; /* Current option */
2358 ppd_group_t *subgroup; /* Current sub-group */
2359
2360
2361 if (group->num_options > 0)
2362 {
2363 for (i = group->num_options, option = group->options;
2364 i > 0;
2365 i --, option ++)
2366 ppd_free_option(option);
2367
2368 ppd_free(group->options);
2369 }
2370
2371 if (group->num_subgroups > 0)
2372 {
2373 for (i = group->num_subgroups, subgroup = group->subgroups;
2374 i > 0;
2375 i --, subgroup ++)
2376 ppd_free_group(subgroup);
2377
2378 ppd_free(group->subgroups);
2379 }
2380}
2381
2382
2383/*
2384 * 'ppd_free_option()' - Free a single option.
2385 */
2386
2387static void
2388ppd_free_option(ppd_option_t *option) /* I - Option to free */
2389{
2390 int i; /* Looping var */
2391 ppd_choice_t *choice; /* Current choice */
2392
2393
2394 if (option->num_choices > 0)
2395 {
2396 for (i = option->num_choices, choice = option->choices;
2397 i > 0;
2398 i --, choice ++)
2399 {
2e4ff8af 2400 _cupsStrFree(choice->code);
ef416fc2 2401 }
2402
2403 ppd_free(option->choices);
2404 }
2405}
2406
2407
ef416fc2 2408/*
fa73b229 2409 * 'ppd_get_coption()' - Get a custom option record.
ef416fc2 2410 */
2411
fa73b229 2412static ppd_coption_t * /* O - Custom option... */
2413ppd_get_coption(ppd_file_t *ppd, /* I - PPD file */
2414 const char *name) /* I - Name of option */
ef416fc2 2415{
fa73b229 2416 ppd_coption_t *copt; /* New custom option */
ef416fc2 2417
2418
2419 /*
2420 * See if the option already exists...
2421 */
2422
fa73b229 2423 if ((copt = ppdFindCustomOption(ppd, name)) != NULL)
2424 return (copt);
ef416fc2 2425
2426 /*
fa73b229 2427 * Not found, so create the custom option record...
ef416fc2 2428 */
2429
fa73b229 2430 if ((copt = calloc(1, sizeof(ppd_coption_t))) == NULL)
ef416fc2 2431 return (NULL);
2432
fa73b229 2433 strlcpy(copt->keyword, name, sizeof(copt->keyword));
ef416fc2 2434
fa73b229 2435 copt->params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL);
ef416fc2 2436
fa73b229 2437 cupsArrayAdd(ppd->coptions, copt);
ef416fc2 2438
2439 /*
2440 * Return the new record...
2441 */
2442
fa73b229 2443 return (copt);
ef416fc2 2444}
2445
2446
2447/*
fa73b229 2448 * 'ppd_get_cparam()' - Get a custom parameter record.
ef416fc2 2449 */
2450
fa73b229 2451static ppd_cparam_t * /* O - Extended option... */
2452ppd_get_cparam(ppd_coption_t *opt, /* I - PPD file */
2453 const char *param, /* I - Name of parameter */
2454 const char *text) /* I - Human-readable text */
ef416fc2 2455{
fa73b229 2456 ppd_cparam_t *cparam; /* New custom parameter */
ef416fc2 2457
2458
2459 /*
2460 * See if the parameter already exists...
2461 */
2462
fa73b229 2463 if ((cparam = ppdFindCustomParam(opt, param)) != NULL)
2464 return (cparam);
ef416fc2 2465
2466 /*
fa73b229 2467 * Not found, so create the custom parameter record...
ef416fc2 2468 */
2469
fa73b229 2470 if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL)
ef416fc2 2471 return (NULL);
2472
fa73b229 2473 strlcpy(cparam->name, param, sizeof(cparam->name));
b86bc4cf 2474 strlcpy(cparam->text, text[0] ? text : param, sizeof(cparam->text));
ef416fc2 2475
2476 /*
fa73b229 2477 * Add this record to the array...
ef416fc2 2478 */
2479
fa73b229 2480 cupsArrayAdd(opt->params, cparam);
ef416fc2 2481
2482 /*
2483 * Return the new record...
2484 */
2485
fa73b229 2486 return (cparam);
ef416fc2 2487}
ef416fc2 2488
2489
2490/*
2491 * 'ppd_get_group()' - Find or create the named group as needed.
2492 */
2493
2494static ppd_group_t * /* O - Named group */
e1d6a774 2495ppd_get_group(ppd_file_t *ppd, /* I - PPD file */
2496 const char *name, /* I - Name of group */
2497 const char *text, /* I - Text for group */
2498 _cups_globals_t *cg, /* I - Global data */
2499 cups_encoding_t encoding) /* I - Encoding of text */
ef416fc2 2500{
2501 int i; /* Looping var */
2502 ppd_group_t *group; /* Group */
2503
2504
2505 DEBUG_printf(("ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)\n",
2506 ppd, name, text, cg));
2507
2508 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
2509 if (!strcmp(group->name, name))
2510 break;
2511
2512 if (i == 0)
2513 {
2514 DEBUG_printf(("Adding group %s...\n", name));
2515
2516 if (cg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
2517 {
2518 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2519
2520 return (NULL);
2521 }
2522
2523 if (ppd->num_groups == 0)
2524 group = malloc(sizeof(ppd_group_t));
2525 else
2526 group = realloc(ppd->groups,
2527 (ppd->num_groups + 1) * sizeof(ppd_group_t));
2528
2529 if (group == NULL)
2530 {
2531 cg->ppd_status = PPD_ALLOC_ERROR;
2532
2533 return (NULL);
2534 }
2535
2536 ppd->groups = group;
2537 group += ppd->num_groups;
2538 ppd->num_groups ++;
2539
2540 memset(group, 0, sizeof(ppd_group_t));
2541 strlcpy(group->name, name, sizeof(group->name));
e1d6a774 2542
2543 cupsCharsetToUTF8((cups_utf8_t *)group->text, text,
2544 sizeof(group->text), encoding);
ef416fc2 2545 }
2546
2547 return (group);
2548}
2549
2550
2551/*
2552 * 'ppd_get_option()' - Find or create the named option as needed.
2553 */
2554
2555static ppd_option_t * /* O - Named option */
2556ppd_get_option(ppd_group_t *group, /* I - Group */
2557 const char *name) /* I - Name of option */
2558{
2559 int i; /* Looping var */
2560 ppd_option_t *option; /* Option */
2561
2562
2563 DEBUG_printf(("ppd_get_option(group=%p(\"%s\"), name=\"%s\")\n",
2564 group, group->name, name));
2565
2566 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
2567 if (!strcmp(option->keyword, name))
2568 break;
2569
2570 if (i == 0)
2571 {
2572 if (group->num_options == 0)
2573 option = malloc(sizeof(ppd_option_t));
2574 else
2575 option = realloc(group->options,
2576 (group->num_options + 1) * sizeof(ppd_option_t));
2577
2578 if (option == NULL)
2579 return (NULL);
2580
2581 group->options = option;
2582 option += group->num_options;
2583 group->num_options ++;
2584
2585 memset(option, 0, sizeof(ppd_option_t));
2586 strlcpy(option->keyword, name, sizeof(option->keyword));
2587 }
2588
2589 return (option);
2590}
2591
2592
b94498cf 2593/*
2594 * 'ppd_hash_option()' - Generate a hash of the option name...
2595 */
2596
2597static int /* O - Hash index */
2598ppd_hash_option(ppd_option_t *option) /* I - Option */
2599{
2600 int hash = 0; /* Hash index */
2601 const char *k; /* Pointer into keyword */
2602
2603
2604 for (hash = option->keyword[0], k = option->keyword + 1; *k;)
2605 hash = 33 * hash + *k++;
2606
2607 return (hash & 511);
2608}
2609
2610
ef416fc2 2611/*
2612 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2613 * necessary.
2614 */
2615
2616static int /* O - Bitmask of fields read */
2617ppd_read(cups_file_t *fp, /* I - File to read from */
2e4ff8af 2618 _ppd_line_t *line, /* I - Line buffer */
ef416fc2 2619 char *keyword, /* O - Keyword from line */
2620 char *option, /* O - Option from line */
2621 char *text, /* O - Human-readable text from line */
2622 char **string, /* O - Code/string data */
2623 int ignoreblank, /* I - Ignore blank lines? */
2624 _cups_globals_t *cg) /* I - Global data */
2625{
2626 int ch, /* Character from file */
2627 col, /* Column in line */
2628 colon, /* Colon seen? */
2629 endquote, /* Waiting for an end quote */
2630 mask, /* Mask to be returned */
2631 startline, /* Start line */
2632 textlen; /* Length of text */
2633 char *keyptr, /* Keyword pointer */
2634 *optptr, /* Option pointer */
2635 *textptr, /* Text pointer */
2636 *strptr, /* Pointer into string */
2e4ff8af 2637 *lineptr; /* Current position in line buffer */
ef416fc2 2638
ef416fc2 2639
2640 /*
2641 * Now loop until we have a valid line...
2642 */
2643
2644 *string = NULL;
2645 col = 0;
2646 startline = cg->ppd_line + 1;
ef416fc2 2647
2e4ff8af
MS
2648 if (!line->buffer)
2649 {
2650 line->bufsize = 1024;
2651 line->buffer = malloc(1024);
2652
2653 if (!line->buffer)
2654 return (0);
2655 }
ef416fc2 2656
2657 do
2658 {
2659 /*
2660 * Read the line...
2661 */
2662
2e4ff8af 2663 lineptr = line->buffer;
ef416fc2 2664 endquote = 0;
2665 colon = 0;
2666
2667 while ((ch = cupsFileGetChar(fp)) != EOF)
2668 {
2e4ff8af 2669 if (lineptr >= (line->buffer + line->bufsize - 1))
ef416fc2 2670 {
2671 /*
2672 * Expand the line buffer...
2673 */
2674
2675 char *temp; /* Temporary line pointer */
2676
2677
2e4ff8af
MS
2678 line->bufsize += 1024;
2679 if (line->bufsize > 262144)
ef416fc2 2680 {
2681 /*
2682 * Don't allow lines longer than 256k!
2683 */
2684
2685 cg->ppd_line = startline;
2686 cg->ppd_status = PPD_LINE_TOO_LONG;
2687
ef416fc2 2688 return (0);
2689 }
2690
2e4ff8af 2691 temp = realloc(line->buffer, line->bufsize);
ef416fc2 2692 if (!temp)
2693 {
2694 cg->ppd_line = startline;
2695 cg->ppd_status = PPD_LINE_TOO_LONG;
2696
ef416fc2 2697 return (0);
2698 }
2699
2e4ff8af
MS
2700 lineptr = temp + (lineptr - line->buffer);
2701 line->buffer = temp;
ef416fc2 2702 }
2703
2704 if (ch == '\r' || ch == '\n')
2705 {
2706 /*
2707 * Line feed or carriage return...
2708 */
2709
2710 cg->ppd_line ++;
2711 col = 0;
2712
2713 if (ch == '\r')
2714 {
2715 /*
2716 * Check for a trailing line feed...
2717 */
2718
2719 if ((ch = cupsFilePeekChar(fp)) == EOF)
fa73b229 2720 {
2721 ch = '\n';
ef416fc2 2722 break;
fa73b229 2723 }
2724
ef416fc2 2725 if (ch == 0x0a)
2726 cupsFileGetChar(fp);
2727 }
2728
2e4ff8af 2729 if (lineptr == line->buffer && ignoreblank)
ef416fc2 2730 continue; /* Skip blank lines */
2731
2732 ch = '\n';
2733
2734 if (!endquote) /* Continue for multi-line text */
2735 break;
2736
2737 *lineptr++ = '\n';
2738 }
2739 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2740 {
2741 /*
2742 * Other control characters...
2743 */
2744
2745 cg->ppd_line = startline;
2746 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2747
ef416fc2 2748 return (0);
2749 }
2750 else if (ch != 0x1a)
2751 {
2752 /*
2753 * Any other character...
2754 */
2755
2756 *lineptr++ = ch;
2757 col ++;
2758
2759 if (col > (PPD_MAX_LINE - 1))
2760 {
2761 /*
2762 * Line is too long...
2763 */
2764
2765 cg->ppd_line = startline;
2766 cg->ppd_status = PPD_LINE_TOO_LONG;
2767
ef416fc2 2768 return (0);
2769 }
2770
2e4ff8af 2771 if (ch == ':' && strncmp(line->buffer, "*%", 2) != 0)
ef416fc2 2772 colon = 1;
2773
2774 if (ch == '\"' && colon)
2775 endquote = !endquote;
2776 }
2777 }
2778
2779 if (endquote)
2780 {
2781 /*
2782 * Didn't finish this quoted string...
2783 */
2784
2785 while ((ch = cupsFileGetChar(fp)) != EOF)
2786 if (ch == '\"')
2787 break;
2788 else if (ch == '\r' || ch == '\n')
2789 {
2790 cg->ppd_line ++;
2791 col = 0;
2792
2793 if (ch == '\r')
2794 {
2795 /*
2796 * Check for a trailing line feed...
2797 */
2798
2799 if ((ch = cupsFilePeekChar(fp)) == EOF)
2800 break;
2801 if (ch == 0x0a)
2802 cupsFileGetChar(fp);
2803 }
ef416fc2 2804 }
2805 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2806 {
2807 /*
2808 * Other control characters...
2809 */
2810
2811 cg->ppd_line = startline;
2812 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2813
ef416fc2 2814 return (0);
2815 }
2816 else if (ch != 0x1a)
2817 {
2818 col ++;
2819
2820 if (col > (PPD_MAX_LINE - 1))
2821 {
2822 /*
2823 * Line is too long...
2824 */
2825
2826 cg->ppd_line = startline;
2827 cg->ppd_status = PPD_LINE_TOO_LONG;
2828
ef416fc2 2829 return (0);
2830 }
2831 }
2832 }
2833
2834 if (ch != '\n')
2835 {
2836 /*
2837 * Didn't finish this line...
2838 */
2839
2840 while ((ch = cupsFileGetChar(fp)) != EOF)
2841 if (ch == '\r' || ch == '\n')
2842 {
2843 /*
2844 * Line feed or carriage return...
2845 */
2846
2847 cg->ppd_line ++;
2848 col = 0;
2849
2850 if (ch == '\r')
2851 {
2852 /*
2853 * Check for a trailing line feed...
2854 */
2855
2856 if ((ch = cupsFilePeekChar(fp)) == EOF)
2857 break;
2858 if (ch == 0x0a)
2859 cupsFileGetChar(fp);
2860 }
2861
2862 break;
2863 }
2864 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2865 {
2866 /*
2867 * Other control characters...
2868 */
2869
2870 cg->ppd_line = startline;
2871 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2872
ef416fc2 2873 return (0);
2874 }
2875 else if (ch != 0x1a)
2876 {
2877 col ++;
2878
2879 if (col > (PPD_MAX_LINE - 1))
2880 {
2881 /*
2882 * Line is too long...
2883 */
2884
2885 cg->ppd_line = startline;
2886 cg->ppd_status = PPD_LINE_TOO_LONG;
2887
ef416fc2 2888 return (0);
2889 }
2890 }
2891 }
2892
2e4ff8af 2893 if (lineptr > line->buffer && lineptr[-1] == '\n')
ef416fc2 2894 lineptr --;
2895
2896 *lineptr = '\0';
2897
ae71f5de 2898 DEBUG_printf(("LINE=\"%s\"\n", line->buffer));
ef416fc2 2899
bd7854cb 2900 /*
2901 * The dynamically created PPDs for older style Mac OS X
2902 * drivers include a large blob of data inserted as comments
2903 * at the end of the file. As an optimization we can stop
2904 * reading the PPD when we get to the start of this data.
2905 */
2906
2e4ff8af 2907 if (!strcmp(line->buffer, "*%APLWORKSET START"))
bd7854cb 2908 return (0);
bd7854cb 2909
2e4ff8af 2910 if (ch == EOF && lineptr == line->buffer)
ef416fc2 2911 return (0);
ef416fc2 2912
2913 /*
2914 * Now parse it...
2915 */
2916
2917 mask = 0;
2e4ff8af 2918 lineptr = line->buffer + 1;
ef416fc2 2919
2920 keyword[0] = '\0';
2921 option[0] = '\0';
2922 text[0] = '\0';
2923 *string = NULL;
2924
2e4ff8af
MS
2925 if ((!line->buffer[0] || /* Blank line */
2926 !strncmp(line->buffer, "*%", 2) || /* Comment line */
2927 !strcmp(line->buffer, "*End")) && /* End of multi-line string */
ef416fc2 2928 ignoreblank) /* Ignore these? */
2929 {
2930 startline = cg->ppd_line + 1;
2931 continue;
2932 }
2933
2e4ff8af 2934 if (!strcmp(line->buffer, "*")) /* (Bad) comment line */
ef416fc2 2935 {
2936 if (cg->ppd_conform == PPD_CONFORM_RELAXED)
2937 {
2938 startline = cg->ppd_line + 1;
2939 continue;
2940 }
2941 else
2942 {
2943 cg->ppd_line = startline;
2944 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
2945
ef416fc2 2946 return (0);
2947 }
2948 }
2949
2e4ff8af 2950 if (line->buffer[0] != '*') /* All lines start with an asterisk */
ef416fc2 2951 {
ef416fc2 2952 /*
2953 * Allow lines consisting of just whitespace...
2954 */
2955
2e4ff8af 2956 for (lineptr = line->buffer; *lineptr; lineptr ++)
ef416fc2 2957 if (!isspace(*lineptr & 255))
2958 break;
2959
2960 if (*lineptr)
2961 {
2962 cg->ppd_status = PPD_MISSING_ASTERISK;
ef416fc2 2963 return (0);
2964 }
2965 else if (ignoreblank)
2966 continue;
2967 else
ef416fc2 2968 return (0);
ef416fc2 2969 }
2970
2971 /*
2972 * Get a keyword...
2973 */
2974
2975 keyptr = keyword;
2976
2977 while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr & 255))
2978 {
2979 if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
2980 (keyptr - keyword) >= (PPD_MAX_NAME - 1))
2981 {
2982 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
ef416fc2 2983 return (0);
2984 }
2985
2986 *keyptr++ = *lineptr++;
2987 }
2988
2989 *keyptr = '\0';
2990
2991 if (!strcmp(keyword, "End"))
2992 continue;
2993
2994 mask |= PPD_KEYWORD;
2995
2996/* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
2997
2998 if (isspace(*lineptr & 255))
2999 {
3000 /*
3001 * Get an option name...
3002 */
3003
3004 while (isspace(*lineptr & 255))
3005 lineptr ++;
3006
3007 optptr = option;
3008
3009 while (*lineptr != '\0' && !isspace(*lineptr & 255) && *lineptr != ':' &&
3010 *lineptr != '/')
3011 {
3012 if (*lineptr <= ' ' || *lineptr > 126 ||
3013 (optptr - option) >= (PPD_MAX_NAME - 1))
3014 {
3015 cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
ef416fc2 3016 return (0);
3017 }
3018
3019 *optptr++ = *lineptr++;
3020 }
3021
3022 *optptr = '\0';
3023
3024 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
3025 {
3026 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
ef416fc2 3027 return (0);
3028 }
3029
3030 while (isspace(*lineptr & 255))
3031 lineptr ++;
3032
3033 mask |= PPD_OPTION;
3034
3035/* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
3036
3037 if (*lineptr == '/')
3038 {
3039 /*
3040 * Get human-readable text...
3041 */
3042
3043 lineptr ++;
3044
3045 textptr = text;
3046
3047 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
3048 {
3049 if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
3050 (textptr - text) >= (PPD_MAX_LINE - 1))
3051 {
3052 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
ef416fc2 3053 return (0);
3054 }
3055
3056 *textptr++ = *lineptr++;
3057 }
3058
3059 *textptr = '\0';
3060 textlen = ppd_decode(text);
3061
3062 if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT)
3063 {
3064 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
ef416fc2 3065 return (0);
3066 }
3067
3068 mask |= PPD_TEXT;
3069 }
3070
3071/* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
3072 }
3073
3074 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
3075 {
3076 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
ef416fc2 3077 return (0);
3078 }
3079
3080 while (isspace(*lineptr & 255))
3081 lineptr ++;
3082
3083 if (*lineptr == ':')
3084 {
3085 /*
3086 * Get string after triming leading and trailing whitespace...
3087 */
3088
3089 lineptr ++;
3090 while (isspace(*lineptr & 255))
3091 lineptr ++;
3092
3093 strptr = lineptr + strlen(lineptr) - 1;
3094 while (strptr >= lineptr && isspace(*strptr & 255))
3095 *strptr-- = '\0';
3096
3097 if (*strptr == '\"')
3098 {
3099 /*
2e4ff8af 3100 * Quoted string by itself, remove quotes...
ef416fc2 3101 */
3102
2e4ff8af
MS
3103 *strptr = '\0';
3104 lineptr ++;
ef416fc2 3105 }
2e4ff8af
MS
3106
3107 *string = _cupsStrAlloc(lineptr);
ef416fc2 3108
3109/* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
3110
3111 mask |= PPD_STRING;
3112 }
3113 }
3114 while (mask == 0);
3115
ef416fc2 3116 return (mask);
3117}
3118
3119
3120/*
b19ccc9e 3121 * End of "$Id: ppd.c 7906 2008-09-03 20:19:43Z mike $".
ef416fc2 3122 */