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