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