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