]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/ppd.c
Group names are now decoded to handle I18N.
[thirdparty/cups.git] / cups / ppd.c
1 /*
2 * "$Id: ppd.c,v 1.21 1999/06/04 21:04:29 mike Exp $"
3 *
4 * PPD file routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-1999 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 * Contents:
34 *
35 * ppdClose() - Free all memory used by the PPD file.
36 * ppd_free_group() - Free a single UI group.
37 * ppd_free_option() - Free a single option.
38 * ppdOpen() - Read a PPD file into memory.
39 * ppdOpenFd() - Read a PPD file into memory.
40 * ppdOpenFile() - Read a PPD file into memory.
41 * ppd_read() - Read a line from a PPD file, skipping comment lines
42 * as necessary.
43 * compare_strings() - Compare two strings.
44 * compare_groups() - Compare two groups.
45 * compare_options() - Compare two options.
46 * compare_choices() - Compare two choices.
47 */
48
49 /*
50 * Include necessary headers.
51 */
52
53 /*#define DEBUG*/
54 #include "ppd.h"
55 #include <stdlib.h>
56 #include <ctype.h>
57 #include "string.h"
58
59
60 /*
61 * Definitions...
62 */
63
64 #if defined(WIN32) || defined(__EMX__)
65 # define READ_BINARY "rb" /* Open a binary file for reading */
66 # define WRITE_BINARY "wb" /* Open a binary file for writing */
67 #else
68 # define READ_BINARY "r" /* Open a binary file for reading */
69 # define WRITE_BINARY "w" /* Open a binary file for writing */
70 #endif /* WIN32 || __EMX__ */
71
72 #define PPD_KEYWORD 1 /* Line contained a keyword */
73 #define PPD_OPTION 2 /* Line contained an option name */
74 #define PPD_TEXT 4 /* Line contained human-readable text */
75 #define PPD_STRING 8 /* Line contained a string or code */
76
77
78 /*
79 * Local functions...
80 */
81
82 static int compare_strings(char *s, char *t);
83 static int compare_groups(ppd_group_t *g0, ppd_group_t *g1);
84 static int compare_options(ppd_option_t *o0, ppd_option_t *o1);
85 static int compare_choices(ppd_choice_t *c0, ppd_choice_t *c1);
86 static int ppd_read(FILE *fp, char *keyword, char *option,
87 char *text, char **string);
88 static void ppd_decode(char *string);
89 static void ppd_free_group(ppd_group_t *group);
90 static void ppd_free_option(ppd_option_t *option);
91 static ppd_group_t *ppd_get_group(ppd_file_t *ppd, char *name);
92 static ppd_option_t *ppd_get_option(ppd_group_t *group, char *name);
93 static ppd_choice_t *ppd_add_choice(ppd_option_t *option, char *name);
94
95
96 /*
97 * 'ppdClose()' - Free all memory used by the PPD file.
98 */
99
100 void
101 ppdClose(ppd_file_t *ppd) /* I - PPD file record */
102 {
103 int i; /* Looping var */
104 ppd_emul_t *emul; /* Current emulation */
105 ppd_group_t *group; /* Current group */
106 char **font; /* Current font */
107
108
109 /*
110 * Range check the PPD file record...
111 */
112
113 if (ppd == NULL)
114 return;
115
116 /*
117 * Free all strings at the top level...
118 */
119
120 free(ppd->lang_encoding);
121 free(ppd->lang_version);
122 free(ppd->modelname);
123 free(ppd->ttrasterizer);
124 free(ppd->manufacturer);
125 free(ppd->product);
126 free(ppd->nickname);
127 free(ppd->shortnickname);
128
129 /*
130 * Free any emulations...
131 */
132
133 if (ppd->num_emulations > 0)
134 {
135 for (i = ppd->num_emulations, emul = ppd->emulations; i > 0; i --, emul ++)
136 {
137 free(emul->start);
138 free(emul->stop);
139 }
140
141 free(ppd->emulations);
142 }
143
144 /*
145 * Free any UI groups, subgroups, and options...
146 */
147
148 if (ppd->num_groups > 0)
149 {
150 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
151 ppd_free_group(group);
152
153 free(ppd->groups);
154 }
155
156 /*
157 * Free any page sizes...
158 */
159
160 if (ppd->num_sizes > 0)
161 free(ppd->sizes);
162
163 /*
164 * Free any constraints...
165 */
166
167 if (ppd->num_consts > 0)
168 free(ppd->consts);
169
170 /*
171 * Free any fonts...
172 */
173
174 if (ppd->num_fonts > 0)
175 {
176 for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++)
177 free(*font);
178
179 free(ppd->fonts);
180 }
181
182 /*
183 * Free any profiles...
184 */
185
186 if (ppd->num_profiles > 0)
187 free(ppd->profiles);
188
189 /*
190 * Free the whole record...
191 */
192
193 free(ppd);
194 }
195
196
197 /*
198 * 'ppd_free_group()' - Free a single UI group.
199 */
200
201 static void
202 ppd_free_group(ppd_group_t *group) /* I - Group to free */
203 {
204 int i; /* Looping var */
205 ppd_option_t *option; /* Current option */
206 ppd_group_t *subgroup; /* Current sub-group */
207
208
209 if (group->num_options > 0)
210 {
211 for (i = group->num_options, option = group->options;
212 i > 0;
213 i --, option ++)
214 ppd_free_option(option);
215
216 free(group->options);
217 }
218
219 if (group->num_subgroups > 0)
220 {
221 for (i = group->num_subgroups, subgroup = group->subgroups;
222 i > 0;
223 i --, subgroup ++)
224 ppd_free_group(subgroup);
225
226 free(group->subgroups);
227 }
228 }
229
230
231 /*
232 * 'ppd_free_option()' - Free a single option.
233 */
234
235 static void
236 ppd_free_option(ppd_option_t *option) /* I - Option to free */
237 {
238 int i; /* Looping var */
239 ppd_choice_t *choice; /* Current choice */
240
241
242 if (option->num_choices > 0)
243 {
244 for (i = option->num_choices, choice = option->choices;
245 i > 0;
246 i --, choice ++)
247 free(choice->code);
248
249 free(option->choices);
250 }
251 }
252
253
254 /*
255 * 'ppd_get_group()' - Find or create the named group as needed.
256 */
257
258 static ppd_group_t * /* O - Named group */
259 ppd_get_group(ppd_file_t *ppd, /* I - PPD file */
260 char *name) /* I - Name of group */
261 {
262 int i; /* Looping var */
263 ppd_group_t *group; /* Group */
264
265
266 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
267 if (strcmp(group->text, name) == 0)
268 break;
269
270 if (i == 0)
271 {
272 if (ppd->num_groups == 0)
273 group = malloc(sizeof(ppd_group_t));
274 else
275 group = realloc(ppd->groups,
276 (ppd->num_groups + 1) * sizeof(ppd_group_t));
277
278 if (group == NULL)
279 return (NULL);
280
281 ppd->groups = group;
282 group += ppd->num_groups;
283 ppd->num_groups ++;
284
285 memset(group, 0, sizeof(ppd_group_t));
286 strcpy(group->text, name);
287 }
288
289 return (group);
290 }
291
292
293 /*
294 * 'ppd_get_option()' - Find or create the named option as needed.
295 */
296
297 static ppd_option_t * /* O - Named option */
298 ppd_get_option(ppd_group_t *group, /* I - Group */
299 char *name) /* I - Name of option */
300 {
301 int i; /* Looping var */
302 ppd_option_t *option; /* Option */
303
304
305 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
306 if (strcmp(option->keyword, name) == 0)
307 break;
308
309 if (i == 0)
310 {
311 if (group->num_options == 0)
312 option = malloc(sizeof(ppd_option_t));
313 else
314 option = realloc(group->options,
315 (group->num_options + 1) * sizeof(ppd_option_t));
316
317 if (option == NULL)
318 return (NULL);
319
320 group->options = option;
321 option += group->num_options;
322 group->num_options ++;
323
324 memset(option, 0, sizeof(ppd_option_t));
325 strcpy(option->keyword, name);
326 }
327
328 return (option);
329 }
330
331
332 /*
333 * 'ppd_add_choice()' - Add a choice to an option.
334 */
335
336 static ppd_choice_t * /* O - Named choice */
337 ppd_add_choice(ppd_option_t *option, /* I - Option */
338 char *name) /* I - Name of choice */
339 {
340 ppd_choice_t *choice; /* Choice */
341
342
343 if (option->num_choices == 0)
344 choice = malloc(sizeof(ppd_choice_t));
345 else
346 choice = realloc(option->choices,
347 sizeof(ppd_choice_t) * (option->num_choices + 1));
348
349 if (choice == NULL)
350 return (NULL);
351
352 option->choices = choice;
353 choice += option->num_choices;
354 option->num_choices ++;
355
356 memset(choice, 0, sizeof(ppd_choice_t));
357 strcpy(choice->choice, name);
358
359 return (choice);
360 }
361
362
363 /*
364 * 'ppd_add_size()' - Add a page size.
365 */
366
367 static ppd_size_t * /* O - Named size */
368 ppd_add_size(ppd_file_t *ppd, /* I - PPD file */
369 char *name) /* I - Name of size */
370 {
371 ppd_size_t *size; /* Size */
372
373
374 if (ppd->num_sizes == 0)
375 size = malloc(sizeof(ppd_size_t));
376 else
377 size = realloc(ppd->sizes, sizeof(ppd_size_t) * (ppd->num_sizes + 1));
378
379 if (size == NULL)
380 return (NULL);
381
382 ppd->sizes = size;
383 size += ppd->num_sizes;
384 ppd->num_sizes ++;
385
386 memset(size, 0, sizeof(ppd_size_t));
387 strcpy(size->name, name);
388
389 return (size);
390 }
391
392
393 /*
394 * 'ppdOpen()' - Read a PPD file into memory.
395 */
396
397 ppd_file_t * /* O - PPD file record */
398 ppdOpen(FILE *fp) /* I - File to read from */
399 {
400 int i, j, k, m; /* Looping vars */
401 int count; /* Temporary count */
402 ppd_file_t *ppd; /* PPD file record */
403 ppd_group_t *group, /* Current group */
404 *subgroup; /* Current sub-group */
405 ppd_option_t *option; /* Current option */
406 ppd_choice_t *choice; /* Current choice */
407 ppd_const_t *constraint; /* Current constraint */
408 ppd_size_t *size; /* Current page size */
409 int mask; /* Line data mask */
410 char keyword[41], /* Keyword from file */
411 name[41], /* Option from file */
412 text[81], /* Human-readable text from file */
413 *string, /* Code/text from file */
414 *sptr, /* Pointer into string */
415 *nameptr; /* Pointer into name */
416 float order; /* Order dependency number */
417 ppd_section_t section; /* Order dependency section */
418 ppd_profile_t *profile; /* Pointer to color profile */
419 char **filter; /* Pointer to filter */
420
421
422 /*
423 * Range check input...
424 */
425
426 if (fp == NULL)
427 return (NULL);
428
429 /*
430 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
431 */
432
433 mask = ppd_read(fp, keyword, name, text, &string);
434
435 if (mask == 0 ||
436 strcmp(keyword, "PPD-Adobe") != 0 ||
437 string == NULL || string[0] != '4')
438 {
439 /*
440 * Either this is not a PPD file, or it is not a 4.x PPD file.
441 */
442
443 if (string != NULL)
444 free(string);
445
446 return (NULL);
447 }
448
449 if (string != NULL)
450 free(string);
451
452 /*
453 * Allocate memory for the PPD file record...
454 */
455
456 if ((ppd = calloc(sizeof(ppd_file_t), 1)) == NULL)
457 return (NULL);
458
459 ppd->language_level = 1;
460 ppd->color_device = 0;
461 ppd->colorspace = PPD_CS_GRAY;
462 ppd->landscape = 90;
463
464 /*
465 * Read lines from the PPD file and add them to the file record...
466 */
467
468 group = NULL;
469 subgroup = NULL;
470 option = NULL;
471 choice = NULL;
472
473 while ((mask = ppd_read(fp, keyword, name, text, &string)) != 0)
474 {
475 #ifdef DEBUG
476 printf("mask = %x, keyword = \"%s\"", mask, keyword);
477
478 if (name[0] != '\0')
479 printf(", name = \"%s\"", name);
480
481 if (text[0] != '\0')
482 printf(", text = \"%s\"", text);
483
484 if (string != NULL)
485 {
486 if (strlen(string) > 40)
487 printf(", string = %08x", string);
488 else
489 printf(", string = \"%s\"", string);
490 }
491
492 puts("");
493 #endif /* DEBUG */
494
495 if (strcmp(keyword, "LanguageLevel") == 0)
496 ppd->language_level = atoi(string);
497 else if (strcmp(keyword, "LanguageEncoding") == 0)
498 {
499 ppd->lang_encoding = string;
500 string = NULL; /* Don't free this string below */
501 }
502 else if (strcmp(keyword, "LanguageVersion") == 0)
503 {
504 ppd->lang_version = string;
505 string = NULL; /* Don't free this string below */
506 }
507 else if (strcmp(keyword, "Manufacturer") == 0)
508 {
509 ppd->manufacturer = string;
510 string = NULL; /* Don't free this string below */
511 }
512 else if (strcmp(keyword, "ModelName") == 0)
513 {
514 ppd->modelname = string;
515 string = NULL; /* Don't free this string below */
516 }
517 else if (strcmp(keyword, "NickName") == 0)
518 {
519 ppd->nickname = string;
520 string = NULL; /* Don't free this string below */
521 }
522 else if (strcmp(keyword, "Product") == 0)
523 {
524 ppd->product = string;
525 string = NULL; /* Don't free this string below */
526 }
527 else if (strcmp(keyword, "ShortNickName") == 0)
528 {
529 ppd->shortnickname = string;
530 string = NULL; /* Don't free this string below */
531 }
532 else if (strcmp(keyword, "TTRasterizer") == 0)
533 {
534 ppd->ttrasterizer = string;
535 string = NULL; /* Don't free this string below */
536 }
537 else if (strcmp(keyword, "JCLBegin") == 0)
538 {
539 ppd_decode(string); /* Decode quoted string */
540 ppd->jcl_begin = string;
541 string = NULL; /* Don't free this string below */
542 }
543 else if (strcmp(keyword, "JCLEnd") == 0)
544 {
545 ppd_decode(string); /* Decode quoted string */
546 ppd->jcl_end = string;
547 string = NULL; /* Don't free this string below */
548 }
549 else if (strcmp(keyword, "JCLToPSInterpreter") == 0)
550 {
551 ppd_decode(string); /* Decode quoted string */
552 ppd->jcl_ps = string;
553 string = NULL; /* Don't free this string below */
554 }
555 else if (strcmp(keyword, "AccurateScreensSupport") == 0)
556 ppd->accurate_screens = strcmp(string, "True") == 0;
557 else if (strcmp(keyword, "ColorDevice") == 0)
558 ppd->color_device = strcmp(string, "True") == 0;
559 else if (strcmp(keyword, "ContoneOnly") == 0)
560 ppd->contone_only = strcmp(string, "True") == 0;
561 else if (strcmp(keyword, "DefaultColorSpace") == 0)
562 {
563 if (strcmp(string, "CMY") == 0)
564 ppd->colorspace = PPD_CS_CMY;
565 else if (strcmp(string, "CMYK") == 0)
566 ppd->colorspace = PPD_CS_CMYK;
567 else if (strcmp(string, "RGB") == 0)
568 ppd->colorspace = PPD_CS_RGB;
569 else if (strcmp(string, "RGBK") == 0)
570 ppd->colorspace = PPD_CS_RGBK;
571 else if (strcmp(string, "N") == 0)
572 ppd->colorspace = PPD_CS_N;
573 else
574 ppd->colorspace = PPD_CS_GRAY;
575 }
576 else if (strcmp(keyword, "cupsManualCopies") == 0)
577 ppd->manual_copies = strcmp(string, "True") == 0;
578 else if (strcmp(keyword, "cupsModelNumber") == 0)
579 ppd->model_number = atoi(string);
580 else if (strcmp(keyword, "cupsColorProfile") == 0)
581 {
582 if (ppd->num_profiles == 0)
583 profile = malloc(sizeof(ppd_profile_t));
584 else
585 profile = realloc(ppd->profiles, sizeof(ppd_profile_t) *
586 (ppd->num_profiles + 1));
587
588 ppd->profiles = profile;
589 profile += ppd->num_profiles;
590 ppd->num_profiles ++;
591
592 memset(profile, 0, sizeof(ppd_profile_t));
593 strcpy(profile->resolution, name);
594 strcpy(profile->media_type, text);
595 sscanf(string, "%f%f%f%f%f%f%f%f%f%f", &(profile->density),
596 profile->matrix[0] + 0, profile->matrix[0] + 1,
597 profile->matrix[0] + 2, profile->matrix[1] + 0,
598 profile->matrix[1] + 1, profile->matrix[1] + 2,
599 profile->matrix[2] + 0, profile->matrix[2] + 1,
600 profile->matrix[2] + 2);
601 }
602 else if (strcmp(keyword, "cupsFilter") == 0)
603 {
604 if (ppd->num_filters == 0)
605 filter = malloc(sizeof(char *));
606 else
607 filter = realloc(ppd->filters, sizeof(char *) * (ppd->num_filters + 1));
608
609 ppd->filters = filter;
610 filter += ppd->num_filters;
611 ppd->num_filters ++;
612
613 /*
614 * Copy filter string and prevent it from being freed below...
615 */
616
617 *filter = string;
618 string = NULL;
619 }
620 else if (strcmp(keyword, "VariablePaperSize") == 0 &&
621 strcmp(string, "True") == 0)
622 {
623 ppd->variable_sizes = 1;
624
625 /*
626 * Add a "Custom" page size entry...
627 */
628
629 ppd_add_size(ppd, "Custom");
630
631 /*
632 * Add a "Custom" page size option...
633 */
634
635 if ((group = ppd_get_group(ppd, "General")) == NULL)
636 {
637 ppdClose(ppd);
638 free(string);
639 return (NULL);
640 }
641
642 if ((option = ppd_get_option(group, "PageSize")) == NULL)
643 {
644 ppdClose(ppd);
645 free(string);
646 return (NULL);
647 }
648
649 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
650 {
651 ppdClose(ppd);
652 free(string);
653 return (NULL);
654 }
655
656 strcpy(choice->text, "Custom Size");
657 group = NULL;
658 option = NULL;
659 }
660 else if (strcmp(keyword, "MaxMediaWidth") == 0)
661 ppd->custom_max[0] = atof(string);
662 else if (strcmp(keyword, "MaxMediaHeight") == 0)
663 ppd->custom_max[1] = atof(string);
664 else if (strcmp(keyword, "ParamCustomPageSize") == 0)
665 {
666 if (strcmp(name, "Width") == 0)
667 sscanf(string, "%*s%*s%f%f", ppd->custom_min + 0,
668 ppd->custom_max + 0);
669 else if (strcmp(name, "Height") == 0)
670 sscanf(string, "%*s%*s%f%f", ppd->custom_min + 1,
671 ppd->custom_max + 1);
672 }
673 else if (strcmp(keyword, "HWMargins") == 0)
674 sscanf(string, "%f%f%f%f", ppd->custom_margins + 0,
675 ppd->custom_margins + 1, ppd->custom_margins + 2,
676 ppd->custom_margins + 3);
677 else if (strcmp(keyword, "CustomPageSize") == 0 &&
678 strcmp(name, "True") == 0 &&
679 ppd->variable_sizes)
680 {
681 if ((option = ppdFindOption(ppd, "PageSize")) == NULL)
682 {
683 ppdClose(ppd);
684 free(string);
685 return (NULL);
686 }
687
688 if ((choice = ppdFindChoice(option, "Custom")) == NULL)
689 {
690 ppdClose(ppd);
691 free(string);
692 return (NULL);
693 }
694
695 choice->code = string;
696 string = NULL;
697 option = NULL;
698 }
699 else if (strcmp(keyword, "LandscapeOrientation") == 0)
700 {
701 if (strcmp(string, "Minus90") == 0)
702 ppd->landscape = -90;
703 else
704 ppd->landscape = 90;
705 }
706 else if (strcmp(keyword, "Emulators") == 0)
707 {
708 for (count = 1, sptr = string; sptr != NULL;)
709 if ((sptr = strchr(sptr, ' ')) != NULL)
710 {
711 count ++;
712 while (*sptr == ' ')
713 sptr ++;
714 }
715
716 ppd->num_emulations = count;
717 ppd->emulations = calloc(sizeof(ppd_emul_t), count);
718
719 for (i = 0, sptr = string; i < count; i ++)
720 {
721 for (nameptr = ppd->emulations[i].name; *sptr != '\0' && *sptr != ' ';)
722 *nameptr ++ = *sptr ++;
723
724 *nameptr = '\0';
725
726 while (*sptr == ' ')
727 sptr ++;
728 }
729 }
730 else if (strncmp(keyword, "StartEmulator_", 14) == 0)
731 {
732 ppd_decode(string);
733
734 for (i = 0; i < ppd->num_emulations; i ++)
735 if (strcmp(keyword + 14, ppd->emulations[i].name) == 0)
736 {
737 ppd->emulations[i].start = string;
738 string = NULL;
739 }
740 }
741 else if (strncmp(keyword, "StopEmulator_", 13) == 0)
742 {
743 ppd_decode(string);
744
745 for (i = 0; i < ppd->num_emulations; i ++)
746 if (strcmp(keyword + 13, ppd->emulations[i].name) == 0)
747 {
748 ppd->emulations[i].stop = string;
749 string = NULL;
750 }
751 }
752 else if (strcmp(keyword, "JobPatchFile") == 0)
753 {
754 if (ppd->patches == NULL)
755 {
756 ppd->patches = string;
757 string = NULL;
758 }
759 else
760 {
761 ppd->patches = realloc(ppd->patches, strlen(ppd->patches) +
762 strlen(string) + 1);
763
764 strcpy(ppd->patches + strlen(ppd->patches), string);
765 }
766 }
767 else if (strcmp(keyword, "OpenUI") == 0)
768 {
769 /*
770 * Add an option record to the current sub-group, group, or file...
771 */
772
773 if (name[0] == '*')
774 strcpy(name, name + 1);
775
776 if (string == NULL)
777 {
778 ppdClose(ppd);
779 return (NULL);
780 }
781
782 if (subgroup != NULL)
783 option = ppd_get_option(subgroup, name);
784 else if (group == NULL)
785 {
786 if (strcmp(name, "Collate") != 0 &&
787 strcmp(name, "Duplex") != 0 &&
788 strcmp(name, "InputSlot") != 0 &&
789 strcmp(name, "ManualFeed") != 0 &&
790 strcmp(name, "MediaType") != 0 &&
791 strcmp(name, "MediaColor") != 0 &&
792 strcmp(name, "MediaWeight") != 0 &&
793 strcmp(name, "OutputBin") != 0 &&
794 strcmp(name, "OutputMode") != 0 &&
795 strcmp(name, "OutputOrder") != 0 &&
796 strcmp(name, "PageSize") != 0 &&
797 strcmp(name, "PageRegion") != 0)
798 group = ppd_get_group(ppd, "Extra");
799 else
800 group = ppd_get_group(ppd, "General");
801
802 if (group == NULL)
803 {
804 ppdClose(ppd);
805 free(string);
806 return (NULL);
807 }
808
809 option = ppd_get_option(group, name);
810 group = NULL;
811 }
812 else
813 option = ppd_get_option(group, name);
814
815 if (option == NULL)
816 {
817 ppdClose(ppd);
818 free(string);
819 return (NULL);
820 }
821
822 /*
823 * Now fill in the initial information for the option...
824 */
825
826 if (strcmp(string, "PickMany") == 0)
827 option->ui = PPD_UI_PICKMANY;
828 else if (strcmp(string, "Boolean") == 0)
829 option->ui = PPD_UI_BOOLEAN;
830 else
831 option->ui = PPD_UI_PICKONE;
832
833 if (text[0])
834 strcpy(option->text, text);
835 else
836 {
837 if (strcmp(name, "PageSize") == 0)
838 strcpy(option->text, "Media Size");
839 else if (strcmp(name, "MediaType") == 0)
840 strcpy(option->text, "Media Type");
841 else if (strcmp(name, "InputSlot") == 0)
842 strcpy(option->text, "Media Source");
843 else
844 strcpy(option->text, name);
845 }
846
847 option->section = PPD_ORDER_ANY;
848 }
849 else if (strcmp(keyword, "JCLOpenUI") == 0)
850 {
851 /*
852 * Find the JCL group, and add if needed...
853 */
854
855 if (group != NULL)
856 {
857 ppdClose(ppd);
858 free(string);
859 return (NULL);
860 }
861
862 group = ppd_get_group(ppd, "JCL");
863
864 if (group == NULL)
865 {
866 ppdClose(ppd);
867 free(string);
868 return (NULL);
869 }
870
871 /*
872 * Add an option record to the current JCLs...
873 */
874
875 if (name[0] == '*')
876 strcpy(name, name + 1);
877
878 option = ppd_get_option(group, name);
879
880 if (option == NULL)
881 {
882 ppdClose(ppd);
883 free(string);
884 return (NULL);
885 }
886
887 /*
888 * Now fill in the initial information for the option...
889 */
890
891 if (strcmp(string, "PickMany") == 0)
892 option->ui = PPD_UI_PICKMANY;
893 else if (strcmp(string, "Boolean") == 0)
894 option->ui = PPD_UI_BOOLEAN;
895 else
896 option->ui = PPD_UI_PICKONE;
897
898 strcpy(option->text, text);
899
900 option->section = PPD_ORDER_JCL;
901 group = NULL;
902 }
903 else if (strcmp(keyword, "CloseUI") == 0 ||
904 strcmp(keyword, "JCLCloseUI") == 0)
905 option = NULL;
906 else if (strcmp(keyword, "OpenGroup") == 0)
907 {
908 /*
909 * Open a new group...
910 */
911
912 if (group != NULL)
913 {
914 ppdClose(ppd);
915 free(string);
916 return (NULL);
917 }
918
919 if (strchr(string, '/') != NULL) /* Just show human readable text */
920 strcpy(string, strchr(string, '/') + 1);
921
922 ppd_decode(string);
923 group = ppd_get_group(ppd, string);
924 }
925 else if (strcmp(keyword, "CloseGroup") == 0)
926 group = NULL;
927 else if (strcmp(keyword, "OpenSubGroup") == 0)
928 {
929 /*
930 * Open a new sub-group...
931 */
932
933 if (group == NULL || subgroup != NULL)
934 {
935 ppdClose(ppd);
936 free(string);
937 return (NULL);
938 }
939
940 if (group->num_subgroups == 0)
941 subgroup = malloc(sizeof(ppd_group_t));
942 else
943 subgroup = realloc(group->subgroups,
944 (group->num_subgroups + 1) * sizeof(ppd_group_t));
945
946 if (subgroup == NULL)
947 {
948 ppdClose(ppd);
949 free(string);
950 return (NULL);
951 }
952
953 group->subgroups = subgroup;
954 subgroup += group->num_subgroups;
955 group->num_subgroups ++;
956
957 memset(subgroup, 0, sizeof(ppd_group_t));
958 strcpy(subgroup->text, string);
959 }
960 else if (strcmp(keyword, "CloseSubGroup") == 0)
961 subgroup = NULL;
962 else if (strcmp(keyword, "OrderDependency") == 0 ||
963 strcmp(keyword, "NonUIOrderDependency") == 0)
964 {
965 if (sscanf(string, "%f%s%s", &order, name, keyword) != 3)
966 {
967 ppdClose(ppd);
968 free(string);
969 return (NULL);
970 }
971
972 if (keyword[0] == '*')
973 strcpy(keyword, keyword + 1);
974
975 if (strcmp(name, "ExitServer") == 0)
976 section = PPD_ORDER_EXIT;
977 else if (strcmp(name, "Prolog") == 0)
978 section = PPD_ORDER_PROLOG;
979 else if (strcmp(name, "DocumentSetup") == 0)
980 section = PPD_ORDER_DOCUMENT;
981 else if (strcmp(name, "PageSetup") == 0)
982 section = PPD_ORDER_PAGE;
983 else if (strcmp(name, "JCLSetup") == 0)
984 section = PPD_ORDER_JCL;
985 else
986 section = PPD_ORDER_ANY;
987
988 if (option == NULL)
989 {
990 /*
991 * Only valid for Non-UI options...
992 */
993
994 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
995 if (group->text[0] == '\0')
996 break;
997
998 if (i > 0)
999 for (i = 0; i < group->num_options; i ++)
1000 if (strcmp(keyword, group->options[i].keyword) == 0)
1001 {
1002 group->options[i].section = section;
1003 group->options[i].order = order;
1004 break;
1005 }
1006
1007 group = NULL;
1008 }
1009 else
1010 {
1011 option->section = section;
1012 option->order = order;
1013 }
1014 }
1015 else if (strncmp(keyword, "Default", 7) == 0)
1016 {
1017 if (strchr(string, '/') != NULL)
1018 *strchr(string, '/') = '\0';
1019
1020 if (option == NULL)
1021 {
1022 /*
1023 * Only valid for Non-UI options...
1024 */
1025
1026 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
1027 if (group->text[0] == '\0')
1028 break;
1029
1030 if (i > 0)
1031 for (i = 0; i < group->num_options; i ++)
1032 if (strcmp(keyword, group->options[i].keyword) == 0)
1033 {
1034 strcpy(group->options[i].defchoice, string);
1035 break;
1036 }
1037
1038 group = NULL;
1039 }
1040 else
1041 strcpy(option->defchoice, string);
1042 }
1043 else if (strcmp(keyword, "UIConstraints") == 0 ||
1044 strcmp(keyword, "NonUIConstraints") == 0)
1045 {
1046 if (ppd->num_consts == 0)
1047 constraint = calloc(sizeof(ppd_const_t), 1);
1048 else
1049 constraint = realloc(ppd->consts,
1050 (ppd->num_consts + 1) * sizeof(ppd_const_t));
1051
1052 if (constraint == NULL)
1053 {
1054 ppdClose(ppd);
1055 free(string);
1056 return (NULL);
1057 }
1058
1059 ppd->consts = constraint;
1060 constraint += ppd->num_consts;
1061 ppd->num_consts ++;
1062
1063 switch (sscanf(string, "%s%s%s%s", constraint->option1,
1064 constraint->choice1, constraint->option2,
1065 constraint->choice2))
1066 {
1067 case 0 : /* Error */
1068 case 1 : /* Error */
1069 ppdClose(ppd);
1070 free(string);
1071 break;
1072
1073 case 2 : /* Two options... */
1074 if (constraint->option1[0] == '*')
1075 strcpy(constraint->option1, constraint->option1 + 1);
1076
1077 if (constraint->choice1[0] == '*')
1078 strcpy(constraint->option2, constraint->choice1 + 1);
1079 else
1080 strcpy(constraint->option2, constraint->choice1);
1081
1082 constraint->choice1[0] = '\0';
1083 constraint->choice2[0] = '\0';
1084 break;
1085
1086 case 3 : /* Two options, one choice... */
1087 if (constraint->option1[0] == '*')
1088 strcpy(constraint->option1, constraint->option1 + 1);
1089
1090 if (constraint->choice1[0] == '*')
1091 {
1092 strcpy(constraint->choice2, constraint->option2);
1093 strcpy(constraint->option2, constraint->choice1 + 1);
1094 constraint->choice1[0] = '\0';
1095 }
1096 else
1097 {
1098 if (constraint->option2[0] == '*')
1099 strcpy(constraint->option2, constraint->option2 + 1);
1100
1101 constraint->choice2[0] = '\0';
1102 }
1103 break;
1104
1105 case 4 : /* Two options, two choices... */
1106 if (constraint->option1[0] == '*')
1107 strcpy(constraint->option1, constraint->option1 + 1);
1108
1109 if (constraint->option2[0] == '*')
1110 strcpy(constraint->option2, constraint->option2 + 1);
1111 break;
1112 }
1113 }
1114 else if (strcmp(keyword, "PaperDimension") == 0)
1115 {
1116 if ((size = ppdPageSize(ppd, name)) != NULL)
1117 sscanf(string, "%f%f", &(size->width), &(size->length));
1118 }
1119 else if (strcmp(keyword, "ImageableArea") == 0)
1120 {
1121 if ((size = ppdPageSize(ppd, name)) != NULL)
1122 sscanf(string, "%f%f%f%f", &(size->left), &(size->bottom),
1123 &(size->right), &(size->top));
1124 }
1125 else if (option != NULL &&
1126 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
1127 (PPD_KEYWORD | PPD_OPTION | PPD_STRING))
1128 {
1129 if (strcmp(keyword, "PageSize") == 0)
1130 {
1131 /*
1132 * Add a page size...
1133 */
1134
1135 ppd_add_size(ppd, name);
1136 }
1137
1138 /*
1139 * Add the option choice...
1140 */
1141
1142 choice = ppd_add_choice(option, name);
1143
1144 if (mask & PPD_TEXT)
1145 strcpy(choice->text, text);
1146 else if (strcmp(name, "True") == 0)
1147 strcpy(choice->text, "Yes");
1148 else if (strcmp(name, "False") == 0)
1149 strcpy(choice->text, "No");
1150 else
1151 strcpy(choice->text, name);
1152
1153 if (strncmp(keyword, "JCL", 3) == 0)
1154 ppd_decode(string); /* Decode quoted string */
1155
1156 choice->code = string;
1157 string = NULL; /* Don't free this string below */
1158 }
1159
1160 if (string != NULL)
1161 free(string);
1162 }
1163
1164 #ifdef DEBUG
1165 if (!feof(fp))
1166 printf("Premature EOF at %d...\n", ftell(fp));
1167 #endif /* DEBUG */
1168
1169 /*
1170 * Set the option back-pointer for each choice...
1171 */
1172
1173 qsort(ppd->groups, ppd->num_groups, sizeof(ppd_group_t),
1174 (int (*)(const void *, const void *))compare_groups);
1175
1176 for (i = ppd->num_groups, group = ppd->groups;
1177 i > 0;
1178 i --, group ++)
1179 {
1180 qsort(group->options, group->num_options, sizeof(ppd_option_t),
1181 (int (*)(const void *, const void *))compare_options);
1182
1183 for (j = group->num_options, option = group->options;
1184 j > 0;
1185 j --, option ++)
1186 {
1187 qsort(option->choices, option->num_choices, sizeof(ppd_choice_t),
1188 (int (*)(const void *, const void *))compare_choices);
1189
1190 for (k = 0; k < option->num_choices; k ++)
1191 option->choices[k].option = (void *)option;
1192 }
1193
1194 qsort(group->subgroups, group->num_subgroups, sizeof(ppd_group_t),
1195 (int (*)(const void *, const void *))compare_groups);
1196
1197 for (j = group->num_subgroups, subgroup = group->subgroups;
1198 j > 0;
1199 j --, subgroup ++)
1200 {
1201 qsort(subgroup->options, subgroup->num_options, sizeof(ppd_option_t),
1202 (int (*)(const void *, const void *))compare_options);
1203
1204 for (k = group->num_options, option = group->options;
1205 k > 0;
1206 k --, option ++)
1207 {
1208 qsort(option->choices, option->num_choices, sizeof(ppd_choice_t),
1209 (int (*)(const void *, const void *))compare_choices);
1210
1211 for (m = 0; m < option->num_choices; m ++)
1212 option->choices[m].option = (void *)option;
1213 }
1214 }
1215 }
1216
1217 return (ppd);
1218 }
1219
1220
1221 /*
1222 * 'ppdOpenFd()' - Read a PPD file into memory.
1223 */
1224
1225 ppd_file_t * /* O - PPD file record */
1226 ppdOpenFd(int fd) /* I - File to read from */
1227 {
1228 FILE *fp; /* File pointer */
1229 ppd_file_t *ppd; /* PPD file record */
1230
1231
1232 /*
1233 * Range check input...
1234 */
1235
1236 if (fd < 0)
1237 return (NULL);
1238
1239 /*
1240 * Try to open the file and parse it...
1241 */
1242
1243 if ((fp = fdopen(fd, "r")) != NULL)
1244 {
1245 setbuf(fp, NULL);
1246
1247 ppd = ppdOpen(fp);
1248
1249 free(fp);
1250 }
1251 else
1252 ppd = NULL;
1253
1254 return (ppd);
1255 }
1256
1257
1258 /*
1259 * 'ppdOpenFile()' - Read a PPD file into memory.
1260 */
1261
1262 ppd_file_t * /* O - PPD file record */
1263 ppdOpenFile(char *filename) /* I - File to read from */
1264 {
1265 FILE *fp; /* File pointer */
1266 ppd_file_t *ppd; /* PPD file record */
1267
1268
1269 /*
1270 * Range check input...
1271 */
1272
1273 if (filename == NULL)
1274 return (NULL);
1275
1276 /*
1277 * Try to open the file and parse it...
1278 */
1279
1280 if ((fp = fopen(filename, "r")) != NULL)
1281 {
1282 ppd = ppdOpen(fp);
1283
1284 fclose(fp);
1285 }
1286 else
1287 ppd = NULL;
1288
1289 return (ppd);
1290 }
1291
1292
1293 /*
1294 * 'compare_strings()' - Compare two strings.
1295 */
1296
1297 int /* O - Result of comparison */
1298 compare_strings(char *s, /* I - First string */
1299 char *t) /* I - Second string */
1300 {
1301 int diff, /* Difference between digits */
1302 digits; /* Number of digits */
1303
1304
1305 /*
1306 * Loop through both strings, returning only when a difference is
1307 * seen. Also, compare whole numbers rather than just characters, too!
1308 */
1309
1310 while (*s && *t)
1311 {
1312 if (isdigit(*s) && isdigit(*t))
1313 {
1314 /*
1315 * Got a number; start by skipping leading 0's...
1316 */
1317
1318 while (*s == '0')
1319 s ++;
1320 while (*t == '0')
1321 t ++;
1322
1323 /*
1324 * Skip equal digits...
1325 */
1326
1327 while (isdigit(*s) && *s == *t)
1328 {
1329 s ++;
1330 t ++;
1331 }
1332
1333 /*
1334 * Bounce out if *s and *t aren't both digits...
1335 */
1336
1337 if (!isdigit(*s) || !isdigit(*t))
1338 continue;
1339
1340 if (*s < *t)
1341 diff = -1;
1342 else
1343 diff = 1;
1344
1345 /*
1346 * Figure out how many more digits there are...
1347 */
1348
1349 digits = 0;
1350
1351 while (isdigit(*s))
1352 {
1353 digits ++;
1354 s ++;
1355 }
1356
1357 while (isdigit(*t))
1358 {
1359 digits --;
1360 t ++;
1361 }
1362
1363 /*
1364 * Return if the number or value of the digits is different...
1365 */
1366
1367 if (digits < 0)
1368 return (-1);
1369 else if (digits > 0)
1370 return (1);
1371 else
1372 return (diff);
1373 }
1374 else if (tolower(*s) < tolower(*t))
1375 return (-1);
1376 else if (tolower(*s) > tolower(*t))
1377 return (1);
1378 else
1379 {
1380 s ++;
1381 t ++;
1382 }
1383 }
1384
1385 /*
1386 * Return the results of the final comparison...
1387 */
1388
1389 if (*s)
1390 return (1);
1391 else if (*t)
1392 return (-1);
1393 else
1394 return (0);
1395 }
1396
1397
1398 /*
1399 * 'compare_groups()' - Compare two groups.
1400 */
1401
1402 static int /* O - Result of comparison */
1403 compare_groups(ppd_group_t *g0, /* I - First group */
1404 ppd_group_t *g1) /* I - Second group */
1405 {
1406 return (compare_strings(g0->text, g1->text));
1407 }
1408
1409
1410 /*
1411 * 'compare_options()' - Compare two options.
1412 */
1413
1414 static int /* O - Result of comparison */
1415 compare_options(ppd_option_t *o0,/* I - First option */
1416 ppd_option_t *o1)/* I - Second option */
1417 {
1418 return (compare_strings(o0->text, o1->text));
1419 }
1420
1421
1422 /*
1423 * 'compare_choices()' - Compare two choices.
1424 */
1425
1426 static int /* O - Result of comparison */
1427 compare_choices(ppd_choice_t *c0,/* I - First choice */
1428 ppd_choice_t *c1)/* I - Second choice */
1429 {
1430 return (compare_strings(c0->text, c1->text));
1431 }
1432
1433
1434 /*
1435 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
1436 * necessary.
1437 */
1438
1439 static int /* O - Bitmask of fields read */
1440 ppd_read(FILE *fp, /* I - File to read from */
1441 char *keyword, /* O - Keyword from line */
1442 char *option, /* O - Option from line */
1443 char *text, /* O - Human-readable text from line */
1444 char **string) /* O - Code/string data */
1445 {
1446 int ch, /* Character from file */
1447 endquote, /* Waiting for an end quote */
1448 mask; /* Mask to be returned */
1449 char *keyptr, /* Keyword pointer */
1450 *optptr, /* Option pointer */
1451 *textptr, /* Text pointer */
1452 *strptr, /* Pointer into string */
1453 *lineptr, /* Current position in line buffer */
1454 line[262144]; /* Line buffer (256k) */
1455
1456
1457 /*
1458 * Range check everything...
1459 */
1460
1461 if (fp == NULL || keyword == NULL || option == NULL || text == NULL ||
1462 string == NULL)
1463 return (0);
1464
1465 /*
1466 * Now loop until we have a valid line...
1467 */
1468
1469 do
1470 {
1471 /*
1472 * Read the line...
1473 */
1474
1475 lineptr = line;
1476 endquote = 0;
1477
1478 while ((ch = getc(fp)) != EOF &&
1479 (lineptr - line) < (sizeof(line) - 1))
1480 {
1481 if (ch == '\r' || ch == '\n')
1482 {
1483 /*
1484 * Line feed or carriage return...
1485 */
1486
1487 if (lineptr == line) /* Skip blank lines */
1488 continue;
1489
1490 if (ch == '\r')
1491 {
1492 /*
1493 * Check for a trailing line feed...
1494 */
1495
1496 if ((ch = getc(fp)) == EOF)
1497 break;
1498 if (ch != 0x0a)
1499 ungetc(ch, fp);
1500 }
1501
1502 *lineptr++ = '\n';
1503
1504 if (!endquote) /* Continue for multi-line text */
1505 break;
1506 }
1507 else
1508 {
1509 /*
1510 * Any other character...
1511 */
1512
1513 *lineptr++ = ch;
1514
1515 if (ch == '\"')
1516 endquote = !endquote;
1517 }
1518 }
1519
1520 if (lineptr > line && lineptr[-1] == '\n')
1521 lineptr --;
1522
1523 *lineptr = '\0';
1524
1525 if (ch == EOF && lineptr == line)
1526 return (0);
1527
1528 /*
1529 * Now parse it...
1530 */
1531
1532 mask = 0;
1533 lineptr = line + 1;
1534
1535 keyword[0] = '\0';
1536 option[0] = '\0';
1537 text[0] = '\0';
1538 *string = NULL;
1539
1540 if (line[0] != '*') /* All lines start with an asterisk */
1541 continue;
1542
1543 if (strncmp(line, "*%", 2) == 0 || /* Comment line */
1544 strncmp(line, "*?", 2) == 0 || /* Query line */
1545 strcmp(line, "*End") == 0) /* End of multi-line string */
1546 continue;
1547
1548 /*
1549 * Get a keyword...
1550 */
1551
1552 keyptr = keyword;
1553
1554 while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr) &&
1555 (keyptr - keyword) < 40)
1556 *keyptr++ = *lineptr++;
1557
1558 *keyptr = '\0';
1559 mask |= PPD_KEYWORD;
1560
1561 if (*lineptr == ' ' || *lineptr == '\t')
1562 {
1563 /*
1564 * Get an option name...
1565 */
1566
1567 while (*lineptr == ' ' || *lineptr == '\t')
1568 lineptr ++;
1569
1570 optptr = option;
1571
1572 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':' &&
1573 *lineptr != '/' && (optptr - option) < 40)
1574 *optptr++ = *lineptr++;
1575
1576 *optptr = '\0';
1577 mask |= PPD_OPTION;
1578
1579 if (*lineptr == '/')
1580 {
1581 /*
1582 * Get human-readable text...
1583 */
1584
1585 lineptr ++;
1586
1587 textptr = text;
1588
1589 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':' &&
1590 (textptr - text) < 80)
1591 *textptr++ = *lineptr++;
1592
1593 *textptr = '\0';
1594 ppd_decode(text);
1595
1596 mask |= PPD_TEXT;
1597 }
1598 }
1599
1600 if (*lineptr == ':')
1601 {
1602 /*
1603 * Get string...
1604 */
1605
1606 *string = malloc(strlen(lineptr) + 1);
1607
1608 while (*lineptr == ':' || isspace(*lineptr))
1609 lineptr ++;
1610
1611 strptr = *string;
1612
1613 while (*lineptr != '\0')
1614 {
1615 if (*lineptr != '\"')
1616 *strptr++ = *lineptr++;
1617 else
1618 lineptr ++;
1619 }
1620
1621 *strptr = '\0';
1622
1623 mask |= PPD_STRING;
1624 }
1625 }
1626 while (mask == 0);
1627
1628 return (mask);
1629 }
1630
1631
1632 /*
1633 * 'ppd_decode()' - Decode a string value...
1634 */
1635
1636 static void
1637 ppd_decode(char *string) /* I - String to decode */
1638 {
1639 char *inptr, /* Input pointer */
1640 *outptr; /* Output pointer */
1641
1642
1643 inptr = string;
1644 outptr = string;
1645
1646 while (*inptr != '\0')
1647 if (*inptr == '<' && isxdigit(inptr[1]))
1648 {
1649 /*
1650 * Convert hex to 8-bit values...
1651 */
1652
1653 inptr ++;
1654 while (isxdigit(*inptr))
1655 {
1656 if (isalpha(*inptr))
1657 *outptr = (tolower(*inptr) - 'a' + 10) << 4;
1658 else
1659 *outptr = (*inptr - '0') << 4;
1660
1661 inptr ++;
1662
1663 if (isalpha(*inptr))
1664 *outptr |= tolower(*inptr) - 'a' + 10;
1665 else
1666 *outptr |= *inptr - '0';
1667
1668 inptr ++;
1669 outptr ++;
1670 }
1671
1672 while (*inptr != '>' && *inptr != '\0')
1673 inptr ++;
1674 while (*inptr == '>')
1675 inptr ++;
1676 }
1677 else
1678 *outptr++ = *inptr++;
1679
1680 *outptr = '\0';
1681 }
1682
1683
1684 /*
1685 * End of "$Id: ppd.c,v 1.21 1999/06/04 21:04:29 mike Exp $".
1686 */