]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/ppd.c
Fix propagation of custom page size parameter values.
[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 *
24c1b5ce 6 * Copyright 1997-2006 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
822 profile->density = _cupsStrScand(string, &sptr, loc);
823 profile->gamma = _cupsStrScand(sptr, &sptr, loc);
824 profile->matrix[0][0] = _cupsStrScand(sptr, &sptr, loc);
825 profile->matrix[0][1] = _cupsStrScand(sptr, &sptr, loc);
826 profile->matrix[0][2] = _cupsStrScand(sptr, &sptr, loc);
827 profile->matrix[1][0] = _cupsStrScand(sptr, &sptr, loc);
828 profile->matrix[1][1] = _cupsStrScand(sptr, &sptr, loc);
829 profile->matrix[1][2] = _cupsStrScand(sptr, &sptr, loc);
830 profile->matrix[2][0] = _cupsStrScand(sptr, &sptr, loc);
831 profile->matrix[2][1] = _cupsStrScand(sptr, &sptr, loc);
832 profile->matrix[2][2] = _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;
94ffdf17 931 cparam->minimum.custom_curve = _cupsStrScand(cminimum, NULL, loc);
932 cparam->maximum.custom_curve = _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;
94ffdf17 943 cparam->minimum.custom_invcurve = _cupsStrScand(cminimum, NULL, loc);
944 cparam->maximum.custom_invcurve = _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;
94ffdf17 961 cparam->minimum.custom_points = _cupsStrScand(cminimum, NULL, loc);
962 cparam->maximum.custom_points = _cupsStrScand(cmaximum, NULL, loc);
ff6a82d3 963 }
964 else if (!strcmp(ctype, "real"))
965 {
966 cparam->type = PPD_CUSTOM_REAL;
94ffdf17 967 cparam->minimum.custom_real = _cupsStrScand(cminimum, NULL, loc);
968 cparam->maximum.custom_real = _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 ++)
1004 ppd->custom_margins[i] = _cupsStrScand(sptr, &sptr, loc);
1005 }
ff6a82d3 1006 else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True"))
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");
1079 }
6fdf969a 1080 }
a501ad17 1081 else if (!strcmp(keyword, "LandscapeOrientation"))
2b85e375 1082 {
a501ad17 1083 if (!strcmp(string, "Minus90"))
2b85e375 1084 ppd->landscape = -90;
a501ad17 1085 else if (!strcmp(string, "Plus90"))
2b85e375 1086 ppd->landscape = 90;
1087 }
a501ad17 1088 else if (!strcmp(keyword, "Emulators"))
8c1333e2 1089 {
d23a857a 1090 for (count = 1, sptr = string; sptr != NULL;)
8c1333e2 1091 if ((sptr = strchr(sptr, ' ')) != NULL)
1092 {
1093 count ++;
1094 while (*sptr == ' ')
1095 sptr ++;
e8fda7b9 1096 }
8c1333e2 1097
1098 ppd->num_emulations = count;
ab94f399 1099 ppd->emulations = calloc(count, sizeof(ppd_emul_t));
8c1333e2 1100
d23a857a 1101 for (i = 0, sptr = string; i < count; i ++)
8c1333e2 1102 {
d2e58bfa 1103 for (nameptr = ppd->emulations[i].name;
1104 *sptr != '\0' && *sptr != ' ';
1105 sptr ++)
1106 if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1))
1107 *nameptr++ = *sptr;
8c1333e2 1108
1109 *nameptr = '\0';
1110
1111 while (*sptr == ' ')
1112 sptr ++;
1113 }
1114 }
a501ad17 1115 else if (!strncmp(keyword, "StartEmulator_", 14))
8c1333e2 1116 {
1117 ppd_decode(string);
1118
1119 for (i = 0; i < ppd->num_emulations; i ++)
a501ad17 1120 if (!strcmp(keyword + 14, ppd->emulations[i].name))
8c1333e2 1121 {
1122 ppd->emulations[i].start = string;
1123 string = NULL;
1124 }
1125 }
a501ad17 1126 else if (!strncmp(keyword, "StopEmulator_", 13))
8c1333e2 1127 {
1128 ppd_decode(string);
1129
1130 for (i = 0; i < ppd->num_emulations; i ++)
a501ad17 1131 if (!strcmp(keyword + 13, ppd->emulations[i].name))
8c1333e2 1132 {
1133 ppd->emulations[i].stop = string;
1134 string = NULL;
1135 }
1136 }
a501ad17 1137 else if (!strcmp(keyword, "JobPatchFile"))
8c1333e2 1138 {
1139 if (ppd->patches == NULL)
2e8cd988 1140 ppd->patches = strdup(string);
8c1333e2 1141 else
1142 {
0819478b 1143 temp = realloc(ppd->patches, strlen(ppd->patches) +
1144 strlen(string) + 1);
1145 if (temp == NULL)
1146 {
03f61bf3 1147 cg->ppd_status = PPD_ALLOC_ERROR;
79f448f9 1148
5a617005 1149 goto error;
0819478b 1150 }
1151
1152 ppd->patches = temp;
8c1333e2 1153
d23a857a 1154 strcpy(ppd->patches + strlen(ppd->patches), string);
8c1333e2 1155 }
1156 }
a501ad17 1157 else if (!strcmp(keyword, "OpenUI"))
2b85e375 1158 {
b3291c5a 1159 /*
1160 * Don't allow nesting of options...
1161 */
1162
03f61bf3 1163 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
b3291c5a 1164 {
03f61bf3 1165 cg->ppd_status = PPD_NESTED_OPEN_UI;
b3291c5a 1166
5a617005 1167 goto error;
b3291c5a 1168 }
1169
2b85e375 1170 /*
1171 * Add an option record to the current sub-group, group, or file...
1172 */
1173
1174 if (name[0] == '*')
2625096f 1175 _cups_strcpy(name, name + 1); /* Eliminate leading asterisk */
2b85e375 1176
b296d7d9 1177 for (i = (int)strlen(name) - 1; i > 0 && isspace(name[i] & 255); i --)
753453e4 1178 name[i] = '\0'; /* Eliminate trailing spaces */
1179
1180 DEBUG_printf(("OpenUI of %s in group %s...\n", name,
1181 group ? group->text : "(null)"));
c21064d2 1182
652e598f 1183 if (subgroup != NULL)
1184 option = ppd_get_option(subgroup, name);
1185 else if (group == NULL)
1186 {
ed04873a 1187 if ((group = ppd_get_group(ppd, "General", _("General"), cg,
1188 encoding)) == NULL)
5a617005 1189 goto error;
caab0820 1190
753453e4 1191 DEBUG_printf(("Adding to group %s...\n", group->text));
652e598f 1192 option = ppd_get_option(group, name);
1193 group = NULL;
1194 }
1195 else
1196 option = ppd_get_option(group, name);
2b85e375 1197
652e598f 1198 if (option == NULL)
1199 {
03f61bf3 1200 cg->ppd_status = PPD_ALLOC_ERROR;
79f448f9 1201
5a617005 1202 goto error;
652e598f 1203 }
2b85e375 1204
652e598f 1205 /*
1206 * Now fill in the initial information for the option...
1207 */
2b85e375 1208
a501ad17 1209 if (string && !strcmp(string, "PickMany"))
652e598f 1210 option->ui = PPD_UI_PICKMANY;
a501ad17 1211 else if (string && !strcmp(string, "Boolean"))
652e598f 1212 option->ui = PPD_UI_BOOLEAN;
a501ad17 1213 else if (string && !strcmp(string, "PickOne"))
652e598f 1214 option->ui = PPD_UI_PICKONE;
03f61bf3 1215 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
b3291c5a 1216 {
03f61bf3 1217 cg->ppd_status = PPD_BAD_OPEN_UI;
b3291c5a 1218
5a617005 1219 goto error;
b3291c5a 1220 }
9e678e84 1221 else
1222 option->ui = PPD_UI_PICKONE;
652e598f 1223
a2b8b819 1224 for (j = 0; j < ppd->num_attrs; j ++)
1225 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
1226 !strcmp(ppd->attrs[j]->name + 7, name) &&
1227 ppd->attrs[j]->value)
1228 {
fd8e0b1e 1229 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
1230 option->keyword, ppd->attrs[j]->value));
a2b8b819 1231 strlcpy(option->defchoice, ppd->attrs[j]->value,
1232 sizeof(option->defchoice));
1233 break;
1234 }
1235
652e598f 1236 if (text[0])
8c4a3f1a 1237 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1238 sizeof(option->text), encoding);
652e598f 1239 else
1240 {
a501ad17 1241 if (!strcmp(name, "PageSize"))
1242 strlcpy(option->text, _("Media Size"), sizeof(option->text));
1243 else if (!strcmp(name, "MediaType"))
1244 strlcpy(option->text, _("Media Type"), sizeof(option->text));
1245 else if (!strcmp(name, "InputSlot"))
1246 strlcpy(option->text, _("Media Source"), sizeof(option->text));
1247 else if (!strcmp(name, "ColorModel"))
1248 strlcpy(option->text, _("Output Mode"), sizeof(option->text));
1249 else if (!strcmp(name, "Resolution"))
1250 strlcpy(option->text, _("Resolution"), sizeof(option->text));
652e598f 1251 else
def978d5 1252 strlcpy(option->text, name, sizeof(option->text));
caab0820 1253 }
652e598f 1254
1255 option->section = PPD_ORDER_ANY;
2e8cd988 1256
1257 ppd_free(string);
1258 string = NULL;
2b85e375 1259 }
a501ad17 1260 else if (!strcmp(keyword, "JCLOpenUI"))
2b85e375 1261 {
b3291c5a 1262 /*
1263 * Don't allow nesting of options...
1264 */
1265
03f61bf3 1266 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
b3291c5a 1267 {
03f61bf3 1268 cg->ppd_status = PPD_NESTED_OPEN_UI;
b3291c5a 1269
5a617005 1270 goto error;
b3291c5a 1271 }
1272
58ec2a95 1273 /*
1274 * Find the JCL group, and add if needed...
1275 */
1276
ed04873a 1277 group = ppd_get_group(ppd, "JCL", _("JCL"), cg, encoding);
58ec2a95 1278
6fdf969a 1279 if (group == NULL)
5a617005 1280 goto error;
58ec2a95 1281
2b85e375 1282 /*
1283 * Add an option record to the current JCLs...
1284 */
1285
1286 if (name[0] == '*')
2625096f 1287 _cups_strcpy(name, name + 1);
2b85e375 1288
6fdf969a 1289 option = ppd_get_option(group, name);
2b85e375 1290
1291 if (option == NULL)
1292 {
03f61bf3 1293 cg->ppd_status = PPD_ALLOC_ERROR;
79f448f9 1294
5a617005 1295 goto error;
e8fda7b9 1296 }
2b85e375 1297
2b85e375 1298 /*
1299 * Now fill in the initial information for the option...
1300 */
1301
a501ad17 1302 if (string && !strcmp(string, "PickMany"))
2b85e375 1303 option->ui = PPD_UI_PICKMANY;
a501ad17 1304 else if (string && !strcmp(string, "Boolean"))
2b85e375 1305 option->ui = PPD_UI_BOOLEAN;
a501ad17 1306 else if (string && !strcmp(string, "PickOne"))
2b85e375 1307 option->ui = PPD_UI_PICKONE;
b3291c5a 1308 else
1309 {
03f61bf3 1310 cg->ppd_status = PPD_BAD_OPEN_UI;
b3291c5a 1311
5a617005 1312 goto error;
b3291c5a 1313 }
2b85e375 1314
a2b8b819 1315 for (j = 0; j < ppd->num_attrs; j ++)
1316 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
1317 !strcmp(ppd->attrs[j]->name + 7, name) &&
1318 ppd->attrs[j]->value)
1319 {
fd8e0b1e 1320 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
1321 option->keyword, ppd->attrs[j]->value));
a2b8b819 1322 strlcpy(option->defchoice, ppd->attrs[j]->value,
1323 sizeof(option->defchoice));
1324 break;
1325 }
1326
ed04873a 1327 if (text[0])
8c4a3f1a 1328 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1329 sizeof(option->text), encoding);
ed04873a 1330 else
1331 strlcpy(option->text, name, sizeof(option->text));
2b85e375 1332
1333 option->section = PPD_ORDER_JCL;
58ec2a95 1334 group = NULL;
2e8cd988 1335
1336 ppd_free(string);
1337 string = NULL;
2b85e375 1338 }
a501ad17 1339 else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI"))
2e8cd988 1340 {
2b85e375 1341 option = NULL;
2e8cd988 1342
1343 ppd_free(string);
1344 string = NULL;
1345 }
a501ad17 1346 else if (!strcmp(keyword, "OpenGroup"))
2b85e375 1347 {
1348 /*
1349 * Open a new group...
1350 */
1351
1352 if (group != NULL)
1353 {
03f61bf3 1354 cg->ppd_status = PPD_NESTED_OPEN_GROUP;
79f448f9 1355
5a617005 1356 goto error;
e8fda7b9 1357 }
2b85e375 1358
b3291c5a 1359 if (!string)
1360 {
03f61bf3 1361 cg->ppd_status = PPD_BAD_OPEN_GROUP;
b3291c5a 1362
5a617005 1363 goto error;
b3291c5a 1364 }
1365
83575f2d 1366 /*
1367 * Separate the group name from the text (name/text)...
1368 */
2b85e375 1369
83575f2d 1370 if ((sptr = strchr(string, '/')) != NULL)
1371 *sptr++ = '\0';
1372 else
1373 sptr = string;
1374
1375 /*
1376 * Fix up the text...
1377 */
1378
1379 ppd_decode(sptr);
83575f2d 1380
1381 /*
1382 * Find/add the group...
1383 */
1384
ed04873a 1385 group = ppd_get_group(ppd, string, sptr, cg, encoding);
2e8cd988 1386
6f83172d 1387 if (group == NULL)
1388 goto error;
1389
2e8cd988 1390 ppd_free(string);
1391 string = NULL;
2b85e375 1392 }
a501ad17 1393 else if (!strcmp(keyword, "CloseGroup"))
2e8cd988 1394 {
2b85e375 1395 group = NULL;
2e8cd988 1396
1397 ppd_free(string);
1398 string = NULL;
1399 }
a501ad17 1400 else if (!strcmp(keyword, "OrderDependency") ||
1401 !strcmp(keyword, "NonUIOrderDependency"))
2b85e375 1402 {
94ffdf17 1403 order = _cupsStrScand(string, &sptr, loc);
1404
1405 if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2)
2b85e375 1406 {
03f61bf3 1407 cg->ppd_status = PPD_BAD_ORDER_DEPENDENCY;
79f448f9 1408
5a617005 1409 goto error;
e8fda7b9 1410 }
2b85e375 1411
1412 if (keyword[0] == '*')
2625096f 1413 _cups_strcpy(keyword, keyword + 1);
2b85e375 1414
a501ad17 1415 if (!strcmp(name, "ExitServer"))
2b85e375 1416 section = PPD_ORDER_EXIT;
a501ad17 1417 else if (!strcmp(name, "Prolog"))
2b85e375 1418 section = PPD_ORDER_PROLOG;
a501ad17 1419 else if (!strcmp(name, "DocumentSetup"))
2b85e375 1420 section = PPD_ORDER_DOCUMENT;
a501ad17 1421 else if (!strcmp(name, "PageSetup"))
2b85e375 1422 section = PPD_ORDER_PAGE;
a501ad17 1423 else if (!strcmp(name, "JCLSetup"))
2b85e375 1424 section = PPD_ORDER_JCL;
1425 else
1426 section = PPD_ORDER_ANY;
1427
1428 if (option == NULL)
1429 {
08379093 1430 ppd_group_t *gtemp;
7d75b814 1431
1432
2b85e375 1433 /*
1434 * Only valid for Non-UI options...
1435 */
1436
08379093 1437 for (i = ppd->num_groups, gtemp = ppd->groups; i > 0; i --, gtemp ++)
1438 if (gtemp->text[0] == '\0')
2b85e375 1439 break;
58ec2a95 1440
1441 if (i > 0)
08379093 1442 for (i = 0; i < gtemp->num_options; i ++)
a501ad17 1443 if (!strcmp(keyword, gtemp->options[i].keyword))
58ec2a95 1444 {
08379093 1445 gtemp->options[i].section = section;
1446 gtemp->options[i].order = order;
58ec2a95 1447 break;
1448 }
2b85e375 1449 }
1450 else
1451 {
1452 option->section = section;
1453 option->order = order;
e8fda7b9 1454 }
2e8cd988 1455
1456 ppd_free(string);
1457 string = NULL;
2b85e375 1458 }
a501ad17 1459 else if (!strncmp(keyword, "Default", 7))
2b85e375 1460 {
6c73d44f 1461 if (string == NULL)
1462 continue;
1463
af50faa7 1464 /*
1465 * Drop UI text, if any, from value...
1466 */
1467
d23a857a 1468 if (strchr(string, '/') != NULL)
1469 *strchr(string, '/') = '\0';
58ec2a95 1470
af50faa7 1471 /*
1472 * Assign the default value as appropriate...
1473 */
43cd52be 1474
a501ad17 1475 if (!strcmp(keyword, "DefaultColorSpace"))
af50faa7 1476 {
1477 /*
1478 * Set default colorspace...
1479 */
43cd52be 1480
a501ad17 1481 if (!strcmp(string, "CMY"))
af50faa7 1482 ppd->colorspace = PPD_CS_CMY;
a501ad17 1483 else if (!strcmp(string, "CMYK"))
af50faa7 1484 ppd->colorspace = PPD_CS_CMYK;
a501ad17 1485 else if (!strcmp(string, "RGB"))
af50faa7 1486 ppd->colorspace = PPD_CS_RGB;
a501ad17 1487 else if (!strcmp(string, "RGBK"))
af50faa7 1488 ppd->colorspace = PPD_CS_RGBK;
a501ad17 1489 else if (!strcmp(string, "N"))
af50faa7 1490 ppd->colorspace = PPD_CS_N;
1491 else
1492 ppd->colorspace = PPD_CS_GRAY;
2b85e375 1493 }
a501ad17 1494 else if (option && !strcmp(keyword + 7, option->keyword))
af50faa7 1495 {
1496 /*
1497 * Set the default as part of the current option...
1498 */
1499
fd8e0b1e 1500 DEBUG_printf(("Setting %s to %s...\n", keyword, string));
1501
def978d5 1502 strlcpy(option->defchoice, string, sizeof(option->defchoice));
fd8e0b1e 1503
1504 DEBUG_printf(("%s is now %s...\n", keyword, option->defchoice));
af50faa7 1505 }
43cd52be 1506 else
1507 {
1508 /*
af50faa7 1509 * Lookup option and set if it has been defined...
43cd52be 1510 */
1511
af50faa7 1512 ppd_option_t *toption; /* Temporary option */
1513
43cd52be 1514
af50faa7 1515 if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL)
fd8e0b1e 1516 {
1517 DEBUG_printf(("Setting %s to %s...\n", keyword, string));
af50faa7 1518 strlcpy(toption->defchoice, string, sizeof(toption->defchoice));
fd8e0b1e 1519 }
43cd52be 1520 }
2b85e375 1521 }
a501ad17 1522 else if (!strcmp(keyword, "UIConstraints") ||
1523 !strcmp(keyword, "NonUIConstraints"))
2b85e375 1524 {
1525 if (ppd->num_consts == 0)
ab94f399 1526 constraint = calloc(1, sizeof(ppd_const_t));
2b85e375 1527 else
1528 constraint = realloc(ppd->consts,
1529 (ppd->num_consts + 1) * sizeof(ppd_const_t));
1530
1531 if (constraint == NULL)
1532 {
03f61bf3 1533 cg->ppd_status = PPD_ALLOC_ERROR;
79f448f9 1534
5a617005 1535 goto error;
e8fda7b9 1536 }
2b85e375 1537
1538 ppd->consts = constraint;
1539 constraint += ppd->num_consts;
1540 ppd->num_consts ++;
1541
fafbba4f 1542 switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1,
8c1333e2 1543 constraint->choice1, constraint->option2,
1544 constraint->choice2))
2b85e375 1545 {
1546 case 0 : /* Error */
1547 case 1 : /* Error */
03f61bf3 1548 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
5a617005 1549 goto error;
2b85e375 1550
8c1333e2 1551 case 2 : /* Two options... */
3f43ed60 1552 /*
1553 * Check for broken constraints like "* Option"...
1554 */
1555
1556 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1557 (!strcmp(constraint->option1, "*") ||
1558 !strcmp(constraint->choice1, "*")))
1559 {
1560 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1561 goto error;
1562 }
1563
d2e58bfa 1564 /*
1565 * The following strcpy's are safe, as optionN and
1566 * choiceN are all the same size (size defined by PPD spec...)
1567 */
1568
2b85e375 1569 if (constraint->option1[0] == '*')
2625096f 1570 _cups_strcpy(constraint->option1, constraint->option1 + 1);
3f43ed60 1571 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1572 {
1573 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1574 goto error;
1575 }
8c1333e2 1576
1577 if (constraint->choice1[0] == '*')
2625096f 1578 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
3f43ed60 1579 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1580 {
1581 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1582 goto error;
1583 }
2b85e375 1584
8c1333e2 1585 constraint->choice1[0] = '\0';
1586 constraint->choice2[0] = '\0';
2b85e375 1587 break;
1588
8c1333e2 1589 case 3 : /* Two options, one choice... */
3f43ed60 1590 /*
1591 * Check for broken constraints like "* Option"...
1592 */
1593
1594 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1595 (!strcmp(constraint->option1, "*") ||
1596 !strcmp(constraint->choice1, "*") ||
1597 !strcmp(constraint->option2, "*")))
1598 {
1599 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1600 goto error;
1601 }
1602
d2e58bfa 1603 /*
2625096f 1604 * The following _cups_strcpy's are safe, as optionN and
d2e58bfa 1605 * choiceN are all the same size (size defined by PPD spec...)
1606 */
1607
2b85e375 1608 if (constraint->option1[0] == '*')
2625096f 1609 _cups_strcpy(constraint->option1, constraint->option1 + 1);
3f43ed60 1610 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1611 {
1612 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1613 goto error;
1614 }
8c1333e2 1615
1616 if (constraint->choice1[0] == '*')
2b85e375 1617 {
3f43ed60 1618 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1619 constraint->option2[0] == '*')
1620 {
1621 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1622 goto error;
1623 }
1624
2625096f 1625 _cups_strcpy(constraint->choice2, constraint->option2);
1626 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
8c1333e2 1627 constraint->choice1[0] = '\0';
2b85e375 1628 }
9cbf7321 1629 else
1630 {
1631 if (constraint->option2[0] == '*')
2625096f 1632 _cups_strcpy(constraint->option2, constraint->option2 + 1);
3f43ed60 1633 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1634 {
1635 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1636 goto error;
1637 }
2b85e375 1638
9cbf7321 1639 constraint->choice2[0] = '\0';
1640 }
2b85e375 1641 break;
1642
8c1333e2 1643 case 4 : /* Two options, two choices... */
3f43ed60 1644 /*
1645 * Check for broken constraints like "* Option"...
1646 */
1647
1648 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1649 (!strcmp(constraint->option1, "*") ||
1650 !strcmp(constraint->choice1, "*") ||
1651 !strcmp(constraint->option2, "*") ||
1652 !strcmp(constraint->choice2, "*")))
1653 {
1654 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1655 goto error;
1656 }
1657
8c1333e2 1658 if (constraint->option1[0] == '*')
2625096f 1659 _cups_strcpy(constraint->option1, constraint->option1 + 1);
3f43ed60 1660 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1661 {
1662 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1663 goto error;
1664 }
1665
1666 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1667 constraint->choice1[0] == '*')
1668 {
1669 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1670 goto error;
1671 }
2b85e375 1672
8c1333e2 1673 if (constraint->option2[0] == '*')
2625096f 1674 _cups_strcpy(constraint->option2, constraint->option2 + 1);
3f43ed60 1675 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1676 {
1677 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1678 goto error;
1679 }
1680
1681 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1682 constraint->choice2[0] == '*')
1683 {
1684 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1685 goto error;
1686 }
2b85e375 1687 break;
e8fda7b9 1688 }
2e8cd988 1689
738de08b 1690 /*
1691 * Handle CustomFoo option constraints...
1692 */
1693
1694 if (!strncasecmp(constraint->option1, "Custom", 6) &&
1695 !strcasecmp(constraint->choice1, "True"))
1696 {
1697 _cups_strcpy(constraint->option1, constraint->option1 + 6);
1698 strcpy(constraint->choice1, "Custom");
1699 }
1700
1701 if (!strncasecmp(constraint->option2, "Custom", 6) &&
1702 !strcasecmp(constraint->choice2, "True"))
1703 {
1704 _cups_strcpy(constraint->option2, constraint->option2 + 6);
1705 strcpy(constraint->choice2, "Custom");
1706 }
1707
1708 /*
1709 * Don't add this one as an attribute...
1710 */
1711
2e8cd988 1712 ppd_free(string);
1713 string = NULL;
2b85e375 1714 }
a501ad17 1715 else if (!strcmp(keyword, "PaperDimension"))
2b85e375 1716 {
753453e4 1717 if ((size = ppdPageSize(ppd, name)) == NULL)
1718 size = ppd_add_size(ppd, name);
1719
1720 if (size == NULL)
1721 {
1722 /*
1723 * Unable to add or find size!
1724 */
1725
03f61bf3 1726 cg->ppd_status = PPD_ALLOC_ERROR;
79f448f9 1727
5a617005 1728 goto error;
753453e4 1729 }
1730
94ffdf17 1731 size->width = _cupsStrScand(string, &sptr, loc);
1732 size->length = _cupsStrScand(sptr, NULL, loc);
2e8cd988 1733
1734 ppd_free(string);
1735 string = NULL;
2b85e375 1736 }
a501ad17 1737 else if (!strcmp(keyword, "ImageableArea"))
2b85e375 1738 {
753453e4 1739 if ((size = ppdPageSize(ppd, name)) == NULL)
1740 size = ppd_add_size(ppd, name);
1741
1742 if (size == NULL)
1743 {
1744 /*
1745 * Unable to add or find size!
1746 */
1747
03f61bf3 1748 cg->ppd_status = PPD_ALLOC_ERROR;
79f448f9 1749
5a617005 1750 goto error;
753453e4 1751 }
1752
94ffdf17 1753 size->left = _cupsStrScand(string, &sptr, loc);
1754 size->bottom = _cupsStrScand(sptr, &sptr, loc);
1755 size->right = _cupsStrScand(sptr, &sptr, loc);
1756 size->top = _cupsStrScand(sptr, NULL, loc);
2e8cd988 1757
1758 ppd_free(string);
1759 string = NULL;
2b85e375 1760 }
1761 else if (option != NULL &&
1762 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
a319615f 1763 (PPD_KEYWORD | PPD_OPTION | PPD_STRING) &&
a501ad17 1764 !strcmp(keyword, option->keyword))
2b85e375 1765 {
7d75b814 1766 DEBUG_printf(("group = %p, subgroup = %p\n", group, subgroup));
1767
a501ad17 1768 if (!strcmp(keyword, "PageSize"))
2b85e375 1769 {
1770 /*
1771 * Add a page size...
1772 */
1773
753453e4 1774 if (ppdPageSize(ppd, name) == NULL)
1775 ppd_add_size(ppd, name);
e8fda7b9 1776 }
2b85e375 1777
1778 /*
1fdc6cd5 1779 * Add the option choice...
1780 */
1781
1782 choice = ppd_add_choice(option, name);
1783
ed04873a 1784 if (text[0])
8c4a3f1a 1785 cupsCharsetToUTF8((cups_utf8_t *)choice->text, text,
1786 sizeof(choice->text), encoding);
a501ad17 1787 else if (!strcmp(name, "True"))
1788 strcpy(choice->text, _("Yes"));
1789 else if (!strcmp(name, "False"))
1790 strcpy(choice->text, _("No"));
1fdc6cd5 1791 else
1792 strlcpy(choice->text, name, sizeof(choice->text));
1793
1794 if (option->section == PPD_ORDER_JCL)
1795 ppd_decode(string); /* Decode quoted string */
1796
1797 choice->code = string;
ff40b65e 1798 string = NULL; /* Don't add as an attribute below */
1fdc6cd5 1799 }
da5bb70a 1800
2e8cd988 1801 /*
1802 * Add remaining lines with keywords and string values as attributes...
1803 */
2b85e375 1804
2e8cd988 1805 if (string &&
1806 (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
1807 ppd_add_attr(ppd, keyword, name, text, string);
1808 else
1809 ppd_free(string);
e8fda7b9 1810 }
2b85e375 1811
7a1c86c5 1812 /*
1813 * Reset language preferences...
1814 */
1815
1816 cupsLangFree(language);
1817
2b85e375 1818#ifdef DEBUG
1819 if (!feof(fp))
ba31b514 1820 printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp));
2b85e375 1821#endif /* DEBUG */
1822
03f61bf3 1823 if (cg->ppd_status != PPD_OK)
43cd52be 1824 {
1825 /*
1826 * Had an error reading the PPD file, cannot continue!
1827 */
1828
1829 ppdClose(ppd);
1830
1831 return (NULL);
1832 }
1833
58ec2a95 1834 /*
ff6a82d3 1835 * Create the sorted options array and set the option back-pointer for
1836 * each choice and custom option...
58ec2a95 1837 */
1838
ff6a82d3 1839 ppd->options = cupsArrayNew((cups_array_func_t)ppd_compare_options, NULL);
caab0820 1840
58ec2a95 1841 for (i = ppd->num_groups, group = ppd->groups;
1842 i > 0;
1843 i --, group ++)
1844 {
1845 for (j = group->num_options, option = group->options;
1846 j > 0;
1847 j --, option ++)
caab0820 1848 {
ff6a82d3 1849 ppd_coption_t *coption; /* Custom option */
caab0820 1850
58ec2a95 1851
ff6a82d3 1852 cupsArrayAdd(ppd->options, option);
58ec2a95 1853
ff6a82d3 1854 for (k = 0; k < option->num_choices; k ++)
1855 option->choices[k].option = option;
1fdc6cd5 1856
ff6a82d3 1857 if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
1858 coption->option = option;
1859 }
1860 }
1fdc6cd5 1861
79f448f9 1862 /*
1863 * Return the PPD file structure...
1864 */
1865
2b85e375 1866 return (ppd);
5a617005 1867
1868 /*
1869 * Common exit point for errors to save code size...
1870 */
1871
1872 error:
1873
1874 ppd_free(string);
1875
1876 ppdClose(ppd);
1877
1878 cupsLangFree(language);
1879
5a617005 1880 return (NULL);
2b85e375 1881}
1882
1883
1884/*
1885 * 'ppdOpenFd()' - Read a PPD file into memory.
1886 */
1887
1fdc6cd5 1888ppd_file_t * /* O - PPD file record */
1889ppdOpenFd(int fd) /* I - File to read from */
2b85e375 1890{
ff6a82d3 1891 cups_file_t *fp; /* CUPS file pointer */
03f61bf3 1892 ppd_file_t *ppd; /* PPD file record */
2625096f 1893 _cups_globals_t *cg = _cupsGlobals();
03f61bf3 1894 /* Global data */
2b85e375 1895
1896
79f448f9 1897 /*
031278ca 1898 * Set the line number to 0...
79f448f9 1899 */
1900
03f61bf3 1901 cg->ppd_line = 0;
79f448f9 1902
2b85e375 1903 /*
1904 * Range check input...
1905 */
1906
1907 if (fd < 0)
79f448f9 1908 {
03f61bf3 1909 cg->ppd_status = PPD_NULL_FILE;
79f448f9 1910
2b85e375 1911 return (NULL);
79f448f9 1912 }
2b85e375 1913
1914 /*
1915 * Try to open the file and parse it...
1916 */
1917
ff6a82d3 1918 if ((fp = cupsFileOpenFd(fd, "r")) != NULL)
2b85e375 1919 {
ff6a82d3 1920 ppd = ppdOpen2(fp);
2b85e375 1921
ff6a82d3 1922 cupsFileClose(fp);
2b85e375 1923 }
1924 else
79f448f9 1925 {
03f61bf3 1926 cg->ppd_status = PPD_FILE_OPEN_ERROR;
ff6a82d3 1927 ppd = NULL;
79f448f9 1928 }
2b85e375 1929
1930 return (ppd);
1931}
1932
1933
1934/*
1935 * 'ppdOpenFile()' - Read a PPD file into memory.
1936 */
1937
1fdc6cd5 1938ppd_file_t * /* O - PPD file record */
1939ppdOpenFile(const char *filename) /* I - File to read from */
2b85e375 1940{
03f61bf3 1941 cups_file_t *fp; /* File pointer */
1942 ppd_file_t *ppd; /* PPD file record */
2625096f 1943 _cups_globals_t *cg = _cupsGlobals();
03f61bf3 1944 /* Global data */
2b85e375 1945
1946
79f448f9 1947 /*
031278ca 1948 * Set the line number to 0...
79f448f9 1949 */
1950
03f61bf3 1951 cg->ppd_line = 0;
79f448f9 1952
2b85e375 1953 /*
1954 * Range check input...
1955 */
1956
1957 if (filename == NULL)
79f448f9 1958 {
03f61bf3 1959 cg->ppd_status = PPD_NULL_FILE;
79f448f9 1960
2b85e375 1961 return (NULL);
79f448f9 1962 }
2b85e375 1963
1964 /*
1965 * Try to open the file and parse it...
1966 */
1967
03f61bf3 1968 if ((fp = cupsFileOpen(filename, "r")) != NULL)
2b85e375 1969 {
03f61bf3 1970 ppd = ppdOpen2(fp);
2b85e375 1971
03f61bf3 1972 cupsFileClose(fp);
2b85e375 1973 }
1974 else
79f448f9 1975 {
03f61bf3 1976 cg->ppd_status = PPD_FILE_OPEN_ERROR;
1977 ppd = NULL;
79f448f9 1978 }
2b85e375 1979
1fdc6cd5 1980 return (ppd);
1981}
1982
1983
49de8bd2 1984/*
1985 * 'ppdSetConformance()' - Set the conformance level for PPD files.
0341722a 1986 *
1987 * @since CUPS 1.1.20@
49de8bd2 1988 */
1989
1990void
1991ppdSetConformance(ppd_conform_t c) /* I - Conformance level */
1992{
2625096f 1993 _cups_globals_t *cg = _cupsGlobals();
03f61bf3 1994 /* Global data */
1995
1996
1997 cg->ppd_conform = c;
49de8bd2 1998}
1999
2000
1fdc6cd5 2001/*
2002 * 'ppd_add_attr()' - Add an attribute to the PPD data.
2003 */
2004
2005static ppd_attr_t * /* O - New attribute */
2006ppd_add_attr(ppd_file_t *ppd, /* I - PPD file data */
2007 const char *name, /* I - Attribute name */
2008 const char *spec, /* I - Specifier string, if any */
1b98ab76 2009 const char *text, /* I - Text string, if any */
1fdc6cd5 2010 const char *value) /* I - Value of attribute */
2011{
2012 ppd_attr_t **ptr, /* New array */
2013 *temp; /* New attribute */
2014
2015
2016 /*
2017 * Range check input...
2018 */
2019
2020 if (ppd == NULL || name == NULL || spec == NULL)
2021 return (NULL);
2022
91ac93ad 2023 /*
2024 * Create the array as needed...
2025 */
2026
2027 if (!ppd->sorted_attrs)
2028 ppd->sorted_attrs = cupsArrayNew((cups_array_func_t)ppd_compare_attrs,
2029 NULL);
2030
1fdc6cd5 2031 /*
2032 * Allocate memory for the new attribute...
2033 */
2034
2035 if (ppd->num_attrs == 0)
2036 ptr = malloc(sizeof(ppd_attr_t *));
2037 else
2038 ptr = realloc(ppd->attrs, (ppd->num_attrs + 1) * sizeof(ppd_attr_t *));
2039
2040 if (ptr == NULL)
2041 return (NULL);
2042
2043 ppd->attrs = ptr;
2044 ptr += ppd->num_attrs;
2045
2046 if ((temp = calloc(1, sizeof(ppd_attr_t))) == NULL)
2047 return (NULL);
2048
2049 *ptr = temp;
2050
2051 ppd->num_attrs ++;
2052
2053 /*
2054 * Copy data over...
2055 */
2056
2057 strlcpy(temp->name, name, sizeof(temp->name));
2058 strlcpy(temp->spec, spec, sizeof(temp->spec));
1b98ab76 2059 strlcpy(temp->text, text, sizeof(temp->text));
1fdc6cd5 2060 temp->value = (char *)value;
2061
91ac93ad 2062 /*
2063 * Add the attribute to the sorted array...
2064 */
2065
2066 cupsArrayAdd(ppd->sorted_attrs, temp);
2067
1fdc6cd5 2068 /*
2069 * Return the attribute...
2070 */
2071
2072 return (temp);
2073}
2074
2075
2076/*
2077 * 'ppd_add_choice()' - Add a choice to an option.
2078 */
2079
2080static ppd_choice_t * /* O - Named choice */
2081ppd_add_choice(ppd_option_t *option, /* I - Option */
2082 const char *name) /* I - Name of choice */
2083{
2084 ppd_choice_t *choice; /* Choice */
2085
2086
2087 if (option->num_choices == 0)
2088 choice = malloc(sizeof(ppd_choice_t));
2089 else
2090 choice = realloc(option->choices,
2091 sizeof(ppd_choice_t) * (option->num_choices + 1));
2092
2093 if (choice == NULL)
2094 return (NULL);
2095
2096 option->choices = choice;
2097 choice += option->num_choices;
2098 option->num_choices ++;
2099
2100 memset(choice, 0, sizeof(ppd_choice_t));
2101 strlcpy(choice->choice, name, sizeof(choice->choice));
2102
2103 return (choice);
2104}
2105
2106
2107/*
2108 * 'ppd_add_size()' - Add a page size.
2109 */
2110
2111static ppd_size_t * /* O - Named size */
2112ppd_add_size(ppd_file_t *ppd, /* I - PPD file */
2113 const char *name) /* I - Name of size */
2114{
2115 ppd_size_t *size; /* Size */
2116
2117
2118 if (ppd->num_sizes == 0)
2119 size = malloc(sizeof(ppd_size_t));
2120 else
2121 size = realloc(ppd->sizes, sizeof(ppd_size_t) * (ppd->num_sizes + 1));
2122
2123 if (size == NULL)
2124 return (NULL);
2125
2126 ppd->sizes = size;
2127 size += ppd->num_sizes;
2128 ppd->num_sizes ++;
2129
2130 memset(size, 0, sizeof(ppd_size_t));
2131 strlcpy(size->name, name, sizeof(size->name));
2132
2133 return (size);
2134}
2135
2136
91ac93ad 2137/*
2138 * 'ppd_compare_attrs()' - Compare two attributes.
2139 */
2140
2141static int /* O - Result of comparison */
2142ppd_compare_attrs(ppd_attr_t *a, /* I - First attribute */
2143 ppd_attr_t *b) /* I - Second attribute */
2144{
2145 int ret; /* Result of comparison */
2146
2147
2148 if ((ret = strcasecmp(a->name, b->name)) != 0)
2149 return (ret);
91ac93ad 2150 else
51c4a398 2151 return (strcasecmp(a->spec, b->spec));
91ac93ad 2152}
2153
2154
1fdc6cd5 2155/*
ff6a82d3 2156 * 'ppd_compare_coptions()' - Compare two custom options.
2157 */
2158
2159static int /* O - Result of comparison */
2160ppd_compare_coptions(ppd_coption_t *a, /* I - First option */
2161 ppd_coption_t *b) /* I - Second option */
2162{
2163 return (strcasecmp(a->keyword, b->keyword));
2164}
2165
2166
2167/*
2168 * 'ppd_compare_cparams()' - Compare two custom parameters.
1fdc6cd5 2169 */
2170
2171static int /* O - Result of comparison */
ff6a82d3 2172ppd_compare_cparams(ppd_cparam_t *a, /* I - First parameter */
2173 ppd_cparam_t *b) /* I - Second parameter */
1fdc6cd5 2174{
ff6a82d3 2175 return (strcasecmp(a->name, b->name));
1fdc6cd5 2176}
2177
2178
2179/*
2180 * 'ppd_compare_options()' - Compare two options.
2181 */
2182
2183static int /* O - Result of comparison */
ff6a82d3 2184ppd_compare_options(ppd_option_t *a, /* I - First option */
2185 ppd_option_t *b) /* I - Second option */
1fdc6cd5 2186{
ff6a82d3 2187 return (strcasecmp(a->keyword, b->keyword));
1fdc6cd5 2188}
2189
2190
2191/*
2192 * 'ppd_decode()' - Decode a string value...
2193 */
2194
0ca3829c 2195static int /* O - Length of decoded string */
1fdc6cd5 2196ppd_decode(char *string) /* I - String to decode */
2197{
2198 char *inptr, /* Input pointer */
2199 *outptr; /* Output pointer */
2200
2201
2202 inptr = string;
2203 outptr = string;
2204
2205 while (*inptr != '\0')
64bbab09 2206 if (*inptr == '<' && isxdigit(inptr[1] & 255))
1fdc6cd5 2207 {
2208 /*
2209 * Convert hex to 8-bit values...
2210 */
2211
2212 inptr ++;
64bbab09 2213 while (isxdigit(*inptr & 255))
1fdc6cd5 2214 {
2215 if (isalpha(*inptr))
2216 *outptr = (tolower(*inptr) - 'a' + 10) << 4;
2217 else
2218 *outptr = (*inptr - '0') << 4;
2219
2220 inptr ++;
2221
64bbab09 2222 if (!isxdigit(*inptr & 255))
2223 break;
2224
1fdc6cd5 2225 if (isalpha(*inptr))
2226 *outptr |= tolower(*inptr) - 'a' + 10;
2227 else
2228 *outptr |= *inptr - '0';
2229
2230 inptr ++;
2231 outptr ++;
2232 }
2233
2234 while (*inptr != '>' && *inptr != '\0')
2235 inptr ++;
2236 while (*inptr == '>')
2237 inptr ++;
2238 }
2239 else
2240 *outptr++ = *inptr++;
2241
2242 *outptr = '\0';
0ca3829c 2243
b296d7d9 2244 return ((int)(outptr - string));
1fdc6cd5 2245}
2246
2247
15166848 2248/*
1fdc6cd5 2249 * 'ppd_free_group()' - Free a single UI group.
15166848 2250 */
2251
1fdc6cd5 2252static void
2253ppd_free_group(ppd_group_t *group) /* I - Group to free */
15166848 2254{
1fdc6cd5 2255 int i; /* Looping var */
2256 ppd_option_t *option; /* Current option */
2257 ppd_group_t *subgroup; /* Current sub-group */
15166848 2258
15166848 2259
1fdc6cd5 2260 if (group->num_options > 0)
15166848 2261 {
1fdc6cd5 2262 for (i = group->num_options, option = group->options;
2263 i > 0;
2264 i --, option ++)
2265 ppd_free_option(option);
15166848 2266
1fdc6cd5 2267 ppd_free(group->options);
15166848 2268 }
2269
1fdc6cd5 2270 if (group->num_subgroups > 0)
2271 {
2272 for (i = group->num_subgroups, subgroup = group->subgroups;
2273 i > 0;
2274 i --, subgroup ++)
2275 ppd_free_group(subgroup);
15166848 2276
1fdc6cd5 2277 ppd_free(group->subgroups);
2278 }
15166848 2279}
2280
2281
caab0820 2282/*
1fdc6cd5 2283 * 'ppd_free_option()' - Free a single option.
caab0820 2284 */
2285
1fdc6cd5 2286static void
2287ppd_free_option(ppd_option_t *option) /* I - Option to free */
caab0820 2288{
1fdc6cd5 2289 int i; /* Looping var */
2290 ppd_choice_t *choice; /* Current choice */
caab0820 2291
2292
1fdc6cd5 2293 if (option->num_choices > 0)
2294 {
2295 for (i = option->num_choices, choice = option->choices;
2296 i > 0;
2297 i --, choice ++)
ff40b65e 2298 {
1fdc6cd5 2299 ppd_free(choice->code);
ff40b65e 2300 }
caab0820 2301
1fdc6cd5 2302 ppd_free(option->choices);
2303 }
caab0820 2304}
2305
2306
239e58b6 2307/*
ff6a82d3 2308 * 'ppd_get_coption()' - Get a custom option record.
239e58b6 2309 */
2310
ff6a82d3 2311static ppd_coption_t * /* O - Custom option... */
2312ppd_get_coption(ppd_file_t *ppd, /* I - PPD file */
2313 const char *name) /* I - Name of option */
239e58b6 2314{
ff6a82d3 2315 ppd_coption_t *copt; /* New custom option */
1fdc6cd5 2316
239e58b6 2317
1fdc6cd5 2318 /*
2319 * See if the option already exists...
2320 */
2321
ff6a82d3 2322 if ((copt = ppdFindCustomOption(ppd, name)) != NULL)
2323 return (copt);
239e58b6 2324
2325 /*
ff6a82d3 2326 * Not found, so create the custom option record...
239e58b6 2327 */
2328
ff6a82d3 2329 if ((copt = calloc(1, sizeof(ppd_coption_t))) == NULL)
239e58b6 2330 return (NULL);
2331
ff6a82d3 2332 strlcpy(copt->keyword, name, sizeof(copt->keyword));
239e58b6 2333
ff6a82d3 2334 copt->params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL);
239e58b6 2335
b9e18094 2336 cupsArrayAdd(ppd->coptions, copt);
2337
239e58b6 2338 /*
2339 * Return the new record...
2340 */
2341
ff6a82d3 2342 return (copt);
239e58b6 2343}
2344
2345
ab94f399 2346/*
ff6a82d3 2347 * 'ppd_get_cparam()' - Get a custom parameter record.
ab94f399 2348 */
2349
ff6a82d3 2350static ppd_cparam_t * /* O - Extended option... */
2351ppd_get_cparam(ppd_coption_t *opt, /* I - PPD file */
2352 const char *param, /* I - Name of parameter */
2353 const char *text) /* I - Human-readable text */
ab94f399 2354{
ff6a82d3 2355 ppd_cparam_t *cparam; /* New custom parameter */
ab94f399 2356
2357
2358 /*
2359 * See if the parameter already exists...
2360 */
2361
ff6a82d3 2362 if ((cparam = ppdFindCustomParam(opt, param)) != NULL)
2363 return (cparam);
ab94f399 2364
2365 /*
ff6a82d3 2366 * Not found, so create the custom parameter record...
ab94f399 2367 */
2368
ff6a82d3 2369 if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL)
ab94f399 2370 return (NULL);
2371
ff6a82d3 2372 strlcpy(cparam->name, param, sizeof(cparam->name));
2373 strlcpy(cparam->text, text, sizeof(cparam->text));
ab94f399 2374
2375 /*
ff6a82d3 2376 * Add this record to the array...
ab94f399 2377 */
2378
ff6a82d3 2379 cupsArrayAdd(opt->params, cparam);
ab94f399 2380
2381 /*
2382 * Return the new record...
2383 */
2384
ff6a82d3 2385 return (cparam);
ab94f399 2386}
2387
2388
1fdc6cd5 2389/*
2390 * 'ppd_get_group()' - Find or create the named group as needed.
2391 */
2392
2393static ppd_group_t * /* O - Named group */
ed04873a 2394ppd_get_group(ppd_file_t *ppd, /* I - PPD file */
2395 const char *name, /* I - Name of group */
2396 const char *text, /* I - Text for group */
2397 _cups_globals_t *cg, /* I - Global data */
2398 cups_encoding_t encoding) /* I - Encoding of text */
1fdc6cd5 2399{
2400 int i; /* Looping var */
2401 ppd_group_t *group; /* Group */
2402
2403
03f61bf3 2404 DEBUG_printf(("ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)\n",
2405 ppd, name, text, cg));
1fdc6cd5 2406
2407 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
a501ad17 2408 if (!strcmp(group->name, name))
1fdc6cd5 2409 break;
2410
2411 if (i == 0)
2412 {
2413 DEBUG_printf(("Adding group %s...\n", name));
2414
03f61bf3 2415 if (cg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
6f83172d 2416 {
03f61bf3 2417 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
6f83172d 2418
2419 return (NULL);
2420 }
2421
1fdc6cd5 2422 if (ppd->num_groups == 0)
2423 group = malloc(sizeof(ppd_group_t));
2424 else
2425 group = realloc(ppd->groups,
2426 (ppd->num_groups + 1) * sizeof(ppd_group_t));
2427
2428 if (group == NULL)
6f83172d 2429 {
03f61bf3 2430 cg->ppd_status = PPD_ALLOC_ERROR;
6f83172d 2431
1fdc6cd5 2432 return (NULL);
6f83172d 2433 }
1fdc6cd5 2434
2435 ppd->groups = group;
2436 group += ppd->num_groups;
2437 ppd->num_groups ++;
2438
2439 memset(group, 0, sizeof(ppd_group_t));
2440 strlcpy(group->name, name, sizeof(group->name));
ed04873a 2441
8c4a3f1a 2442 cupsCharsetToUTF8((cups_utf8_t *)group->text, text,
2443 sizeof(group->text), encoding);
1fdc6cd5 2444 }
2445
2446 return (group);
2447}
2448
2449
2450/*
2451 * 'ppd_get_option()' - Find or create the named option as needed.
2452 */
2453
2454static ppd_option_t * /* O - Named option */
2455ppd_get_option(ppd_group_t *group, /* I - Group */
2456 const char *name) /* I - Name of option */
2457{
2458 int i; /* Looping var */
2459 ppd_option_t *option; /* Option */
2460
2461
fd8e0b1e 2462 DEBUG_printf(("ppd_get_option(group=%p(\"%s\"), name=\"%s\")\n",
2463 group, group->name, name));
2464
1fdc6cd5 2465 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
a501ad17 2466 if (!strcmp(option->keyword, name))
1fdc6cd5 2467 break;
2468
2469 if (i == 0)
2470 {
2471 if (group->num_options == 0)
2472 option = malloc(sizeof(ppd_option_t));
2473 else
2474 option = realloc(group->options,
2475 (group->num_options + 1) * sizeof(ppd_option_t));
2476
2477 if (option == NULL)
2478 return (NULL);
2479
2480 group->options = option;
2481 option += group->num_options;
2482 group->num_options ++;
2483
2484 memset(option, 0, sizeof(ppd_option_t));
2485 strlcpy(option->keyword, name, sizeof(option->keyword));
2486 }
2487
2488 return (option);
2489}
2490
2491
2b85e375 2492/*
2493 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2494 * necessary.
2495 */
2496
1fdc6cd5 2497static int /* O - Bitmask of fields read */
03f61bf3 2498ppd_read(cups_file_t *fp, /* I - File to read from */
2499 char *keyword, /* O - Keyword from line */
2500 char *option, /* O - Option from line */
2501 char *text, /* O - Human-readable text from line */
2502 char **string, /* O - Code/string data */
2503 int ignoreblank, /* I - Ignore blank lines? */
2625096f 2504 _cups_globals_t *cg) /* I - Global data */
2b85e375 2505{
1fdc6cd5 2506 int ch, /* Character from file */
43cd52be 2507 col, /* Column in line */
1fdc6cd5 2508 colon, /* Colon seen? */
2509 endquote, /* Waiting for an end quote */
eb885f10 2510 mask, /* Mask to be returned */
0ca3829c 2511 startline, /* Start line */
2512 textlen; /* Length of text */
1fdc6cd5 2513 char *keyptr, /* Keyword pointer */
2514 *optptr, /* Option pointer */
2515 *textptr, /* Text pointer */
2516 *strptr, /* Pointer into string */
2517 *lineptr, /* Current position in line buffer */
5215179e 2518 *line; /* Line buffer */
2519 int linesize; /* Current size of line buffer */
2b85e375 2520
2521 /*
2522 * Range check everything...
2523 */
2524
08379093 2525 if (!fp || !keyword || !option || !text || !string)
2b85e375 2526 return (0);
2527
2528 /*
2529 * Now loop until we have a valid line...
2530 */
2531
eb885f10 2532 *string = NULL;
2533 col = 0;
03f61bf3 2534 startline = cg->ppd_line + 1;
5215179e 2535 linesize = 1024;
2536 line = malloc(linesize);
2537
2538 if (!line)
2539 return (0);
c5b83b99 2540
2b85e375 2541 do
2542 {
2543 /*
2544 * Read the line...
2545 */
2546
2547 lineptr = line;
2548 endquote = 0;
753453e4 2549 colon = 0;
2b85e375 2550
5215179e 2551 while ((ch = cupsFileGetChar(fp)) != EOF)
2b85e375 2552 {
5215179e 2553 if (lineptr >= (line + linesize - 1))
2554 {
2555 /*
2556 * Expand the line buffer...
2557 */
2558
2559 char *temp; /* Temporary line pointer */
2560
2561
2562 linesize += 1024;
2563 if (linesize > 262144)
2564 {
2565 /*
2566 * Don't allow lines longer than 256k!
2567 */
2568
03f61bf3 2569 cg->ppd_line = startline;
2570 cg->ppd_status = PPD_LINE_TOO_LONG;
5215179e 2571
2572 free(line);
2573
2574 return (0);
2575 }
2576
2577 temp = realloc(line, linesize);
2578 if (!temp)
2579 {
03f61bf3 2580 cg->ppd_line = startline;
2581 cg->ppd_status = PPD_LINE_TOO_LONG;
5215179e 2582
2583 free(line);
2584
2585 return (0);
2586 }
2587
2588 lineptr = temp + (lineptr - line);
2589 line = temp;
2590 }
2591
2b85e375 2592 if (ch == '\r' || ch == '\n')
2593 {
2594 /*
2595 * Line feed or carriage return...
2596 */
2597
03f61bf3 2598 cg->ppd_line ++;
43cd52be 2599 col = 0;
79f448f9 2600
2b85e375 2601 if (ch == '\r')
2602 {
2603 /*
2604 * Check for a trailing line feed...
2605 */
2606
08379093 2607 if ((ch = cupsFilePeekChar(fp)) == EOF)
b0a98a63 2608 {
2609 ch = '\n';
2b85e375 2610 break;
b0a98a63 2611 }
2612
08379093 2613 if (ch == 0x0a)
2614 cupsFileGetChar(fp);
e8fda7b9 2615 }
2b85e375 2616
60dc191d 2617 if (lineptr == line && ignoreblank)
2618 continue; /* Skip blank lines */
e7186d00 2619
c5b83b99 2620 ch = '\n';
2b85e375 2621
2622 if (!endquote) /* Continue for multi-line text */
2623 break;
c5b83b99 2624
2625 *lineptr++ = '\n';
2b85e375 2626 }
03f61bf3 2627 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
43cd52be 2628 {
2629 /*
2630 * Other control characters...
2631 */
2632
03f61bf3 2633 cg->ppd_line = startline;
2634 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
43cd52be 2635
5215179e 2636 free(line);
2637
43cd52be 2638 return (0);
2639 }
974d95a1 2640 else if (ch != 0x1a)
2b85e375 2641 {
2642 /*
2643 * Any other character...
2644 */
2645
2646 *lineptr++ = ch;
43cd52be 2647 col ++;
2648
2649 if (col > (PPD_MAX_LINE - 1))
2650 {
2651 /*
2652 * Line is too long...
2653 */
2654
03f61bf3 2655 cg->ppd_line = startline;
2656 cg->ppd_status = PPD_LINE_TOO_LONG;
43cd52be 2657
5215179e 2658 free(line);
2659
43cd52be 2660 return (0);
2661 }
2b85e375 2662
0203af93 2663 if (ch == ':' && strncmp(line, "*%", 2) != 0)
753453e4 2664 colon = 1;
2665
2666 if (ch == '\"' && colon)
132e0c72 2667 endquote = !endquote;
e8fda7b9 2668 }
2669 }
2b85e375 2670
c5b83b99 2671 if (endquote)
2672 {
2673 /*
2674 * Didn't finish this quoted string...
2675 */
2676
08379093 2677 while ((ch = cupsFileGetChar(fp)) != EOF)
c5b83b99 2678 if (ch == '\"')
2679 break;
43cd52be 2680 else if (ch == '\r' || ch == '\n')
2681 {
03f61bf3 2682 cg->ppd_line ++;
43cd52be 2683 col = 0;
2684
2685 if (ch == '\r')
2686 {
2687 /*
2688 * Check for a trailing line feed...
2689 */
2690
08379093 2691 if ((ch = cupsFilePeekChar(fp)) == EOF)
43cd52be 2692 break;
08379093 2693 if (ch == 0x0a)
2694 cupsFileGetChar(fp);
43cd52be 2695 }
2696
2697 ch = '\n';
2698 }
03f61bf3 2699 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
43cd52be 2700 {
2701 /*
2702 * Other control characters...
2703 */
2704
03f61bf3 2705 cg->ppd_line = startline;
2706 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
43cd52be 2707
5215179e 2708 free(line);
2709
43cd52be 2710 return (0);
2711 }
974d95a1 2712 else if (ch != 0x1a)
43cd52be 2713 {
2714 col ++;
2715
2716 if (col > (PPD_MAX_LINE - 1))
2717 {
2718 /*
2719 * Line is too long...
2720 */
2721
03f61bf3 2722 cg->ppd_line = startline;
2723 cg->ppd_status = PPD_LINE_TOO_LONG;
43cd52be 2724
5215179e 2725 free(line);
2726
43cd52be 2727 return (0);
2728 }
2729 }
c5b83b99 2730 }
2731
2732 if (ch != '\n')
2733 {
2734 /*
2735 * Didn't finish this line...
2736 */
2737
08379093 2738 while ((ch = cupsFileGetChar(fp)) != EOF)
c5b83b99 2739 if (ch == '\r' || ch == '\n')
2740 {
2741 /*
2742 * Line feed or carriage return...
2743 */
2744
03f61bf3 2745 cg->ppd_line ++;
43cd52be 2746 col = 0;
031278ca 2747
c5b83b99 2748 if (ch == '\r')
2749 {
2750 /*
2751 * Check for a trailing line feed...
2752 */
2753
08379093 2754 if ((ch = cupsFilePeekChar(fp)) == EOF)
c5b83b99 2755 break;
08379093 2756 if (ch == 0x0a)
2757 cupsFileGetChar(fp);
c5b83b99 2758 }
2759
2760 break;
2761 }
03f61bf3 2762 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
43cd52be 2763 {
2764 /*
2765 * Other control characters...
2766 */
2767
03f61bf3 2768 cg->ppd_line = startline;
2769 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
43cd52be 2770
5215179e 2771 free(line);
2772
43cd52be 2773 return (0);
2774 }
974d95a1 2775 else if (ch != 0x1a)
43cd52be 2776 {
2777 col ++;
2778
2779 if (col > (PPD_MAX_LINE - 1))
2780 {
2781 /*
2782 * Line is too long...
2783 */
2784
03f61bf3 2785 cg->ppd_line = startline;
2786 cg->ppd_status = PPD_LINE_TOO_LONG;
43cd52be 2787
5215179e 2788 free(line);
2789
43cd52be 2790 return (0);
2791 }
2792 }
c5b83b99 2793 }
2794
2b85e375 2795 if (lineptr > line && lineptr[-1] == '\n')
2796 lineptr --;
2797
2798 *lineptr = '\0';
2799
60dc191d 2800 DEBUG_printf(("LINE = \"%s\"\n", line));
753453e4 2801
91ac93ad 2802 /*
2803 * The dynamically created PPDs for older style Mac OS X
2804 * drivers include a large blob of data inserted as comments
2805 * at the end of the file. As an optimization we can stop
2806 * reading the PPD when we get to the start of this data.
2807 */
2808
2809 if (!strcmp(line, "*%APLWORKSET START"))
2810 {
2811 free(line);
2812 return (0);
2813 }
2814
2b85e375 2815 if (ch == EOF && lineptr == line)
5215179e 2816 {
2817 free(line);
2b85e375 2818 return (0);
5215179e 2819 }
2b85e375 2820
2821 /*
2822 * Now parse it...
2823 */
2824
2825 mask = 0;
2826 lineptr = line + 1;
2827
2828 keyword[0] = '\0';
2829 option[0] = '\0';
2830 text[0] = '\0';
2831 *string = NULL;
2832
60dc191d 2833 if ((!line[0] || /* Blank line */
a501ad17 2834 !strncmp(line, "*%", 2) || /* Comment line */
2835 !strcmp(line, "*End")) && /* End of multi-line string */
60dc191d 2836 ignoreblank) /* Ignore these? */
eb885f10 2837 {
03f61bf3 2838 startline = cg->ppd_line + 1;
2b85e375 2839 continue;
eb885f10 2840 }
2b85e375 2841
a501ad17 2842 if (!strcmp(line, "*")) /* (Bad) comment line */
49de8bd2 2843 {
03f61bf3 2844 if (cg->ppd_conform == PPD_CONFORM_RELAXED)
49de8bd2 2845 {
03f61bf3 2846 startline = cg->ppd_line + 1;
49de8bd2 2847 continue;
2848 }
2849 else
2850 {
03f61bf3 2851 cg->ppd_line = startline;
2852 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
49de8bd2 2853
5215179e 2854 free(line);
49de8bd2 2855 return (0);
2856 }
2857 }
2858
43cd52be 2859 if (line[0] != '*') /* All lines start with an asterisk */
2860 {
b96c21b1 2861 /*
2862 * Allow lines consisting of just whitespace...
2863 */
2864
2865 for (lineptr = line; *lineptr; lineptr ++)
64bbab09 2866 if (!isspace(*lineptr & 255))
b96c21b1 2867 break;
2868
2869 if (*lineptr)
2870 {
03f61bf3 2871 cg->ppd_status = PPD_MISSING_ASTERISK;
5215179e 2872 free(line);
b96c21b1 2873 return (0);
2874 }
60dc191d 2875 else if (ignoreblank)
b96c21b1 2876 continue;
60dc191d 2877 else
5215179e 2878 {
2879 free(line);
60dc191d 2880 return (0);
5215179e 2881 }
43cd52be 2882 }
2883
2b85e375 2884 /*
2885 * Get a keyword...
2886 */
2887
2888 keyptr = keyword;
2889
64bbab09 2890 while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr & 255))
43cd52be 2891 {
2892 if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
2893 (keyptr - keyword) >= (PPD_MAX_NAME - 1))
2894 {
03f61bf3 2895 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
5215179e 2896 free(line);
43cd52be 2897 return (0);
2898 }
2899
2900 *keyptr++ = *lineptr++;
2901 }
2b85e375 2902
2903 *keyptr = '\0';
753453e4 2904
a501ad17 2905 if (!strcmp(keyword, "End"))
753453e4 2906 continue;
2907
2b85e375 2908 mask |= PPD_KEYWORD;
2909
753453e4 2910/* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
2911
64bbab09 2912 if (isspace(*lineptr & 255))
2b85e375 2913 {
2914 /*
2915 * Get an option name...
2916 */
2917
64bbab09 2918 while (isspace(*lineptr & 255))
2b85e375 2919 lineptr ++;
2920
2921 optptr = option;
2922
64bbab09 2923 while (*lineptr != '\0' && !isspace(*lineptr & 255) && *lineptr != ':' &&
43cd52be 2924 *lineptr != '/')
2925 {
2926 if (*lineptr <= ' ' || *lineptr > 126 ||
2927 (optptr - option) >= (PPD_MAX_NAME - 1))
2928 {
03f61bf3 2929 cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
5215179e 2930 free(line);
43cd52be 2931 return (0);
2932 }
2933
2934 *optptr++ = *lineptr++;
2935 }
2b85e375 2936
2937 *optptr = '\0';
49de8bd2 2938
03f61bf3 2939 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
49de8bd2 2940 {
03f61bf3 2941 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
5215179e 2942 free(line);
49de8bd2 2943 return (0);
2944 }
2945
64bbab09 2946 while (isspace(*lineptr & 255))
9e678e84 2947 lineptr ++;
2948
2b85e375 2949 mask |= PPD_OPTION;
2950
753453e4 2951/* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
2952
2b85e375 2953 if (*lineptr == '/')
2954 {
2955 /*
2956 * Get human-readable text...
2957 */
2958
2959 lineptr ++;
2960
2961 textptr = text;
2962
43cd52be 2963 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
2964 {
974d95a1 2965 if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
43cd52be 2966 (textptr - text) >= (PPD_MAX_LINE - 1))
2967 {
03f61bf3 2968 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
5215179e 2969 free(line);
43cd52be 2970 return (0);
2971 }
2972
2973 *textptr++ = *lineptr++;
2974 }
2b85e375 2975
2976 *textptr = '\0';
0ca3829c 2977 textlen = ppd_decode(text);
2b85e375 2978
03f61bf3 2979 if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT)
0ca3829c 2980 {
03f61bf3 2981 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
5215179e 2982 free(line);
0ca3829c 2983 return (0);
2984 }
2985
2b85e375 2986 mask |= PPD_TEXT;
e8fda7b9 2987 }
753453e4 2988
2989/* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
e8fda7b9 2990 }
2b85e375 2991
03f61bf3 2992 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
49de8bd2 2993 {
03f61bf3 2994 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
5215179e 2995 free(line);
49de8bd2 2996 return (0);
2997 }
2998
64bbab09 2999 while (isspace(*lineptr & 255))
49de8bd2 3000 lineptr ++;
3001
2b85e375 3002 if (*lineptr == ':')
3003 {
3004 /*
e7186d00 3005 * Get string after triming leading and trailing whitespace...
2b85e375 3006 */
3007
49de8bd2 3008 lineptr ++;
64bbab09 3009 while (isspace(*lineptr & 255))
2b85e375 3010 lineptr ++;
3011
e2c9ebc5 3012 strptr = lineptr + strlen(lineptr) - 1;
64bbab09 3013 while (strptr >= lineptr && isspace(*strptr & 255))
e7186d00 3014 *strptr-- = '\0';
3015
2e8cd988 3016 if (*strptr == '\"')
3017 {
3018 /*
3019 * Quoted string by itself...
3020 */
3021
3022 *string = malloc(strlen(lineptr) + 1);
e7186d00 3023
2e8cd988 3024 strptr = *string;
2b85e375 3025
2e8cd988 3026 for (; *lineptr != '\0'; lineptr ++)
3027 if (*lineptr != '\"')
3028 *strptr++ = *lineptr;
2b85e375 3029
2e8cd988 3030 *strptr = '\0';
3031 }
3032 else
3033 *string = strdup(lineptr);
58ec2a95 3034
753453e4 3035/* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
3036
2b85e375 3037 mask |= PPD_STRING;
e8fda7b9 3038 }
2b85e375 3039 }
3040 while (mask == 0);
3041
5215179e 3042 free(line);
3043
2b85e375 3044 return (mask);
3045}
3046
3047
3048/*
b2e10895 3049 * End of "$Id$".
90a24de4 3050 */