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