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