]> 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/*
b423cd4c 2 * "$Id: ppd.c 5200 2006-02-28 00:10:32Z 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
b423cd4c 247 cupsArrayDelete(ppd->sorted_attrs);
248
fa73b229 249 /*
250 * Free custom options...
251 */
252
253 for (coption = (ppd_coption_t *)cupsArrayFirst(ppd->coptions);
254 coption;
255 coption = (ppd_coption_t *)cupsArrayNext(ppd->coptions))
ef416fc2 256 {
fa73b229 257 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
258 cparam;
259 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
ef416fc2 260 {
fa73b229 261 switch (cparam->type)
262 {
263 case PPD_CUSTOM_PASSCODE :
264 case PPD_CUSTOM_PASSWORD :
265 case PPD_CUSTOM_STRING :
266 ppd_free(cparam->current.custom_string);
fa73b229 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 else if (!strncmp(keyword, "ParamCustom", 11))
ef416fc2 836 {
fa73b229 837 ppd_coption_t *coption; /* Custom option */
838 ppd_cparam_t *cparam; /* Custom parameter */
839 int corder; /* Order number */
840 char ctype[33], /* Data type */
841 cminimum[65], /* Minimum value */
842 cmaximum[65]; /* Maximum value */
843
844
845 /*
846 * Get the custom option and parameter...
847 */
ef416fc2 848
fa73b229 849 if ((coption = ppd_get_coption(ppd, keyword + 11)) == NULL)
ef416fc2 850 {
fa73b229 851 cg->ppd_status = PPD_ALLOC_ERROR;
ef416fc2 852
fa73b229 853 goto error;
854 }
ef416fc2 855
fa73b229 856 if ((cparam = ppd_get_cparam(coption, name, text)) == NULL)
857 {
858 cg->ppd_status = PPD_ALLOC_ERROR;
ef416fc2 859
fa73b229 860 goto error;
861 }
862
863 /*
864 * Get the parameter data...
865 */
866
867 if (sscanf(string, "%d%32s%64s%64s", &corder, ctype, cminimum,
868 cmaximum) != 4)
869 {
870 cg->ppd_status = PPD_BAD_CUSTOM_PARAM;
871
872 goto error;
873 }
874
875 cparam->order = corder;
ef416fc2 876
fa73b229 877 if (!strcmp(ctype, "curve"))
878 {
879 cparam->type = PPD_CUSTOM_CURVE;
880 cparam->minimum.custom_curve = atof(cminimum);
881 cparam->maximum.custom_curve = atof(cmaximum);
882 }
883 else if (!strcmp(ctype, "int"))
884 {
885 cparam->type = PPD_CUSTOM_INT;
886 cparam->minimum.custom_int = atoi(cminimum);
887 cparam->maximum.custom_int = atoi(cmaximum);
888 }
889 else if (!strcmp(ctype, "invcurve"))
890 {
891 cparam->type = PPD_CUSTOM_INVCURVE;
892 cparam->minimum.custom_invcurve = atof(cminimum);
893 cparam->maximum.custom_invcurve = atof(cmaximum);
894 }
895 else if (!strcmp(ctype, "passcode"))
896 {
897 cparam->type = PPD_CUSTOM_PASSCODE;
b423cd4c 898 cparam->minimum.custom_passcode = atoi(cminimum);
899 cparam->maximum.custom_passcode = atoi(cmaximum);
fa73b229 900 }
901 else if (!strcmp(ctype, "password"))
902 {
903 cparam->type = PPD_CUSTOM_PASSWORD;
b423cd4c 904 cparam->minimum.custom_password = atoi(cminimum);
905 cparam->maximum.custom_password = atoi(cmaximum);
fa73b229 906 }
907 else if (!strcmp(ctype, "points"))
908 {
909 cparam->type = PPD_CUSTOM_POINTS;
910 cparam->minimum.custom_points = atof(cminimum);
911 cparam->maximum.custom_points = atof(cmaximum);
912 }
913 else if (!strcmp(ctype, "real"))
914 {
915 cparam->type = PPD_CUSTOM_REAL;
916 cparam->minimum.custom_real = atof(cminimum);
917 cparam->maximum.custom_real = atof(cmaximum);
918 }
919 else if (!strcmp(ctype, "string"))
920 {
921 cparam->type = PPD_CUSTOM_STRING;
b423cd4c 922 cparam->minimum.custom_string = atoi(cminimum);
923 cparam->maximum.custom_string = atoi(cmaximum);
fa73b229 924 }
925 else
926 {
927 cg->ppd_status = PPD_BAD_CUSTOM_PARAM;
928
929 goto error;
930 }
931
932 /*
933 * Now special-case for CustomPageSize...
934 */
935
936 if (!strcmp(coption->keyword, "PageSize"))
937 {
938 if (!strcmp(name, "Width"))
939 {
940 ppd->custom_min[0] = cparam->minimum.custom_points;
941 ppd->custom_max[0] = cparam->maximum.custom_points;
942 }
943 else if (!strcmp(name, "Height"))
ef416fc2 944 {
fa73b229 945 ppd->custom_min[1] = cparam->minimum.custom_points;
946 ppd->custom_max[1] = cparam->maximum.custom_points;
947 }
948 }
949 }
950 else if (!strcmp(keyword, "HWMargins"))
951 sscanf(string, "%f%f%f%f", ppd->custom_margins + 0,
952 ppd->custom_margins + 1, ppd->custom_margins + 2,
953 ppd->custom_margins + 3);
954 else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True"))
955 {
956 ppd_coption_t *coption; /* Custom option */
ef416fc2 957
958
fa73b229 959 DEBUG_puts("Processing Custom option...");
ef416fc2 960
fa73b229 961 /*
962 * Get the option and custom option...
963 */
ef416fc2 964
fa73b229 965 if ((option = ppdFindOption(ppd, keyword + 6)) == NULL)
966 {
967 ppd_group_t *gtemp; /* Temporary group */
ef416fc2 968
ef416fc2 969
fa73b229 970 DEBUG_printf(("%s option not found for %s...\n", keyword + 6, keyword));
ef416fc2 971
fa73b229 972 if ((gtemp = ppd_get_group(ppd, "General", _("General"), cg)) == NULL)
973 {
974 DEBUG_puts("Unable to get general group!");
ef416fc2 975
fa73b229 976 goto error;
977 }
978
979 if ((option = ppd_get_option(gtemp, keyword + 6)) == NULL)
ef416fc2 980 {
fa73b229 981 DEBUG_printf(("Unable to get %s option!\n", keyword + 6));
ef416fc2 982
983 cg->ppd_status = PPD_ALLOC_ERROR;
984
985 goto error;
986 }
ef416fc2 987 }
988
fa73b229 989 if ((coption = ppd_get_coption(ppd, keyword + 6)) == NULL)
ef416fc2 990 {
fa73b229 991 cg->ppd_status = PPD_ALLOC_ERROR;
ef416fc2 992
993 goto error;
994 }
995
fa73b229 996 /*
997 * Add the "custom" option...
998 */
999
1000 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
ef416fc2 1001 {
fa73b229 1002 DEBUG_puts("Unable to add Custom choice!");
ef416fc2 1003
fa73b229 1004 cg->ppd_status = PPD_ALLOC_ERROR;
ef416fc2 1005
1006 goto error;
1007 }
1008
fa73b229 1009 strlcpy(choice->text, text[0] ? text : _("Custom"),
1010 sizeof(choice->text));
1011
ef416fc2 1012 choice->code = string;
ef416fc2 1013 string = NULL; /* Don't add as an attribute below */
fa73b229 1014 option = NULL;
1015
1016 /*
1017 * Now process custom page sizes specially...
1018 */
1019
1020 if (!strcmp(keyword, "CustomPageSize"))
1021 {
1022 ppd->variable_sizes = 1;
1023
1024 /*
1025 * Add a "Custom" page size entry...
1026 */
1027
1028 ppd_add_size(ppd, "Custom");
1029 }
ef416fc2 1030 }
1031 else if (!strcmp(keyword, "LandscapeOrientation"))
1032 {
1033 if (!strcmp(string, "Minus90"))
1034 ppd->landscape = -90;
1035 else if (!strcmp(string, "Plus90"))
1036 ppd->landscape = 90;
1037 }
1038 else if (!strcmp(keyword, "Emulators"))
1039 {
1040 for (count = 1, sptr = string; sptr != NULL;)
1041 if ((sptr = strchr(sptr, ' ')) != NULL)
1042 {
1043 count ++;
1044 while (*sptr == ' ')
1045 sptr ++;
1046 }
1047
1048 ppd->num_emulations = count;
1049 ppd->emulations = calloc(count, sizeof(ppd_emul_t));
1050
1051 for (i = 0, sptr = string; i < count; i ++)
1052 {
1053 for (nameptr = ppd->emulations[i].name;
1054 *sptr != '\0' && *sptr != ' ';
1055 sptr ++)
1056 if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1))
1057 *nameptr++ = *sptr;
1058
1059 *nameptr = '\0';
1060
1061 while (*sptr == ' ')
1062 sptr ++;
1063 }
1064 }
1065 else if (!strncmp(keyword, "StartEmulator_", 14))
1066 {
1067 ppd_decode(string);
1068
1069 for (i = 0; i < ppd->num_emulations; i ++)
1070 if (!strcmp(keyword + 14, ppd->emulations[i].name))
1071 {
1072 ppd->emulations[i].start = string;
1073 string = NULL;
1074 }
1075 }
1076 else if (!strncmp(keyword, "StopEmulator_", 13))
1077 {
1078 ppd_decode(string);
1079
1080 for (i = 0; i < ppd->num_emulations; i ++)
1081 if (!strcmp(keyword + 13, ppd->emulations[i].name))
1082 {
1083 ppd->emulations[i].stop = string;
1084 string = NULL;
1085 }
1086 }
1087 else if (!strcmp(keyword, "JobPatchFile"))
1088 {
1089 if (ppd->patches == NULL)
1090 ppd->patches = strdup(string);
1091 else
1092 {
1093 temp = realloc(ppd->patches, strlen(ppd->patches) +
1094 strlen(string) + 1);
1095 if (temp == NULL)
1096 {
1097 cg->ppd_status = PPD_ALLOC_ERROR;
1098
1099 goto error;
1100 }
1101
1102 ppd->patches = temp;
1103
1104 strcpy(ppd->patches + strlen(ppd->patches), string);
1105 }
1106 }
1107 else if (!strcmp(keyword, "OpenUI"))
1108 {
1109 /*
1110 * Don't allow nesting of options...
1111 */
1112
1113 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
1114 {
1115 cg->ppd_status = PPD_NESTED_OPEN_UI;
1116
1117 goto error;
1118 }
1119
1120 /*
1121 * Add an option record to the current sub-group, group, or file...
1122 */
1123
1124 if (name[0] == '*')
1125 _cups_strcpy(name, name + 1); /* Eliminate leading asterisk */
1126
1127 for (i = (int)strlen(name) - 1; i > 0 && isspace(name[i] & 255); i --)
1128 name[i] = '\0'; /* Eliminate trailing spaces */
1129
1130 DEBUG_printf(("OpenUI of %s in group %s...\n", name,
1131 group ? group->text : "(null)"));
1132
1133 if (subgroup != NULL)
1134 option = ppd_get_option(subgroup, name);
1135 else if (group == NULL)
1136 {
bd7854cb 1137 if ((group = ppd_get_group(ppd, "General", _("General"), cg)) == NULL)
ef416fc2 1138 goto error;
1139
1140 DEBUG_printf(("Adding to group %s...\n", group->text));
1141 option = ppd_get_option(group, name);
1142 group = NULL;
1143 }
1144 else
1145 option = ppd_get_option(group, name);
1146
1147 if (option == NULL)
1148 {
1149 cg->ppd_status = PPD_ALLOC_ERROR;
1150
1151 goto error;
1152 }
1153
1154 /*
1155 * Now fill in the initial information for the option...
1156 */
1157
1158 if (string && !strcmp(string, "PickMany"))
1159 option->ui = PPD_UI_PICKMANY;
1160 else if (string && !strcmp(string, "Boolean"))
1161 option->ui = PPD_UI_BOOLEAN;
1162 else if (string && !strcmp(string, "PickOne"))
1163 option->ui = PPD_UI_PICKONE;
1164 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1165 {
1166 cg->ppd_status = PPD_BAD_OPEN_UI;
1167
1168 goto error;
1169 }
1170 else
1171 option->ui = PPD_UI_PICKONE;
1172
1173 for (j = 0; j < ppd->num_attrs; j ++)
1174 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
1175 !strcmp(ppd->attrs[j]->name + 7, name) &&
1176 ppd->attrs[j]->value)
1177 {
1178 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
1179 option->keyword, ppd->attrs[j]->value));
1180 strlcpy(option->defchoice, ppd->attrs[j]->value,
1181 sizeof(option->defchoice));
1182 break;
1183 }
1184
1185 if (text[0])
1186 strlcpy(option->text, text, sizeof(option->text));
1187 else
1188 {
1189 if (!strcmp(name, "PageSize"))
1190 strlcpy(option->text, _("Media Size"), sizeof(option->text));
1191 else if (!strcmp(name, "MediaType"))
1192 strlcpy(option->text, _("Media Type"), sizeof(option->text));
1193 else if (!strcmp(name, "InputSlot"))
1194 strlcpy(option->text, _("Media Source"), sizeof(option->text));
1195 else if (!strcmp(name, "ColorModel"))
1196 strlcpy(option->text, _("Output Mode"), sizeof(option->text));
1197 else if (!strcmp(name, "Resolution"))
1198 strlcpy(option->text, _("Resolution"), sizeof(option->text));
1199 else
1200 strlcpy(option->text, name, sizeof(option->text));
1201 }
1202
1203 option->section = PPD_ORDER_ANY;
1204
1205 ppd_free(string);
1206 string = NULL;
1207 }
1208 else if (!strcmp(keyword, "JCLOpenUI"))
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 * Find the JCL group, and add if needed...
1223 */
1224
fa73b229 1225 group = ppd_get_group(ppd, "JCL", _("JCL"), cg);
ef416fc2 1226
1227 if (group == NULL)
1228 goto error;
1229
1230 /*
1231 * Add an option record to the current JCLs...
1232 */
1233
1234 if (name[0] == '*')
1235 _cups_strcpy(name, name + 1);
1236
1237 option = ppd_get_option(group, name);
1238
1239 if (option == NULL)
1240 {
1241 cg->ppd_status = PPD_ALLOC_ERROR;
1242
1243 goto error;
1244 }
1245
1246 /*
1247 * Now fill in the initial information for the option...
1248 */
1249
1250 if (string && !strcmp(string, "PickMany"))
1251 option->ui = PPD_UI_PICKMANY;
1252 else if (string && !strcmp(string, "Boolean"))
1253 option->ui = PPD_UI_BOOLEAN;
1254 else if (string && !strcmp(string, "PickOne"))
1255 option->ui = PPD_UI_PICKONE;
1256 else
1257 {
1258 cg->ppd_status = PPD_BAD_OPEN_UI;
1259
1260 goto error;
1261 }
1262
1263 for (j = 0; j < ppd->num_attrs; j ++)
1264 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
1265 !strcmp(ppd->attrs[j]->name + 7, name) &&
1266 ppd->attrs[j]->value)
1267 {
1268 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
1269 option->keyword, ppd->attrs[j]->value));
1270 strlcpy(option->defchoice, ppd->attrs[j]->value,
1271 sizeof(option->defchoice));
1272 break;
1273 }
1274
1275 strlcpy(option->text, text, sizeof(option->text));
1276
1277 option->section = PPD_ORDER_JCL;
1278 group = NULL;
1279
1280 ppd_free(string);
1281 string = NULL;
1282 }
1283 else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI"))
1284 {
1285 option = NULL;
1286
1287 ppd_free(string);
1288 string = NULL;
1289 }
1290 else if (!strcmp(keyword, "OpenGroup"))
1291 {
1292 /*
1293 * Open a new group...
1294 */
1295
1296 if (group != NULL)
1297 {
1298 cg->ppd_status = PPD_NESTED_OPEN_GROUP;
1299
1300 goto error;
1301 }
1302
1303 if (!string)
1304 {
1305 cg->ppd_status = PPD_BAD_OPEN_GROUP;
1306
1307 goto error;
1308 }
1309
1310 /*
1311 * Separate the group name from the text (name/text)...
1312 */
1313
1314 if ((sptr = strchr(string, '/')) != NULL)
1315 *sptr++ = '\0';
1316 else
1317 sptr = string;
1318
1319 /*
1320 * Fix up the text...
1321 */
1322
1323 ppd_decode(sptr);
1324
1325 /*
1326 * Find/add the group...
1327 */
1328
1329 group = ppd_get_group(ppd, string, sptr, cg);
1330
1331 if (group == NULL)
1332 goto error;
1333
1334 ppd_free(string);
1335 string = NULL;
1336 }
1337 else if (!strcmp(keyword, "CloseGroup"))
1338 {
1339 group = NULL;
1340
1341 ppd_free(string);
1342 string = NULL;
1343 }
1344 else if (!strcmp(keyword, "OrderDependency") ||
1345 !strcmp(keyword, "NonUIOrderDependency"))
1346 {
1347 if (sscanf(string, "%f%40s%40s", &order, name, keyword) != 3)
1348 {
1349 cg->ppd_status = PPD_BAD_ORDER_DEPENDENCY;
1350
1351 goto error;
1352 }
1353
1354 if (keyword[0] == '*')
1355 _cups_strcpy(keyword, keyword + 1);
1356
1357 if (!strcmp(name, "ExitServer"))
1358 section = PPD_ORDER_EXIT;
1359 else if (!strcmp(name, "Prolog"))
1360 section = PPD_ORDER_PROLOG;
1361 else if (!strcmp(name, "DocumentSetup"))
1362 section = PPD_ORDER_DOCUMENT;
1363 else if (!strcmp(name, "PageSetup"))
1364 section = PPD_ORDER_PAGE;
1365 else if (!strcmp(name, "JCLSetup"))
1366 section = PPD_ORDER_JCL;
1367 else
1368 section = PPD_ORDER_ANY;
1369
1370 if (option == NULL)
1371 {
1372 ppd_group_t *gtemp;
1373
1374
1375 /*
1376 * Only valid for Non-UI options...
1377 */
1378
1379 for (i = ppd->num_groups, gtemp = ppd->groups; i > 0; i --, gtemp ++)
1380 if (gtemp->text[0] == '\0')
1381 break;
1382
1383 if (i > 0)
1384 for (i = 0; i < gtemp->num_options; i ++)
1385 if (!strcmp(keyword, gtemp->options[i].keyword))
1386 {
1387 gtemp->options[i].section = section;
1388 gtemp->options[i].order = order;
1389 break;
1390 }
1391 }
1392 else
1393 {
1394 option->section = section;
1395 option->order = order;
1396 }
1397
1398 ppd_free(string);
1399 string = NULL;
1400 }
1401 else if (!strncmp(keyword, "Default", 7))
1402 {
1403 if (string == NULL)
1404 continue;
1405
1406 /*
1407 * Drop UI text, if any, from value...
1408 */
1409
1410 if (strchr(string, '/') != NULL)
1411 *strchr(string, '/') = '\0';
1412
1413 /*
1414 * Assign the default value as appropriate...
1415 */
1416
1417 if (!strcmp(keyword, "DefaultColorSpace"))
1418 {
1419 /*
1420 * Set default colorspace...
1421 */
1422
1423 if (!strcmp(string, "CMY"))
1424 ppd->colorspace = PPD_CS_CMY;
1425 else if (!strcmp(string, "CMYK"))
1426 ppd->colorspace = PPD_CS_CMYK;
1427 else if (!strcmp(string, "RGB"))
1428 ppd->colorspace = PPD_CS_RGB;
1429 else if (!strcmp(string, "RGBK"))
1430 ppd->colorspace = PPD_CS_RGBK;
1431 else if (!strcmp(string, "N"))
1432 ppd->colorspace = PPD_CS_N;
1433 else
1434 ppd->colorspace = PPD_CS_GRAY;
1435 }
1436 else if (option && !strcmp(keyword + 7, option->keyword))
1437 {
1438 /*
1439 * Set the default as part of the current option...
1440 */
1441
1442 DEBUG_printf(("Setting %s to %s...\n", keyword, string));
1443
1444 strlcpy(option->defchoice, string, sizeof(option->defchoice));
1445
1446 DEBUG_printf(("%s is now %s...\n", keyword, option->defchoice));
1447 }
1448 else
1449 {
1450 /*
1451 * Lookup option and set if it has been defined...
1452 */
1453
1454 ppd_option_t *toption; /* Temporary option */
1455
1456
1457 if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL)
1458 {
1459 DEBUG_printf(("Setting %s to %s...\n", keyword, string));
1460 strlcpy(toption->defchoice, string, sizeof(toption->defchoice));
1461 }
1462 }
1463 }
1464 else if (!strcmp(keyword, "UIConstraints") ||
1465 !strcmp(keyword, "NonUIConstraints"))
1466 {
1467 if (ppd->num_consts == 0)
1468 constraint = calloc(1, sizeof(ppd_const_t));
1469 else
1470 constraint = realloc(ppd->consts,
1471 (ppd->num_consts + 1) * sizeof(ppd_const_t));
1472
1473 if (constraint == NULL)
1474 {
1475 cg->ppd_status = PPD_ALLOC_ERROR;
1476
1477 goto error;
1478 }
1479
1480 ppd->consts = constraint;
1481 constraint += ppd->num_consts;
1482 ppd->num_consts ++;
1483
1484 switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1,
1485 constraint->choice1, constraint->option2,
1486 constraint->choice2))
1487 {
1488 case 0 : /* Error */
1489 case 1 : /* Error */
1490 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1491 goto error;
1492
1493 case 2 : /* Two options... */
1494 /*
1495 * The following strcpy's are safe, as optionN and
1496 * choiceN are all the same size (size defined by PPD spec...)
1497 */
1498
1499 if (constraint->option1[0] == '*')
1500 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1501
1502 if (constraint->choice1[0] == '*')
1503 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1504 else
1505 _cups_strcpy(constraint->option2, constraint->choice1);
1506
1507 constraint->choice1[0] = '\0';
1508 constraint->choice2[0] = '\0';
1509 break;
1510
1511 case 3 : /* Two options, one choice... */
1512 /*
1513 * The following _cups_strcpy's are safe, as optionN and
1514 * choiceN are all the same size (size defined by PPD spec...)
1515 */
1516
1517 if (constraint->option1[0] == '*')
1518 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1519
1520 if (constraint->choice1[0] == '*')
1521 {
1522 _cups_strcpy(constraint->choice2, constraint->option2);
1523 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1524 constraint->choice1[0] = '\0';
1525 }
1526 else
1527 {
1528 if (constraint->option2[0] == '*')
1529 _cups_strcpy(constraint->option2, constraint->option2 + 1);
1530
1531 constraint->choice2[0] = '\0';
1532 }
1533 break;
1534
1535 case 4 : /* Two options, two choices... */
1536 if (constraint->option1[0] == '*')
1537 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1538
1539 if (constraint->option2[0] == '*')
1540 _cups_strcpy(constraint->option2, constraint->option2 + 1);
1541 break;
1542 }
1543
1544 ppd_free(string);
1545 string = NULL;
1546 }
1547 else if (!strcmp(keyword, "PaperDimension"))
1548 {
1549 if ((size = ppdPageSize(ppd, name)) == NULL)
1550 size = ppd_add_size(ppd, name);
1551
1552 if (size == NULL)
1553 {
1554 /*
1555 * Unable to add or find size!
1556 */
1557
1558 cg->ppd_status = PPD_ALLOC_ERROR;
1559
1560 goto error;
1561 }
1562
1563 sscanf(string, "%f%f", &(size->width), &(size->length));
1564
1565 ppd_free(string);
1566 string = NULL;
1567 }
1568 else if (!strcmp(keyword, "ImageableArea"))
1569 {
1570 if ((size = ppdPageSize(ppd, name)) == NULL)
1571 size = ppd_add_size(ppd, name);
1572
1573 if (size == NULL)
1574 {
1575 /*
1576 * Unable to add or find size!
1577 */
1578
1579 cg->ppd_status = PPD_ALLOC_ERROR;
1580
1581 goto error;
1582 }
1583
1584 sscanf(string, "%f%f%f%f", &(size->left), &(size->bottom),
1585 &(size->right), &(size->top));
1586
1587 ppd_free(string);
1588 string = NULL;
1589 }
1590 else if (option != NULL &&
1591 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
1592 (PPD_KEYWORD | PPD_OPTION | PPD_STRING) &&
1593 !strcmp(keyword, option->keyword))
1594 {
1595 DEBUG_printf(("group = %p, subgroup = %p\n", group, subgroup));
1596
1597 if (!strcmp(keyword, "PageSize"))
1598 {
1599 /*
1600 * Add a page size...
1601 */
1602
1603 if (ppdPageSize(ppd, name) == NULL)
1604 ppd_add_size(ppd, name);
1605 }
1606
1607 /*
1608 * Add the option choice...
1609 */
1610
1611 choice = ppd_add_choice(option, name);
1612
1613 if (mask & PPD_TEXT)
1614 strlcpy(choice->text, text, sizeof(choice->text));
1615 else if (!strcmp(name, "True"))
1616 strcpy(choice->text, _("Yes"));
1617 else if (!strcmp(name, "False"))
1618 strcpy(choice->text, _("No"));
1619 else
1620 strlcpy(choice->text, name, sizeof(choice->text));
1621
1622 if (option->section == PPD_ORDER_JCL)
1623 ppd_decode(string); /* Decode quoted string */
1624
1625 choice->code = string;
1626 string = NULL; /* Don't add as an attribute below */
1627 }
ef416fc2 1628
1629 /*
1630 * Add remaining lines with keywords and string values as attributes...
1631 */
1632
1633 if (string &&
1634 (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
1635 ppd_add_attr(ppd, keyword, name, text, string);
1636 else
ef416fc2 1637 ppd_free(string);
ef416fc2 1638 }
1639
1640 /*
1641 * Reset language preferences...
1642 */
1643
1644 cupsLangFree(language);
1645
1646#ifdef LC_NUMERIC
1647 _cupsRestoreLocale(LC_NUMERIC, oldlocale);
1648#else
1649 _cupsRestoreLocale(LC_ALL, oldlocale);
1650#endif /* LC_NUMERIC */
1651
1652#ifdef DEBUG
1653 if (!feof(fp))
1654 printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp));
1655#endif /* DEBUG */
1656
1657 if (cg->ppd_status != PPD_OK)
1658 {
1659 /*
1660 * Had an error reading the PPD file, cannot continue!
1661 */
1662
1663 ppdClose(ppd);
1664
1665 return (NULL);
1666 }
1667
ef416fc2 1668 /*
fa73b229 1669 * Create the sorted options array and set the option back-pointer for
1670 * each choice and custom option...
ef416fc2 1671 */
1672
fa73b229 1673 ppd->options = cupsArrayNew((cups_array_func_t)ppd_compare_options, NULL);
ef416fc2 1674
1675 for (i = ppd->num_groups, group = ppd->groups;
1676 i > 0;
1677 i --, group ++)
1678 {
ef416fc2 1679 for (j = group->num_options, option = group->options;
1680 j > 0;
1681 j --, option ++)
1682 {
fa73b229 1683 ppd_coption_t *coption; /* Custom option */
ef416fc2 1684
ef416fc2 1685
fa73b229 1686 cupsArrayAdd(ppd->options, option);
ef416fc2 1687
fa73b229 1688 for (k = 0; k < option->num_choices; k ++)
1689 option->choices[k].option = option;
ef416fc2 1690
fa73b229 1691 if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
1692 coption->option = option;
1693 }
1694 }
ef416fc2 1695
ef416fc2 1696 /*
1697 * Return the PPD file structure...
1698 */
1699
1700 return (ppd);
1701
1702 /*
1703 * Common exit point for errors to save code size...
1704 */
1705
1706 error:
1707
1708 ppd_free(string);
1709
1710 ppdClose(ppd);
1711
1712 cupsLangFree(language);
1713
1714#ifdef LC_NUMERIC
1715 _cupsRestoreLocale(LC_NUMERIC, oldlocale);
1716#else
1717 _cupsRestoreLocale(LC_ALL, oldlocale);
1718#endif /* LC_NUMERIC */
1719
1720 return (NULL);
1721}
1722
1723
1724/*
1725 * 'ppdOpenFd()' - Read a PPD file into memory.
1726 */
1727
1728ppd_file_t * /* O - PPD file record */
1729ppdOpenFd(int fd) /* I - File to read from */
1730{
fa73b229 1731 cups_file_t *fp; /* CUPS file pointer */
ef416fc2 1732 ppd_file_t *ppd; /* PPD file record */
1733 _cups_globals_t *cg = _cupsGlobals();
1734 /* Global data */
1735
1736
1737 /*
1738 * Set the line number to 0...
1739 */
1740
1741 cg->ppd_line = 0;
1742
1743 /*
1744 * Range check input...
1745 */
1746
1747 if (fd < 0)
1748 {
1749 cg->ppd_status = PPD_NULL_FILE;
1750
1751 return (NULL);
1752 }
1753
1754 /*
1755 * Try to open the file and parse it...
1756 */
1757
fa73b229 1758 if ((fp = cupsFileOpenFd(fd, "r")) != NULL)
ef416fc2 1759 {
fa73b229 1760 ppd = ppdOpen2(fp);
ef416fc2 1761
fa73b229 1762 cupsFileClose(fp);
ef416fc2 1763 }
1764 else
1765 {
1766 cg->ppd_status = PPD_FILE_OPEN_ERROR;
fa73b229 1767 ppd = NULL;
ef416fc2 1768 }
1769
1770 return (ppd);
1771}
1772
1773
1774/*
1775 * 'ppdOpenFile()' - Read a PPD file into memory.
1776 */
1777
1778ppd_file_t * /* O - PPD file record */
1779ppdOpenFile(const char *filename) /* I - File to read from */
1780{
1781 cups_file_t *fp; /* File pointer */
1782 ppd_file_t *ppd; /* PPD file record */
1783 _cups_globals_t *cg = _cupsGlobals();
1784 /* Global data */
1785
1786
1787 /*
1788 * Set the line number to 0...
1789 */
1790
1791 cg->ppd_line = 0;
1792
1793 /*
1794 * Range check input...
1795 */
1796
1797 if (filename == NULL)
1798 {
1799 cg->ppd_status = PPD_NULL_FILE;
1800
1801 return (NULL);
1802 }
1803
1804 /*
1805 * Try to open the file and parse it...
1806 */
1807
1808 if ((fp = cupsFileOpen(filename, "r")) != NULL)
1809 {
1810 ppd = ppdOpen2(fp);
1811
1812 cupsFileClose(fp);
1813 }
1814 else
1815 {
1816 cg->ppd_status = PPD_FILE_OPEN_ERROR;
1817 ppd = NULL;
1818 }
1819
1820 return (ppd);
1821}
1822
1823
1824/*
1825 * 'ppdSetConformance()' - Set the conformance level for PPD files.
1826 *
1827 * @since CUPS 1.1.20@
1828 */
1829
1830void
1831ppdSetConformance(ppd_conform_t c) /* I - Conformance level */
1832{
1833 _cups_globals_t *cg = _cupsGlobals();
1834 /* Global data */
1835
1836
1837 cg->ppd_conform = c;
1838}
1839
1840
1841/*
1842 * 'ppd_add_attr()' - Add an attribute to the PPD data.
1843 */
1844
1845static ppd_attr_t * /* O - New attribute */
1846ppd_add_attr(ppd_file_t *ppd, /* I - PPD file data */
1847 const char *name, /* I - Attribute name */
1848 const char *spec, /* I - Specifier string, if any */
1849 const char *text, /* I - Text string, if any */
1850 const char *value) /* I - Value of attribute */
1851{
1852 ppd_attr_t **ptr, /* New array */
1853 *temp; /* New attribute */
1854
1855
1856 /*
1857 * Range check input...
1858 */
1859
1860 if (ppd == NULL || name == NULL || spec == NULL)
1861 return (NULL);
1862
bd7854cb 1863 /*
1864 * Create the array as needed...
1865 */
1866
1867 if (!ppd->sorted_attrs)
1868 ppd->sorted_attrs = cupsArrayNew((cups_array_func_t)ppd_compare_attrs,
1869 NULL);
1870
ef416fc2 1871 /*
1872 * Allocate memory for the new attribute...
1873 */
1874
1875 if (ppd->num_attrs == 0)
1876 ptr = malloc(sizeof(ppd_attr_t *));
1877 else
1878 ptr = realloc(ppd->attrs, (ppd->num_attrs + 1) * sizeof(ppd_attr_t *));
1879
1880 if (ptr == NULL)
1881 return (NULL);
1882
1883 ppd->attrs = ptr;
1884 ptr += ppd->num_attrs;
1885
1886 if ((temp = calloc(1, sizeof(ppd_attr_t))) == NULL)
1887 return (NULL);
1888
1889 *ptr = temp;
1890
1891 ppd->num_attrs ++;
1892
1893 /*
1894 * Copy data over...
1895 */
1896
1897 strlcpy(temp->name, name, sizeof(temp->name));
1898 strlcpy(temp->spec, spec, sizeof(temp->spec));
1899 strlcpy(temp->text, text, sizeof(temp->text));
1900 temp->value = (char *)value;
1901
bd7854cb 1902 /*
1903 * Add the attribute to the sorted array...
1904 */
1905
1906 cupsArrayAdd(ppd->sorted_attrs, temp);
1907
ef416fc2 1908 /*
1909 * Return the attribute...
1910 */
1911
1912 return (temp);
1913}
1914
1915
1916/*
1917 * 'ppd_add_choice()' - Add a choice to an option.
1918 */
1919
1920static ppd_choice_t * /* O - Named choice */
1921ppd_add_choice(ppd_option_t *option, /* I - Option */
1922 const char *name) /* I - Name of choice */
1923{
1924 ppd_choice_t *choice; /* Choice */
1925
1926
1927 if (option->num_choices == 0)
1928 choice = malloc(sizeof(ppd_choice_t));
1929 else
1930 choice = realloc(option->choices,
1931 sizeof(ppd_choice_t) * (option->num_choices + 1));
1932
1933 if (choice == NULL)
1934 return (NULL);
1935
1936 option->choices = choice;
1937 choice += option->num_choices;
1938 option->num_choices ++;
1939
1940 memset(choice, 0, sizeof(ppd_choice_t));
1941 strlcpy(choice->choice, name, sizeof(choice->choice));
1942
1943 return (choice);
1944}
1945
1946
1947/*
1948 * 'ppd_add_size()' - Add a page size.
1949 */
1950
1951static ppd_size_t * /* O - Named size */
1952ppd_add_size(ppd_file_t *ppd, /* I - PPD file */
1953 const char *name) /* I - Name of size */
1954{
1955 ppd_size_t *size; /* Size */
1956
1957
1958 if (ppd->num_sizes == 0)
1959 size = malloc(sizeof(ppd_size_t));
1960 else
1961 size = realloc(ppd->sizes, sizeof(ppd_size_t) * (ppd->num_sizes + 1));
1962
1963 if (size == NULL)
1964 return (NULL);
1965
1966 ppd->sizes = size;
1967 size += ppd->num_sizes;
1968 ppd->num_sizes ++;
1969
1970 memset(size, 0, sizeof(ppd_size_t));
1971 strlcpy(size->name, name, sizeof(size->name));
1972
1973 return (size);
1974}
1975
1976
bd7854cb 1977/*
1978 * 'ppd_compare_attrs()' - Compare two attributes.
1979 */
1980
1981static int /* O - Result of comparison */
1982ppd_compare_attrs(ppd_attr_t *a, /* I - First attribute */
1983 ppd_attr_t *b) /* I - Second attribute */
1984{
1985 int ret; /* Result of comparison */
1986
1987
1988 if ((ret = strcasecmp(a->name, b->name)) != 0)
1989 return (ret);
1990 else if (a->spec[0] && b->spec[0])
1991 return (strcasecmp(a->spec, b->spec));
1992 else
1993 return (0);
1994}
1995
1996
ef416fc2 1997/*
fa73b229 1998 * 'ppd_compare_coptions()' - Compare two custom options.
ef416fc2 1999 */
2000
2001static int /* O - Result of comparison */
fa73b229 2002ppd_compare_coptions(ppd_coption_t *a, /* I - First option */
2003 ppd_coption_t *b) /* I - Second option */
ef416fc2 2004{
fa73b229 2005 return (strcasecmp(a->keyword, b->keyword));
2006}
2007
2008
2009/*
2010 * 'ppd_compare_cparams()' - Compare two custom parameters.
2011 */
2012
2013static int /* O - Result of comparison */
2014ppd_compare_cparams(ppd_cparam_t *a, /* I - First parameter */
2015 ppd_cparam_t *b) /* I - Second parameter */
2016{
2017 return (strcasecmp(a->name, b->name));
ef416fc2 2018}
2019
2020
2021/*
2022 * 'ppd_compare_options()' - Compare two options.
2023 */
2024
2025static int /* O - Result of comparison */
fa73b229 2026ppd_compare_options(ppd_option_t *a, /* I - First option */
2027 ppd_option_t *b) /* I - Second option */
ef416fc2 2028{
fa73b229 2029 return (strcasecmp(a->keyword, b->keyword));
ef416fc2 2030}
ef416fc2 2031
2032
2033/*
2034 * 'ppd_decode()' - Decode a string value...
2035 */
2036
2037static int /* O - Length of decoded string */
2038ppd_decode(char *string) /* I - String to decode */
2039{
2040 char *inptr, /* Input pointer */
2041 *outptr; /* Output pointer */
2042
2043
2044 inptr = string;
2045 outptr = string;
2046
2047 while (*inptr != '\0')
2048 if (*inptr == '<' && isxdigit(inptr[1] & 255))
2049 {
2050 /*
2051 * Convert hex to 8-bit values...
2052 */
2053
2054 inptr ++;
2055 while (isxdigit(*inptr & 255))
2056 {
2057 if (isalpha(*inptr))
2058 *outptr = (tolower(*inptr) - 'a' + 10) << 4;
2059 else
2060 *outptr = (*inptr - '0') << 4;
2061
2062 inptr ++;
2063
2064 if (!isxdigit(*inptr & 255))
2065 break;
2066
2067 if (isalpha(*inptr))
2068 *outptr |= tolower(*inptr) - 'a' + 10;
2069 else
2070 *outptr |= *inptr - '0';
2071
2072 inptr ++;
2073 outptr ++;
2074 }
2075
2076 while (*inptr != '>' && *inptr != '\0')
2077 inptr ++;
2078 while (*inptr == '>')
2079 inptr ++;
2080 }
2081 else
2082 *outptr++ = *inptr++;
2083
2084 *outptr = '\0';
2085
2086 return ((int)(outptr - string));
2087}
2088
2089
2090/*
2091 * 'ppd_free_group()' - Free a single UI group.
2092 */
2093
2094static void
2095ppd_free_group(ppd_group_t *group) /* I - Group to free */
2096{
2097 int i; /* Looping var */
2098 ppd_option_t *option; /* Current option */
2099 ppd_group_t *subgroup; /* Current sub-group */
2100
2101
2102 if (group->num_options > 0)
2103 {
2104 for (i = group->num_options, option = group->options;
2105 i > 0;
2106 i --, option ++)
2107 ppd_free_option(option);
2108
2109 ppd_free(group->options);
2110 }
2111
2112 if (group->num_subgroups > 0)
2113 {
2114 for (i = group->num_subgroups, subgroup = group->subgroups;
2115 i > 0;
2116 i --, subgroup ++)
2117 ppd_free_group(subgroup);
2118
2119 ppd_free(group->subgroups);
2120 }
2121}
2122
2123
2124/*
2125 * 'ppd_free_option()' - Free a single option.
2126 */
2127
2128static void
2129ppd_free_option(ppd_option_t *option) /* I - Option to free */
2130{
2131 int i; /* Looping var */
2132 ppd_choice_t *choice; /* Current choice */
2133
2134
2135 if (option->num_choices > 0)
2136 {
2137 for (i = option->num_choices, choice = option->choices;
2138 i > 0;
2139 i --, choice ++)
2140 {
2141 ppd_free(choice->code);
2142 }
2143
2144 ppd_free(option->choices);
2145 }
2146}
2147
2148
ef416fc2 2149/*
fa73b229 2150 * 'ppd_get_coption()' - Get a custom option record.
ef416fc2 2151 */
2152
fa73b229 2153static ppd_coption_t * /* O - Custom option... */
2154ppd_get_coption(ppd_file_t *ppd, /* I - PPD file */
2155 const char *name) /* I - Name of option */
ef416fc2 2156{
fa73b229 2157 ppd_coption_t *copt; /* New custom option */
ef416fc2 2158
2159
2160 /*
2161 * See if the option already exists...
2162 */
2163
fa73b229 2164 if ((copt = ppdFindCustomOption(ppd, name)) != NULL)
2165 return (copt);
ef416fc2 2166
2167 /*
fa73b229 2168 * Not found, so create the custom option record...
ef416fc2 2169 */
2170
fa73b229 2171 if ((copt = calloc(1, sizeof(ppd_coption_t))) == NULL)
ef416fc2 2172 return (NULL);
2173
fa73b229 2174 strlcpy(copt->keyword, name, sizeof(copt->keyword));
ef416fc2 2175
fa73b229 2176 copt->params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL);
ef416fc2 2177
fa73b229 2178 cupsArrayAdd(ppd->coptions, copt);
ef416fc2 2179
2180 /*
2181 * Return the new record...
2182 */
2183
fa73b229 2184 return (copt);
ef416fc2 2185}
2186
2187
2188/*
fa73b229 2189 * 'ppd_get_cparam()' - Get a custom parameter record.
ef416fc2 2190 */
2191
fa73b229 2192static ppd_cparam_t * /* O - Extended option... */
2193ppd_get_cparam(ppd_coption_t *opt, /* I - PPD file */
2194 const char *param, /* I - Name of parameter */
2195 const char *text) /* I - Human-readable text */
ef416fc2 2196{
fa73b229 2197 ppd_cparam_t *cparam; /* New custom parameter */
ef416fc2 2198
2199
2200 /*
2201 * See if the parameter already exists...
2202 */
2203
fa73b229 2204 if ((cparam = ppdFindCustomParam(opt, param)) != NULL)
2205 return (cparam);
ef416fc2 2206
2207 /*
fa73b229 2208 * Not found, so create the custom parameter record...
ef416fc2 2209 */
2210
fa73b229 2211 if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL)
ef416fc2 2212 return (NULL);
2213
fa73b229 2214 strlcpy(cparam->name, param, sizeof(cparam->name));
2215 strlcpy(cparam->text, text, sizeof(cparam->text));
ef416fc2 2216
2217 /*
fa73b229 2218 * Add this record to the array...
ef416fc2 2219 */
2220
fa73b229 2221 cupsArrayAdd(opt->params, cparam);
ef416fc2 2222
2223 /*
2224 * Return the new record...
2225 */
2226
fa73b229 2227 return (cparam);
ef416fc2 2228}
ef416fc2 2229
2230
2231/*
2232 * 'ppd_get_group()' - Find or create the named group as needed.
2233 */
2234
2235static ppd_group_t * /* O - Named group */
2236ppd_get_group(ppd_file_t *ppd, /* I - PPD file */
2237 const char *name, /* I - Name of group */
2238 const char *text, /* I - Text for group */
2239 _cups_globals_t *cg) /* I - Global data */
2240{
2241 int i; /* Looping var */
2242 ppd_group_t *group; /* Group */
2243
2244
2245 DEBUG_printf(("ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)\n",
2246 ppd, name, text, cg));
2247
2248 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
2249 if (!strcmp(group->name, name))
2250 break;
2251
2252 if (i == 0)
2253 {
2254 DEBUG_printf(("Adding group %s...\n", name));
2255
2256 if (cg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
2257 {
2258 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2259
2260 return (NULL);
2261 }
2262
2263 if (ppd->num_groups == 0)
2264 group = malloc(sizeof(ppd_group_t));
2265 else
2266 group = realloc(ppd->groups,
2267 (ppd->num_groups + 1) * sizeof(ppd_group_t));
2268
2269 if (group == NULL)
2270 {
2271 cg->ppd_status = PPD_ALLOC_ERROR;
2272
2273 return (NULL);
2274 }
2275
2276 ppd->groups = group;
2277 group += ppd->num_groups;
2278 ppd->num_groups ++;
2279
2280 memset(group, 0, sizeof(ppd_group_t));
2281 strlcpy(group->name, name, sizeof(group->name));
2282 strlcpy(group->text, text, sizeof(group->text));
2283 }
2284
2285 return (group);
2286}
2287
2288
2289/*
2290 * 'ppd_get_option()' - Find or create the named option as needed.
2291 */
2292
2293static ppd_option_t * /* O - Named option */
2294ppd_get_option(ppd_group_t *group, /* I - Group */
2295 const char *name) /* I - Name of option */
2296{
2297 int i; /* Looping var */
2298 ppd_option_t *option; /* Option */
2299
2300
2301 DEBUG_printf(("ppd_get_option(group=%p(\"%s\"), name=\"%s\")\n",
2302 group, group->name, name));
2303
2304 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
2305 if (!strcmp(option->keyword, name))
2306 break;
2307
2308 if (i == 0)
2309 {
2310 if (group->num_options == 0)
2311 option = malloc(sizeof(ppd_option_t));
2312 else
2313 option = realloc(group->options,
2314 (group->num_options + 1) * sizeof(ppd_option_t));
2315
2316 if (option == NULL)
2317 return (NULL);
2318
2319 group->options = option;
2320 option += group->num_options;
2321 group->num_options ++;
2322
2323 memset(option, 0, sizeof(ppd_option_t));
2324 strlcpy(option->keyword, name, sizeof(option->keyword));
2325 }
2326
2327 return (option);
2328}
2329
2330
2331/*
2332 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2333 * necessary.
2334 */
2335
2336static int /* O - Bitmask of fields read */
2337ppd_read(cups_file_t *fp, /* I - File to read from */
2338 char *keyword, /* O - Keyword from line */
2339 char *option, /* O - Option from line */
2340 char *text, /* O - Human-readable text from line */
2341 char **string, /* O - Code/string data */
2342 int ignoreblank, /* I - Ignore blank lines? */
2343 _cups_globals_t *cg) /* I - Global data */
2344{
2345 int ch, /* Character from file */
2346 col, /* Column in line */
2347 colon, /* Colon seen? */
2348 endquote, /* Waiting for an end quote */
2349 mask, /* Mask to be returned */
2350 startline, /* Start line */
2351 textlen; /* Length of text */
2352 char *keyptr, /* Keyword pointer */
2353 *optptr, /* Option pointer */
2354 *textptr, /* Text pointer */
2355 *strptr, /* Pointer into string */
2356 *lineptr, /* Current position in line buffer */
2357 *line; /* Line buffer */
2358 int linesize; /* Current size of line buffer */
2359
2360 /*
2361 * Range check everything...
2362 */
2363
2364 if (!fp || !keyword || !option || !text || !string)
2365 return (0);
2366
2367 /*
2368 * Now loop until we have a valid line...
2369 */
2370
2371 *string = NULL;
2372 col = 0;
2373 startline = cg->ppd_line + 1;
2374 linesize = 1024;
2375 line = malloc(linesize);
2376
2377 if (!line)
2378 return (0);
2379
2380 do
2381 {
2382 /*
2383 * Read the line...
2384 */
2385
2386 lineptr = line;
2387 endquote = 0;
2388 colon = 0;
2389
2390 while ((ch = cupsFileGetChar(fp)) != EOF)
2391 {
2392 if (lineptr >= (line + linesize - 1))
2393 {
2394 /*
2395 * Expand the line buffer...
2396 */
2397
2398 char *temp; /* Temporary line pointer */
2399
2400
2401 linesize += 1024;
2402 if (linesize > 262144)
2403 {
2404 /*
2405 * Don't allow lines longer than 256k!
2406 */
2407
2408 cg->ppd_line = startline;
2409 cg->ppd_status = PPD_LINE_TOO_LONG;
2410
2411 free(line);
2412
2413 return (0);
2414 }
2415
2416 temp = realloc(line, linesize);
2417 if (!temp)
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 lineptr = temp + (lineptr - line);
2428 line = temp;
2429 }
2430
2431 if (ch == '\r' || ch == '\n')
2432 {
2433 /*
2434 * Line feed or carriage return...
2435 */
2436
2437 cg->ppd_line ++;
2438 col = 0;
2439
2440 if (ch == '\r')
2441 {
2442 /*
2443 * Check for a trailing line feed...
2444 */
2445
2446 if ((ch = cupsFilePeekChar(fp)) == EOF)
fa73b229 2447 {
2448 ch = '\n';
ef416fc2 2449 break;
fa73b229 2450 }
2451
ef416fc2 2452 if (ch == 0x0a)
2453 cupsFileGetChar(fp);
2454 }
2455
2456 if (lineptr == line && ignoreblank)
2457 continue; /* Skip blank lines */
2458
2459 ch = '\n';
2460
2461 if (!endquote) /* Continue for multi-line text */
2462 break;
2463
2464 *lineptr++ = '\n';
2465 }
2466 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2467 {
2468 /*
2469 * Other control characters...
2470 */
2471
2472 cg->ppd_line = startline;
2473 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2474
2475 free(line);
2476
2477 return (0);
2478 }
2479 else if (ch != 0x1a)
2480 {
2481 /*
2482 * Any other character...
2483 */
2484
2485 *lineptr++ = ch;
2486 col ++;
2487
2488 if (col > (PPD_MAX_LINE - 1))
2489 {
2490 /*
2491 * Line is too long...
2492 */
2493
2494 cg->ppd_line = startline;
2495 cg->ppd_status = PPD_LINE_TOO_LONG;
2496
2497 free(line);
2498
2499 return (0);
2500 }
2501
2502 if (ch == ':' && strncmp(line, "*%", 2) != 0)
2503 colon = 1;
2504
2505 if (ch == '\"' && colon)
2506 endquote = !endquote;
2507 }
2508 }
2509
2510 if (endquote)
2511 {
2512 /*
2513 * Didn't finish this quoted string...
2514 */
2515
2516 while ((ch = cupsFileGetChar(fp)) != EOF)
2517 if (ch == '\"')
2518 break;
2519 else if (ch == '\r' || ch == '\n')
2520 {
2521 cg->ppd_line ++;
2522 col = 0;
2523
2524 if (ch == '\r')
2525 {
2526 /*
2527 * Check for a trailing line feed...
2528 */
2529
2530 if ((ch = cupsFilePeekChar(fp)) == EOF)
2531 break;
2532 if (ch == 0x0a)
2533 cupsFileGetChar(fp);
2534 }
2535
2536 ch = '\n';
2537 }
2538 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2539 {
2540 /*
2541 * Other control characters...
2542 */
2543
2544 cg->ppd_line = startline;
2545 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2546
2547 free(line);
2548
2549 return (0);
2550 }
2551 else if (ch != 0x1a)
2552 {
2553 col ++;
2554
2555 if (col > (PPD_MAX_LINE - 1))
2556 {
2557 /*
2558 * Line is too long...
2559 */
2560
2561 cg->ppd_line = startline;
2562 cg->ppd_status = PPD_LINE_TOO_LONG;
2563
2564 free(line);
2565
2566 return (0);
2567 }
2568 }
2569 }
2570
2571 if (ch != '\n')
2572 {
2573 /*
2574 * Didn't finish this line...
2575 */
2576
2577 while ((ch = cupsFileGetChar(fp)) != EOF)
2578 if (ch == '\r' || ch == '\n')
2579 {
2580 /*
2581 * Line feed or carriage return...
2582 */
2583
2584 cg->ppd_line ++;
2585 col = 0;
2586
2587 if (ch == '\r')
2588 {
2589 /*
2590 * Check for a trailing line feed...
2591 */
2592
2593 if ((ch = cupsFilePeekChar(fp)) == EOF)
2594 break;
2595 if (ch == 0x0a)
2596 cupsFileGetChar(fp);
2597 }
2598
2599 break;
2600 }
2601 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2602 {
2603 /*
2604 * Other control characters...
2605 */
2606
2607 cg->ppd_line = startline;
2608 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2609
2610 free(line);
2611
2612 return (0);
2613 }
2614 else if (ch != 0x1a)
2615 {
2616 col ++;
2617
2618 if (col > (PPD_MAX_LINE - 1))
2619 {
2620 /*
2621 * Line is too long...
2622 */
2623
2624 cg->ppd_line = startline;
2625 cg->ppd_status = PPD_LINE_TOO_LONG;
2626
2627 free(line);
2628
2629 return (0);
2630 }
2631 }
2632 }
2633
2634 if (lineptr > line && lineptr[-1] == '\n')
2635 lineptr --;
2636
2637 *lineptr = '\0';
2638
2639 DEBUG_printf(("LINE = \"%s\"\n", line));
2640
bd7854cb 2641 /*
2642 * The dynamically created PPDs for older style Mac OS X
2643 * drivers include a large blob of data inserted as comments
2644 * at the end of the file. As an optimization we can stop
2645 * reading the PPD when we get to the start of this data.
2646 */
2647
2648 if (!strcmp(line, "*%APLWORKSET START"))
2649 {
2650 free(line);
2651 return (0);
2652 }
2653
ef416fc2 2654 if (ch == EOF && lineptr == line)
2655 {
2656 free(line);
2657 return (0);
2658 }
2659
2660 /*
2661 * Now parse it...
2662 */
2663
2664 mask = 0;
2665 lineptr = line + 1;
2666
2667 keyword[0] = '\0';
2668 option[0] = '\0';
2669 text[0] = '\0';
2670 *string = NULL;
2671
2672 if ((!line[0] || /* Blank line */
2673 !strncmp(line, "*%", 2) || /* Comment line */
2674 !strcmp(line, "*End")) && /* End of multi-line string */
2675 ignoreblank) /* Ignore these? */
2676 {
2677 startline = cg->ppd_line + 1;
2678 continue;
2679 }
2680
2681 if (!strcmp(line, "*")) /* (Bad) comment line */
2682 {
2683 if (cg->ppd_conform == PPD_CONFORM_RELAXED)
2684 {
2685 startline = cg->ppd_line + 1;
2686 continue;
2687 }
2688 else
2689 {
2690 cg->ppd_line = startline;
2691 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
2692
2693 free(line);
2694 return (0);
2695 }
2696 }
2697
2698 if (line[0] != '*') /* All lines start with an asterisk */
2699 {
ef416fc2 2700 /*
2701 * Allow lines consisting of just whitespace...
2702 */
2703
2704 for (lineptr = line; *lineptr; lineptr ++)
2705 if (!isspace(*lineptr & 255))
2706 break;
2707
2708 if (*lineptr)
2709 {
2710 cg->ppd_status = PPD_MISSING_ASTERISK;
2711 free(line);
2712 return (0);
2713 }
2714 else if (ignoreblank)
2715 continue;
2716 else
2717 {
2718 free(line);
2719 return (0);
2720 }
2721 }
2722
2723 /*
2724 * Get a keyword...
2725 */
2726
2727 keyptr = keyword;
2728
2729 while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr & 255))
2730 {
2731 if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
2732 (keyptr - keyword) >= (PPD_MAX_NAME - 1))
2733 {
2734 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
2735 free(line);
2736 return (0);
2737 }
2738
2739 *keyptr++ = *lineptr++;
2740 }
2741
2742 *keyptr = '\0';
2743
2744 if (!strcmp(keyword, "End"))
2745 continue;
2746
2747 mask |= PPD_KEYWORD;
2748
2749/* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
2750
2751 if (isspace(*lineptr & 255))
2752 {
2753 /*
2754 * Get an option name...
2755 */
2756
2757 while (isspace(*lineptr & 255))
2758 lineptr ++;
2759
2760 optptr = option;
2761
2762 while (*lineptr != '\0' && !isspace(*lineptr & 255) && *lineptr != ':' &&
2763 *lineptr != '/')
2764 {
2765 if (*lineptr <= ' ' || *lineptr > 126 ||
2766 (optptr - option) >= (PPD_MAX_NAME - 1))
2767 {
2768 cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
2769 free(line);
2770 return (0);
2771 }
2772
2773 *optptr++ = *lineptr++;
2774 }
2775
2776 *optptr = '\0';
2777
2778 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
2779 {
2780 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
2781 free(line);
2782 return (0);
2783 }
2784
2785 while (isspace(*lineptr & 255))
2786 lineptr ++;
2787
2788 mask |= PPD_OPTION;
2789
2790/* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
2791
2792 if (*lineptr == '/')
2793 {
2794 /*
2795 * Get human-readable text...
2796 */
2797
2798 lineptr ++;
2799
2800 textptr = text;
2801
2802 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
2803 {
2804 if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
2805 (textptr - text) >= (PPD_MAX_LINE - 1))
2806 {
2807 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2808 free(line);
2809 return (0);
2810 }
2811
2812 *textptr++ = *lineptr++;
2813 }
2814
2815 *textptr = '\0';
2816 textlen = ppd_decode(text);
2817
2818 if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT)
2819 {
2820 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2821 free(line);
2822 return (0);
2823 }
2824
2825 mask |= PPD_TEXT;
2826 }
2827
2828/* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
2829 }
2830
2831 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
2832 {
2833 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
2834 free(line);
2835 return (0);
2836 }
2837
2838 while (isspace(*lineptr & 255))
2839 lineptr ++;
2840
2841 if (*lineptr == ':')
2842 {
2843 /*
2844 * Get string after triming leading and trailing whitespace...
2845 */
2846
2847 lineptr ++;
2848 while (isspace(*lineptr & 255))
2849 lineptr ++;
2850
2851 strptr = lineptr + strlen(lineptr) - 1;
2852 while (strptr >= lineptr && isspace(*strptr & 255))
2853 *strptr-- = '\0';
2854
2855 if (*strptr == '\"')
2856 {
2857 /*
2858 * Quoted string by itself...
2859 */
2860
2861 *string = malloc(strlen(lineptr) + 1);
2862
2863 strptr = *string;
2864
2865 for (; *lineptr != '\0'; lineptr ++)
2866 if (*lineptr != '\"')
2867 *strptr++ = *lineptr;
2868
2869 *strptr = '\0';
2870 }
2871 else
2872 *string = strdup(lineptr);
2873
2874/* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
2875
2876 mask |= PPD_STRING;
2877 }
2878 }
2879 while (mask == 0);
2880
2881 free(line);
2882
2883 return (mask);
2884}
2885
2886
2887/*
b423cd4c 2888 * End of "$Id: ppd.c 5200 2006-02-28 00:10:32Z mike $".
ef416fc2 2889 */