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