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