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