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