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