]> 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/*
757d2cad 2 * "$Id: ppd.c 5238 2006-03-07 04:41:42Z 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{
fa73b229 396 int i, j, k; /* Looping vars */
ef416fc2 397 int count; /* Temporary count */
398 ppd_file_t *ppd; /* PPD file record */
399 ppd_group_t *group, /* Current group */
400 *subgroup; /* Current sub-group */
401 ppd_option_t *option; /* Current option */
402 ppd_choice_t *choice; /* Current choice */
403 ppd_const_t *constraint; /* Current constraint */
404 ppd_size_t *size; /* Current page size */
405 int mask; /* Line data mask */
406 char keyword[PPD_MAX_NAME],
407 /* Keyword from file */
408 name[PPD_MAX_NAME],
409 /* Option from file */
410 text[PPD_MAX_LINE],
411 /* Human-readable text from file */
412 *string, /* Code/text from file */
413 *sptr, /* Pointer into string */
414 *nameptr, /* Pointer into name */
415 *temp, /* Temporary string pointer */
416 **tempfonts; /* Temporary fonts pointer */
417 float order; /* Order dependency number */
418 ppd_section_t section; /* Order dependency section */
419 ppd_profile_t *profile; /* Pointer to color profile */
420 char **filter; /* Pointer to filter */
421 cups_lang_t *language; /* Default language */
757d2cad 422 struct lconv *loc; /* Locale data */
ef416fc2 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();
757d2cad 557 loc = localeconv();
ef416fc2 558
559 /*
560 * Read lines from the PPD file and add them to the file record...
561 */
562
563 group = NULL;
564 subgroup = NULL;
565 option = NULL;
566 choice = NULL;
567 ui_keyword = 0;
568
569 while ((mask = ppd_read(fp, keyword, name, text, &string, 1, cg)) != 0)
570 {
571#ifdef DEBUG
572 printf("mask = %x, keyword = \"%s\"", mask, keyword);
573
574 if (name[0] != '\0')
575 printf(", name = \"%s\"", name);
576
577 if (text[0] != '\0')
578 printf(", text = \"%s\"", text);
579
580 if (string != NULL)
581 {
582 if (strlen(string) > 40)
583 printf(", string = %p", string);
584 else
585 printf(", string = \"%s\"", string);
586 }
587
588 puts("");
589#endif /* DEBUG */
590
591 if (strcmp(keyword, "CloseUI") && strcmp(keyword, "CloseGroup") &&
592 strcmp(keyword, "CloseSubGroup") && strncmp(keyword, "Default", 7) &&
593 strcmp(keyword, "JCLCloseUI") && strcmp(keyword, "JCLOpenUI") &&
594 strcmp(keyword, "OpenUI") && strcmp(keyword, "OpenGroup") &&
595 strcmp(keyword, "OpenSubGroup") && string == NULL)
596 {
597 /*
598 * Need a string value!
599 */
600
601 cg->ppd_status = PPD_MISSING_VALUE;
602
603 goto error;
604 }
605
606 /*
607 * Certain main keywords (as defined by the PPD spec) may be used
608 * without the usual OpenUI/CloseUI stuff. Presumably this is just
609 * so that Adobe wouldn't completely break compatibility with PPD
610 * files prior to v4.0 of the spec, but it is hopelessly
611 * inconsistent... Catch these main keywords and automatically
612 * create the corresponding option, as needed...
613 */
614
615 if (ui_keyword)
616 {
617 /*
618 * Previous line was a UI keyword...
619 */
620
621 option = NULL;
622 ui_keyword = 0;
623 }
624
625 if (option == NULL &&
626 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
627 (PPD_KEYWORD | PPD_OPTION | PPD_STRING))
628 {
629 for (i = 0; i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])); i ++)
630 if (!strcmp(keyword, ui_keywords[i]))
631 break;
632
633 if (i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])))
634 {
635 /*
636 * Create the option in the appropriate group...
637 */
638
639 ui_keyword = 1;
640
641 DEBUG_printf(("**** FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!\n",
642 keyword));
643
644 if (!group)
645 {
bd7854cb 646 if ((group = ppd_get_group(ppd, "General", _("General"), cg)) == NULL)
ef416fc2 647 goto error;
648
649 DEBUG_printf(("Adding to group %s...\n", group->text));
650 option = ppd_get_option(group, keyword);
651 group = NULL;
652 }
653 else
654 option = ppd_get_option(group, keyword);
655
656 if (option == NULL)
657 {
658 cg->ppd_status = PPD_ALLOC_ERROR;
659
660 goto error;
661 }
662
663 /*
664 * Now fill in the initial information for the option...
665 */
666
667 if (!strncmp(keyword, "JCL", 3))
668 option->section = PPD_ORDER_JCL;
669 else
670 option->section = PPD_ORDER_ANY;
671
672 option->order = 10.0f;
673
674 if (i < 8)
675 option->ui = PPD_UI_BOOLEAN;
676 else
677 option->ui = PPD_UI_PICKONE;
678
679 for (j = 0; j < ppd->num_attrs; j ++)
680 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
681 !strcmp(ppd->attrs[j]->name + 7, keyword) &&
682 ppd->attrs[j]->value)
683 {
684 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
685 option->keyword, ppd->attrs[j]->value));
686 strlcpy(option->defchoice, ppd->attrs[j]->value,
687 sizeof(option->defchoice));
688 break;
689 }
690
691 if (!strcmp(keyword, "PageSize"))
692 strlcpy(option->text, _("Media Size"), sizeof(option->text));
693 else if (!strcmp(keyword, "MediaType"))
694 strlcpy(option->text, _("Media Type"), sizeof(option->text));
695 else if (!strcmp(keyword, "InputSlot"))
696 strlcpy(option->text, _("Media Source"), sizeof(option->text));
697 else if (!strcmp(keyword, "ColorModel"))
698 strlcpy(option->text, _("Output Mode"), sizeof(option->text));
699 else if (!strcmp(keyword, "Resolution"))
700 strlcpy(option->text, _("Resolution"), sizeof(option->text));
701 else
702 strlcpy(option->text, keyword, sizeof(option->text));
703 }
704 }
705
706 if (!strcmp(keyword, "LanguageLevel"))
707 ppd->language_level = atoi(string);
708 else if (!strcmp(keyword, "LanguageEncoding"))
709 ppd->lang_encoding = string;
710 else if (!strcmp(keyword, "LanguageVersion"))
711 ppd->lang_version = string;
712 else if (!strcmp(keyword, "Manufacturer"))
713 ppd->manufacturer = string;
714 else if (!strcmp(keyword, "ModelName"))
715 ppd->modelname = string;
716 else if (!strcmp(keyword, "Protocols"))
717 ppd->protocols = string;
718 else if (!strcmp(keyword, "PCFileName"))
719 ppd->pcfilename = string;
720 else if (!strcmp(keyword, "NickName"))
721 ppd->nickname = string;
722 else if (!strcmp(keyword, "Product"))
723 ppd->product = string;
724 else if (!strcmp(keyword, "ShortNickName"))
725 ppd->shortnickname = string;
726 else if (!strcmp(keyword, "TTRasterizer"))
727 ppd->ttrasterizer = string;
728 else if (!strcmp(keyword, "JCLBegin"))
729 {
730 ppd->jcl_begin = strdup(string);
731 ppd_decode(ppd->jcl_begin); /* Decode quoted string */
732 }
733 else if (!strcmp(keyword, "JCLEnd"))
734 {
735 ppd->jcl_end = strdup(string);
736 ppd_decode(ppd->jcl_end); /* Decode quoted string */
737 }
738 else if (!strcmp(keyword, "JCLToPSInterpreter"))
739 {
740 ppd->jcl_ps = strdup(string);
741 ppd_decode(ppd->jcl_ps); /* Decode quoted string */
742 }
743 else if (!strcmp(keyword, "AccurateScreensSupport"))
744 ppd->accurate_screens = !strcmp(string, "True");
745 else if (!strcmp(keyword, "ColorDevice"))
746 ppd->color_device = !strcmp(string, "True");
747 else if (!strcmp(keyword, "ContoneOnly"))
748 ppd->contone_only = !strcmp(string, "True");
749 else if (!strcmp(keyword, "cupsFlipDuplex"))
750 ppd->flip_duplex = !strcmp(string, "True");
751 else if (!strcmp(keyword, "cupsManualCopies"))
752 ppd->manual_copies = !strcmp(string, "True");
753 else if (!strcmp(keyword, "cupsModelNumber"))
754 ppd->model_number = atoi(string);
755 else if (!strcmp(keyword, "cupsColorProfile"))
756 {
757 if (ppd->num_profiles == 0)
758 profile = malloc(sizeof(ppd_profile_t));
759 else
760 profile = realloc(ppd->profiles, sizeof(ppd_profile_t) *
761 (ppd->num_profiles + 1));
762
763 ppd->profiles = profile;
764 profile += ppd->num_profiles;
765 ppd->num_profiles ++;
766
767 memset(profile, 0, sizeof(ppd_profile_t));
768 strlcpy(profile->resolution, name, sizeof(profile->resolution));
769 strlcpy(profile->media_type, text, sizeof(profile->media_type));
757d2cad 770
771 profile->density = _cupsStrScand(string, &sptr, loc);
772 profile->gamma = _cupsStrScand(sptr, &sptr, loc);
773 profile->matrix[0][0] = _cupsStrScand(sptr, &sptr, loc);
774 profile->matrix[0][1] = _cupsStrScand(sptr, &sptr, loc);
775 profile->matrix[0][2] = _cupsStrScand(sptr, &sptr, loc);
776 profile->matrix[1][0] = _cupsStrScand(sptr, &sptr, loc);
777 profile->matrix[1][1] = _cupsStrScand(sptr, &sptr, loc);
778 profile->matrix[1][2] = _cupsStrScand(sptr, &sptr, loc);
779 profile->matrix[2][0] = _cupsStrScand(sptr, &sptr, loc);
780 profile->matrix[2][1] = _cupsStrScand(sptr, &sptr, loc);
781 profile->matrix[2][2] = _cupsStrScand(sptr, &sptr, loc);
ef416fc2 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;
757d2cad 880 cparam->minimum.custom_curve = _cupsStrScand(cminimum, NULL, loc);
881 cparam->maximum.custom_curve = _cupsStrScand(cmaximum, NULL, loc);
fa73b229 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;
757d2cad 892 cparam->minimum.custom_invcurve = _cupsStrScand(cminimum, NULL, loc);
893 cparam->maximum.custom_invcurve = _cupsStrScand(cmaximum, NULL, loc);
fa73b229 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;
757d2cad 910 cparam->minimum.custom_points = _cupsStrScand(cminimum, NULL, loc);
911 cparam->maximum.custom_points = _cupsStrScand(cmaximum, NULL, loc);
fa73b229 912 }
913 else if (!strcmp(ctype, "real"))
914 {
915 cparam->type = PPD_CUSTOM_REAL;
757d2cad 916 cparam->minimum.custom_real = _cupsStrScand(cminimum, NULL, loc);
917 cparam->maximum.custom_real = _cupsStrScand(cmaximum, NULL, loc);
fa73b229 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"))
757d2cad 951 {
952 for (i = 0, sptr = string; i < 4; i ++)
953 ppd->custom_margins[i] = _cupsStrScand(sptr, &sptr, loc);
954 }
fa73b229 955 else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True"))
956 {
957 ppd_coption_t *coption; /* Custom option */
ef416fc2 958
959
fa73b229 960 DEBUG_puts("Processing Custom option...");
ef416fc2 961
fa73b229 962 /*
963 * Get the option and custom option...
964 */
ef416fc2 965
fa73b229 966 if ((option = ppdFindOption(ppd, keyword + 6)) == NULL)
967 {
968 ppd_group_t *gtemp; /* Temporary group */
ef416fc2 969
ef416fc2 970
fa73b229 971 DEBUG_printf(("%s option not found for %s...\n", keyword + 6, keyword));
ef416fc2 972
fa73b229 973 if ((gtemp = ppd_get_group(ppd, "General", _("General"), cg)) == NULL)
974 {
975 DEBUG_puts("Unable to get general group!");
ef416fc2 976
fa73b229 977 goto error;
978 }
979
980 if ((option = ppd_get_option(gtemp, keyword + 6)) == NULL)
ef416fc2 981 {
fa73b229 982 DEBUG_printf(("Unable to get %s option!\n", keyword + 6));
ef416fc2 983
984 cg->ppd_status = PPD_ALLOC_ERROR;
985
986 goto error;
987 }
ef416fc2 988 }
989
fa73b229 990 if ((coption = ppd_get_coption(ppd, keyword + 6)) == NULL)
ef416fc2 991 {
fa73b229 992 cg->ppd_status = PPD_ALLOC_ERROR;
ef416fc2 993
994 goto error;
995 }
996
fa73b229 997 /*
998 * Add the "custom" option...
999 */
1000
1001 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
ef416fc2 1002 {
fa73b229 1003 DEBUG_puts("Unable to add Custom choice!");
ef416fc2 1004
fa73b229 1005 cg->ppd_status = PPD_ALLOC_ERROR;
ef416fc2 1006
1007 goto error;
1008 }
1009
fa73b229 1010 strlcpy(choice->text, text[0] ? text : _("Custom"),
1011 sizeof(choice->text));
1012
ef416fc2 1013 choice->code = string;
ef416fc2 1014 string = NULL; /* Don't add as an attribute below */
fa73b229 1015 option = NULL;
1016
1017 /*
1018 * Now process custom page sizes specially...
1019 */
1020
1021 if (!strcmp(keyword, "CustomPageSize"))
1022 {
1023 ppd->variable_sizes = 1;
1024
1025 /*
1026 * Add a "Custom" page size entry...
1027 */
1028
1029 ppd_add_size(ppd, "Custom");
1030 }
ef416fc2 1031 }
1032 else if (!strcmp(keyword, "LandscapeOrientation"))
1033 {
1034 if (!strcmp(string, "Minus90"))
1035 ppd->landscape = -90;
1036 else if (!strcmp(string, "Plus90"))
1037 ppd->landscape = 90;
1038 }
1039 else if (!strcmp(keyword, "Emulators"))
1040 {
1041 for (count = 1, sptr = string; sptr != NULL;)
1042 if ((sptr = strchr(sptr, ' ')) != NULL)
1043 {
1044 count ++;
1045 while (*sptr == ' ')
1046 sptr ++;
1047 }
1048
1049 ppd->num_emulations = count;
1050 ppd->emulations = calloc(count, sizeof(ppd_emul_t));
1051
1052 for (i = 0, sptr = string; i < count; i ++)
1053 {
1054 for (nameptr = ppd->emulations[i].name;
1055 *sptr != '\0' && *sptr != ' ';
1056 sptr ++)
1057 if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1))
1058 *nameptr++ = *sptr;
1059
1060 *nameptr = '\0';
1061
1062 while (*sptr == ' ')
1063 sptr ++;
1064 }
1065 }
1066 else if (!strncmp(keyword, "StartEmulator_", 14))
1067 {
1068 ppd_decode(string);
1069
1070 for (i = 0; i < ppd->num_emulations; i ++)
1071 if (!strcmp(keyword + 14, ppd->emulations[i].name))
1072 {
1073 ppd->emulations[i].start = string;
1074 string = NULL;
1075 }
1076 }
1077 else if (!strncmp(keyword, "StopEmulator_", 13))
1078 {
1079 ppd_decode(string);
1080
1081 for (i = 0; i < ppd->num_emulations; i ++)
1082 if (!strcmp(keyword + 13, ppd->emulations[i].name))
1083 {
1084 ppd->emulations[i].stop = string;
1085 string = NULL;
1086 }
1087 }
1088 else if (!strcmp(keyword, "JobPatchFile"))
1089 {
1090 if (ppd->patches == NULL)
1091 ppd->patches = strdup(string);
1092 else
1093 {
1094 temp = realloc(ppd->patches, strlen(ppd->patches) +
1095 strlen(string) + 1);
1096 if (temp == NULL)
1097 {
1098 cg->ppd_status = PPD_ALLOC_ERROR;
1099
1100 goto error;
1101 }
1102
1103 ppd->patches = temp;
1104
1105 strcpy(ppd->patches + strlen(ppd->patches), string);
1106 }
1107 }
1108 else if (!strcmp(keyword, "OpenUI"))
1109 {
1110 /*
1111 * Don't allow nesting of options...
1112 */
1113
1114 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
1115 {
1116 cg->ppd_status = PPD_NESTED_OPEN_UI;
1117
1118 goto error;
1119 }
1120
1121 /*
1122 * Add an option record to the current sub-group, group, or file...
1123 */
1124
1125 if (name[0] == '*')
1126 _cups_strcpy(name, name + 1); /* Eliminate leading asterisk */
1127
1128 for (i = (int)strlen(name) - 1; i > 0 && isspace(name[i] & 255); i --)
1129 name[i] = '\0'; /* Eliminate trailing spaces */
1130
1131 DEBUG_printf(("OpenUI of %s in group %s...\n", name,
1132 group ? group->text : "(null)"));
1133
1134 if (subgroup != NULL)
1135 option = ppd_get_option(subgroup, name);
1136 else if (group == NULL)
1137 {
bd7854cb 1138 if ((group = ppd_get_group(ppd, "General", _("General"), cg)) == NULL)
ef416fc2 1139 goto error;
1140
1141 DEBUG_printf(("Adding to group %s...\n", group->text));
1142 option = ppd_get_option(group, name);
1143 group = NULL;
1144 }
1145 else
1146 option = ppd_get_option(group, name);
1147
1148 if (option == NULL)
1149 {
1150 cg->ppd_status = PPD_ALLOC_ERROR;
1151
1152 goto error;
1153 }
1154
1155 /*
1156 * Now fill in the initial information for the option...
1157 */
1158
1159 if (string && !strcmp(string, "PickMany"))
1160 option->ui = PPD_UI_PICKMANY;
1161 else if (string && !strcmp(string, "Boolean"))
1162 option->ui = PPD_UI_BOOLEAN;
1163 else if (string && !strcmp(string, "PickOne"))
1164 option->ui = PPD_UI_PICKONE;
1165 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1166 {
1167 cg->ppd_status = PPD_BAD_OPEN_UI;
1168
1169 goto error;
1170 }
1171 else
1172 option->ui = PPD_UI_PICKONE;
1173
1174 for (j = 0; j < ppd->num_attrs; j ++)
1175 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
1176 !strcmp(ppd->attrs[j]->name + 7, name) &&
1177 ppd->attrs[j]->value)
1178 {
1179 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
1180 option->keyword, ppd->attrs[j]->value));
1181 strlcpy(option->defchoice, ppd->attrs[j]->value,
1182 sizeof(option->defchoice));
1183 break;
1184 }
1185
1186 if (text[0])
1187 strlcpy(option->text, text, sizeof(option->text));
1188 else
1189 {
1190 if (!strcmp(name, "PageSize"))
1191 strlcpy(option->text, _("Media Size"), sizeof(option->text));
1192 else if (!strcmp(name, "MediaType"))
1193 strlcpy(option->text, _("Media Type"), sizeof(option->text));
1194 else if (!strcmp(name, "InputSlot"))
1195 strlcpy(option->text, _("Media Source"), sizeof(option->text));
1196 else if (!strcmp(name, "ColorModel"))
1197 strlcpy(option->text, _("Output Mode"), sizeof(option->text));
1198 else if (!strcmp(name, "Resolution"))
1199 strlcpy(option->text, _("Resolution"), sizeof(option->text));
1200 else
1201 strlcpy(option->text, name, sizeof(option->text));
1202 }
1203
1204 option->section = PPD_ORDER_ANY;
1205
1206 ppd_free(string);
1207 string = NULL;
1208 }
1209 else if (!strcmp(keyword, "JCLOpenUI"))
1210 {
1211 /*
1212 * Don't allow nesting of options...
1213 */
1214
1215 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
1216 {
1217 cg->ppd_status = PPD_NESTED_OPEN_UI;
1218
1219 goto error;
1220 }
1221
1222 /*
1223 * Find the JCL group, and add if needed...
1224 */
1225
fa73b229 1226 group = ppd_get_group(ppd, "JCL", _("JCL"), cg);
ef416fc2 1227
1228 if (group == NULL)
1229 goto error;
1230
1231 /*
1232 * Add an option record to the current JCLs...
1233 */
1234
1235 if (name[0] == '*')
1236 _cups_strcpy(name, name + 1);
1237
1238 option = ppd_get_option(group, name);
1239
1240 if (option == NULL)
1241 {
1242 cg->ppd_status = PPD_ALLOC_ERROR;
1243
1244 goto error;
1245 }
1246
1247 /*
1248 * Now fill in the initial information for the option...
1249 */
1250
1251 if (string && !strcmp(string, "PickMany"))
1252 option->ui = PPD_UI_PICKMANY;
1253 else if (string && !strcmp(string, "Boolean"))
1254 option->ui = PPD_UI_BOOLEAN;
1255 else if (string && !strcmp(string, "PickOne"))
1256 option->ui = PPD_UI_PICKONE;
1257 else
1258 {
1259 cg->ppd_status = PPD_BAD_OPEN_UI;
1260
1261 goto error;
1262 }
1263
1264 for (j = 0; j < ppd->num_attrs; j ++)
1265 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
1266 !strcmp(ppd->attrs[j]->name + 7, name) &&
1267 ppd->attrs[j]->value)
1268 {
1269 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
1270 option->keyword, ppd->attrs[j]->value));
1271 strlcpy(option->defchoice, ppd->attrs[j]->value,
1272 sizeof(option->defchoice));
1273 break;
1274 }
1275
1276 strlcpy(option->text, text, sizeof(option->text));
1277
1278 option->section = PPD_ORDER_JCL;
1279 group = NULL;
1280
1281 ppd_free(string);
1282 string = NULL;
1283 }
1284 else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI"))
1285 {
1286 option = NULL;
1287
1288 ppd_free(string);
1289 string = NULL;
1290 }
1291 else if (!strcmp(keyword, "OpenGroup"))
1292 {
1293 /*
1294 * Open a new group...
1295 */
1296
1297 if (group != NULL)
1298 {
1299 cg->ppd_status = PPD_NESTED_OPEN_GROUP;
1300
1301 goto error;
1302 }
1303
1304 if (!string)
1305 {
1306 cg->ppd_status = PPD_BAD_OPEN_GROUP;
1307
1308 goto error;
1309 }
1310
1311 /*
1312 * Separate the group name from the text (name/text)...
1313 */
1314
1315 if ((sptr = strchr(string, '/')) != NULL)
1316 *sptr++ = '\0';
1317 else
1318 sptr = string;
1319
1320 /*
1321 * Fix up the text...
1322 */
1323
1324 ppd_decode(sptr);
1325
1326 /*
1327 * Find/add the group...
1328 */
1329
1330 group = ppd_get_group(ppd, string, sptr, cg);
1331
1332 if (group == NULL)
1333 goto error;
1334
1335 ppd_free(string);
1336 string = NULL;
1337 }
1338 else if (!strcmp(keyword, "CloseGroup"))
1339 {
1340 group = NULL;
1341
1342 ppd_free(string);
1343 string = NULL;
1344 }
1345 else if (!strcmp(keyword, "OrderDependency") ||
1346 !strcmp(keyword, "NonUIOrderDependency"))
1347 {
757d2cad 1348 order = _cupsStrScand(string, &sptr, loc);
1349
1350 if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2)
ef416fc2 1351 {
1352 cg->ppd_status = PPD_BAD_ORDER_DEPENDENCY;
1353
1354 goto error;
1355 }
1356
1357 if (keyword[0] == '*')
1358 _cups_strcpy(keyword, keyword + 1);
1359
1360 if (!strcmp(name, "ExitServer"))
1361 section = PPD_ORDER_EXIT;
1362 else if (!strcmp(name, "Prolog"))
1363 section = PPD_ORDER_PROLOG;
1364 else if (!strcmp(name, "DocumentSetup"))
1365 section = PPD_ORDER_DOCUMENT;
1366 else if (!strcmp(name, "PageSetup"))
1367 section = PPD_ORDER_PAGE;
1368 else if (!strcmp(name, "JCLSetup"))
1369 section = PPD_ORDER_JCL;
1370 else
1371 section = PPD_ORDER_ANY;
1372
1373 if (option == NULL)
1374 {
1375 ppd_group_t *gtemp;
1376
1377
1378 /*
1379 * Only valid for Non-UI options...
1380 */
1381
1382 for (i = ppd->num_groups, gtemp = ppd->groups; i > 0; i --, gtemp ++)
1383 if (gtemp->text[0] == '\0')
1384 break;
1385
1386 if (i > 0)
1387 for (i = 0; i < gtemp->num_options; i ++)
1388 if (!strcmp(keyword, gtemp->options[i].keyword))
1389 {
1390 gtemp->options[i].section = section;
1391 gtemp->options[i].order = order;
1392 break;
1393 }
1394 }
1395 else
1396 {
1397 option->section = section;
1398 option->order = order;
1399 }
1400
1401 ppd_free(string);
1402 string = NULL;
1403 }
1404 else if (!strncmp(keyword, "Default", 7))
1405 {
1406 if (string == NULL)
1407 continue;
1408
1409 /*
1410 * Drop UI text, if any, from value...
1411 */
1412
1413 if (strchr(string, '/') != NULL)
1414 *strchr(string, '/') = '\0';
1415
1416 /*
1417 * Assign the default value as appropriate...
1418 */
1419
1420 if (!strcmp(keyword, "DefaultColorSpace"))
1421 {
1422 /*
1423 * Set default colorspace...
1424 */
1425
1426 if (!strcmp(string, "CMY"))
1427 ppd->colorspace = PPD_CS_CMY;
1428 else if (!strcmp(string, "CMYK"))
1429 ppd->colorspace = PPD_CS_CMYK;
1430 else if (!strcmp(string, "RGB"))
1431 ppd->colorspace = PPD_CS_RGB;
1432 else if (!strcmp(string, "RGBK"))
1433 ppd->colorspace = PPD_CS_RGBK;
1434 else if (!strcmp(string, "N"))
1435 ppd->colorspace = PPD_CS_N;
1436 else
1437 ppd->colorspace = PPD_CS_GRAY;
1438 }
1439 else if (option && !strcmp(keyword + 7, option->keyword))
1440 {
1441 /*
1442 * Set the default as part of the current option...
1443 */
1444
1445 DEBUG_printf(("Setting %s to %s...\n", keyword, string));
1446
1447 strlcpy(option->defchoice, string, sizeof(option->defchoice));
1448
1449 DEBUG_printf(("%s is now %s...\n", keyword, option->defchoice));
1450 }
1451 else
1452 {
1453 /*
1454 * Lookup option and set if it has been defined...
1455 */
1456
1457 ppd_option_t *toption; /* Temporary option */
1458
1459
1460 if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL)
1461 {
1462 DEBUG_printf(("Setting %s to %s...\n", keyword, string));
1463 strlcpy(toption->defchoice, string, sizeof(toption->defchoice));
1464 }
1465 }
1466 }
1467 else if (!strcmp(keyword, "UIConstraints") ||
1468 !strcmp(keyword, "NonUIConstraints"))
1469 {
1470 if (ppd->num_consts == 0)
1471 constraint = calloc(1, sizeof(ppd_const_t));
1472 else
1473 constraint = realloc(ppd->consts,
1474 (ppd->num_consts + 1) * sizeof(ppd_const_t));
1475
1476 if (constraint == NULL)
1477 {
1478 cg->ppd_status = PPD_ALLOC_ERROR;
1479
1480 goto error;
1481 }
1482
1483 ppd->consts = constraint;
1484 constraint += ppd->num_consts;
1485 ppd->num_consts ++;
1486
1487 switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1,
1488 constraint->choice1, constraint->option2,
1489 constraint->choice2))
1490 {
1491 case 0 : /* Error */
1492 case 1 : /* Error */
1493 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1494 goto error;
1495
1496 case 2 : /* Two options... */
1497 /*
1498 * The following strcpy's are safe, as optionN and
1499 * choiceN are all the same size (size defined by PPD spec...)
1500 */
1501
1502 if (constraint->option1[0] == '*')
1503 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1504
1505 if (constraint->choice1[0] == '*')
1506 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1507 else
1508 _cups_strcpy(constraint->option2, constraint->choice1);
1509
1510 constraint->choice1[0] = '\0';
1511 constraint->choice2[0] = '\0';
1512 break;
1513
1514 case 3 : /* Two options, one choice... */
1515 /*
1516 * The following _cups_strcpy's are safe, as optionN and
1517 * choiceN are all the same size (size defined by PPD spec...)
1518 */
1519
1520 if (constraint->option1[0] == '*')
1521 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1522
1523 if (constraint->choice1[0] == '*')
1524 {
1525 _cups_strcpy(constraint->choice2, constraint->option2);
1526 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1527 constraint->choice1[0] = '\0';
1528 }
1529 else
1530 {
1531 if (constraint->option2[0] == '*')
1532 _cups_strcpy(constraint->option2, constraint->option2 + 1);
1533
1534 constraint->choice2[0] = '\0';
1535 }
1536 break;
1537
1538 case 4 : /* Two options, two choices... */
1539 if (constraint->option1[0] == '*')
1540 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1541
1542 if (constraint->option2[0] == '*')
1543 _cups_strcpy(constraint->option2, constraint->option2 + 1);
1544 break;
1545 }
1546
1547 ppd_free(string);
1548 string = NULL;
1549 }
1550 else if (!strcmp(keyword, "PaperDimension"))
1551 {
1552 if ((size = ppdPageSize(ppd, name)) == NULL)
1553 size = ppd_add_size(ppd, name);
1554
1555 if (size == NULL)
1556 {
1557 /*
1558 * Unable to add or find size!
1559 */
1560
1561 cg->ppd_status = PPD_ALLOC_ERROR;
1562
1563 goto error;
1564 }
1565
757d2cad 1566 size->width = _cupsStrScand(string, &sptr, loc);
1567 size->length = _cupsStrScand(sptr, NULL, loc);
ef416fc2 1568
1569 ppd_free(string);
1570 string = NULL;
1571 }
1572 else if (!strcmp(keyword, "ImageableArea"))
1573 {
1574 if ((size = ppdPageSize(ppd, name)) == NULL)
1575 size = ppd_add_size(ppd, name);
1576
1577 if (size == NULL)
1578 {
1579 /*
1580 * Unable to add or find size!
1581 */
1582
1583 cg->ppd_status = PPD_ALLOC_ERROR;
1584
1585 goto error;
1586 }
1587
757d2cad 1588 size->left = _cupsStrScand(string, &sptr, loc);
1589 size->bottom = _cupsStrScand(sptr, &sptr, loc);
1590 size->right = _cupsStrScand(sptr, &sptr, loc);
1591 size->top = _cupsStrScand(sptr, NULL, loc);
ef416fc2 1592
1593 ppd_free(string);
1594 string = NULL;
1595 }
1596 else if (option != NULL &&
1597 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
1598 (PPD_KEYWORD | PPD_OPTION | PPD_STRING) &&
1599 !strcmp(keyword, option->keyword))
1600 {
1601 DEBUG_printf(("group = %p, subgroup = %p\n", group, subgroup));
1602
1603 if (!strcmp(keyword, "PageSize"))
1604 {
1605 /*
1606 * Add a page size...
1607 */
1608
1609 if (ppdPageSize(ppd, name) == NULL)
1610 ppd_add_size(ppd, name);
1611 }
1612
1613 /*
1614 * Add the option choice...
1615 */
1616
1617 choice = ppd_add_choice(option, name);
1618
1619 if (mask & PPD_TEXT)
1620 strlcpy(choice->text, text, sizeof(choice->text));
1621 else if (!strcmp(name, "True"))
1622 strcpy(choice->text, _("Yes"));
1623 else if (!strcmp(name, "False"))
1624 strcpy(choice->text, _("No"));
1625 else
1626 strlcpy(choice->text, name, sizeof(choice->text));
1627
1628 if (option->section == PPD_ORDER_JCL)
1629 ppd_decode(string); /* Decode quoted string */
1630
1631 choice->code = string;
1632 string = NULL; /* Don't add as an attribute below */
1633 }
ef416fc2 1634
1635 /*
1636 * Add remaining lines with keywords and string values as attributes...
1637 */
1638
1639 if (string &&
1640 (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
1641 ppd_add_attr(ppd, keyword, name, text, string);
1642 else
ef416fc2 1643 ppd_free(string);
ef416fc2 1644 }
1645
1646 /*
1647 * Reset language preferences...
1648 */
1649
1650 cupsLangFree(language);
1651
ef416fc2 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
ef416fc2 1714 return (NULL);
1715}
1716
1717
1718/*
1719 * 'ppdOpenFd()' - Read a PPD file into memory.
1720 */
1721
1722ppd_file_t * /* O - PPD file record */
1723ppdOpenFd(int fd) /* I - File to read from */
1724{
fa73b229 1725 cups_file_t *fp; /* CUPS file pointer */
ef416fc2 1726 ppd_file_t *ppd; /* PPD file record */
1727 _cups_globals_t *cg = _cupsGlobals();
1728 /* Global data */
1729
1730
1731 /*
1732 * Set the line number to 0...
1733 */
1734
1735 cg->ppd_line = 0;
1736
1737 /*
1738 * Range check input...
1739 */
1740
1741 if (fd < 0)
1742 {
1743 cg->ppd_status = PPD_NULL_FILE;
1744
1745 return (NULL);
1746 }
1747
1748 /*
1749 * Try to open the file and parse it...
1750 */
1751
fa73b229 1752 if ((fp = cupsFileOpenFd(fd, "r")) != NULL)
ef416fc2 1753 {
fa73b229 1754 ppd = ppdOpen2(fp);
ef416fc2 1755
fa73b229 1756 cupsFileClose(fp);
ef416fc2 1757 }
1758 else
1759 {
1760 cg->ppd_status = PPD_FILE_OPEN_ERROR;
fa73b229 1761 ppd = NULL;
ef416fc2 1762 }
1763
1764 return (ppd);
1765}
1766
1767
1768/*
1769 * 'ppdOpenFile()' - Read a PPD file into memory.
1770 */
1771
1772ppd_file_t * /* O - PPD file record */
1773ppdOpenFile(const char *filename) /* I - File to read from */
1774{
1775 cups_file_t *fp; /* File pointer */
1776 ppd_file_t *ppd; /* PPD file record */
1777 _cups_globals_t *cg = _cupsGlobals();
1778 /* Global data */
1779
1780
1781 /*
1782 * Set the line number to 0...
1783 */
1784
1785 cg->ppd_line = 0;
1786
1787 /*
1788 * Range check input...
1789 */
1790
1791 if (filename == NULL)
1792 {
1793 cg->ppd_status = PPD_NULL_FILE;
1794
1795 return (NULL);
1796 }
1797
1798 /*
1799 * Try to open the file and parse it...
1800 */
1801
1802 if ((fp = cupsFileOpen(filename, "r")) != NULL)
1803 {
1804 ppd = ppdOpen2(fp);
1805
1806 cupsFileClose(fp);
1807 }
1808 else
1809 {
1810 cg->ppd_status = PPD_FILE_OPEN_ERROR;
1811 ppd = NULL;
1812 }
1813
1814 return (ppd);
1815}
1816
1817
1818/*
1819 * 'ppdSetConformance()' - Set the conformance level for PPD files.
1820 *
1821 * @since CUPS 1.1.20@
1822 */
1823
1824void
1825ppdSetConformance(ppd_conform_t c) /* I - Conformance level */
1826{
1827 _cups_globals_t *cg = _cupsGlobals();
1828 /* Global data */
1829
1830
1831 cg->ppd_conform = c;
1832}
1833
1834
1835/*
1836 * 'ppd_add_attr()' - Add an attribute to the PPD data.
1837 */
1838
1839static ppd_attr_t * /* O - New attribute */
1840ppd_add_attr(ppd_file_t *ppd, /* I - PPD file data */
1841 const char *name, /* I - Attribute name */
1842 const char *spec, /* I - Specifier string, if any */
1843 const char *text, /* I - Text string, if any */
1844 const char *value) /* I - Value of attribute */
1845{
1846 ppd_attr_t **ptr, /* New array */
1847 *temp; /* New attribute */
1848
1849
1850 /*
1851 * Range check input...
1852 */
1853
1854 if (ppd == NULL || name == NULL || spec == NULL)
1855 return (NULL);
1856
bd7854cb 1857 /*
1858 * Create the array as needed...
1859 */
1860
1861 if (!ppd->sorted_attrs)
1862 ppd->sorted_attrs = cupsArrayNew((cups_array_func_t)ppd_compare_attrs,
1863 NULL);
1864
ef416fc2 1865 /*
1866 * Allocate memory for the new attribute...
1867 */
1868
1869 if (ppd->num_attrs == 0)
1870 ptr = malloc(sizeof(ppd_attr_t *));
1871 else
1872 ptr = realloc(ppd->attrs, (ppd->num_attrs + 1) * sizeof(ppd_attr_t *));
1873
1874 if (ptr == NULL)
1875 return (NULL);
1876
1877 ppd->attrs = ptr;
1878 ptr += ppd->num_attrs;
1879
1880 if ((temp = calloc(1, sizeof(ppd_attr_t))) == NULL)
1881 return (NULL);
1882
1883 *ptr = temp;
1884
1885 ppd->num_attrs ++;
1886
1887 /*
1888 * Copy data over...
1889 */
1890
1891 strlcpy(temp->name, name, sizeof(temp->name));
1892 strlcpy(temp->spec, spec, sizeof(temp->spec));
1893 strlcpy(temp->text, text, sizeof(temp->text));
1894 temp->value = (char *)value;
1895
bd7854cb 1896 /*
1897 * Add the attribute to the sorted array...
1898 */
1899
1900 cupsArrayAdd(ppd->sorted_attrs, temp);
1901
ef416fc2 1902 /*
1903 * Return the attribute...
1904 */
1905
1906 return (temp);
1907}
1908
1909
1910/*
1911 * 'ppd_add_choice()' - Add a choice to an option.
1912 */
1913
1914static ppd_choice_t * /* O - Named choice */
1915ppd_add_choice(ppd_option_t *option, /* I - Option */
1916 const char *name) /* I - Name of choice */
1917{
1918 ppd_choice_t *choice; /* Choice */
1919
1920
1921 if (option->num_choices == 0)
1922 choice = malloc(sizeof(ppd_choice_t));
1923 else
1924 choice = realloc(option->choices,
1925 sizeof(ppd_choice_t) * (option->num_choices + 1));
1926
1927 if (choice == NULL)
1928 return (NULL);
1929
1930 option->choices = choice;
1931 choice += option->num_choices;
1932 option->num_choices ++;
1933
1934 memset(choice, 0, sizeof(ppd_choice_t));
1935 strlcpy(choice->choice, name, sizeof(choice->choice));
1936
1937 return (choice);
1938}
1939
1940
1941/*
1942 * 'ppd_add_size()' - Add a page size.
1943 */
1944
1945static ppd_size_t * /* O - Named size */
1946ppd_add_size(ppd_file_t *ppd, /* I - PPD file */
1947 const char *name) /* I - Name of size */
1948{
1949 ppd_size_t *size; /* Size */
1950
1951
1952 if (ppd->num_sizes == 0)
1953 size = malloc(sizeof(ppd_size_t));
1954 else
1955 size = realloc(ppd->sizes, sizeof(ppd_size_t) * (ppd->num_sizes + 1));
1956
1957 if (size == NULL)
1958 return (NULL);
1959
1960 ppd->sizes = size;
1961 size += ppd->num_sizes;
1962 ppd->num_sizes ++;
1963
1964 memset(size, 0, sizeof(ppd_size_t));
1965 strlcpy(size->name, name, sizeof(size->name));
1966
1967 return (size);
1968}
1969
1970
bd7854cb 1971/*
1972 * 'ppd_compare_attrs()' - Compare two attributes.
1973 */
1974
1975static int /* O - Result of comparison */
1976ppd_compare_attrs(ppd_attr_t *a, /* I - First attribute */
1977 ppd_attr_t *b) /* I - Second attribute */
1978{
1979 int ret; /* Result of comparison */
1980
1981
1982 if ((ret = strcasecmp(a->name, b->name)) != 0)
1983 return (ret);
1984 else if (a->spec[0] && b->spec[0])
1985 return (strcasecmp(a->spec, b->spec));
1986 else
1987 return (0);
1988}
1989
1990
ef416fc2 1991/*
fa73b229 1992 * 'ppd_compare_coptions()' - Compare two custom options.
ef416fc2 1993 */
1994
1995static int /* O - Result of comparison */
fa73b229 1996ppd_compare_coptions(ppd_coption_t *a, /* I - First option */
1997 ppd_coption_t *b) /* I - Second option */
ef416fc2 1998{
fa73b229 1999 return (strcasecmp(a->keyword, b->keyword));
2000}
2001
2002
2003/*
2004 * 'ppd_compare_cparams()' - Compare two custom parameters.
2005 */
2006
2007static int /* O - Result of comparison */
2008ppd_compare_cparams(ppd_cparam_t *a, /* I - First parameter */
2009 ppd_cparam_t *b) /* I - Second parameter */
2010{
2011 return (strcasecmp(a->name, b->name));
ef416fc2 2012}
2013
2014
2015/*
2016 * 'ppd_compare_options()' - Compare two options.
2017 */
2018
2019static int /* O - Result of comparison */
fa73b229 2020ppd_compare_options(ppd_option_t *a, /* I - First option */
2021 ppd_option_t *b) /* I - Second option */
ef416fc2 2022{
fa73b229 2023 return (strcasecmp(a->keyword, b->keyword));
ef416fc2 2024}
ef416fc2 2025
2026
2027/*
2028 * 'ppd_decode()' - Decode a string value...
2029 */
2030
2031static int /* O - Length of decoded string */
2032ppd_decode(char *string) /* I - String to decode */
2033{
2034 char *inptr, /* Input pointer */
2035 *outptr; /* Output pointer */
2036
2037
2038 inptr = string;
2039 outptr = string;
2040
2041 while (*inptr != '\0')
2042 if (*inptr == '<' && isxdigit(inptr[1] & 255))
2043 {
2044 /*
2045 * Convert hex to 8-bit values...
2046 */
2047
2048 inptr ++;
2049 while (isxdigit(*inptr & 255))
2050 {
2051 if (isalpha(*inptr))
2052 *outptr = (tolower(*inptr) - 'a' + 10) << 4;
2053 else
2054 *outptr = (*inptr - '0') << 4;
2055
2056 inptr ++;
2057
2058 if (!isxdigit(*inptr & 255))
2059 break;
2060
2061 if (isalpha(*inptr))
2062 *outptr |= tolower(*inptr) - 'a' + 10;
2063 else
2064 *outptr |= *inptr - '0';
2065
2066 inptr ++;
2067 outptr ++;
2068 }
2069
2070 while (*inptr != '>' && *inptr != '\0')
2071 inptr ++;
2072 while (*inptr == '>')
2073 inptr ++;
2074 }
2075 else
2076 *outptr++ = *inptr++;
2077
2078 *outptr = '\0';
2079
2080 return ((int)(outptr - string));
2081}
2082
2083
2084/*
2085 * 'ppd_free_group()' - Free a single UI group.
2086 */
2087
2088static void
2089ppd_free_group(ppd_group_t *group) /* I - Group to free */
2090{
2091 int i; /* Looping var */
2092 ppd_option_t *option; /* Current option */
2093 ppd_group_t *subgroup; /* Current sub-group */
2094
2095
2096 if (group->num_options > 0)
2097 {
2098 for (i = group->num_options, option = group->options;
2099 i > 0;
2100 i --, option ++)
2101 ppd_free_option(option);
2102
2103 ppd_free(group->options);
2104 }
2105
2106 if (group->num_subgroups > 0)
2107 {
2108 for (i = group->num_subgroups, subgroup = group->subgroups;
2109 i > 0;
2110 i --, subgroup ++)
2111 ppd_free_group(subgroup);
2112
2113 ppd_free(group->subgroups);
2114 }
2115}
2116
2117
2118/*
2119 * 'ppd_free_option()' - Free a single option.
2120 */
2121
2122static void
2123ppd_free_option(ppd_option_t *option) /* I - Option to free */
2124{
2125 int i; /* Looping var */
2126 ppd_choice_t *choice; /* Current choice */
2127
2128
2129 if (option->num_choices > 0)
2130 {
2131 for (i = option->num_choices, choice = option->choices;
2132 i > 0;
2133 i --, choice ++)
2134 {
2135 ppd_free(choice->code);
2136 }
2137
2138 ppd_free(option->choices);
2139 }
2140}
2141
2142
ef416fc2 2143/*
fa73b229 2144 * 'ppd_get_coption()' - Get a custom option record.
ef416fc2 2145 */
2146
fa73b229 2147static ppd_coption_t * /* O - Custom option... */
2148ppd_get_coption(ppd_file_t *ppd, /* I - PPD file */
2149 const char *name) /* I - Name of option */
ef416fc2 2150{
fa73b229 2151 ppd_coption_t *copt; /* New custom option */
ef416fc2 2152
2153
2154 /*
2155 * See if the option already exists...
2156 */
2157
fa73b229 2158 if ((copt = ppdFindCustomOption(ppd, name)) != NULL)
2159 return (copt);
ef416fc2 2160
2161 /*
fa73b229 2162 * Not found, so create the custom option record...
ef416fc2 2163 */
2164
fa73b229 2165 if ((copt = calloc(1, sizeof(ppd_coption_t))) == NULL)
ef416fc2 2166 return (NULL);
2167
fa73b229 2168 strlcpy(copt->keyword, name, sizeof(copt->keyword));
ef416fc2 2169
fa73b229 2170 copt->params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL);
ef416fc2 2171
fa73b229 2172 cupsArrayAdd(ppd->coptions, copt);
ef416fc2 2173
2174 /*
2175 * Return the new record...
2176 */
2177
fa73b229 2178 return (copt);
ef416fc2 2179}
2180
2181
2182/*
fa73b229 2183 * 'ppd_get_cparam()' - Get a custom parameter record.
ef416fc2 2184 */
2185
fa73b229 2186static ppd_cparam_t * /* O - Extended option... */
2187ppd_get_cparam(ppd_coption_t *opt, /* I - PPD file */
2188 const char *param, /* I - Name of parameter */
2189 const char *text) /* I - Human-readable text */
ef416fc2 2190{
fa73b229 2191 ppd_cparam_t *cparam; /* New custom parameter */
ef416fc2 2192
2193
2194 /*
2195 * See if the parameter already exists...
2196 */
2197
fa73b229 2198 if ((cparam = ppdFindCustomParam(opt, param)) != NULL)
2199 return (cparam);
ef416fc2 2200
2201 /*
fa73b229 2202 * Not found, so create the custom parameter record...
ef416fc2 2203 */
2204
fa73b229 2205 if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL)
ef416fc2 2206 return (NULL);
2207
fa73b229 2208 strlcpy(cparam->name, param, sizeof(cparam->name));
2209 strlcpy(cparam->text, text, sizeof(cparam->text));
ef416fc2 2210
2211 /*
fa73b229 2212 * Add this record to the array...
ef416fc2 2213 */
2214
fa73b229 2215 cupsArrayAdd(opt->params, cparam);
ef416fc2 2216
2217 /*
2218 * Return the new record...
2219 */
2220
fa73b229 2221 return (cparam);
ef416fc2 2222}
ef416fc2 2223
2224
2225/*
2226 * 'ppd_get_group()' - Find or create the named group as needed.
2227 */
2228
2229static ppd_group_t * /* O - Named group */
2230ppd_get_group(ppd_file_t *ppd, /* I - PPD file */
2231 const char *name, /* I - Name of group */
2232 const char *text, /* I - Text for group */
2233 _cups_globals_t *cg) /* I - Global data */
2234{
2235 int i; /* Looping var */
2236 ppd_group_t *group; /* Group */
2237
2238
2239 DEBUG_printf(("ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)\n",
2240 ppd, name, text, cg));
2241
2242 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
2243 if (!strcmp(group->name, name))
2244 break;
2245
2246 if (i == 0)
2247 {
2248 DEBUG_printf(("Adding group %s...\n", name));
2249
2250 if (cg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
2251 {
2252 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2253
2254 return (NULL);
2255 }
2256
2257 if (ppd->num_groups == 0)
2258 group = malloc(sizeof(ppd_group_t));
2259 else
2260 group = realloc(ppd->groups,
2261 (ppd->num_groups + 1) * sizeof(ppd_group_t));
2262
2263 if (group == NULL)
2264 {
2265 cg->ppd_status = PPD_ALLOC_ERROR;
2266
2267 return (NULL);
2268 }
2269
2270 ppd->groups = group;
2271 group += ppd->num_groups;
2272 ppd->num_groups ++;
2273
2274 memset(group, 0, sizeof(ppd_group_t));
2275 strlcpy(group->name, name, sizeof(group->name));
2276 strlcpy(group->text, text, sizeof(group->text));
2277 }
2278
2279 return (group);
2280}
2281
2282
2283/*
2284 * 'ppd_get_option()' - Find or create the named option as needed.
2285 */
2286
2287static ppd_option_t * /* O - Named option */
2288ppd_get_option(ppd_group_t *group, /* I - Group */
2289 const char *name) /* I - Name of option */
2290{
2291 int i; /* Looping var */
2292 ppd_option_t *option; /* Option */
2293
2294
2295 DEBUG_printf(("ppd_get_option(group=%p(\"%s\"), name=\"%s\")\n",
2296 group, group->name, name));
2297
2298 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
2299 if (!strcmp(option->keyword, name))
2300 break;
2301
2302 if (i == 0)
2303 {
2304 if (group->num_options == 0)
2305 option = malloc(sizeof(ppd_option_t));
2306 else
2307 option = realloc(group->options,
2308 (group->num_options + 1) * sizeof(ppd_option_t));
2309
2310 if (option == NULL)
2311 return (NULL);
2312
2313 group->options = option;
2314 option += group->num_options;
2315 group->num_options ++;
2316
2317 memset(option, 0, sizeof(ppd_option_t));
2318 strlcpy(option->keyword, name, sizeof(option->keyword));
2319 }
2320
2321 return (option);
2322}
2323
2324
2325/*
2326 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2327 * necessary.
2328 */
2329
2330static int /* O - Bitmask of fields read */
2331ppd_read(cups_file_t *fp, /* I - File to read from */
2332 char *keyword, /* O - Keyword from line */
2333 char *option, /* O - Option from line */
2334 char *text, /* O - Human-readable text from line */
2335 char **string, /* O - Code/string data */
2336 int ignoreblank, /* I - Ignore blank lines? */
2337 _cups_globals_t *cg) /* I - Global data */
2338{
2339 int ch, /* Character from file */
2340 col, /* Column in line */
2341 colon, /* Colon seen? */
2342 endquote, /* Waiting for an end quote */
2343 mask, /* Mask to be returned */
2344 startline, /* Start line */
2345 textlen; /* Length of text */
2346 char *keyptr, /* Keyword pointer */
2347 *optptr, /* Option pointer */
2348 *textptr, /* Text pointer */
2349 *strptr, /* Pointer into string */
2350 *lineptr, /* Current position in line buffer */
2351 *line; /* Line buffer */
2352 int linesize; /* Current size of line buffer */
2353
2354 /*
2355 * Range check everything...
2356 */
2357
2358 if (!fp || !keyword || !option || !text || !string)
2359 return (0);
2360
2361 /*
2362 * Now loop until we have a valid line...
2363 */
2364
2365 *string = NULL;
2366 col = 0;
2367 startline = cg->ppd_line + 1;
2368 linesize = 1024;
2369 line = malloc(linesize);
2370
2371 if (!line)
2372 return (0);
2373
2374 do
2375 {
2376 /*
2377 * Read the line...
2378 */
2379
2380 lineptr = line;
2381 endquote = 0;
2382 colon = 0;
2383
2384 while ((ch = cupsFileGetChar(fp)) != EOF)
2385 {
2386 if (lineptr >= (line + linesize - 1))
2387 {
2388 /*
2389 * Expand the line buffer...
2390 */
2391
2392 char *temp; /* Temporary line pointer */
2393
2394
2395 linesize += 1024;
2396 if (linesize > 262144)
2397 {
2398 /*
2399 * Don't allow lines longer than 256k!
2400 */
2401
2402 cg->ppd_line = startline;
2403 cg->ppd_status = PPD_LINE_TOO_LONG;
2404
2405 free(line);
2406
2407 return (0);
2408 }
2409
2410 temp = realloc(line, linesize);
2411 if (!temp)
2412 {
2413 cg->ppd_line = startline;
2414 cg->ppd_status = PPD_LINE_TOO_LONG;
2415
2416 free(line);
2417
2418 return (0);
2419 }
2420
2421 lineptr = temp + (lineptr - line);
2422 line = temp;
2423 }
2424
2425 if (ch == '\r' || ch == '\n')
2426 {
2427 /*
2428 * Line feed or carriage return...
2429 */
2430
2431 cg->ppd_line ++;
2432 col = 0;
2433
2434 if (ch == '\r')
2435 {
2436 /*
2437 * Check for a trailing line feed...
2438 */
2439
2440 if ((ch = cupsFilePeekChar(fp)) == EOF)
fa73b229 2441 {
2442 ch = '\n';
ef416fc2 2443 break;
fa73b229 2444 }
2445
ef416fc2 2446 if (ch == 0x0a)
2447 cupsFileGetChar(fp);
2448 }
2449
2450 if (lineptr == line && ignoreblank)
2451 continue; /* Skip blank lines */
2452
2453 ch = '\n';
2454
2455 if (!endquote) /* Continue for multi-line text */
2456 break;
2457
2458 *lineptr++ = '\n';
2459 }
2460 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2461 {
2462 /*
2463 * Other control characters...
2464 */
2465
2466 cg->ppd_line = startline;
2467 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2468
2469 free(line);
2470
2471 return (0);
2472 }
2473 else if (ch != 0x1a)
2474 {
2475 /*
2476 * Any other character...
2477 */
2478
2479 *lineptr++ = ch;
2480 col ++;
2481
2482 if (col > (PPD_MAX_LINE - 1))
2483 {
2484 /*
2485 * Line is too long...
2486 */
2487
2488 cg->ppd_line = startline;
2489 cg->ppd_status = PPD_LINE_TOO_LONG;
2490
2491 free(line);
2492
2493 return (0);
2494 }
2495
2496 if (ch == ':' && strncmp(line, "*%", 2) != 0)
2497 colon = 1;
2498
2499 if (ch == '\"' && colon)
2500 endquote = !endquote;
2501 }
2502 }
2503
2504 if (endquote)
2505 {
2506 /*
2507 * Didn't finish this quoted string...
2508 */
2509
2510 while ((ch = cupsFileGetChar(fp)) != EOF)
2511 if (ch == '\"')
2512 break;
2513 else if (ch == '\r' || ch == '\n')
2514 {
2515 cg->ppd_line ++;
2516 col = 0;
2517
2518 if (ch == '\r')
2519 {
2520 /*
2521 * Check for a trailing line feed...
2522 */
2523
2524 if ((ch = cupsFilePeekChar(fp)) == EOF)
2525 break;
2526 if (ch == 0x0a)
2527 cupsFileGetChar(fp);
2528 }
2529
2530 ch = '\n';
2531 }
2532 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2533 {
2534 /*
2535 * Other control characters...
2536 */
2537
2538 cg->ppd_line = startline;
2539 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2540
2541 free(line);
2542
2543 return (0);
2544 }
2545 else if (ch != 0x1a)
2546 {
2547 col ++;
2548
2549 if (col > (PPD_MAX_LINE - 1))
2550 {
2551 /*
2552 * Line is too long...
2553 */
2554
2555 cg->ppd_line = startline;
2556 cg->ppd_status = PPD_LINE_TOO_LONG;
2557
2558 free(line);
2559
2560 return (0);
2561 }
2562 }
2563 }
2564
2565 if (ch != '\n')
2566 {
2567 /*
2568 * Didn't finish this line...
2569 */
2570
2571 while ((ch = cupsFileGetChar(fp)) != EOF)
2572 if (ch == '\r' || ch == '\n')
2573 {
2574 /*
2575 * Line feed or carriage return...
2576 */
2577
2578 cg->ppd_line ++;
2579 col = 0;
2580
2581 if (ch == '\r')
2582 {
2583 /*
2584 * Check for a trailing line feed...
2585 */
2586
2587 if ((ch = cupsFilePeekChar(fp)) == EOF)
2588 break;
2589 if (ch == 0x0a)
2590 cupsFileGetChar(fp);
2591 }
2592
2593 break;
2594 }
2595 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2596 {
2597 /*
2598 * Other control characters...
2599 */
2600
2601 cg->ppd_line = startline;
2602 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2603
2604 free(line);
2605
2606 return (0);
2607 }
2608 else if (ch != 0x1a)
2609 {
2610 col ++;
2611
2612 if (col > (PPD_MAX_LINE - 1))
2613 {
2614 /*
2615 * Line is too long...
2616 */
2617
2618 cg->ppd_line = startline;
2619 cg->ppd_status = PPD_LINE_TOO_LONG;
2620
2621 free(line);
2622
2623 return (0);
2624 }
2625 }
2626 }
2627
2628 if (lineptr > line && lineptr[-1] == '\n')
2629 lineptr --;
2630
2631 *lineptr = '\0';
2632
2633 DEBUG_printf(("LINE = \"%s\"\n", line));
2634
bd7854cb 2635 /*
2636 * The dynamically created PPDs for older style Mac OS X
2637 * drivers include a large blob of data inserted as comments
2638 * at the end of the file. As an optimization we can stop
2639 * reading the PPD when we get to the start of this data.
2640 */
2641
2642 if (!strcmp(line, "*%APLWORKSET START"))
2643 {
2644 free(line);
2645 return (0);
2646 }
2647
ef416fc2 2648 if (ch == EOF && lineptr == line)
2649 {
2650 free(line);
2651 return (0);
2652 }
2653
2654 /*
2655 * Now parse it...
2656 */
2657
2658 mask = 0;
2659 lineptr = line + 1;
2660
2661 keyword[0] = '\0';
2662 option[0] = '\0';
2663 text[0] = '\0';
2664 *string = NULL;
2665
2666 if ((!line[0] || /* Blank line */
2667 !strncmp(line, "*%", 2) || /* Comment line */
2668 !strcmp(line, "*End")) && /* End of multi-line string */
2669 ignoreblank) /* Ignore these? */
2670 {
2671 startline = cg->ppd_line + 1;
2672 continue;
2673 }
2674
2675 if (!strcmp(line, "*")) /* (Bad) comment line */
2676 {
2677 if (cg->ppd_conform == PPD_CONFORM_RELAXED)
2678 {
2679 startline = cg->ppd_line + 1;
2680 continue;
2681 }
2682 else
2683 {
2684 cg->ppd_line = startline;
2685 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
2686
2687 free(line);
2688 return (0);
2689 }
2690 }
2691
2692 if (line[0] != '*') /* All lines start with an asterisk */
2693 {
ef416fc2 2694 /*
2695 * Allow lines consisting of just whitespace...
2696 */
2697
2698 for (lineptr = line; *lineptr; lineptr ++)
2699 if (!isspace(*lineptr & 255))
2700 break;
2701
2702 if (*lineptr)
2703 {
2704 cg->ppd_status = PPD_MISSING_ASTERISK;
2705 free(line);
2706 return (0);
2707 }
2708 else if (ignoreblank)
2709 continue;
2710 else
2711 {
2712 free(line);
2713 return (0);
2714 }
2715 }
2716
2717 /*
2718 * Get a keyword...
2719 */
2720
2721 keyptr = keyword;
2722
2723 while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr & 255))
2724 {
2725 if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
2726 (keyptr - keyword) >= (PPD_MAX_NAME - 1))
2727 {
2728 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
2729 free(line);
2730 return (0);
2731 }
2732
2733 *keyptr++ = *lineptr++;
2734 }
2735
2736 *keyptr = '\0';
2737
2738 if (!strcmp(keyword, "End"))
2739 continue;
2740
2741 mask |= PPD_KEYWORD;
2742
2743/* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
2744
2745 if (isspace(*lineptr & 255))
2746 {
2747 /*
2748 * Get an option name...
2749 */
2750
2751 while (isspace(*lineptr & 255))
2752 lineptr ++;
2753
2754 optptr = option;
2755
2756 while (*lineptr != '\0' && !isspace(*lineptr & 255) && *lineptr != ':' &&
2757 *lineptr != '/')
2758 {
2759 if (*lineptr <= ' ' || *lineptr > 126 ||
2760 (optptr - option) >= (PPD_MAX_NAME - 1))
2761 {
2762 cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
2763 free(line);
2764 return (0);
2765 }
2766
2767 *optptr++ = *lineptr++;
2768 }
2769
2770 *optptr = '\0';
2771
2772 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
2773 {
2774 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
2775 free(line);
2776 return (0);
2777 }
2778
2779 while (isspace(*lineptr & 255))
2780 lineptr ++;
2781
2782 mask |= PPD_OPTION;
2783
2784/* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
2785
2786 if (*lineptr == '/')
2787 {
2788 /*
2789 * Get human-readable text...
2790 */
2791
2792 lineptr ++;
2793
2794 textptr = text;
2795
2796 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
2797 {
2798 if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
2799 (textptr - text) >= (PPD_MAX_LINE - 1))
2800 {
2801 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2802 free(line);
2803 return (0);
2804 }
2805
2806 *textptr++ = *lineptr++;
2807 }
2808
2809 *textptr = '\0';
2810 textlen = ppd_decode(text);
2811
2812 if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT)
2813 {
2814 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2815 free(line);
2816 return (0);
2817 }
2818
2819 mask |= PPD_TEXT;
2820 }
2821
2822/* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
2823 }
2824
2825 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
2826 {
2827 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
2828 free(line);
2829 return (0);
2830 }
2831
2832 while (isspace(*lineptr & 255))
2833 lineptr ++;
2834
2835 if (*lineptr == ':')
2836 {
2837 /*
2838 * Get string after triming leading and trailing whitespace...
2839 */
2840
2841 lineptr ++;
2842 while (isspace(*lineptr & 255))
2843 lineptr ++;
2844
2845 strptr = lineptr + strlen(lineptr) - 1;
2846 while (strptr >= lineptr && isspace(*strptr & 255))
2847 *strptr-- = '\0';
2848
2849 if (*strptr == '\"')
2850 {
2851 /*
2852 * Quoted string by itself...
2853 */
2854
2855 *string = malloc(strlen(lineptr) + 1);
2856
2857 strptr = *string;
2858
2859 for (; *lineptr != '\0'; lineptr ++)
2860 if (*lineptr != '\"')
2861 *strptr++ = *lineptr;
2862
2863 *strptr = '\0';
2864 }
2865 else
2866 *string = strdup(lineptr);
2867
2868/* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
2869
2870 mask |= PPD_STRING;
2871 }
2872 }
2873 while (mask == 0);
2874
2875 free(line);
2876
2877 return (mask);
2878}
2879
2880
2881/*
757d2cad 2882 * End of "$Id: ppd.c 5238 2006-03-07 04:41:42Z mike $".
ef416fc2 2883 */