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