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