]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/ppd.c
Mirror 1.1.x changes to use strlcpy() and strlcat().
[thirdparty/cups.git] / cups / ppd.c
1 /*
2 * "$Id: ppd.c,v 1.51.2.15 2002/05/16 13:59:59 mike Exp $"
3 *
4 * PPD file routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2002 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 * ppdClose() - Free all memory used by the PPD file.
38 * ppd_free_group() - Free a single UI group.
39 * ppd_free_option() - Free a single option.
40 * ppdOpen() - Read a PPD file into memory.
41 * ppdOpenFd() - Read a PPD file into memory.
42 * ppdOpenFile() - Read a PPD file into memory.
43 * ppd_read() - Read a line from a PPD file, skipping comment lines
44 * as necessary.
45 * compare_strings() - Compare two strings.
46 * compare_groups() - Compare two groups.
47 * compare_options() - Compare two options.
48 * compare_choices() - Compare two choices.
49 */
50
51 /*
52 * Include necessary headers.
53 */
54
55 #include "ppd.h"
56 #include <stdlib.h>
57 #include <ctype.h>
58 #include "string.h"
59 #include "language.h"
60 #include "debug.h"
61
62
63 /*
64 * Definitions...
65 */
66
67 #if defined(WIN32) || defined(__EMX__)
68 # define READ_BINARY "rb" /* Open a binary file for reading */
69 # define WRITE_BINARY "wb" /* Open a binary file for writing */
70 #else
71 # define READ_BINARY "r" /* Open a binary file for reading */
72 # define WRITE_BINARY "w" /* Open a binary file for writing */
73 #endif /* WIN32 || __EMX__ */
74
75 #define safe_free(p) if (p) free(p) /* Safe free macro */
76
77 #define PPD_KEYWORD 1 /* Line contained a keyword */
78 #define PPD_OPTION 2 /* Line contained an option name */
79 #define PPD_TEXT 4 /* Line contained human-readable text */
80 #define PPD_STRING 8 /* Line contained a string or code */
81
82
83 /*
84 * Local functions...
85 */
86
87 static int compare_strings(char *s, char *t);
88 static int compare_groups(ppd_group_t *g0, ppd_group_t *g1);
89 static int compare_options(ppd_option_t *o0, ppd_option_t *o1);
90 static int compare_choices(ppd_choice_t *c0, ppd_choice_t *c1);
91 static int ppd_read(FILE *fp, char *keyword, char *option,
92 char *text, char **string);
93 static void ppd_decode(char *string);
94 static void ppd_fix(char *string);
95 static void ppd_free_group(ppd_group_t *group);
96 static void ppd_free_option(ppd_option_t *option);
97 static ppd_group_t *ppd_get_group(ppd_file_t *ppd, const char *name,
98 const char *text);
99 static ppd_attr_t *ppd_add_attr(ppd_file_t *ppd, const char *name,
100 const char *spec, const char *value);
101 static ppd_option_t *ppd_get_option(ppd_group_t *group, const char *name);
102 static ppd_choice_t *ppd_add_choice(ppd_option_t *option, const char *name);
103
104
105 /*
106 * 'ppdClose()' - Free all memory used by the PPD file.
107 */
108
109 void
110 ppdClose(ppd_file_t *ppd) /* I - PPD file record */
111 {
112 int i; /* Looping var */
113 ppd_emul_t *emul; /* Current emulation */
114 ppd_group_t *group; /* Current group */
115 char **font; /* Current font */
116 char **filter; /* Current filter */
117 ppd_attr_t **attr; /* Current attribute */
118
119
120 /*
121 * Range check the PPD file record...
122 */
123
124 if (ppd == NULL)
125 return;
126
127 /*
128 * Free all strings at the top level...
129 */
130
131 safe_free(ppd->patches);
132 safe_free(ppd->jcl_begin);
133 safe_free(ppd->jcl_ps);
134 safe_free(ppd->jcl_end);
135 safe_free(ppd->lang_encoding);
136 safe_free(ppd->lang_version);
137 safe_free(ppd->modelname);
138 safe_free(ppd->ttrasterizer);
139 safe_free(ppd->manufacturer);
140 safe_free(ppd->product);
141 safe_free(ppd->nickname);
142 safe_free(ppd->shortnickname);
143
144 /*
145 * Free any emulations...
146 */
147
148 if (ppd->num_emulations > 0)
149 {
150 for (i = ppd->num_emulations, emul = ppd->emulations; i > 0; i --, emul ++)
151 {
152 safe_free(emul->start);
153 safe_free(emul->stop);
154 }
155
156 safe_free(ppd->emulations);
157 }
158
159 /*
160 * Free any UI groups, subgroups, and options...
161 */
162
163 if (ppd->num_groups > 0)
164 {
165 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
166 ppd_free_group(group);
167
168 safe_free(ppd->groups);
169 }
170
171 /*
172 * Free any page sizes...
173 */
174
175 if (ppd->num_sizes > 0)
176 safe_free(ppd->sizes);
177
178 /*
179 * Free any constraints...
180 */
181
182 if (ppd->num_consts > 0)
183 safe_free(ppd->consts);
184
185 /*
186 * Free any filters...
187 */
188
189 if (ppd->num_filters > 0)
190 {
191 for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++)
192 safe_free(*filter);
193
194 safe_free(ppd->filters);
195 }
196
197 /*
198 * Free any fonts...
199 */
200
201 if (ppd->num_fonts > 0)
202 {
203 for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++)
204 safe_free(*font);
205
206 safe_free(ppd->fonts);
207 }
208
209 /*
210 * Free any profiles...
211 */
212
213 if (ppd->num_profiles > 0)
214 safe_free(ppd->profiles);
215
216 /*
217 * Free any attributes...
218 */
219
220 if (ppd->num_attrs > 0)
221 {
222 for (i = ppd->num_attrs, attr = ppd->attrs; i > 0; i --, attr ++)
223 {
224 safe_free((*attr)->value);
225 safe_free(*attr);
226 }
227
228 safe_free(ppd->attrs);
229 }
230
231 /*
232 * Free the whole record...
233 */
234
235 safe_free(ppd);
236 }
237
238
239 /*
240 * 'ppd_add_attr()' - Add an attribute to the PPD data.
241 */
242
243 static ppd_attr_t * /* O - New attribute */
244 ppd_add_attr(ppd_file_t *ppd, /* I - PPD file data */
245 const char *name, /* I - Attribute name */
246 const char *spec, /* I - Specifier string, if any */
247 const char *value) /* I - Value of attribute */
248 {
249 ppd_attr_t **ptr, /* New array */
250 *temp; /* New attribute */
251
252
253 /*
254 * Range check input...
255 */
256
257 if (ppd == NULL || name == NULL || spec == NULL)
258 return (NULL);
259
260 /*
261 * Allocate memory for the new attribute...
262 */
263
264 if (ppd->num_attrs == 0)
265 ptr = malloc(sizeof(ppd_attr_t *));
266 else
267 ptr = realloc(ppd->attrs, (ppd->num_attrs + 1) * sizeof(ppd_attr_t *));
268
269 if (ptr == NULL)
270 return (NULL);
271
272 ppd->attrs = ptr;
273 ptr += ppd->num_attrs;
274
275 if ((temp = calloc(1, sizeof(ppd_attr_t))) == NULL)
276 return (NULL);
277
278 *ptr = temp;
279
280 ppd->num_attrs ++;
281
282 /*
283 * Copy data over...
284 */
285
286 strlcpy(temp->name, name, sizeof(temp->name));
287 strlcpy(temp->spec, spec, sizeof(temp->spec));
288 temp->value = (char *)value;
289
290 /*
291 * Return the attribute...
292 */
293
294 return (temp);
295 }
296
297
298 /*
299 * '_ppd_attr_compare()' - Compare two attributes.
300 */
301
302 int /* O - Result of comparison */
303 _ppd_attr_compare(ppd_attr_t **a, /* I - First attribute */
304 ppd_attr_t **b) /* I - Second attribute */
305 {
306 int ret; /* Result of comparison */
307
308
309 if ((ret = strcasecmp((*a)->name, (*b)->name)) != 0)
310 return (ret);
311 else if ((*a)->spec[0] && (*b)->spec[0])
312 return (strcasecmp((*a)->spec, (*b)->spec));
313 else
314 return (0);
315 }
316
317
318 /*
319 * 'ppd_free_group()' - Free a single UI group.
320 */
321
322 static void
323 ppd_free_group(ppd_group_t *group) /* I - Group to free */
324 {
325 int i; /* Looping var */
326 ppd_option_t *option; /* Current option */
327 ppd_group_t *subgroup; /* Current sub-group */
328
329
330 if (group->num_options > 0)
331 {
332 for (i = group->num_options, option = group->options;
333 i > 0;
334 i --, option ++)
335 ppd_free_option(option);
336
337 safe_free(group->options);
338 }
339
340 if (group->num_subgroups > 0)
341 {
342 for (i = group->num_subgroups, subgroup = group->subgroups;
343 i > 0;
344 i --, subgroup ++)
345 ppd_free_group(subgroup);
346
347 safe_free(group->subgroups);
348 }
349 }
350
351
352 /*
353 * 'ppd_free_option()' - Free a single option.
354 */
355
356 static void
357 ppd_free_option(ppd_option_t *option) /* I - Option to free */
358 {
359 int i; /* Looping var */
360 ppd_choice_t *choice; /* Current choice */
361
362
363 if (option->num_choices > 0)
364 {
365 for (i = option->num_choices, choice = option->choices;
366 i > 0;
367 i --, choice ++)
368 safe_free(choice->code);
369
370 safe_free(option->choices);
371 }
372 }
373
374
375 /*
376 * 'ppd_get_group()' - Find or create the named group as needed.
377 */
378
379 static ppd_group_t * /* O - Named group */
380 ppd_get_group(ppd_file_t *ppd, /* I - PPD file */
381 const char *name, /* I - Name of group */
382 const char *text) /* I - Text for group */
383 {
384 int i; /* Looping var */
385 ppd_group_t *group; /* Group */
386
387
388 DEBUG_printf(("ppd_get_group(%p, \"%s\")\n", ppd, name));
389
390 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
391 if (strcmp(group->name, name) == 0)
392 break;
393
394 if (i == 0)
395 {
396 DEBUG_printf(("Adding group %s...\n", name));
397
398 if (ppd->num_groups == 0)
399 group = malloc(sizeof(ppd_group_t));
400 else
401 group = realloc(ppd->groups,
402 (ppd->num_groups + 1) * sizeof(ppd_group_t));
403
404 if (group == NULL)
405 return (NULL);
406
407 ppd->groups = group;
408 group += ppd->num_groups;
409 ppd->num_groups ++;
410
411 memset(group, 0, sizeof(ppd_group_t));
412 strlcpy(group->name, name, sizeof(group->name));
413 strlcpy(group->text, text, sizeof(group->text));
414 }
415
416 return (group);
417 }
418
419
420 /*
421 * 'ppd_get_option()' - Find or create the named option as needed.
422 */
423
424 static ppd_option_t * /* O - Named option */
425 ppd_get_option(ppd_group_t *group, /* I - Group */
426 const char *name) /* I - Name of option */
427 {
428 int i; /* Looping var */
429 ppd_option_t *option; /* Option */
430
431
432 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
433 if (strcmp(option->keyword, name) == 0)
434 break;
435
436 if (i == 0)
437 {
438 if (group->num_options == 0)
439 option = malloc(sizeof(ppd_option_t));
440 else
441 option = realloc(group->options,
442 (group->num_options + 1) * sizeof(ppd_option_t));
443
444 if (option == NULL)
445 return (NULL);
446
447 group->options = option;
448 option += group->num_options;
449 group->num_options ++;
450
451 memset(option, 0, sizeof(ppd_option_t));
452 strlcpy(option->keyword, name, sizeof(option->keyword));
453 }
454
455 return (option);
456 }
457
458
459 /*
460 * 'ppd_add_choice()' - Add a choice to an option.
461 */
462
463 static ppd_choice_t * /* O - Named choice */
464 ppd_add_choice(ppd_option_t *option, /* I - Option */
465 const char *name) /* I - Name of choice */
466 {
467 ppd_choice_t *choice; /* Choice */
468
469
470 if (option->num_choices == 0)
471 choice = malloc(sizeof(ppd_choice_t));
472 else
473 choice = realloc(option->choices,
474 sizeof(ppd_choice_t) * (option->num_choices + 1));
475
476 if (choice == NULL)
477 return (NULL);
478
479 option->choices = choice;
480 choice += option->num_choices;
481 option->num_choices ++;
482
483 memset(choice, 0, sizeof(ppd_choice_t));
484 strlcpy(choice->choice, name, sizeof(choice->choice));
485
486 return (choice);
487 }
488
489
490 /*
491 * 'ppd_add_size()' - Add a page size.
492 */
493
494 static ppd_size_t * /* O - Named size */
495 ppd_add_size(ppd_file_t *ppd, /* I - PPD file */
496 const char *name) /* I - Name of size */
497 {
498 ppd_size_t *size; /* Size */
499
500
501 if (ppd->num_sizes == 0)
502 size = malloc(sizeof(ppd_size_t));
503 else
504 size = realloc(ppd->sizes, sizeof(ppd_size_t) * (ppd->num_sizes + 1));
505
506 if (size == NULL)
507 return (NULL);
508
509 ppd->sizes = size;
510 size += ppd->num_sizes;
511 ppd->num_sizes ++;
512
513 memset(size, 0, sizeof(ppd_size_t));
514 strlcpy(size->name, name, sizeof(size->name));
515
516 return (size);
517 }
518
519
520 /*
521 * 'ppdOpen()' - Read a PPD file into memory.
522 */
523
524 ppd_file_t * /* O - PPD file record */
525 ppdOpen(FILE *fp) /* I - File to read from */
526 {
527 int i, j, k, m; /* Looping vars */
528 int count; /* Temporary count */
529 ppd_file_t *ppd; /* PPD file record */
530 ppd_group_t *group, /* Current group */
531 *subgroup; /* Current sub-group */
532 ppd_option_t *option; /* Current option */
533 ppd_choice_t *choice; /* Current choice */
534 ppd_const_t *constraint; /* Current constraint */
535 ppd_size_t *size; /* Current page size */
536 int mask; /* Line data mask */
537 char keyword[PPD_MAX_NAME],
538 /* Keyword from file */
539 name[PPD_MAX_NAME],
540 /* Option from file */
541 text[PPD_MAX_LINE],
542 /* Human-readable text from file */
543 *string, /* Code/text from file */
544 *sptr, /* Pointer into string */
545 *nameptr, /* Pointer into name */
546 *temp, /* Temporary string pointer */
547 **tempfonts; /* Temporary fonts pointer */
548 float order; /* Order dependency number */
549 ppd_section_t section; /* Order dependency section */
550 ppd_profile_t *profile; /* Pointer to color profile */
551 char **filter; /* Pointer to filter */
552 cups_lang_t *language; /* Default language */
553
554
555 /*
556 * Get the default language for the user...
557 */
558
559 language = cupsLangDefault();
560
561 /*
562 * Range check input...
563 */
564
565 if (fp == NULL)
566 return (NULL);
567
568 /*
569 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
570 */
571
572 mask = ppd_read(fp, keyword, name, text, &string);
573
574 if (mask == 0 ||
575 strcmp(keyword, "PPD-Adobe") != 0 ||
576 string == NULL || string[0] != '4')
577 {
578 /*
579 * Either this is not a PPD file, or it is not a 4.x PPD file.
580 */
581
582 safe_free(string);
583
584 return (NULL);
585 }
586
587 DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword, string));
588
589 safe_free(string);
590
591 /*
592 * Allocate memory for the PPD file record...
593 */
594
595 if ((ppd = calloc(sizeof(ppd_file_t), 1)) == NULL)
596 return (NULL);
597
598 ppd->language_level = 1;
599 ppd->color_device = 0;
600 ppd->colorspace = PPD_CS_GRAY;
601 ppd->landscape = -90;
602
603 /*
604 * Read lines from the PPD file and add them to the file record...
605 */
606
607 group = NULL;
608 subgroup = NULL;
609 option = NULL;
610 choice = NULL;
611
612 while ((mask = ppd_read(fp, keyword, name, text, &string)) != 0)
613 {
614 #ifdef DEBUG
615 printf("mask = %x, keyword = \"%s\"", mask, keyword);
616
617 if (name[0] != '\0')
618 printf(", name = \"%s\"", name);
619
620 if (text[0] != '\0')
621 printf(", text = \"%s\"", text);
622
623 if (string != NULL)
624 {
625 if (strlen(string) > 40)
626 printf(", string = %p", string);
627 else
628 printf(", string = \"%s\"", string);
629 }
630
631 puts("");
632 #endif /* DEBUG */
633
634 if (strcmp(keyword, "CloseUI") != 0 &&
635 strcmp(keyword, "JCLCloseUI") != 0 &&
636 strcmp(keyword, "CloseGroup") != 0 &&
637 strcmp(keyword, "CloseSubGroup") != 0 &&
638 strncmp(keyword, "Default", 7) != 0 &&
639 string == NULL)
640 {
641 /*
642 * Need a string value!
643 */
644
645 ppdClose(ppd);
646 return (NULL);
647 }
648
649 if (strcmp(keyword, "LanguageLevel") == 0)
650 ppd->language_level = atoi(string);
651 else if (strcmp(keyword, "LanguageEncoding") == 0)
652 {
653 ppd->lang_encoding = string;
654 string = NULL; /* Don't free this string below */
655 }
656 else if (strcmp(keyword, "LanguageVersion") == 0)
657 {
658 ppd->lang_version = string;
659 string = NULL; /* Don't free this string below */
660 }
661 else if (strcmp(keyword, "Manufacturer") == 0)
662 {
663 ppd->manufacturer = string;
664 string = NULL; /* Don't free this string below */
665 }
666 else if (strcmp(keyword, "ModelName") == 0)
667 {
668 ppd->modelname = string;
669 string = NULL; /* Don't free this string below */
670 }
671 else if (strcmp(keyword, "PCFileName") == 0)
672 {
673 ppd->pcfilename = string;
674 string = NULL; /* Don't free this string below */
675 }
676 else if (strcmp(keyword, "NickName") == 0)
677 {
678 ppd->nickname = string;
679 string = NULL; /* Don't free this string below */
680 }
681 else if (strcmp(keyword, "Product") == 0)
682 {
683 ppd->product = string;
684 string = NULL; /* Don't free this string below */
685 }
686 else if (strcmp(keyword, "ShortNickName") == 0)
687 {
688 ppd->shortnickname = string;
689 string = NULL; /* Don't free this string below */
690 }
691 else if (strcmp(keyword, "TTRasterizer") == 0)
692 {
693 ppd->ttrasterizer = string;
694 string = NULL; /* Don't free this string below */
695 }
696 else if (strcmp(keyword, "JCLBegin") == 0)
697 {
698 ppd_decode(string); /* Decode quoted string */
699 ppd->jcl_begin = string;
700 string = NULL; /* Don't free this string below */
701 }
702 else if (strcmp(keyword, "JCLEnd") == 0)
703 {
704 ppd_decode(string); /* Decode quoted string */
705 ppd->jcl_end = string;
706 string = NULL; /* Don't free this string below */
707 }
708 else if (strcmp(keyword, "JCLToPSInterpreter") == 0)
709 {
710 ppd_decode(string); /* Decode quoted string */
711 ppd->jcl_ps = string;
712 string = NULL; /* Don't free this string below */
713 }
714 else if (strcmp(keyword, "AccurateScreensSupport") == 0)
715 ppd->accurate_screens = strcmp(string, "True") == 0;
716 else if (strcmp(keyword, "ColorDevice") == 0)
717 ppd->color_device = strcmp(string, "True") == 0;
718 else if (strcmp(keyword, "ContoneOnly") == 0)
719 ppd->contone_only = strcmp(string, "True") == 0;
720 else if (strcmp(keyword, "DefaultColorSpace") == 0)
721 {
722 if (strcmp(string, "CMY") == 0)
723 ppd->colorspace = PPD_CS_CMY;
724 else if (strcmp(string, "CMYK") == 0)
725 ppd->colorspace = PPD_CS_CMYK;
726 else if (strcmp(string, "RGB") == 0)
727 ppd->colorspace = PPD_CS_RGB;
728 else if (strcmp(string, "RGBK") == 0)
729 ppd->colorspace = PPD_CS_RGBK;
730 else if (strcmp(string, "N") == 0)
731 ppd->colorspace = PPD_CS_N;
732 else
733 ppd->colorspace = PPD_CS_GRAY;
734 }
735 else if (strcmp(keyword, "cupsFlipDuplex") == 0)
736 ppd->flip_duplex = strcmp(string, "True") == 0;
737 else if (strcmp(keyword, "cupsManualCopies") == 0)
738 ppd->manual_copies = strcmp(string, "True") == 0;
739 else if (strcmp(keyword, "cupsModelNumber") == 0)
740 ppd->model_number = atoi(string);
741 else if (strcmp(keyword, "cupsColorProfile") == 0)
742 {
743 if (ppd->num_profiles == 0)
744 profile = malloc(sizeof(ppd_profile_t));
745 else
746 profile = realloc(ppd->profiles, sizeof(ppd_profile_t) *
747 (ppd->num_profiles + 1));
748
749 ppd->profiles = profile;
750 profile += ppd->num_profiles;
751 ppd->num_profiles ++;
752
753 memset(profile, 0, sizeof(ppd_profile_t));
754 strlcpy(profile->resolution, name, sizeof(profile->resolution));
755 strlcpy(profile->media_type, text, sizeof(profile->media_type));
756 sscanf(string, "%f%f%f%f%f%f%f%f%f%f%f", &(profile->density),
757 &(profile->gamma),
758 profile->matrix[0] + 0, profile->matrix[0] + 1,
759 profile->matrix[0] + 2, profile->matrix[1] + 0,
760 profile->matrix[1] + 1, profile->matrix[1] + 2,
761 profile->matrix[2] + 0, profile->matrix[2] + 1,
762 profile->matrix[2] + 2);
763 }
764 else if (strcmp(keyword, "cupsFilter") == 0)
765 {
766 if (ppd->num_filters == 0)
767 filter = malloc(sizeof(char *));
768 else
769 filter = realloc(ppd->filters, sizeof(char *) * (ppd->num_filters + 1));
770
771 if (filter == NULL)
772 {
773 safe_free(filter);
774 ppdClose(ppd);
775 return (NULL);
776 }
777
778 ppd->filters = filter;
779 filter += ppd->num_filters;
780 ppd->num_filters ++;
781
782 /*
783 * Copy filter string and prevent it from being freed below...
784 */
785
786 *filter = string;
787 string = NULL;
788 }
789 else if (strcmp(keyword, "Throughput") == 0)
790 ppd->throughput = atoi(string);
791 else if (strcmp(keyword, "Font") == 0)
792 {
793 /*
794 * Add this font to the list of available fonts...
795 */
796
797 if (ppd->num_fonts == 0)
798 tempfonts = (char **)malloc(sizeof(char *));
799 else
800 tempfonts = (char **)realloc(ppd->fonts,
801 sizeof(char *) * (ppd->num_fonts + 1));
802
803 if (tempfonts == NULL)
804 {
805 safe_free(string);
806 ppdClose(ppd);
807 return (NULL);
808 }
809
810 ppd->fonts = tempfonts;
811 ppd->fonts[ppd->num_fonts] = strdup(name);
812 ppd->num_fonts ++;
813 }
814 else if (strcmp(keyword, "VariablePaperSize") == 0 &&
815 strcmp(string, "True") == 0 &&
816 !ppd->variable_sizes)
817 {
818 ppd->variable_sizes = 1;
819
820 /*
821 * Add a "Custom" page size entry...
822 */
823
824 ppd_add_size(ppd, "Custom");
825
826 /*
827 * Add a "Custom" page size option...
828 */
829
830 if ((option = ppdFindOption(ppd, "PageSize")) == NULL)
831 {
832 ppd_group_t *temp;
833
834
835 if ((temp = ppd_get_group(ppd, "General",
836 cupsLangString(language,
837 CUPS_MSG_GENERAL))) == NULL)
838 {
839 ppdClose(ppd);
840 safe_free(string);
841 return (NULL);
842 }
843
844 if ((option = ppd_get_option(temp, "PageSize")) == NULL)
845 {
846 ppdClose(ppd);
847 safe_free(string);
848 return (NULL);
849 }
850 }
851
852 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
853 {
854 ppdClose(ppd);
855 safe_free(string);
856 return (NULL);
857 }
858
859 strlcpy(choice->text, cupsLangString(language, CUPS_MSG_VARIABLE),
860 sizeof(choice->text));
861 option = NULL;
862 }
863 else if (strcmp(keyword, "MaxMediaWidth") == 0)
864 ppd->custom_max[0] = (float)atof(string);
865 else if (strcmp(keyword, "MaxMediaHeight") == 0)
866 ppd->custom_max[1] = (float)atof(string);
867 else if (strcmp(keyword, "ParamCustomPageSize") == 0)
868 {
869 if (strcmp(name, "Width") == 0)
870 sscanf(string, "%*s%*s%f%f", ppd->custom_min + 0,
871 ppd->custom_max + 0);
872 else if (strcmp(name, "Height") == 0)
873 sscanf(string, "%*s%*s%f%f", ppd->custom_min + 1,
874 ppd->custom_max + 1);
875 }
876 else if (strcmp(keyword, "HWMargins") == 0)
877 sscanf(string, "%f%f%f%f", ppd->custom_margins + 0,
878 ppd->custom_margins + 1, ppd->custom_margins + 2,
879 ppd->custom_margins + 3);
880 else if (strcmp(keyword, "CustomPageSize") == 0 &&
881 strcmp(name, "True") == 0)
882 {
883 if (!ppd->variable_sizes)
884 {
885 ppd->variable_sizes = 1;
886
887 /*
888 * Add a "Custom" page size entry...
889 */
890
891 ppd_add_size(ppd, "Custom");
892
893 /*
894 * Add a "Custom" page size option...
895 */
896
897 if ((option = ppdFindOption(ppd, "PageSize")) == NULL)
898 {
899 ppd_group_t *temp;
900
901
902 if ((temp = ppd_get_group(ppd, "General",
903 cupsLangString(language,
904 CUPS_MSG_GENERAL))) == NULL)
905 {
906 DEBUG_puts("Unable to get general group!");
907 ppdClose(ppd);
908 safe_free(string);
909 return (NULL);
910 }
911
912 if ((option = ppd_get_option(temp, "PageSize")) == NULL)
913 {
914 DEBUG_puts("Unable to get PageSize option!");
915 ppdClose(ppd);
916 safe_free(string);
917 return (NULL);
918 }
919 }
920
921 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
922 {
923 DEBUG_puts("Unable to add Custom choice!");
924 ppdClose(ppd);
925 safe_free(string);
926 return (NULL);
927 }
928
929 strlcpy(choice->text, cupsLangString(language, CUPS_MSG_VARIABLE),
930 sizeof(choice->text));
931 option = NULL;
932 }
933
934 if ((option = ppdFindOption(ppd, "PageSize")) == NULL)
935 {
936 DEBUG_puts("Unable to find PageSize option!");
937 ppdClose(ppd);
938 safe_free(string);
939 return (NULL);
940 }
941
942 if ((choice = ppdFindChoice(option, "Custom")) == NULL)
943 {
944 DEBUG_puts("Unable to find Custom choice!");
945 ppdClose(ppd);
946 safe_free(string);
947 return (NULL);
948 }
949
950 choice->code = string;
951 string = NULL;
952 option = NULL;
953 }
954 else if (strcmp(keyword, "LandscapeOrientation") == 0)
955 {
956 if (strcmp(string, "Minus90") == 0)
957 ppd->landscape = -90;
958 else if (strcmp(string, "Plus90") == 0)
959 ppd->landscape = 90;
960 }
961 else if (strcmp(keyword, "Emulators") == 0)
962 {
963 for (count = 1, sptr = string; sptr != NULL;)
964 if ((sptr = strchr(sptr, ' ')) != NULL)
965 {
966 count ++;
967 while (*sptr == ' ')
968 sptr ++;
969 }
970
971 ppd->num_emulations = count;
972 ppd->emulations = calloc(sizeof(ppd_emul_t), count);
973
974 for (i = 0, sptr = string; i < count; i ++)
975 {
976 for (nameptr = ppd->emulations[i].name;
977 *sptr != '\0' && *sptr != ' ';
978 sptr ++)
979 if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1))
980 *nameptr++ = *sptr;
981
982 *nameptr = '\0';
983
984 while (*sptr == ' ')
985 sptr ++;
986 }
987 }
988 else if (strncmp(keyword, "StartEmulator_", 14) == 0)
989 {
990 ppd_decode(string);
991
992 for (i = 0; i < ppd->num_emulations; i ++)
993 if (strcmp(keyword + 14, ppd->emulations[i].name) == 0)
994 {
995 ppd->emulations[i].start = string;
996 string = NULL;
997 }
998 }
999 else if (strncmp(keyword, "StopEmulator_", 13) == 0)
1000 {
1001 ppd_decode(string);
1002
1003 for (i = 0; i < ppd->num_emulations; i ++)
1004 if (strcmp(keyword + 13, ppd->emulations[i].name) == 0)
1005 {
1006 ppd->emulations[i].stop = string;
1007 string = NULL;
1008 }
1009 }
1010 else if (strcmp(keyword, "JobPatchFile") == 0)
1011 {
1012 if (ppd->patches == NULL)
1013 {
1014 ppd->patches = string;
1015 string = NULL;
1016 }
1017 else
1018 {
1019 temp = realloc(ppd->patches, strlen(ppd->patches) +
1020 strlen(string) + 1);
1021 if (temp == NULL)
1022 {
1023 safe_free(string);
1024 ppdClose(ppd);
1025 return (NULL);
1026 }
1027
1028 ppd->patches = temp;
1029
1030 strcpy(ppd->patches + strlen(ppd->patches), string);
1031 }
1032 }
1033 else if (strcmp(keyword, "OpenUI") == 0)
1034 {
1035 /*
1036 * Add an option record to the current sub-group, group, or file...
1037 */
1038
1039 if (name[0] == '*')
1040 strcpy(name, name + 1); /* Eliminate leading asterisk */
1041
1042 for (i = strlen(name) - 1; i > 0 && isspace(name[i]); i --)
1043 name[i] = '\0'; /* Eliminate trailing spaces */
1044
1045 DEBUG_printf(("OpenUI of %s in group %s...\n", name,
1046 group ? group->text : "(null)"));
1047
1048 if (subgroup != NULL)
1049 option = ppd_get_option(subgroup, name);
1050 else if (group == NULL)
1051 {
1052 if (strcmp(name, "Collate") != 0 &&
1053 strcmp(name, "Duplex") != 0 &&
1054 strcmp(name, "InputSlot") != 0 &&
1055 strcmp(name, "ManualFeed") != 0 &&
1056 strcmp(name, "MediaType") != 0 &&
1057 strcmp(name, "MediaColor") != 0 &&
1058 strcmp(name, "MediaWeight") != 0 &&
1059 strcmp(name, "OutputBin") != 0 &&
1060 strcmp(name, "OutputMode") != 0 &&
1061 strcmp(name, "OutputOrder") != 0 &&
1062 strcmp(name, "PageSize") != 0 &&
1063 strcmp(name, "PageRegion") != 0)
1064 group = ppd_get_group(ppd, "Extra",
1065 cupsLangString(language, CUPS_MSG_EXTRA));
1066 else
1067 group = ppd_get_group(ppd, "General",
1068 cupsLangString(language, CUPS_MSG_GENERAL));
1069
1070 if (group == NULL)
1071 {
1072 ppdClose(ppd);
1073 safe_free(string);
1074 return (NULL);
1075 }
1076
1077 DEBUG_printf(("Adding to group %s...\n", group->text));
1078 option = ppd_get_option(group, name);
1079 group = NULL;
1080 }
1081 else
1082 option = ppd_get_option(group, name);
1083
1084 if (option == NULL)
1085 {
1086 ppdClose(ppd);
1087 safe_free(string);
1088 return (NULL);
1089 }
1090
1091 /*
1092 * Now fill in the initial information for the option...
1093 */
1094
1095 if (strcmp(string, "PickMany") == 0)
1096 option->ui = PPD_UI_PICKMANY;
1097 else if (strcmp(string, "Boolean") == 0)
1098 option->ui = PPD_UI_BOOLEAN;
1099 else
1100 option->ui = PPD_UI_PICKONE;
1101
1102 if (text[0])
1103 {
1104 strlcpy(option->text, text, sizeof(option->text));
1105 ppd_fix(option->text);
1106 }
1107 else
1108 {
1109 if (strcmp(name, "PageSize") == 0)
1110 strlcpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_SIZE),
1111 sizeof(option->text));
1112 else if (strcmp(name, "MediaType") == 0)
1113 strlcpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_TYPE),
1114 sizeof(option->text));
1115 else if (strcmp(name, "InputSlot") == 0)
1116 strlcpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_SOURCE),
1117 sizeof(option->text));
1118 else if (strcmp(name, "ColorModel") == 0)
1119 strlcpy(option->text, cupsLangString(language, CUPS_MSG_OUTPUT_MODE),
1120 sizeof(option->text));
1121 else if (strcmp(name, "Resolution") == 0)
1122 strlcpy(option->text, cupsLangString(language, CUPS_MSG_RESOLUTION),
1123 sizeof(option->text));
1124 else
1125 strlcpy(option->text, name, sizeof(option->text));
1126 }
1127
1128 option->section = PPD_ORDER_ANY;
1129 }
1130 else if (strcmp(keyword, "JCLOpenUI") == 0)
1131 {
1132 /*
1133 * Find the JCL group, and add if needed...
1134 */
1135
1136 group = ppd_get_group(ppd, "JCL", "JCL");
1137
1138 if (group == NULL)
1139 {
1140 ppdClose(ppd);
1141 safe_free(string);
1142 return (NULL);
1143 }
1144
1145 /*
1146 * Add an option record to the current JCLs...
1147 */
1148
1149 if (name[0] == '*')
1150 strcpy(name, name + 1);
1151
1152 option = ppd_get_option(group, name);
1153
1154 if (option == NULL)
1155 {
1156 ppdClose(ppd);
1157 safe_free(string);
1158 return (NULL);
1159 }
1160
1161 /*
1162 * Now fill in the initial information for the option...
1163 */
1164
1165 if (strcmp(string, "PickMany") == 0)
1166 option->ui = PPD_UI_PICKMANY;
1167 else if (strcmp(string, "Boolean") == 0)
1168 option->ui = PPD_UI_BOOLEAN;
1169 else
1170 option->ui = PPD_UI_PICKONE;
1171
1172 strlcpy(option->text, text, sizeof(option->text));
1173
1174 option->section = PPD_ORDER_JCL;
1175 group = NULL;
1176 }
1177 else if (strcmp(keyword, "CloseUI") == 0 ||
1178 strcmp(keyword, "JCLCloseUI") == 0)
1179 option = NULL;
1180 else if (strcmp(keyword, "OpenGroup") == 0)
1181 {
1182 /*
1183 * Open a new group...
1184 */
1185
1186 if (group != NULL)
1187 {
1188 ppdClose(ppd);
1189 safe_free(string);
1190 return (NULL);
1191 }
1192
1193 /*
1194 * Separate the group name from the text (name/text)...
1195 */
1196
1197 if ((sptr = strchr(string, '/')) != NULL)
1198 *sptr++ = '\0';
1199 else
1200 sptr = string;
1201
1202 /*
1203 * Fix up the text...
1204 */
1205
1206 ppd_decode(sptr);
1207 ppd_fix(sptr);
1208
1209 /*
1210 * Find/add the group...
1211 */
1212
1213 group = ppd_get_group(ppd, string, sptr);
1214 }
1215 else if (strcmp(keyword, "CloseGroup") == 0)
1216 group = NULL;
1217 else if (strcmp(keyword, "OrderDependency") == 0 ||
1218 strcmp(keyword, "NonUIOrderDependency") == 0)
1219 {
1220 if (sscanf(string, "%f%40s%40s", &order, name, keyword) != 3)
1221 {
1222 ppdClose(ppd);
1223 safe_free(string);
1224 return (NULL);
1225 }
1226
1227 if (keyword[0] == '*')
1228 strcpy(keyword, keyword + 1);
1229
1230 if (strcmp(name, "ExitServer") == 0)
1231 section = PPD_ORDER_EXIT;
1232 else if (strcmp(name, "Prolog") == 0)
1233 section = PPD_ORDER_PROLOG;
1234 else if (strcmp(name, "DocumentSetup") == 0)
1235 section = PPD_ORDER_DOCUMENT;
1236 else if (strcmp(name, "PageSetup") == 0)
1237 section = PPD_ORDER_PAGE;
1238 else if (strcmp(name, "JCLSetup") == 0)
1239 section = PPD_ORDER_JCL;
1240 else
1241 section = PPD_ORDER_ANY;
1242
1243 if (option == NULL)
1244 {
1245 ppd_group_t *temp;
1246
1247
1248 /*
1249 * Only valid for Non-UI options...
1250 */
1251
1252 for (i = ppd->num_groups, temp = ppd->groups; i > 0; i --, temp ++)
1253 if (temp->text[0] == '\0')
1254 break;
1255
1256 if (i > 0)
1257 for (i = 0; i < temp->num_options; i ++)
1258 if (strcmp(keyword, temp->options[i].keyword) == 0)
1259 {
1260 temp->options[i].section = section;
1261 temp->options[i].order = order;
1262 break;
1263 }
1264 }
1265 else
1266 {
1267 option->section = section;
1268 option->order = order;
1269 }
1270 }
1271 else if (strncmp(keyword, "Default", 7) == 0)
1272 {
1273 if (string == NULL)
1274 continue;
1275
1276 if (strchr(string, '/') != NULL)
1277 *strchr(string, '/') = '\0';
1278
1279 if (option == NULL)
1280 {
1281 ppd_group_t *temp;
1282
1283
1284 /*
1285 * Only valid for Non-UI options...
1286 */
1287
1288 for (i = ppd->num_groups, temp = ppd->groups; i > 0; i --, temp ++)
1289 if (temp->text[0] == '\0')
1290 break;
1291
1292 if (i > 0)
1293 for (i = 0; i < temp->num_options; i ++)
1294 if (strcmp(keyword, temp->options[i].keyword) == 0)
1295 {
1296 strlcpy(temp->options[i].defchoice, string,
1297 sizeof(temp->options[i].defchoice));
1298 break;
1299 }
1300 }
1301 else
1302 strlcpy(option->defchoice, string, sizeof(option->defchoice));
1303 }
1304 else if (strcmp(keyword, "UIConstraints") == 0 ||
1305 strcmp(keyword, "NonUIConstraints") == 0)
1306 {
1307 if (ppd->num_consts == 0)
1308 constraint = calloc(sizeof(ppd_const_t), 1);
1309 else
1310 constraint = realloc(ppd->consts,
1311 (ppd->num_consts + 1) * sizeof(ppd_const_t));
1312
1313 if (constraint == NULL)
1314 {
1315 ppdClose(ppd);
1316 safe_free(string);
1317 return (NULL);
1318 }
1319
1320 ppd->consts = constraint;
1321 constraint += ppd->num_consts;
1322 ppd->num_consts ++;
1323
1324 switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1,
1325 constraint->choice1, constraint->option2,
1326 constraint->choice2))
1327 {
1328 case 0 : /* Error */
1329 case 1 : /* Error */
1330 ppdClose(ppd);
1331 safe_free(string);
1332 break;
1333
1334 case 2 : /* Two options... */
1335 /*
1336 * The following strcpy's are safe, as optionN and
1337 * choiceN are all the same size (size defined by PPD spec...)
1338 */
1339
1340 if (constraint->option1[0] == '*')
1341 strcpy(constraint->option1, constraint->option1 + 1);
1342
1343 if (constraint->choice1[0] == '*')
1344 strcpy(constraint->option2, constraint->choice1 + 1);
1345 else
1346 strcpy(constraint->option2, constraint->choice1);
1347
1348 constraint->choice1[0] = '\0';
1349 constraint->choice2[0] = '\0';
1350 break;
1351
1352 case 3 : /* Two options, one choice... */
1353 /*
1354 * The following strcpy's are safe, as optionN and
1355 * choiceN are all the same size (size defined by PPD spec...)
1356 */
1357
1358 if (constraint->option1[0] == '*')
1359 strcpy(constraint->option1, constraint->option1 + 1);
1360
1361 if (constraint->choice1[0] == '*')
1362 {
1363 strcpy(constraint->choice2, constraint->option2);
1364 strcpy(constraint->option2, constraint->choice1 + 1);
1365 constraint->choice1[0] = '\0';
1366 }
1367 else
1368 {
1369 if (constraint->option2[0] == '*')
1370 strcpy(constraint->option2, constraint->option2 + 1);
1371
1372 constraint->choice2[0] = '\0';
1373 }
1374 break;
1375
1376 case 4 : /* Two options, two choices... */
1377 if (constraint->option1[0] == '*')
1378 strcpy(constraint->option1, constraint->option1 + 1);
1379
1380 if (constraint->option2[0] == '*')
1381 strcpy(constraint->option2, constraint->option2 + 1);
1382 break;
1383 }
1384 }
1385 else if (strcmp(keyword, "PaperDimension") == 0)
1386 {
1387 if ((size = ppdPageSize(ppd, name)) == NULL)
1388 size = ppd_add_size(ppd, name);
1389
1390 if (size == NULL)
1391 {
1392 /*
1393 * Unable to add or find size!
1394 */
1395
1396 ppdClose(ppd);
1397 safe_free(string);
1398 return (NULL);
1399 }
1400
1401 sscanf(string, "%f%f", &(size->width), &(size->length));
1402 }
1403 else if (strcmp(keyword, "ImageableArea") == 0)
1404 {
1405 if ((size = ppdPageSize(ppd, name)) == NULL)
1406 size = ppd_add_size(ppd, name);
1407
1408 if (size == NULL)
1409 {
1410 /*
1411 * Unable to add or find size!
1412 */
1413
1414 ppdClose(ppd);
1415 safe_free(string);
1416 return (NULL);
1417 }
1418
1419 sscanf(string, "%f%f%f%f", &(size->left), &(size->bottom),
1420 &(size->right), &(size->top));
1421 }
1422 else if (option != NULL &&
1423 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
1424 (PPD_KEYWORD | PPD_OPTION | PPD_STRING))
1425 {
1426 DEBUG_printf(("group = %p, subgroup = %p\n", group, subgroup));
1427
1428 if (strcmp(keyword, "PageSize") == 0)
1429 {
1430 /*
1431 * Add a page size...
1432 */
1433
1434 if (ppdPageSize(ppd, name) == NULL)
1435 ppd_add_size(ppd, name);
1436 }
1437
1438 /*
1439 * Add the option choice...
1440 */
1441
1442 choice = ppd_add_choice(option, name);
1443
1444 if (mask & PPD_TEXT)
1445 {
1446 strlcpy(choice->text, text, sizeof(choice->text));
1447 ppd_fix(choice->text);
1448 }
1449 else if (strcmp(name, "True") == 0)
1450 strcpy(choice->text, "Yes");
1451 else if (strcmp(name, "False") == 0)
1452 strcpy(choice->text, "No");
1453 else
1454 strlcpy(choice->text, name, sizeof(choice->text));
1455
1456 if (option->section == PPD_ORDER_JCL)
1457 ppd_decode(string); /* Decode quoted string */
1458
1459 choice->code = string;
1460 string = NULL; /* Don't free this string below */
1461 }
1462 else if (strcmp(keyword, "OpenSubGroup") != 0 &&
1463 strcmp(keyword, "CloseSubGroup") != 0)
1464 {
1465 char spec[PPD_MAX_NAME + PPD_MAX_TEXT];
1466
1467 snprintf(spec, sizeof(spec), "%s/%s", name, text);
1468 ppd_add_attr(ppd, keyword, spec, string);
1469
1470 string = NULL; /* Don't free this string below */
1471 }
1472
1473 safe_free(string);
1474 }
1475
1476 #ifdef DEBUG
1477 if (!feof(fp))
1478 printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp));
1479 #endif /* DEBUG */
1480
1481 /*
1482 * Set the option back-pointer for each choice...
1483 */
1484
1485 qsort(ppd->groups, ppd->num_groups, sizeof(ppd_group_t),
1486 (int (*)(const void *, const void *))compare_groups);
1487
1488 for (i = ppd->num_groups, group = ppd->groups;
1489 i > 0;
1490 i --, group ++)
1491 {
1492 qsort(group->options, group->num_options, sizeof(ppd_option_t),
1493 (int (*)(const void *, const void *))compare_options);
1494
1495 for (j = group->num_options, option = group->options;
1496 j > 0;
1497 j --, option ++)
1498 {
1499 qsort(option->choices, option->num_choices, sizeof(ppd_choice_t),
1500 (int (*)(const void *, const void *))compare_choices);
1501
1502 for (k = 0; k < option->num_choices; k ++)
1503 option->choices[k].option = (void *)option;
1504 }
1505
1506 qsort(group->subgroups, group->num_subgroups, sizeof(ppd_group_t),
1507 (int (*)(const void *, const void *))compare_groups);
1508
1509 for (j = group->num_subgroups, subgroup = group->subgroups;
1510 j > 0;
1511 j --, subgroup ++)
1512 {
1513 qsort(subgroup->options, subgroup->num_options, sizeof(ppd_option_t),
1514 (int (*)(const void *, const void *))compare_options);
1515
1516 for (k = group->num_options, option = group->options;
1517 k > 0;
1518 k --, option ++)
1519 {
1520 qsort(option->choices, option->num_choices, sizeof(ppd_choice_t),
1521 (int (*)(const void *, const void *))compare_choices);
1522
1523 for (m = 0; m < option->num_choices; m ++)
1524 option->choices[m].option = (void *)option;
1525 }
1526 }
1527 }
1528
1529 /*
1530 * Sort the attributes...
1531 */
1532
1533 if (ppd->num_attrs > 1)
1534 qsort(ppd->attrs, ppd->num_attrs, sizeof(ppd_attr_t *),
1535 (int (*)(const void *, const void *))_ppd_attr_compare);
1536
1537 return (ppd);
1538 }
1539
1540
1541 /*
1542 * 'ppdOpenFd()' - Read a PPD file into memory.
1543 */
1544
1545 ppd_file_t * /* O - PPD file record */
1546 ppdOpenFd(int fd) /* I - File to read from */
1547 {
1548 FILE *fp; /* File pointer */
1549 ppd_file_t *ppd; /* PPD file record */
1550
1551
1552 /*
1553 * Range check input...
1554 */
1555
1556 if (fd < 0)
1557 return (NULL);
1558
1559 /*
1560 * Try to open the file and parse it...
1561 */
1562
1563 if ((fp = fdopen(fd, "r")) != NULL)
1564 {
1565 setbuf(fp, NULL);
1566
1567 ppd = ppdOpen(fp);
1568
1569 safe_free(fp);
1570 }
1571 else
1572 ppd = NULL;
1573
1574 return (ppd);
1575 }
1576
1577
1578 /*
1579 * 'ppdOpenFile()' - Read a PPD file into memory.
1580 */
1581
1582 ppd_file_t * /* O - PPD file record */
1583 ppdOpenFile(const char *filename) /* I - File to read from */
1584 {
1585 FILE *fp; /* File pointer */
1586 ppd_file_t *ppd; /* PPD file record */
1587
1588
1589 /*
1590 * Range check input...
1591 */
1592
1593 if (filename == NULL)
1594 return (NULL);
1595
1596 /*
1597 * Try to open the file and parse it...
1598 */
1599
1600 if ((fp = fopen(filename, "r")) != NULL)
1601 {
1602 ppd = ppdOpen(fp);
1603
1604 fclose(fp);
1605 }
1606 else
1607 ppd = NULL;
1608
1609 return (ppd);
1610 }
1611
1612
1613 /*
1614 * 'compare_strings()' - Compare two strings.
1615 */
1616
1617 static int /* O - Result of comparison */
1618 compare_strings(char *s, /* I - First string */
1619 char *t) /* I - Second string */
1620 {
1621 int diff, /* Difference between digits */
1622 digits; /* Number of digits */
1623
1624
1625 /*
1626 * Loop through both strings, returning only when a difference is
1627 * seen. Also, compare whole numbers rather than just characters, too!
1628 */
1629
1630 while (*s && *t)
1631 {
1632 if (isdigit(*s) && isdigit(*t))
1633 {
1634 /*
1635 * Got a number; start by skipping leading 0's...
1636 */
1637
1638 while (*s == '0')
1639 s ++;
1640 while (*t == '0')
1641 t ++;
1642
1643 /*
1644 * Skip equal digits...
1645 */
1646
1647 while (isdigit(*s) && *s == *t)
1648 {
1649 s ++;
1650 t ++;
1651 }
1652
1653 /*
1654 * Bounce out if *s and *t aren't both digits...
1655 */
1656
1657 if (isdigit(*s) && !isdigit(*t))
1658 return (1);
1659 else if (!isdigit(*s) && isdigit(*t))
1660 return (-1);
1661 else if (!isdigit(*s) || !isdigit(*t))
1662 continue;
1663
1664 if (*s < *t)
1665 diff = -1;
1666 else
1667 diff = 1;
1668
1669 /*
1670 * Figure out how many more digits there are...
1671 */
1672
1673 digits = 0;
1674
1675 while (isdigit(*s))
1676 {
1677 digits ++;
1678 s ++;
1679 }
1680
1681 while (isdigit(*t))
1682 {
1683 digits --;
1684 t ++;
1685 }
1686
1687 /*
1688 * Return if the number or value of the digits is different...
1689 */
1690
1691 if (digits < 0)
1692 return (-1);
1693 else if (digits > 0)
1694 return (1);
1695 else
1696 return (diff);
1697 }
1698 else if (tolower(*s) < tolower(*t))
1699 return (-1);
1700 else if (tolower(*s) > tolower(*t))
1701 return (1);
1702 else
1703 {
1704 s ++;
1705 t ++;
1706 }
1707 }
1708
1709 /*
1710 * Return the results of the final comparison...
1711 */
1712
1713 if (*s)
1714 return (1);
1715 else if (*t)
1716 return (-1);
1717 else
1718 return (0);
1719 }
1720
1721
1722 /*
1723 * 'compare_groups()' - Compare two groups.
1724 */
1725
1726 static int /* O - Result of comparison */
1727 compare_groups(ppd_group_t *g0, /* I - First group */
1728 ppd_group_t *g1) /* I - Second group */
1729 {
1730 return (compare_strings(g0->text, g1->text));
1731 }
1732
1733
1734 /*
1735 * 'compare_options()' - Compare two options.
1736 */
1737
1738 static int /* O - Result of comparison */
1739 compare_options(ppd_option_t *o0,/* I - First option */
1740 ppd_option_t *o1)/* I - Second option */
1741 {
1742 return (compare_strings(o0->text, o1->text));
1743 }
1744
1745
1746 /*
1747 * 'compare_choices()' - Compare two choices.
1748 */
1749
1750 static int /* O - Result of comparison */
1751 compare_choices(ppd_choice_t *c0,/* I - First choice */
1752 ppd_choice_t *c1)/* I - Second choice */
1753 {
1754 return (compare_strings(c0->text, c1->text));
1755 }
1756
1757
1758 /*
1759 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
1760 * necessary.
1761 */
1762
1763 static int /* O - Bitmask of fields read */
1764 ppd_read(FILE *fp, /* I - File to read from */
1765 char *keyword, /* O - Keyword from line */
1766 char *option, /* O - Option from line */
1767 char *text, /* O - Human-readable text from line */
1768 char **string) /* O - Code/string data */
1769 {
1770 int ch, /* Character from file */
1771 colon, /* Colon seen? */
1772 endquote, /* Waiting for an end quote */
1773 mask; /* Mask to be returned */
1774 char *keyptr, /* Keyword pointer */
1775 *optptr, /* Option pointer */
1776 *textptr, /* Text pointer */
1777 *strptr, /* Pointer into string */
1778 *lineptr, /* Current position in line buffer */
1779 line[65536]; /* Line buffer (64k) */
1780
1781
1782 /*
1783 * Range check everything...
1784 */
1785
1786 if (fp == NULL || keyword == NULL || option == NULL || text == NULL ||
1787 string == NULL)
1788 return (0);
1789
1790 /*
1791 * Now loop until we have a valid line...
1792 */
1793
1794 *string = NULL;
1795
1796 do
1797 {
1798 /*
1799 * Read the line...
1800 */
1801
1802 lineptr = line;
1803 endquote = 0;
1804 colon = 0;
1805
1806 while ((ch = getc(fp)) != EOF &&
1807 (lineptr - line) < (sizeof(line) - 1))
1808 {
1809 if (ch == '\r' || ch == '\n')
1810 {
1811 /*
1812 * Line feed or carriage return...
1813 */
1814
1815 if (lineptr == line) /* Skip blank lines */
1816 continue;
1817
1818 if (ch == '\r')
1819 {
1820 /*
1821 * Check for a trailing line feed...
1822 */
1823
1824 if ((ch = getc(fp)) == EOF)
1825 break;
1826 if (ch != 0x0a)
1827 ungetc(ch, fp);
1828 }
1829
1830 ch = '\n';
1831
1832 if (!endquote) /* Continue for multi-line text */
1833 break;
1834
1835 *lineptr++ = '\n';
1836 }
1837 else
1838 {
1839 /*
1840 * Any other character...
1841 */
1842
1843 *lineptr++ = ch;
1844
1845 if (ch == ':' && strncmp(line, "*%", 2) != 0)
1846 colon = 1;
1847
1848 if (ch == '\"' && colon)
1849 {
1850 endquote = !endquote;
1851
1852 if (!endquote)
1853 {
1854 /*
1855 * End of quoted string; ignore trailing characters...
1856 */
1857
1858 while ((ch = getc(fp)) != EOF)
1859 if (ch == '\n')
1860 break;
1861 else if (ch == '\r')
1862 {
1863 ch = getc(fp);
1864 if (ch != '\n')
1865 ungetc(ch, fp);
1866
1867 ch = '\n';
1868 break;
1869 }
1870
1871 break;
1872 }
1873 }
1874 }
1875 }
1876
1877 if (endquote)
1878 {
1879 /*
1880 * Didn't finish this quoted string...
1881 */
1882
1883 while ((ch = getc(fp)) != EOF)
1884 if (ch == '\"')
1885 break;
1886 }
1887
1888 if (ch != '\n')
1889 {
1890 /*
1891 * Didn't finish this line...
1892 */
1893
1894 while ((ch = getc(fp)) != EOF)
1895 if (ch == '\r' || ch == '\n')
1896 {
1897 /*
1898 * Line feed or carriage return...
1899 */
1900
1901 if (ch == '\r')
1902 {
1903 /*
1904 * Check for a trailing line feed...
1905 */
1906
1907 if ((ch = getc(fp)) == EOF)
1908 break;
1909 if (ch != 0x0a)
1910 ungetc(ch, fp);
1911 }
1912
1913 break;
1914 }
1915 }
1916
1917 if (lineptr > line && lineptr[-1] == '\n')
1918 lineptr --;
1919
1920 *lineptr = '\0';
1921
1922 /* DEBUG_printf(("LINE = \"%s\"\n", line));*/
1923
1924 if (ch == EOF && lineptr == line)
1925 return (0);
1926
1927 /*
1928 * Now parse it...
1929 */
1930
1931 mask = 0;
1932 lineptr = line + 1;
1933
1934 keyword[0] = '\0';
1935 option[0] = '\0';
1936 text[0] = '\0';
1937 *string = NULL;
1938
1939 if (line[0] != '*') /* All lines start with an asterisk */
1940 continue;
1941
1942 if (strcmp(line, "*") == 0 || /* (Bad) comment line */
1943 strncmp(line, "*%", 2) == 0 || /* Comment line */
1944 strncmp(line, "*?", 2) == 0 || /* Query line */
1945 strcmp(line, "*End") == 0) /* End of multi-line string */
1946 continue;
1947
1948 /*
1949 * Get a keyword...
1950 */
1951
1952 keyptr = keyword;
1953
1954 while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr))
1955 if ((keyptr - keyword) < (PPD_MAX_NAME - 1))
1956 *keyptr++ = *lineptr++;
1957
1958 *keyptr = '\0';
1959
1960 if (strcmp(keyword, "End") == 0)
1961 continue;
1962
1963 mask |= PPD_KEYWORD;
1964
1965 /* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
1966
1967 if (isspace(*lineptr))
1968 {
1969 /*
1970 * Get an option name...
1971 */
1972
1973 while (isspace(*lineptr))
1974 lineptr ++;
1975
1976 optptr = option;
1977
1978 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':' &&
1979 *lineptr != '/')
1980 if ((optptr - option) < (PPD_MAX_NAME - 1))
1981 *optptr++ = *lineptr++;
1982
1983 *optptr = '\0';
1984 mask |= PPD_OPTION;
1985
1986 /* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
1987
1988 if (*lineptr == '/')
1989 {
1990 /*
1991 * Get human-readable text...
1992 */
1993
1994 lineptr ++;
1995
1996 textptr = text;
1997
1998 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
1999 if ((textptr - text) < (PPD_MAX_LINE - 1))
2000 *textptr++ = *lineptr++;
2001
2002 *textptr = '\0';
2003 ppd_decode(text);
2004
2005 mask |= PPD_TEXT;
2006 }
2007
2008 /* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
2009 }
2010
2011 if (*lineptr == ':')
2012 {
2013 /*
2014 * Get string...
2015 */
2016
2017 *string = malloc(strlen(lineptr) + 1);
2018
2019 while (*lineptr == ':' || isspace(*lineptr))
2020 lineptr ++;
2021
2022 strptr = *string;
2023
2024 while (*lineptr != '\0')
2025 {
2026 if (*lineptr != '\"')
2027 *strptr++ = *lineptr++;
2028 else
2029 lineptr ++;
2030 }
2031
2032 *strptr = '\0';
2033
2034 /* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
2035
2036 mask |= PPD_STRING;
2037 }
2038 }
2039 while (mask == 0);
2040
2041 return (mask);
2042 }
2043
2044
2045 /*
2046 * 'ppd_decode()' - Decode a string value...
2047 */
2048
2049 static void
2050 ppd_decode(char *string) /* I - String to decode */
2051 {
2052 char *inptr, /* Input pointer */
2053 *outptr; /* Output pointer */
2054
2055
2056 inptr = string;
2057 outptr = string;
2058
2059 while (*inptr != '\0')
2060 if (*inptr == '<' && isxdigit(inptr[1]))
2061 {
2062 /*
2063 * Convert hex to 8-bit values...
2064 */
2065
2066 inptr ++;
2067 while (isxdigit(*inptr))
2068 {
2069 if (isalpha(*inptr))
2070 *outptr = (tolower(*inptr) - 'a' + 10) << 4;
2071 else
2072 *outptr = (*inptr - '0') << 4;
2073
2074 inptr ++;
2075
2076 if (isalpha(*inptr))
2077 *outptr |= tolower(*inptr) - 'a' + 10;
2078 else
2079 *outptr |= *inptr - '0';
2080
2081 inptr ++;
2082 outptr ++;
2083 }
2084
2085 while (*inptr != '>' && *inptr != '\0')
2086 inptr ++;
2087 while (*inptr == '>')
2088 inptr ++;
2089 }
2090 else
2091 *outptr++ = *inptr++;
2092
2093 *outptr = '\0';
2094 }
2095
2096
2097 /*
2098 * 'ppd_fix()' - Fix WinANSI characters in the range 0x80 to 0x9f to be
2099 * valid ISO-8859-1 characters...
2100 */
2101
2102 static void
2103 ppd_fix(char *string) /* IO - String to fix */
2104 {
2105 unsigned char *p; /* Pointer into string */
2106 static unsigned char lut[32] =/* Lookup table for characters */
2107 {
2108 0x20,
2109 0x20,
2110 0x20,
2111 0x20,
2112 0x20,
2113 0x20,
2114 0x20,
2115 0x20,
2116 0x20,
2117 0x20,
2118 0x20,
2119 0x20,
2120 0x20,
2121 0x20,
2122 0x20,
2123 0x20,
2124 'l',
2125 '`',
2126 '\'',
2127 '^',
2128 '~',
2129 0x20, /* bar */
2130 0x20, /* circumflex */
2131 0x20, /* dot */
2132 0x20, /* double dot */
2133 0x20,
2134 0x20, /* circle */
2135 0x20, /* ??? */
2136 0x20,
2137 '\"', /* should be right quotes */
2138 0x20, /* ??? */
2139 0x20 /* accent */
2140 };
2141
2142
2143 for (p = (unsigned char *)string; *p; p ++)
2144 if (*p >= 0x80 && *p < 0xa0)
2145 *p = lut[*p - 0x80];
2146 }
2147
2148
2149 /*
2150 * End of "$Id: ppd.c,v 1.51.2.15 2002/05/16 13:59:59 mike Exp $".
2151 */