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