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