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