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