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