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