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