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