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