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