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