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