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