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