]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/ppd.c
Don't need to look for SetResolution option.
[thirdparty/cups.git] / cups / ppd.c
1 /*
2 * "$Id: ppd.c,v 1.93 2003/02/19 14:46:10 mike Exp $"
3 *
4 * PPD file routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2003 by Easy Software Products, all rights reserved.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * PostScript is a trademark of Adobe Systems, Inc.
25 *
26 * This code and any derivative of it may be used and distributed
27 * freely under the terms of the GNU General Public License when
28 * used with GNU Ghostscript or its derivatives. Use of the code
29 * (or any derivative of it) with software other than GNU
30 * GhostScript (or its derivatives) is governed by the CUPS license
31 * agreement.
32 *
33 * This file is subject to the Apple OS-Developed Software exception.
34 *
35 * Contents:
36 *
37 * _ppd_attr_compare() - Compare two attributes.
38 * ppdClose() - Free all memory used by the PPD file.
39 * ppdErrorString() - Returns the text assocated with a status.
40 * ppdLastError() - Return the status from the last ppdOpen*().
41 * ppdOpen() - Read a PPD file into memory.
42 * ppdOpenFd() - Read a PPD file into memory.
43 * ppdOpenFile() - Read a PPD file into memory.
44 * ppd_add_attr() - Add an attribute to the PPD data.
45 * ppd_add_choice() - Add a choice to an option.
46 * ppd_add_size() - Add a page size.
47 * ppd_compare_groups() - Compare two groups.
48 * ppd_compare_options() - Compare two options.
49 * ppd_decode() - Decode a string value...
50 * ppd_fix() - Fix WinANSI characters in the range 0x80 to
51 * 0x9f to be valid ISO-8859-1 characters...
52 * ppd_free_group() - Free a single UI group.
53 * ppd_free_option() - Free a single option.
54 * ppd_get_group() - Find or create the named group as needed.
55 * ppd_get_option() - Find or create the named option as needed.
56 * ppd_read() - Read a line from a PPD file, skipping comment
57 * lines as necessary.
58 */
59
60 /*
61 * Include necessary headers.
62 */
63
64 #include "ppd.h"
65 #include <stdlib.h>
66 #include <ctype.h>
67 #include "string.h"
68 #include "language.h"
69 #include "debug.h"
70
71
72 /*
73 * Definitions...
74 */
75
76 #if defined(WIN32) || defined(__EMX__)
77 # define READ_BINARY "rb" /* Open a binary file for reading */
78 # define WRITE_BINARY "wb" /* Open a binary file for writing */
79 #else
80 # define READ_BINARY "r" /* Open a binary file for reading */
81 # define WRITE_BINARY "w" /* Open a binary file for writing */
82 #endif /* WIN32 || __EMX__ */
83
84 #define ppd_free(p) if (p) free(p) /* Safe free macro */
85
86 #define PPD_KEYWORD 1 /* Line contained a keyword */
87 #define PPD_OPTION 2 /* Line contained an option name */
88 #define PPD_TEXT 4 /* Line contained human-readable text */
89 #define PPD_STRING 8 /* Line contained a string or code */
90
91
92 /*
93 * Local globals...
94 */
95
96 static ppd_status_t ppd_status = PPD_OK;
97 /* Status of last ppdOpen*() */
98 static int ppd_line = 0; /* Current line number */
99
100
101 /*
102 * Local functions...
103 */
104
105 static ppd_attr_t *ppd_add_attr(ppd_file_t *ppd, const char *name,
106 const char *spec, const char *value);
107 static ppd_choice_t *ppd_add_choice(ppd_option_t *option, const char *name);
108 static ppd_size_t *ppd_add_size(ppd_file_t *ppd, const char *name);
109 #ifndef __APPLE__
110 static int ppd_compare_groups(ppd_group_t *g0, ppd_group_t *g1);
111 static int ppd_compare_options(ppd_option_t *o0, ppd_option_t *o1);
112 #endif /* !__APPLE__ */
113 static void ppd_decode(char *string);
114 #ifndef __APPLE__
115 static void ppd_fix(char *string);
116 #else
117 # define ppd_fix(s)
118 #endif /* !__APPLE__ */
119 static void ppd_free_group(ppd_group_t *group);
120 static void ppd_free_option(ppd_option_t *option);
121 static ppd_group_t *ppd_get_group(ppd_file_t *ppd, const char *name,
122 const char *text);
123 static ppd_option_t *ppd_get_option(ppd_group_t *group, const char *name);
124 static int ppd_read(FILE *fp, char *keyword, char *option,
125 char *text, char **string);
126
127
128 /*
129 * '_ppd_attr_compare()' - Compare two attributes.
130 */
131
132 int /* O - Result of comparison */
133 _ppd_attr_compare(ppd_attr_t **a, /* I - First attribute */
134 ppd_attr_t **b) /* I - Second attribute */
135 {
136 int ret; /* Result of comparison */
137
138
139 if ((ret = strcasecmp((*a)->name, (*b)->name)) != 0)
140 return (ret);
141 else if ((*a)->spec[0] && (*b)->spec[0])
142 return (strcasecmp((*a)->spec, (*b)->spec));
143 else
144 return (0);
145 }
146
147
148 /*
149 * 'ppdClose()' - Free all memory used by the PPD file.
150 */
151
152 void
153 ppdClose(ppd_file_t *ppd) /* I - PPD file record */
154 {
155 int i; /* Looping var */
156 ppd_emul_t *emul; /* Current emulation */
157 ppd_group_t *group; /* Current group */
158 char **font; /* Current font */
159 char **filter; /* Current filter */
160 ppd_attr_t **attr; /* Current attribute */
161
162
163 /*
164 * Range check the PPD file record...
165 */
166
167 if (ppd == NULL)
168 return;
169
170 /*
171 * Free all strings at the top level...
172 */
173
174 ppd_free(ppd->patches);
175 ppd_free(ppd->jcl_begin);
176 ppd_free(ppd->jcl_ps);
177 ppd_free(ppd->jcl_end);
178 ppd_free(ppd->lang_encoding);
179 ppd_free(ppd->lang_version);
180 ppd_free(ppd->modelname);
181 ppd_free(ppd->ttrasterizer);
182 ppd_free(ppd->manufacturer);
183 ppd_free(ppd->nickname);
184 ppd_free(ppd->shortnickname);
185 ppd_free(ppd->protocols);
186 ppd_free(ppd->pcfilename);
187
188 /*
189 * Free any emulations...
190 */
191
192 if (ppd->num_emulations > 0)
193 {
194 for (i = ppd->num_emulations, emul = ppd->emulations; i > 0; i --, emul ++)
195 {
196 ppd_free(emul->start);
197 ppd_free(emul->stop);
198 }
199
200 ppd_free(ppd->emulations);
201 }
202
203 /*
204 * Free any UI groups, subgroups, and options...
205 */
206
207 if (ppd->num_groups > 0)
208 {
209 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
210 ppd_free_group(group);
211
212 ppd_free(ppd->groups);
213 }
214
215 /*
216 * Free any page sizes...
217 */
218
219 if (ppd->num_sizes > 0)
220 ppd_free(ppd->sizes);
221
222 /*
223 * Free any constraints...
224 */
225
226 if (ppd->num_consts > 0)
227 ppd_free(ppd->consts);
228
229 /*
230 * Free any filters...
231 */
232
233 if (ppd->num_filters > 0)
234 {
235 for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++)
236 ppd_free(*filter);
237
238 ppd_free(ppd->filters);
239 }
240
241 /*
242 * Free any fonts...
243 */
244
245 if (ppd->num_fonts > 0)
246 {
247 for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++)
248 ppd_free(*font);
249
250 ppd_free(ppd->fonts);
251 }
252
253 /*
254 * Free any profiles...
255 */
256
257 if (ppd->num_profiles > 0)
258 ppd_free(ppd->profiles);
259
260 /*
261 * Free any attributes...
262 */
263
264 if (ppd->num_attrs > 0)
265 {
266 for (i = ppd->num_attrs, attr = ppd->attrs; i > 0; i --, attr ++)
267 {
268 ppd_free((*attr)->value);
269 ppd_free(*attr);
270 }
271
272 ppd_free(ppd->attrs);
273 }
274
275 /*
276 * Free the whole record...
277 */
278
279 ppd_free(ppd);
280 }
281
282
283 /*
284 * 'ppdErrorString()' - Returns the text assocated with a status.
285 */
286
287 const char * /* O - Status string */
288 ppdErrorString(ppd_status_t status) /* I - PPD status */
289 {
290 static const char * const messages[] =/* Status messages */
291 {
292 "OK",
293 "Unable to open PPD file",
294 "NULL PPD file pointer",
295 "Memory allocation error",
296 "Missing PPD-Adobe-4.x header",
297 "Missing value string",
298 "Internal error",
299 "Bad OpenGroup",
300 "OpenGroup without a CloseGroup first",
301 "Bad OpenUI/JCLOpenUI",
302 "OpenUI/JCLOpenUI without a CloseUI/JCLCLoseUI first",
303 "Bad OrderDependency",
304 "Bad UIConstraints",
305 "Missing asterisk in column 1",
306 "Line longer than the maximum allowed (255 characters)",
307 "Illegal control character",
308 "Illegal main keyword string",
309 "Illegal option keyword string",
310 "Illegal translation string"
311 };
312
313
314 if (status < PPD_OK || status > PPD_ILLEGAL_TRANSLATION)
315 return ("Unknown");
316 else
317 return (messages[status]);
318 }
319
320
321 /*
322 * 'ppdLastError()' - Return the status from the last ppdOpen*().
323 */
324
325 ppd_status_t /* O - Status code */
326 ppdLastError(int *line) /* O - Line number */
327 {
328 if (line)
329 *line = ppd_line;
330
331 return (ppd_status);
332 }
333
334
335 /*
336 * 'ppdOpen()' - Read a PPD file into memory.
337 */
338
339 ppd_file_t * /* O - PPD file record */
340 ppdOpen(FILE *fp) /* I - File to read from */
341 {
342 char *oldlocale; /* Old locale settings */
343 int i, j, k, m; /* Looping vars */
344 int count; /* Temporary count */
345 ppd_file_t *ppd; /* PPD file record */
346 ppd_group_t *group, /* Current group */
347 *subgroup; /* Current sub-group */
348 ppd_option_t *option; /* Current option */
349 ppd_choice_t *choice; /* Current choice */
350 ppd_const_t *constraint; /* Current constraint */
351 ppd_size_t *size; /* Current page size */
352 int mask; /* Line data mask */
353 char keyword[PPD_MAX_NAME],
354 /* Keyword from file */
355 name[PPD_MAX_NAME],
356 /* Option from file */
357 text[PPD_MAX_LINE],
358 /* Human-readable text from file */
359 *string, /* Code/text from file */
360 *sptr, /* Pointer into string */
361 *nameptr, /* Pointer into name */
362 *temp, /* Temporary string pointer */
363 **tempfonts; /* Temporary fonts pointer */
364 float order; /* Order dependency number */
365 ppd_section_t section; /* Order dependency section */
366 ppd_profile_t *profile; /* Pointer to color profile */
367 char **filter; /* Pointer to filter */
368 cups_lang_t *language; /* Default language */
369 static const char * const ui_keywords[] =
370 {
371 /* Boolean keywords */
372 "BlackSubstitution",
373 "Booklet",
374 "Collate",
375 "ManualFeed",
376 "MirrorPrint",
377 "NegativePrint",
378 "Sorter",
379 "TraySwitch",
380
381 /* PickOne keywords */
382 "AdvanceMedia",
383 "BindColor",
384 "BindEdge",
385 "BindType",
386 "BindWhen",
387 "BitsPerPixel",
388 "ColorModel",
389 "CutMedia",
390 "Duplex",
391 "FoldType",
392 "FoldWhen",
393 "InputSlot",
394 "JCLFrameBufferSize",
395 "JCLResolution",
396 "Jog",
397 "MediaColor",
398 "MediaType",
399 "MediaWeight",
400 "OutputBin",
401 "OutputMode",
402 "OutputOrder",
403 "PageRegion",
404 "PageSize",
405 "Resolution",
406 "Separations",
407 "Signature",
408 "Slipsheet",
409 "Smoothing",
410 "StapleLocation",
411 "StapleOrientation",
412 "StapleWhen",
413 "StapleX",
414 "StapleY"
415 };
416
417
418 /*
419 * Default to "OK" status...
420 */
421
422 ppd_status = PPD_OK;
423 ppd_line = 0;
424
425 /*
426 * Range check input...
427 */
428
429 if (fp == NULL)
430 {
431 ppd_status = PPD_NULL_FILE;
432 return (NULL);
433 }
434
435 /*
436 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
437 */
438
439 mask = ppd_read(fp, keyword, name, text, &string);
440
441 if (mask == 0 ||
442 strcmp(keyword, "PPD-Adobe") != 0 ||
443 string == NULL || string[0] != '4')
444 {
445 /*
446 * Either this is not a PPD file, or it is not a 4.x PPD file.
447 */
448
449 if (ppd_status != PPD_OK)
450 ppd_status = PPD_MISSING_PPDADOBE4;
451
452 ppd_free(string);
453
454 return (NULL);
455 }
456
457 DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword, string));
458
459 ppd_free(string);
460
461 /*
462 * Allocate memory for the PPD file record...
463 */
464
465 if ((ppd = calloc(sizeof(ppd_file_t), 1)) == NULL)
466 {
467 ppd_status = PPD_ALLOC_ERROR;
468
469 return (NULL);
470 }
471
472 ppd->language_level = 1;
473 ppd->color_device = 0;
474 ppd->colorspace = PPD_CS_GRAY;
475 ppd->landscape = -90;
476
477 /*
478 * Get the default language for the user...
479 */
480
481 language = cupsLangDefault();
482
483 #ifdef LC_NUMERIC
484 oldlocale = setlocale(LC_NUMERIC, "C");
485 #else
486 oldlocale = setlocale(LC_ALL, "C");
487 #endif /* LC_NUMERIC */
488
489 /*
490 * Read lines from the PPD file and add them to the file record...
491 */
492
493 group = NULL;
494 subgroup = NULL;
495 option = NULL;
496 choice = NULL;
497
498 while ((mask = ppd_read(fp, keyword, name, text, &string)) != 0)
499 {
500 #ifdef DEBUG
501 printf("mask = %x, keyword = \"%s\"", mask, keyword);
502
503 if (name[0] != '\0')
504 printf(", name = \"%s\"", name);
505
506 if (text[0] != '\0')
507 printf(", text = \"%s\"", text);
508
509 if (string != NULL)
510 {
511 if (strlen(string) > 40)
512 printf(", string = %p", string);
513 else
514 printf(", string = \"%s\"", string);
515 }
516
517 puts("");
518 #endif /* DEBUG */
519
520 if (strcmp(keyword, "CloseUI") && strcmp(keyword, "CloseGroup") &&
521 strcmp(keyword, "CloseSubGroup") && strncmp(keyword, "Default", 7) &&
522 strcmp(keyword, "JCLCloseUI") && strcmp(keyword, "JCLOpenUI") &&
523 strcmp(keyword, "OpenUI") && strcmp(keyword, "OpenGroup") &&
524 strcmp(keyword, "OpenSubGroup") && string == NULL)
525 {
526 /*
527 * Need a string value!
528 */
529
530 ppdClose(ppd);
531
532 cupsLangFree(language);
533
534 #ifdef LC_NUMERIC
535 setlocale(LC_NUMERIC, oldlocale);
536 #else
537 setlocale(LC_ALL, oldlocale);
538 #endif /* LC_NUMERIC */
539
540 ppd_status = PPD_MISSING_VALUE;
541
542 return (NULL);
543 }
544
545 /*
546 * Certain main keywords (as defined by the PPD spec) may be used
547 * without the usual OpenUI/CloseUI stuff. Presumably this is just
548 * so that Adobe wouldn't completely break compatibility with PPD
549 * files prior to v4.0 of the spec, but it is hopelessly
550 * inconsistent... Catch these main keywords and automatically
551 * create the corresponding option, as needed...
552 */
553
554 if (option == NULL)
555 {
556 for (i = 0; i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])); i ++)
557 if (!strcmp(name, ui_keywords[i]))
558 break;
559
560 if (i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])))
561 {
562 /*
563 * Create the option in the appropriate group...
564 */
565
566 if (!group)
567 {
568 if (strcmp(name, "Collate") && strcmp(name, "Duplex") &&
569 strcmp(name, "InputSlot") && strcmp(name, "ManualFeed") &&
570 strcmp(name, "MediaType") && strcmp(name, "MediaColor") &&
571 strcmp(name, "MediaWeight") && strcmp(name, "OutputBin") &&
572 strcmp(name, "OutputMode") && strcmp(name, "OutputOrder") &&
573 strcmp(name, "PageSize") && strcmp(name, "PageRegion"))
574 group = ppd_get_group(ppd, "Extra",
575 cupsLangString(language, CUPS_MSG_EXTRA));
576 else
577 group = ppd_get_group(ppd, "General",
578 cupsLangString(language, CUPS_MSG_GENERAL));
579
580 if (group == NULL)
581 {
582 ppdClose(ppd);
583
584 ppd_free(string);
585
586 cupsLangFree(language);
587
588 #ifdef LC_NUMERIC
589 setlocale(LC_NUMERIC, oldlocale);
590 #else
591 setlocale(LC_ALL, oldlocale);
592 #endif /* LC_NUMERIC */
593
594 ppd_status = PPD_ALLOC_ERROR;
595
596 return (NULL);
597 }
598
599 DEBUG_printf(("Adding to group %s...\n", group->text));
600 option = ppd_get_option(group, name);
601 group = NULL;
602 }
603 else
604 option = ppd_get_option(group, name);
605
606 if (option == NULL)
607 {
608 ppdClose(ppd);
609
610 ppd_free(string);
611
612 cupsLangFree(language);
613
614 #ifdef LC_NUMERIC
615 setlocale(LC_NUMERIC, oldlocale);
616 #else
617 setlocale(LC_ALL, oldlocale);
618 #endif /* LC_NUMERIC */
619
620 ppd_status = PPD_ALLOC_ERROR;
621
622 return (NULL);
623 }
624
625 /*
626 * Now fill in the initial information for the option...
627 */
628
629 if (!strncmp(name, "JCL", 3))
630 option->section = PPD_ORDER_JCL;
631 else
632 option->section = PPD_ORDER_ANY;
633
634 option->order = 10.0f;
635
636 if (i < 8)
637 option->ui = PPD_UI_BOOLEAN;
638 else
639 option->ui = PPD_UI_PICKONE;
640 }
641 }
642
643 if (strcmp(keyword, "LanguageLevel") == 0)
644 ppd->language_level = atoi(string);
645 else if (strcmp(keyword, "LanguageEncoding") == 0)
646 {
647 ppd_free(ppd->lang_encoding);
648 ppd->lang_encoding = string;
649 string = NULL; /* Don't free this string below */
650 }
651 else if (strcmp(keyword, "LanguageVersion") == 0)
652 {
653 ppd_free(ppd->lang_version);
654 ppd->lang_version = string;
655 string = NULL; /* Don't free this string below */
656 }
657 else if (strcmp(keyword, "Manufacturer") == 0)
658 {
659 ppd_free(ppd->manufacturer);
660 ppd->manufacturer = string;
661 string = NULL; /* Don't free this string below */
662 }
663 else if (strcmp(keyword, "ModelName") == 0)
664 {
665 ppd_free(ppd->modelname);
666 ppd->modelname = string;
667 string = NULL; /* Don't free this string below */
668 }
669 else if (strcmp(keyword, "Protocols") == 0)
670 {
671 ppd_free(ppd->protocols);
672 ppd->protocols = string;
673 string = NULL; /* Don't free this string below */
674 }
675 else if (strcmp(keyword, "PCFileName") == 0)
676 {
677 ppd_free(ppd->pcfilename);
678 ppd->pcfilename = string;
679 string = NULL; /* Don't free this string below */
680 }
681 else if (strcmp(keyword, "NickName") == 0)
682 {
683 ppd_free(ppd->nickname);
684 ppd->nickname = string;
685 string = NULL; /* Don't free this string below */
686 }
687 else if (strcmp(keyword, "Product") == 0)
688 {
689 /*
690 * Add each Product keyword as an attribute...
691 */
692
693 ppd_add_attr(ppd, keyword, "", string);
694
695 /*
696 * Save the last one in the product element...
697 */
698
699 ppd->product = string;
700 string = NULL; /* Don't free this string below */
701 }
702 else if (strcmp(keyword, "ShortNickName") == 0)
703 {
704 ppd_free(ppd->shortnickname);
705 ppd->shortnickname = string;
706 string = NULL; /* Don't free this string below */
707 }
708 else if (strcmp(keyword, "TTRasterizer") == 0)
709 {
710 ppd_free(ppd->ttrasterizer);
711 ppd->ttrasterizer = string;
712 string = NULL; /* Don't free this string below */
713 }
714 else if (strcmp(keyword, "JCLBegin") == 0)
715 {
716 ppd_free(ppd->jcl_begin);
717 ppd_decode(string); /* Decode quoted string */
718 ppd->jcl_begin = string;
719 string = NULL; /* Don't free this string below */
720 }
721 else if (strcmp(keyword, "JCLEnd") == 0)
722 {
723 ppd_free(ppd->jcl_end);
724 ppd_decode(string); /* Decode quoted string */
725 ppd->jcl_end = string;
726 string = NULL; /* Don't free this string below */
727 }
728 else if (strcmp(keyword, "JCLToPSInterpreter") == 0)
729 {
730 ppd_free(ppd->jcl_ps);
731 ppd_decode(string); /* Decode quoted string */
732 ppd->jcl_ps = string;
733 string = NULL; /* Don't free this string below */
734 }
735 else if (strcmp(keyword, "AccurateScreensSupport") == 0)
736 ppd->accurate_screens = strcmp(string, "True") == 0;
737 else if (strcmp(keyword, "ColorDevice") == 0)
738 ppd->color_device = strcmp(string, "True") == 0;
739 else if (strcmp(keyword, "ContoneOnly") == 0)
740 ppd->contone_only = strcmp(string, "True") == 0;
741 else if (strcmp(keyword, "DefaultColorSpace") == 0)
742 {
743 if (strcmp(string, "CMY") == 0)
744 ppd->colorspace = PPD_CS_CMY;
745 else if (strcmp(string, "CMYK") == 0)
746 ppd->colorspace = PPD_CS_CMYK;
747 else if (strcmp(string, "RGB") == 0)
748 ppd->colorspace = PPD_CS_RGB;
749 else if (strcmp(string, "RGBK") == 0)
750 ppd->colorspace = PPD_CS_RGBK;
751 else if (strcmp(string, "N") == 0)
752 ppd->colorspace = PPD_CS_N;
753 else
754 ppd->colorspace = PPD_CS_GRAY;
755 }
756 else if (strcmp(keyword, "cupsFlipDuplex") == 0)
757 ppd->flip_duplex = strcmp(string, "True") == 0;
758 else if (strcmp(keyword, "cupsManualCopies") == 0)
759 ppd->manual_copies = strcmp(string, "True") == 0;
760 else if (strcmp(keyword, "cupsModelNumber") == 0)
761 ppd->model_number = atoi(string);
762 else if (strcmp(keyword, "cupsColorProfile") == 0)
763 {
764 if (ppd->num_profiles == 0)
765 profile = malloc(sizeof(ppd_profile_t));
766 else
767 profile = realloc(ppd->profiles, sizeof(ppd_profile_t) *
768 (ppd->num_profiles + 1));
769
770 ppd->profiles = profile;
771 profile += ppd->num_profiles;
772 ppd->num_profiles ++;
773
774 memset(profile, 0, sizeof(ppd_profile_t));
775 strlcpy(profile->resolution, name, sizeof(profile->resolution));
776 strlcpy(profile->media_type, text, sizeof(profile->media_type));
777 sscanf(string, "%f%f%f%f%f%f%f%f%f%f%f", &(profile->density),
778 &(profile->gamma),
779 profile->matrix[0] + 0, profile->matrix[0] + 1,
780 profile->matrix[0] + 2, profile->matrix[1] + 0,
781 profile->matrix[1] + 1, profile->matrix[1] + 2,
782 profile->matrix[2] + 0, profile->matrix[2] + 1,
783 profile->matrix[2] + 2);
784 }
785 else if (strcmp(keyword, "cupsFilter") == 0)
786 {
787 if (ppd->num_filters == 0)
788 filter = malloc(sizeof(char *));
789 else
790 filter = realloc(ppd->filters, sizeof(char *) * (ppd->num_filters + 1));
791
792 if (filter == NULL)
793 {
794 ppd_free(filter);
795
796 ppdClose(ppd);
797
798 cupsLangFree(language);
799
800 #ifdef LC_NUMERIC
801 setlocale(LC_NUMERIC, oldlocale);
802 #else
803 setlocale(LC_ALL, oldlocale);
804 #endif /* LC_NUMERIC */
805
806 ppd_status = PPD_ALLOC_ERROR;
807
808 return (NULL);
809 }
810
811 ppd->filters = filter;
812 filter += ppd->num_filters;
813 ppd->num_filters ++;
814
815 /*
816 * Copy filter string and prevent it from being freed below...
817 */
818
819 *filter = string;
820 string = NULL;
821 }
822 else if (strcmp(keyword, "Throughput") == 0)
823 ppd->throughput = atoi(string);
824 else if (strcmp(keyword, "Font") == 0)
825 {
826 /*
827 * Add this font to the list of available fonts...
828 */
829
830 if (ppd->num_fonts == 0)
831 tempfonts = (char **)malloc(sizeof(char *));
832 else
833 tempfonts = (char **)realloc(ppd->fonts,
834 sizeof(char *) * (ppd->num_fonts + 1));
835
836 if (tempfonts == NULL)
837 {
838 ppd_free(string);
839
840 ppdClose(ppd);
841
842 cupsLangFree(language);
843
844 #ifdef LC_NUMERIC
845 setlocale(LC_NUMERIC, oldlocale);
846 #else
847 setlocale(LC_ALL, oldlocale);
848 #endif /* LC_NUMERIC */
849
850 ppd_status = PPD_ALLOC_ERROR;
851
852 return (NULL);
853 }
854
855 ppd->fonts = tempfonts;
856 ppd->fonts[ppd->num_fonts] = strdup(name);
857 ppd->num_fonts ++;
858 }
859 else if (strcmp(keyword, "VariablePaperSize") == 0 &&
860 strcmp(string, "True") == 0 &&
861 !ppd->variable_sizes)
862 {
863 ppd->variable_sizes = 1;
864
865 /*
866 * Add a "Custom" page size entry...
867 */
868
869 ppd_add_size(ppd, "Custom");
870
871 /*
872 * Add a "Custom" page size option...
873 */
874
875 if ((option = ppdFindOption(ppd, "PageSize")) == NULL)
876 {
877 ppd_group_t *temp;
878
879
880 if ((temp = ppd_get_group(ppd, "General",
881 cupsLangString(language,
882 CUPS_MSG_GENERAL))) == NULL)
883 {
884 ppdClose(ppd);
885
886 ppd_free(string);
887
888 cupsLangFree(language);
889
890 #ifdef LC_NUMERIC
891 setlocale(LC_NUMERIC, oldlocale);
892 #else
893 setlocale(LC_ALL, oldlocale);
894 #endif /* LC_NUMERIC */
895
896 ppd_status = PPD_ALLOC_ERROR;
897
898 return (NULL);
899 }
900
901 if ((option = ppd_get_option(temp, "PageSize")) == NULL)
902 {
903 ppdClose(ppd);
904
905 ppd_free(string);
906
907 cupsLangFree(language);
908
909 #ifdef LC_NUMERIC
910 setlocale(LC_NUMERIC, oldlocale);
911 #else
912 setlocale(LC_ALL, oldlocale);
913 #endif /* LC_NUMERIC */
914
915 ppd_status = PPD_ALLOC_ERROR;
916
917 return (NULL);
918 }
919 }
920
921 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
922 {
923 ppdClose(ppd);
924
925 ppd_free(string);
926
927 cupsLangFree(language);
928
929 #ifdef LC_NUMERIC
930 setlocale(LC_NUMERIC, oldlocale);
931 #else
932 setlocale(LC_ALL, oldlocale);
933 #endif /* LC_NUMERIC */
934
935 ppd_status = PPD_ALLOC_ERROR;
936
937 return (NULL);
938 }
939
940 strlcpy(choice->text, cupsLangString(language, CUPS_MSG_VARIABLE),
941 sizeof(choice->text));
942 option = NULL;
943 }
944 else if (strcmp(keyword, "MaxMediaWidth") == 0)
945 ppd->custom_max[0] = (float)atof(string);
946 else if (strcmp(keyword, "MaxMediaHeight") == 0)
947 ppd->custom_max[1] = (float)atof(string);
948 else if (strcmp(keyword, "ParamCustomPageSize") == 0)
949 {
950 if (strcmp(name, "Width") == 0)
951 sscanf(string, "%*s%*s%f%f", ppd->custom_min + 0,
952 ppd->custom_max + 0);
953 else if (strcmp(name, "Height") == 0)
954 sscanf(string, "%*s%*s%f%f", ppd->custom_min + 1,
955 ppd->custom_max + 1);
956 }
957 else if (strcmp(keyword, "HWMargins") == 0)
958 sscanf(string, "%f%f%f%f", ppd->custom_margins + 0,
959 ppd->custom_margins + 1, ppd->custom_margins + 2,
960 ppd->custom_margins + 3);
961 else if (strcmp(keyword, "CustomPageSize") == 0 &&
962 strcmp(name, "True") == 0)
963 {
964 if (!ppd->variable_sizes)
965 {
966 ppd->variable_sizes = 1;
967
968 /*
969 * Add a "Custom" page size entry...
970 */
971
972 ppd_add_size(ppd, "Custom");
973
974 /*
975 * Add a "Custom" page size option...
976 */
977
978 if ((option = ppdFindOption(ppd, "PageSize")) == NULL)
979 {
980 ppd_group_t *temp;
981
982
983 if ((temp = ppd_get_group(ppd, "General",
984 cupsLangString(language,
985 CUPS_MSG_GENERAL))) == NULL)
986 {
987 DEBUG_puts("Unable to get general group!");
988
989 ppdClose(ppd);
990
991 ppd_free(string);
992
993 cupsLangFree(language);
994
995 #ifdef LC_NUMERIC
996 setlocale(LC_NUMERIC, oldlocale);
997 #else
998 setlocale(LC_ALL, oldlocale);
999 #endif /* LC_NUMERIC */
1000
1001 ppd_status = PPD_ALLOC_ERROR;
1002
1003 return (NULL);
1004 }
1005
1006 if ((option = ppd_get_option(temp, "PageSize")) == NULL)
1007 {
1008 DEBUG_puts("Unable to get PageSize option!");
1009
1010 ppdClose(ppd);
1011
1012 ppd_free(string);
1013
1014 cupsLangFree(language);
1015
1016 #ifdef LC_NUMERIC
1017 setlocale(LC_NUMERIC, oldlocale);
1018 #else
1019 setlocale(LC_ALL, oldlocale);
1020 #endif /* LC_NUMERIC */
1021
1022 ppd_status = PPD_ALLOC_ERROR;
1023
1024 return (NULL);
1025 }
1026 }
1027
1028 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
1029 {
1030 DEBUG_puts("Unable to add Custom choice!");
1031
1032 ppdClose(ppd);
1033
1034 ppd_free(string);
1035
1036 cupsLangFree(language);
1037
1038 #ifdef LC_NUMERIC
1039 setlocale(LC_NUMERIC, oldlocale);
1040 #else
1041 setlocale(LC_ALL, oldlocale);
1042 #endif /* LC_NUMERIC */
1043
1044 ppd_status = PPD_ALLOC_ERROR;
1045
1046 return (NULL);
1047 }
1048
1049 strlcpy(choice->text, cupsLangString(language, CUPS_MSG_VARIABLE),
1050 sizeof(choice->text));
1051 option = NULL;
1052 }
1053
1054 if ((option = ppdFindOption(ppd, "PageSize")) == NULL)
1055 {
1056 DEBUG_puts("Unable to find PageSize option!");
1057
1058 ppdClose(ppd);
1059
1060 ppd_free(string);
1061
1062 cupsLangFree(language);
1063
1064 #ifdef LC_NUMERIC
1065 setlocale(LC_NUMERIC, oldlocale);
1066 #else
1067 setlocale(LC_ALL, oldlocale);
1068 #endif /* LC_NUMERIC */
1069
1070 ppd_status = PPD_INTERNAL_ERROR;
1071
1072 return (NULL);
1073 }
1074
1075 if ((choice = ppdFindChoice(option, "Custom")) == NULL)
1076 {
1077 DEBUG_puts("Unable to find Custom choice!");
1078
1079 ppdClose(ppd);
1080
1081 ppd_free(string);
1082
1083 cupsLangFree(language);
1084
1085 #ifdef LC_NUMERIC
1086 setlocale(LC_NUMERIC, oldlocale);
1087 #else
1088 setlocale(LC_ALL, oldlocale);
1089 #endif /* LC_NUMERIC */
1090
1091 ppd_status = PPD_INTERNAL_ERROR;
1092
1093 return (NULL);
1094 }
1095
1096 choice->code = string;
1097 string = NULL;
1098 option = NULL;
1099 }
1100 else if (strcmp(keyword, "LandscapeOrientation") == 0)
1101 {
1102 if (strcmp(string, "Minus90") == 0)
1103 ppd->landscape = -90;
1104 else if (strcmp(string, "Plus90") == 0)
1105 ppd->landscape = 90;
1106 }
1107 else if (strcmp(keyword, "Emulators") == 0)
1108 {
1109 for (count = 1, sptr = string; sptr != NULL;)
1110 if ((sptr = strchr(sptr, ' ')) != NULL)
1111 {
1112 count ++;
1113 while (*sptr == ' ')
1114 sptr ++;
1115 }
1116
1117 ppd->num_emulations = count;
1118 ppd->emulations = calloc(sizeof(ppd_emul_t), count);
1119
1120 for (i = 0, sptr = string; i < count; i ++)
1121 {
1122 for (nameptr = ppd->emulations[i].name;
1123 *sptr != '\0' && *sptr != ' ';
1124 sptr ++)
1125 if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1))
1126 *nameptr++ = *sptr;
1127
1128 *nameptr = '\0';
1129
1130 while (*sptr == ' ')
1131 sptr ++;
1132 }
1133 }
1134 else if (strncmp(keyword, "StartEmulator_", 14) == 0)
1135 {
1136 ppd_decode(string);
1137
1138 for (i = 0; i < ppd->num_emulations; i ++)
1139 if (strcmp(keyword + 14, ppd->emulations[i].name) == 0)
1140 {
1141 ppd->emulations[i].start = string;
1142 string = NULL;
1143 }
1144 }
1145 else if (strncmp(keyword, "StopEmulator_", 13) == 0)
1146 {
1147 ppd_decode(string);
1148
1149 for (i = 0; i < ppd->num_emulations; i ++)
1150 if (strcmp(keyword + 13, ppd->emulations[i].name) == 0)
1151 {
1152 ppd->emulations[i].stop = string;
1153 string = NULL;
1154 }
1155 }
1156 else if (strcmp(keyword, "JobPatchFile") == 0)
1157 {
1158 if (ppd->patches == NULL)
1159 {
1160 ppd->patches = string;
1161 string = NULL;
1162 }
1163 else
1164 {
1165 temp = realloc(ppd->patches, strlen(ppd->patches) +
1166 strlen(string) + 1);
1167 if (temp == NULL)
1168 {
1169 ppdClose(ppd);
1170
1171 ppd_free(string);
1172
1173 cupsLangFree(language);
1174
1175 #ifdef LC_NUMERIC
1176 setlocale(LC_NUMERIC, oldlocale);
1177 #else
1178 setlocale(LC_ALL, oldlocale);
1179 #endif /* LC_NUMERIC */
1180
1181 ppd_status = PPD_ALLOC_ERROR;
1182
1183 return (NULL);
1184 }
1185
1186 ppd->patches = temp;
1187
1188 strcpy(ppd->patches + strlen(ppd->patches), string);
1189 }
1190 }
1191 else if (strcmp(keyword, "OpenUI") == 0)
1192 {
1193 /*
1194 * Don't allow nesting of options...
1195 */
1196
1197 if (option)
1198 {
1199 ppdClose(ppd);
1200
1201 ppd_free(string);
1202
1203 cupsLangFree(language);
1204
1205 #ifdef LC_NUMERIC
1206 setlocale(LC_NUMERIC, oldlocale);
1207 #else
1208 setlocale(LC_ALL, oldlocale);
1209 #endif /* LC_NUMERIC */
1210
1211 ppd_status = PPD_NESTED_OPEN_UI;
1212
1213 return (NULL);
1214 }
1215
1216 /*
1217 * Add an option record to the current sub-group, group, or file...
1218 */
1219
1220 if (name[0] == '*')
1221 strcpy(name, name + 1); /* Eliminate leading asterisk */
1222
1223 for (i = strlen(name) - 1; i > 0 && isspace(name[i]); i --)
1224 name[i] = '\0'; /* Eliminate trailing spaces */
1225
1226 DEBUG_printf(("OpenUI of %s in group %s...\n", name,
1227 group ? group->text : "(null)"));
1228
1229 if (subgroup != NULL)
1230 option = ppd_get_option(subgroup, name);
1231 else if (group == NULL)
1232 {
1233 if (strcmp(name, "Collate") && strcmp(name, "Duplex") &&
1234 strcmp(name, "InputSlot") && strcmp(name, "ManualFeed") &&
1235 strcmp(name, "MediaType") && strcmp(name, "MediaColor") &&
1236 strcmp(name, "MediaWeight") && strcmp(name, "OutputBin") &&
1237 strcmp(name, "OutputMode") && strcmp(name, "OutputOrder") &&
1238 strcmp(name, "PageSize") && strcmp(name, "PageRegion"))
1239 group = ppd_get_group(ppd, "Extra",
1240 cupsLangString(language, CUPS_MSG_EXTRA));
1241 else
1242 group = ppd_get_group(ppd, "General",
1243 cupsLangString(language, CUPS_MSG_GENERAL));
1244
1245 if (group == NULL)
1246 {
1247 ppdClose(ppd);
1248
1249 ppd_free(string);
1250
1251 cupsLangFree(language);
1252
1253 #ifdef LC_NUMERIC
1254 setlocale(LC_NUMERIC, oldlocale);
1255 #else
1256 setlocale(LC_ALL, oldlocale);
1257 #endif /* LC_NUMERIC */
1258
1259 ppd_status = PPD_ALLOC_ERROR;
1260
1261 return (NULL);
1262 }
1263
1264 DEBUG_printf(("Adding to group %s...\n", group->text));
1265 option = ppd_get_option(group, name);
1266 group = NULL;
1267 }
1268 else
1269 option = ppd_get_option(group, name);
1270
1271 if (option == NULL)
1272 {
1273 ppdClose(ppd);
1274
1275 ppd_free(string);
1276
1277 cupsLangFree(language);
1278
1279 #ifdef LC_NUMERIC
1280 setlocale(LC_NUMERIC, oldlocale);
1281 #else
1282 setlocale(LC_ALL, oldlocale);
1283 #endif /* LC_NUMERIC */
1284
1285 ppd_status = PPD_ALLOC_ERROR;
1286
1287 return (NULL);
1288 }
1289
1290 /*
1291 * Now fill in the initial information for the option...
1292 */
1293
1294 if (string && strcmp(string, "PickMany") == 0)
1295 option->ui = PPD_UI_PICKMANY;
1296 else if (string && strcmp(string, "Boolean") == 0)
1297 option->ui = PPD_UI_BOOLEAN;
1298 else if (string && strcmp(string, "PickOne") == 0)
1299 option->ui = PPD_UI_PICKONE;
1300 else
1301 {
1302 ppdClose(ppd);
1303
1304 ppd_free(string);
1305
1306 cupsLangFree(language);
1307
1308 #ifdef LC_NUMERIC
1309 setlocale(LC_NUMERIC, oldlocale);
1310 #else
1311 setlocale(LC_ALL, oldlocale);
1312 #endif /* LC_NUMERIC */
1313
1314 ppd_status = PPD_BAD_OPEN_UI;
1315
1316 return (NULL);
1317 }
1318
1319 if (text[0])
1320 {
1321 strlcpy(option->text, text, sizeof(option->text));
1322 ppd_fix(option->text);
1323 }
1324 else
1325 {
1326 if (strcmp(name, "PageSize") == 0)
1327 strlcpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_SIZE),
1328 sizeof(option->text));
1329 else if (strcmp(name, "MediaType") == 0)
1330 strlcpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_TYPE),
1331 sizeof(option->text));
1332 else if (strcmp(name, "InputSlot") == 0)
1333 strlcpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_SOURCE),
1334 sizeof(option->text));
1335 else if (strcmp(name, "ColorModel") == 0)
1336 strlcpy(option->text, cupsLangString(language, CUPS_MSG_OUTPUT_MODE),
1337 sizeof(option->text));
1338 else if (strcmp(name, "Resolution") == 0)
1339 strlcpy(option->text, cupsLangString(language, CUPS_MSG_RESOLUTION),
1340 sizeof(option->text));
1341 else
1342 strlcpy(option->text, name, sizeof(option->text));
1343 }
1344
1345 option->section = PPD_ORDER_ANY;
1346 }
1347 else if (strcmp(keyword, "JCLOpenUI") == 0)
1348 {
1349 /*
1350 * Don't allow nesting of options...
1351 */
1352
1353 if (option)
1354 {
1355 ppdClose(ppd);
1356
1357 ppd_free(string);
1358
1359 cupsLangFree(language);
1360
1361 #ifdef LC_NUMERIC
1362 setlocale(LC_NUMERIC, oldlocale);
1363 #else
1364 setlocale(LC_ALL, oldlocale);
1365 #endif /* LC_NUMERIC */
1366
1367 ppd_status = PPD_NESTED_OPEN_UI;
1368
1369 return (NULL);
1370 }
1371
1372 /*
1373 * Find the JCL group, and add if needed...
1374 */
1375
1376 group = ppd_get_group(ppd, "JCL", "JCL");
1377
1378 if (group == NULL)
1379 {
1380 ppdClose(ppd);
1381
1382 ppd_free(string);
1383
1384 cupsLangFree(language);
1385
1386 #ifdef LC_NUMERIC
1387 setlocale(LC_NUMERIC, oldlocale);
1388 #else
1389 setlocale(LC_ALL, oldlocale);
1390 #endif /* LC_NUMERIC */
1391
1392 ppd_status = PPD_ALLOC_ERROR;
1393
1394 return (NULL);
1395 }
1396
1397 /*
1398 * Add an option record to the current JCLs...
1399 */
1400
1401 if (name[0] == '*')
1402 strcpy(name, name + 1);
1403
1404 option = ppd_get_option(group, name);
1405
1406 if (option == NULL)
1407 {
1408 ppdClose(ppd);
1409
1410 ppd_free(string);
1411
1412 cupsLangFree(language);
1413
1414 #ifdef LC_NUMERIC
1415 setlocale(LC_NUMERIC, oldlocale);
1416 #else
1417 setlocale(LC_ALL, oldlocale);
1418 #endif /* LC_NUMERIC */
1419
1420 ppd_status = PPD_ALLOC_ERROR;
1421
1422 return (NULL);
1423 }
1424
1425 /*
1426 * Now fill in the initial information for the option...
1427 */
1428
1429 if (string && strcmp(string, "PickMany") == 0)
1430 option->ui = PPD_UI_PICKMANY;
1431 else if (string && strcmp(string, "Boolean") == 0)
1432 option->ui = PPD_UI_BOOLEAN;
1433 else if (string && strcmp(string, "PickOne") == 0)
1434 option->ui = PPD_UI_PICKONE;
1435 else
1436 {
1437 ppdClose(ppd);
1438
1439 ppd_free(string);
1440
1441 cupsLangFree(language);
1442
1443 #ifdef LC_NUMERIC
1444 setlocale(LC_NUMERIC, oldlocale);
1445 #else
1446 setlocale(LC_ALL, oldlocale);
1447 #endif /* LC_NUMERIC */
1448
1449 ppd_status = PPD_BAD_OPEN_UI;
1450
1451 return (NULL);
1452 }
1453
1454 strlcpy(option->text, text, sizeof(option->text));
1455
1456 option->section = PPD_ORDER_JCL;
1457 group = NULL;
1458 }
1459 else if (strcmp(keyword, "CloseUI") == 0 ||
1460 strcmp(keyword, "JCLCloseUI") == 0)
1461 option = NULL;
1462 else if (strcmp(keyword, "OpenGroup") == 0)
1463 {
1464 /*
1465 * Open a new group...
1466 */
1467
1468 if (group != NULL)
1469 {
1470 ppdClose(ppd);
1471
1472 ppd_free(string);
1473
1474 cupsLangFree(language);
1475
1476 #ifdef LC_NUMERIC
1477 setlocale(LC_NUMERIC, oldlocale);
1478 #else
1479 setlocale(LC_ALL, oldlocale);
1480 #endif /* LC_NUMERIC */
1481
1482 ppd_status = PPD_NESTED_OPEN_GROUP;
1483
1484 return (NULL);
1485 }
1486
1487 if (!string)
1488 {
1489 ppdClose(ppd);
1490
1491 ppd_free(string);
1492
1493 cupsLangFree(language);
1494
1495 #ifdef LC_NUMERIC
1496 setlocale(LC_NUMERIC, oldlocale);
1497 #else
1498 setlocale(LC_ALL, oldlocale);
1499 #endif /* LC_NUMERIC */
1500
1501 ppd_status = PPD_BAD_OPEN_GROUP;
1502
1503 return (NULL);
1504 }
1505
1506 /*
1507 * Separate the group name from the text (name/text)...
1508 */
1509
1510 if ((sptr = strchr(string, '/')) != NULL)
1511 *sptr++ = '\0';
1512 else
1513 sptr = string;
1514
1515 /*
1516 * Fix up the text...
1517 */
1518
1519 ppd_decode(sptr);
1520 ppd_fix(sptr);
1521
1522 /*
1523 * Find/add the group...
1524 */
1525
1526 group = ppd_get_group(ppd, string, sptr);
1527 }
1528 else if (strcmp(keyword, "CloseGroup") == 0)
1529 group = NULL;
1530 else if (strcmp(keyword, "OrderDependency") == 0 ||
1531 strcmp(keyword, "NonUIOrderDependency") == 0)
1532 {
1533 if (sscanf(string, "%f%40s%40s", &order, name, keyword) != 3)
1534 {
1535 ppdClose(ppd);
1536
1537 ppd_free(string);
1538
1539 cupsLangFree(language);
1540
1541 #ifdef LC_NUMERIC
1542 setlocale(LC_NUMERIC, oldlocale);
1543 #else
1544 setlocale(LC_ALL, oldlocale);
1545 #endif /* LC_NUMERIC */
1546
1547 ppd_status = PPD_BAD_ORDER_DEPENDENCY;
1548
1549 return (NULL);
1550 }
1551
1552 if (keyword[0] == '*')
1553 strcpy(keyword, keyword + 1);
1554
1555 if (strcmp(name, "ExitServer") == 0)
1556 section = PPD_ORDER_EXIT;
1557 else if (strcmp(name, "Prolog") == 0)
1558 section = PPD_ORDER_PROLOG;
1559 else if (strcmp(name, "DocumentSetup") == 0)
1560 section = PPD_ORDER_DOCUMENT;
1561 else if (strcmp(name, "PageSetup") == 0)
1562 section = PPD_ORDER_PAGE;
1563 else if (strcmp(name, "JCLSetup") == 0)
1564 section = PPD_ORDER_JCL;
1565 else
1566 section = PPD_ORDER_ANY;
1567
1568 if (option == NULL)
1569 {
1570 ppd_group_t *temp;
1571
1572
1573 /*
1574 * Only valid for Non-UI options...
1575 */
1576
1577 for (i = ppd->num_groups, temp = ppd->groups; i > 0; i --, temp ++)
1578 if (temp->text[0] == '\0')
1579 break;
1580
1581 if (i > 0)
1582 for (i = 0; i < temp->num_options; i ++)
1583 if (strcmp(keyword, temp->options[i].keyword) == 0)
1584 {
1585 temp->options[i].section = section;
1586 temp->options[i].order = order;
1587 break;
1588 }
1589 }
1590 else
1591 {
1592 option->section = section;
1593 option->order = order;
1594 }
1595 }
1596 else if (strncmp(keyword, "Default", 7) == 0)
1597 {
1598 if (string == NULL)
1599 continue;
1600
1601 if (strchr(string, '/') != NULL)
1602 *strchr(string, '/') = '\0';
1603
1604 if (option == NULL)
1605 {
1606 ppd_group_t *temp;
1607
1608
1609 /*
1610 * Only valid for Non-UI options...
1611 */
1612
1613 for (i = ppd->num_groups, temp = ppd->groups; i > 0; i --, temp ++)
1614 if (temp->text[0] == '\0')
1615 break;
1616
1617 if (i > 0)
1618 {
1619 for (i = 0; i < temp->num_options; i ++)
1620 if (strcmp(keyword + 7, temp->options[i].keyword) == 0)
1621 {
1622 strlcpy(temp->options[i].defchoice, string,
1623 sizeof(temp->options[i].defchoice));
1624 break;
1625 }
1626
1627 if (i >= temp->num_options)
1628 {
1629 /*
1630 * Option not found; add this as an attribute...
1631 */
1632
1633 ppd_add_attr(ppd, keyword, "", string);
1634
1635 string = NULL; /* Don't free this string below */
1636 }
1637 }
1638 else
1639 {
1640 /*
1641 * Default group not found; add this as an attribute...
1642 */
1643
1644 ppd_add_attr(ppd, keyword, "", string);
1645
1646 string = NULL; /* Don't free this string below */
1647 }
1648 }
1649 else if (strcmp(keyword + 7, option->keyword) == 0)
1650 strlcpy(option->defchoice, string, sizeof(option->defchoice));
1651 else
1652 {
1653 /*
1654 * Default doesn't match this option; add as an attribute...
1655 */
1656
1657 ppd_add_attr(ppd, keyword, "", string);
1658
1659 string = NULL; /* Don't free this string below */
1660 }
1661 }
1662 else if (strcmp(keyword, "UIConstraints") == 0 ||
1663 strcmp(keyword, "NonUIConstraints") == 0)
1664 {
1665 if (ppd->num_consts == 0)
1666 constraint = calloc(sizeof(ppd_const_t), 1);
1667 else
1668 constraint = realloc(ppd->consts,
1669 (ppd->num_consts + 1) * sizeof(ppd_const_t));
1670
1671 if (constraint == NULL)
1672 {
1673 ppdClose(ppd);
1674
1675 ppd_free(string);
1676
1677 cupsLangFree(language);
1678
1679 #ifdef LC_NUMERIC
1680 setlocale(LC_NUMERIC, oldlocale);
1681 #else
1682 setlocale(LC_ALL, oldlocale);
1683 #endif /* LC_NUMERIC */
1684
1685 ppd_status = PPD_ALLOC_ERROR;
1686
1687 return (NULL);
1688 }
1689
1690 ppd->consts = constraint;
1691 constraint += ppd->num_consts;
1692 ppd->num_consts ++;
1693
1694 switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1,
1695 constraint->choice1, constraint->option2,
1696 constraint->choice2))
1697 {
1698 case 0 : /* Error */
1699 case 1 : /* Error */
1700 ppdClose(ppd);
1701 ppd_free(string);
1702 ppd_status = PPD_BAD_UI_CONSTRAINTS;
1703 return (NULL);
1704
1705 case 2 : /* Two options... */
1706 /*
1707 * The following strcpy's are safe, as optionN and
1708 * choiceN are all the same size (size defined by PPD spec...)
1709 */
1710
1711 if (constraint->option1[0] == '*')
1712 strcpy(constraint->option1, constraint->option1 + 1);
1713
1714 if (constraint->choice1[0] == '*')
1715 strcpy(constraint->option2, constraint->choice1 + 1);
1716 else
1717 strcpy(constraint->option2, constraint->choice1);
1718
1719 constraint->choice1[0] = '\0';
1720 constraint->choice2[0] = '\0';
1721 break;
1722
1723 case 3 : /* Two options, one choice... */
1724 /*
1725 * The following strcpy's are safe, as optionN and
1726 * choiceN are all the same size (size defined by PPD spec...)
1727 */
1728
1729 if (constraint->option1[0] == '*')
1730 strcpy(constraint->option1, constraint->option1 + 1);
1731
1732 if (constraint->choice1[0] == '*')
1733 {
1734 strcpy(constraint->choice2, constraint->option2);
1735 strcpy(constraint->option2, constraint->choice1 + 1);
1736 constraint->choice1[0] = '\0';
1737 }
1738 else
1739 {
1740 if (constraint->option2[0] == '*')
1741 strcpy(constraint->option2, constraint->option2 + 1);
1742
1743 constraint->choice2[0] = '\0';
1744 }
1745 break;
1746
1747 case 4 : /* Two options, two choices... */
1748 if (constraint->option1[0] == '*')
1749 strcpy(constraint->option1, constraint->option1 + 1);
1750
1751 if (constraint->option2[0] == '*')
1752 strcpy(constraint->option2, constraint->option2 + 1);
1753 break;
1754 }
1755 }
1756 else if (strcmp(keyword, "PaperDimension") == 0)
1757 {
1758 if ((size = ppdPageSize(ppd, name)) == NULL)
1759 size = ppd_add_size(ppd, name);
1760
1761 if (size == NULL)
1762 {
1763 /*
1764 * Unable to add or find size!
1765 */
1766
1767 ppdClose(ppd);
1768
1769 ppd_free(string);
1770
1771 cupsLangFree(language);
1772
1773 #ifdef LC_NUMERIC
1774 setlocale(LC_NUMERIC, oldlocale);
1775 #else
1776 setlocale(LC_ALL, oldlocale);
1777 #endif /* LC_NUMERIC */
1778
1779 ppd_status = PPD_ALLOC_ERROR;
1780
1781 return (NULL);
1782 }
1783
1784 sscanf(string, "%f%f", &(size->width), &(size->length));
1785 }
1786 else if (strcmp(keyword, "ImageableArea") == 0)
1787 {
1788 if ((size = ppdPageSize(ppd, name)) == NULL)
1789 size = ppd_add_size(ppd, name);
1790
1791 if (size == NULL)
1792 {
1793 /*
1794 * Unable to add or find size!
1795 */
1796
1797 ppdClose(ppd);
1798
1799 ppd_free(string);
1800
1801 cupsLangFree(language);
1802
1803 #ifdef LC_NUMERIC
1804 setlocale(LC_NUMERIC, oldlocale);
1805 #else
1806 setlocale(LC_ALL, oldlocale);
1807 #endif /* LC_NUMERIC */
1808
1809 ppd_status = PPD_ALLOC_ERROR;
1810
1811 return (NULL);
1812 }
1813
1814 sscanf(string, "%f%f%f%f", &(size->left), &(size->bottom),
1815 &(size->right), &(size->top));
1816 }
1817 else if (option != NULL &&
1818 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
1819 (PPD_KEYWORD | PPD_OPTION | PPD_STRING) &&
1820 strcmp(keyword, option->keyword) == 0)
1821 {
1822 DEBUG_printf(("group = %p, subgroup = %p\n", group, subgroup));
1823
1824 if (strcmp(keyword, "PageSize") == 0)
1825 {
1826 /*
1827 * Add a page size...
1828 */
1829
1830 if (ppdPageSize(ppd, name) == NULL)
1831 ppd_add_size(ppd, name);
1832 }
1833
1834 /*
1835 * Add the option choice...
1836 */
1837
1838 choice = ppd_add_choice(option, name);
1839
1840 if (mask & PPD_TEXT)
1841 {
1842 strlcpy(choice->text, text, sizeof(choice->text));
1843 ppd_fix(choice->text);
1844 }
1845 else if (strcmp(name, "True") == 0)
1846 strcpy(choice->text, "Yes");
1847 else if (strcmp(name, "False") == 0)
1848 strcpy(choice->text, "No");
1849 else
1850 strlcpy(choice->text, name, sizeof(choice->text));
1851
1852 if (option->section == PPD_ORDER_JCL)
1853 ppd_decode(string); /* Decode quoted string */
1854
1855 choice->code = string;
1856 string = NULL; /* Don't free this string below */
1857 }
1858 else if (strcmp(keyword, "OpenSubGroup") != 0 &&
1859 strcmp(keyword, "CloseSubGroup") != 0)
1860 {
1861 char spec[PPD_MAX_NAME + PPD_MAX_TEXT];
1862
1863 snprintf(spec, sizeof(spec), "%s/%s", name, text);
1864 ppd_add_attr(ppd, keyword, spec, string);
1865
1866 string = NULL; /* Don't free this string below */
1867 }
1868
1869 ppd_free(string);
1870 }
1871
1872 /*
1873 * Reset language preferences...
1874 */
1875
1876 cupsLangFree(language);
1877
1878 #ifdef LC_NUMERIC
1879 setlocale(LC_NUMERIC, oldlocale);
1880 #else
1881 setlocale(LC_ALL, oldlocale);
1882 #endif /* LC_NUMERIC */
1883
1884 #ifdef DEBUG
1885 if (!feof(fp))
1886 printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp));
1887 #endif /* DEBUG */
1888
1889 if (ppd_status != PPD_OK)
1890 {
1891 /*
1892 * Had an error reading the PPD file, cannot continue!
1893 */
1894
1895 ppdClose(ppd);
1896
1897 return (NULL);
1898 }
1899
1900 #ifndef __APPLE__
1901 /*
1902 * Make sure that all PPD files with an InputSlot option have an
1903 * "auto" choice that maps to no specific tray or media type.
1904 */
1905
1906 if ((option = ppdFindOption(ppd, "InputSlot")) != NULL)
1907 {
1908 for (i = 0; i < option->num_choices; i ++)
1909 if (option->choices[i].code == NULL || !option->choices[i].code[0])
1910 break;
1911
1912 if (i >= option->num_choices)
1913 {
1914 /*
1915 * No "auto" input slot, add one...
1916 */
1917
1918 choice = ppd_add_choice(option, "Auto");
1919
1920 strlcpy(choice->text, cupsLangString(language, CUPS_MSG_AUTO),
1921 sizeof(choice->text));
1922 choice->code = NULL;
1923 }
1924 }
1925 #endif /* !__APPLE__ */
1926
1927 /*
1928 * Set the option back-pointer for each choice...
1929 */
1930
1931 #ifndef __APPLE__
1932 qsort(ppd->groups, ppd->num_groups, sizeof(ppd_group_t),
1933 (int (*)(const void *, const void *))ppd_compare_groups);
1934 #endif /* !__APPLE__ */
1935
1936 for (i = ppd->num_groups, group = ppd->groups;
1937 i > 0;
1938 i --, group ++)
1939 {
1940 #ifndef __APPLE__
1941 qsort(group->options, group->num_options, sizeof(ppd_option_t),
1942 (int (*)(const void *, const void *))ppd_compare_options);
1943 #endif /* !__APPLE__ */
1944
1945 for (j = group->num_options, option = group->options;
1946 j > 0;
1947 j --, option ++)
1948 {
1949 for (k = 0; k < option->num_choices; k ++)
1950 option->choices[k].option = (void *)option;
1951 }
1952
1953 #ifndef __APPLE__
1954 qsort(group->subgroups, group->num_subgroups, sizeof(ppd_group_t),
1955 (int (*)(const void *, const void *))ppd_compare_groups);
1956 #endif /* !__APPLE__ */
1957
1958 for (j = group->num_subgroups, subgroup = group->subgroups;
1959 j > 0;
1960 j --, subgroup ++)
1961 {
1962 #ifndef __APPLE__
1963 qsort(subgroup->options, subgroup->num_options, sizeof(ppd_option_t),
1964 (int (*)(const void *, const void *))ppd_compare_options);
1965 #endif /* !__APPLE__ */
1966
1967 for (k = group->num_options, option = group->options;
1968 k > 0;
1969 k --, option ++)
1970 {
1971 for (m = 0; m < option->num_choices; m ++)
1972 option->choices[m].option = (void *)option;
1973 }
1974 }
1975 }
1976
1977 /*
1978 * Sort the attributes...
1979 */
1980
1981 if (ppd->num_attrs > 1)
1982 qsort(ppd->attrs, ppd->num_attrs, sizeof(ppd_attr_t *),
1983 (int (*)(const void *, const void *))_ppd_attr_compare);
1984
1985 /*
1986 * Return the PPD file structure...
1987 */
1988
1989 return (ppd);
1990 }
1991
1992
1993 /*
1994 * 'ppdOpenFd()' - Read a PPD file into memory.
1995 */
1996
1997 ppd_file_t * /* O - PPD file record */
1998 ppdOpenFd(int fd) /* I - File to read from */
1999 {
2000 FILE *fp; /* File pointer */
2001 ppd_file_t *ppd; /* PPD file record */
2002
2003
2004 /*
2005 * Set the line number to 0...
2006 */
2007
2008 ppd_line = 0;
2009
2010 /*
2011 * Range check input...
2012 */
2013
2014 if (fd < 0)
2015 {
2016 ppd_status = PPD_NULL_FILE;
2017
2018 return (NULL);
2019 }
2020
2021 /*
2022 * Try to open the file and parse it...
2023 */
2024
2025 if ((fp = fdopen(fd, "r")) != NULL)
2026 {
2027 setbuf(fp, NULL);
2028
2029 ppd = ppdOpen(fp);
2030
2031 fclose(fp);
2032 }
2033 else
2034 {
2035 ppd_status = PPD_FILE_OPEN_ERROR;
2036 ppd = NULL;
2037 }
2038
2039 return (ppd);
2040 }
2041
2042
2043 /*
2044 * 'ppdOpenFile()' - Read a PPD file into memory.
2045 */
2046
2047 ppd_file_t * /* O - PPD file record */
2048 ppdOpenFile(const char *filename) /* I - File to read from */
2049 {
2050 FILE *fp; /* File pointer */
2051 ppd_file_t *ppd; /* PPD file record */
2052
2053
2054 /*
2055 * Set the line number to 0...
2056 */
2057
2058 ppd_line = 0;
2059
2060 /*
2061 * Range check input...
2062 */
2063
2064 if (filename == NULL)
2065 {
2066 ppd_status = PPD_NULL_FILE;
2067
2068 return (NULL);
2069 }
2070
2071 /*
2072 * Try to open the file and parse it...
2073 */
2074
2075 if ((fp = fopen(filename, "r")) != NULL)
2076 {
2077 ppd = ppdOpen(fp);
2078
2079 fclose(fp);
2080 }
2081 else
2082 {
2083 ppd_status = PPD_FILE_OPEN_ERROR;
2084 ppd = NULL;
2085 }
2086
2087 return (ppd);
2088 }
2089
2090
2091 /*
2092 * 'ppd_add_attr()' - Add an attribute to the PPD data.
2093 */
2094
2095 static ppd_attr_t * /* O - New attribute */
2096 ppd_add_attr(ppd_file_t *ppd, /* I - PPD file data */
2097 const char *name, /* I - Attribute name */
2098 const char *spec, /* I - Specifier string, if any */
2099 const char *value) /* I - Value of attribute */
2100 {
2101 ppd_attr_t **ptr, /* New array */
2102 *temp; /* New attribute */
2103
2104
2105 /*
2106 * Range check input...
2107 */
2108
2109 if (ppd == NULL || name == NULL || spec == NULL)
2110 return (NULL);
2111
2112 /*
2113 * Allocate memory for the new attribute...
2114 */
2115
2116 if (ppd->num_attrs == 0)
2117 ptr = malloc(sizeof(ppd_attr_t *));
2118 else
2119 ptr = realloc(ppd->attrs, (ppd->num_attrs + 1) * sizeof(ppd_attr_t *));
2120
2121 if (ptr == NULL)
2122 return (NULL);
2123
2124 ppd->attrs = ptr;
2125 ptr += ppd->num_attrs;
2126
2127 if ((temp = calloc(1, sizeof(ppd_attr_t))) == NULL)
2128 return (NULL);
2129
2130 *ptr = temp;
2131
2132 ppd->num_attrs ++;
2133
2134 /*
2135 * Copy data over...
2136 */
2137
2138 strlcpy(temp->name, name, sizeof(temp->name));
2139 strlcpy(temp->spec, spec, sizeof(temp->spec));
2140 temp->value = (char *)value;
2141
2142 /*
2143 * Return the attribute...
2144 */
2145
2146 return (temp);
2147 }
2148
2149
2150 /*
2151 * 'ppd_add_choice()' - Add a choice to an option.
2152 */
2153
2154 static ppd_choice_t * /* O - Named choice */
2155 ppd_add_choice(ppd_option_t *option, /* I - Option */
2156 const char *name) /* I - Name of choice */
2157 {
2158 ppd_choice_t *choice; /* Choice */
2159
2160
2161 if (option->num_choices == 0)
2162 choice = malloc(sizeof(ppd_choice_t));
2163 else
2164 choice = realloc(option->choices,
2165 sizeof(ppd_choice_t) * (option->num_choices + 1));
2166
2167 if (choice == NULL)
2168 return (NULL);
2169
2170 option->choices = choice;
2171 choice += option->num_choices;
2172 option->num_choices ++;
2173
2174 memset(choice, 0, sizeof(ppd_choice_t));
2175 strlcpy(choice->choice, name, sizeof(choice->choice));
2176
2177 return (choice);
2178 }
2179
2180
2181 /*
2182 * 'ppd_add_size()' - Add a page size.
2183 */
2184
2185 static ppd_size_t * /* O - Named size */
2186 ppd_add_size(ppd_file_t *ppd, /* I - PPD file */
2187 const char *name) /* I - Name of size */
2188 {
2189 ppd_size_t *size; /* Size */
2190
2191
2192 if (ppd->num_sizes == 0)
2193 size = malloc(sizeof(ppd_size_t));
2194 else
2195 size = realloc(ppd->sizes, sizeof(ppd_size_t) * (ppd->num_sizes + 1));
2196
2197 if (size == NULL)
2198 return (NULL);
2199
2200 ppd->sizes = size;
2201 size += ppd->num_sizes;
2202 ppd->num_sizes ++;
2203
2204 memset(size, 0, sizeof(ppd_size_t));
2205 strlcpy(size->name, name, sizeof(size->name));
2206
2207 return (size);
2208 }
2209
2210
2211 #ifndef __APPLE__
2212 /*
2213 * 'ppd_compare_groups()' - Compare two groups.
2214 */
2215
2216 static int /* O - Result of comparison */
2217 ppd_compare_groups(ppd_group_t *g0, /* I - First group */
2218 ppd_group_t *g1) /* I - Second group */
2219 {
2220 return (strcasecmp(g0->text, g1->text));
2221 }
2222
2223
2224 /*
2225 * 'ppd_compare_options()' - Compare two options.
2226 */
2227
2228 static int /* O - Result of comparison */
2229 ppd_compare_options(ppd_option_t *o0, /* I - First option */
2230 ppd_option_t *o1) /* I - Second option */
2231 {
2232 return (strcasecmp(o0->text, o1->text));
2233 }
2234 #endif /* !__APPLE__ */
2235
2236
2237 /*
2238 * 'ppd_decode()' - Decode a string value...
2239 */
2240
2241 static void
2242 ppd_decode(char *string) /* I - String to decode */
2243 {
2244 char *inptr, /* Input pointer */
2245 *outptr; /* Output pointer */
2246
2247
2248 inptr = string;
2249 outptr = string;
2250
2251 while (*inptr != '\0')
2252 if (*inptr == '<' && isxdigit(inptr[1]))
2253 {
2254 /*
2255 * Convert hex to 8-bit values...
2256 */
2257
2258 inptr ++;
2259 while (isxdigit(*inptr))
2260 {
2261 if (isalpha(*inptr))
2262 *outptr = (tolower(*inptr) - 'a' + 10) << 4;
2263 else
2264 *outptr = (*inptr - '0') << 4;
2265
2266 inptr ++;
2267
2268 if (isalpha(*inptr))
2269 *outptr |= tolower(*inptr) - 'a' + 10;
2270 else
2271 *outptr |= *inptr - '0';
2272
2273 inptr ++;
2274 outptr ++;
2275 }
2276
2277 while (*inptr != '>' && *inptr != '\0')
2278 inptr ++;
2279 while (*inptr == '>')
2280 inptr ++;
2281 }
2282 else
2283 *outptr++ = *inptr++;
2284
2285 *outptr = '\0';
2286 }
2287
2288
2289 #ifndef __APPLE__
2290 /*
2291 * 'ppd_fix()' - Fix WinANSI characters in the range 0x80 to 0x9f to be
2292 * valid ISO-8859-1 characters...
2293 */
2294
2295 static void
2296 ppd_fix(char *string) /* IO - String to fix */
2297 {
2298 unsigned char *p; /* Pointer into string */
2299 static const unsigned char lut[32] = /* Lookup table for characters */
2300 {
2301 0x20,
2302 0x20,
2303 0x20,
2304 0x20,
2305 0x20,
2306 0x20,
2307 0x20,
2308 0x20,
2309 0x20,
2310 0x20,
2311 0x20,
2312 0x20,
2313 0x20,
2314 0x20,
2315 0x20,
2316 0x20,
2317 'l',
2318 '`',
2319 '\'',
2320 '^',
2321 '~',
2322 0x20, /* bar */
2323 0x20, /* circumflex */
2324 0x20, /* dot */
2325 0x20, /* double dot */
2326 0x20,
2327 0x20, /* circle */
2328 0x20, /* ??? */
2329 0x20,
2330 '\"', /* should be right quotes */
2331 0x20, /* ??? */
2332 0x20 /* accent */
2333 };
2334
2335
2336 for (p = (unsigned char *)string; *p; p ++)
2337 if (*p >= 0x80 && *p < 0xa0)
2338 *p = lut[*p - 0x80];
2339 }
2340 #endif /* !__APPLE__ */
2341
2342
2343 /*
2344 * 'ppd_free_group()' - Free a single UI group.
2345 */
2346
2347 static void
2348 ppd_free_group(ppd_group_t *group) /* I - Group to free */
2349 {
2350 int i; /* Looping var */
2351 ppd_option_t *option; /* Current option */
2352 ppd_group_t *subgroup; /* Current sub-group */
2353
2354
2355 if (group->num_options > 0)
2356 {
2357 for (i = group->num_options, option = group->options;
2358 i > 0;
2359 i --, option ++)
2360 ppd_free_option(option);
2361
2362 ppd_free(group->options);
2363 }
2364
2365 if (group->num_subgroups > 0)
2366 {
2367 for (i = group->num_subgroups, subgroup = group->subgroups;
2368 i > 0;
2369 i --, subgroup ++)
2370 ppd_free_group(subgroup);
2371
2372 ppd_free(group->subgroups);
2373 }
2374 }
2375
2376
2377 /*
2378 * 'ppd_free_option()' - Free a single option.
2379 */
2380
2381 static void
2382 ppd_free_option(ppd_option_t *option) /* I - Option to free */
2383 {
2384 int i; /* Looping var */
2385 ppd_choice_t *choice; /* Current choice */
2386
2387
2388 if (option->num_choices > 0)
2389 {
2390 for (i = option->num_choices, choice = option->choices;
2391 i > 0;
2392 i --, choice ++)
2393 ppd_free(choice->code);
2394
2395 ppd_free(option->choices);
2396 }
2397 }
2398
2399
2400 /*
2401 * 'ppd_get_group()' - Find or create the named group as needed.
2402 */
2403
2404 static ppd_group_t * /* O - Named group */
2405 ppd_get_group(ppd_file_t *ppd, /* I - PPD file */
2406 const char *name, /* I - Name of group */
2407 const char *text) /* I - Text for group */
2408 {
2409 int i; /* Looping var */
2410 ppd_group_t *group; /* Group */
2411
2412
2413 DEBUG_printf(("ppd_get_group(%p, \"%s\")\n", ppd, name));
2414
2415 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
2416 if (strcmp(group->name, name) == 0)
2417 break;
2418
2419 if (i == 0)
2420 {
2421 DEBUG_printf(("Adding group %s...\n", name));
2422
2423 if (ppd->num_groups == 0)
2424 group = malloc(sizeof(ppd_group_t));
2425 else
2426 group = realloc(ppd->groups,
2427 (ppd->num_groups + 1) * sizeof(ppd_group_t));
2428
2429 if (group == NULL)
2430 return (NULL);
2431
2432 ppd->groups = group;
2433 group += ppd->num_groups;
2434 ppd->num_groups ++;
2435
2436 memset(group, 0, sizeof(ppd_group_t));
2437 strlcpy(group->name, name, sizeof(group->name));
2438 strlcpy(group->text, text, sizeof(group->text));
2439 }
2440
2441 return (group);
2442 }
2443
2444
2445 /*
2446 * 'ppd_get_option()' - Find or create the named option as needed.
2447 */
2448
2449 static ppd_option_t * /* O - Named option */
2450 ppd_get_option(ppd_group_t *group, /* I - Group */
2451 const char *name) /* I - Name of option */
2452 {
2453 int i; /* Looping var */
2454 ppd_option_t *option; /* Option */
2455
2456
2457 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
2458 if (strcmp(option->keyword, name) == 0)
2459 break;
2460
2461 if (i == 0)
2462 {
2463 if (group->num_options == 0)
2464 option = malloc(sizeof(ppd_option_t));
2465 else
2466 option = realloc(group->options,
2467 (group->num_options + 1) * sizeof(ppd_option_t));
2468
2469 if (option == NULL)
2470 return (NULL);
2471
2472 group->options = option;
2473 option += group->num_options;
2474 group->num_options ++;
2475
2476 memset(option, 0, sizeof(ppd_option_t));
2477 strlcpy(option->keyword, name, sizeof(option->keyword));
2478 }
2479
2480 return (option);
2481 }
2482
2483
2484 /*
2485 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2486 * necessary.
2487 */
2488
2489 static int /* O - Bitmask of fields read */
2490 ppd_read(FILE *fp, /* I - File to read from */
2491 char *keyword, /* O - Keyword from line */
2492 char *option, /* O - Option from line */
2493 char *text, /* O - Human-readable text from line */
2494 char **string) /* O - Code/string data */
2495 {
2496 int ch, /* Character from file */
2497 col, /* Column in line */
2498 colon, /* Colon seen? */
2499 endquote, /* Waiting for an end quote */
2500 mask; /* Mask to be returned */
2501 char *keyptr, /* Keyword pointer */
2502 *optptr, /* Option pointer */
2503 *textptr, /* Text pointer */
2504 *strptr, /* Pointer into string */
2505 *lineptr, /* Current position in line buffer */
2506 line[65536]; /* Line buffer (64k) */
2507
2508
2509 /*
2510 * Range check everything...
2511 */
2512
2513 if (fp == NULL || keyword == NULL || option == NULL || text == NULL ||
2514 string == NULL)
2515 return (0);
2516
2517 /*
2518 * Now loop until we have a valid line...
2519 */
2520
2521 *string = NULL;
2522 col = 0;
2523
2524 do
2525 {
2526 /*
2527 * Read the line...
2528 */
2529
2530 lineptr = line;
2531 endquote = 0;
2532 colon = 0;
2533
2534 while ((ch = getc(fp)) != EOF &&
2535 (lineptr - line) < (sizeof(line) - 1))
2536 {
2537 if (ch == '\r' || ch == '\n')
2538 {
2539 /*
2540 * Line feed or carriage return...
2541 */
2542
2543 ppd_line ++;
2544 col = 0;
2545
2546 if (lineptr == line) /* Skip blank lines */
2547 continue;
2548
2549 if (ch == '\r')
2550 {
2551 /*
2552 * Check for a trailing line feed...
2553 */
2554
2555 if ((ch = getc(fp)) == EOF)
2556 break;
2557 if (ch != 0x0a)
2558 ungetc(ch, fp);
2559 }
2560
2561 ch = '\n';
2562
2563 if (!endquote) /* Continue for multi-line text */
2564 break;
2565
2566 *lineptr++ = '\n';
2567 }
2568 else if (ch < ' ' && ch != '\t' && ch != 0x1a)
2569 {
2570 /*
2571 * Other control characters...
2572 */
2573
2574 ppd_status = PPD_ILLEGAL_CHARACTER;
2575
2576 return (0);
2577 }
2578 else if (ch != 0x1a)
2579 {
2580 /*
2581 * Any other character...
2582 */
2583
2584 *lineptr++ = ch;
2585 col ++;
2586
2587 if (col > (PPD_MAX_LINE - 1))
2588 {
2589 /*
2590 * Line is too long...
2591 */
2592
2593 ppd_status = PPD_LINE_TOO_LONG;
2594
2595 return (0);
2596 }
2597
2598 if (ch == ':' && strncmp(line, "*%", 2) != 0)
2599 colon = 1;
2600
2601 if (ch == '\"' && colon)
2602 {
2603 endquote = !endquote;
2604
2605 if (!endquote)
2606 {
2607 /*
2608 * End of quoted string; ignore trailing characters...
2609 */
2610
2611 while ((ch = getc(fp)) != EOF)
2612 if (ch == '\r' || ch == '\n')
2613 {
2614 ppd_line ++;
2615 col = 0;
2616
2617 if (ch == '\r')
2618 {
2619 ch = getc(fp);
2620 if (ch != '\n')
2621 ungetc(ch, fp);
2622
2623 ch = '\n';
2624 }
2625
2626 break;
2627 }
2628 else if (ch < ' ' && ch != '\t' && ch != 0x1a)
2629 {
2630 /*
2631 * Other control characters...
2632 */
2633
2634 ppd_status = PPD_ILLEGAL_CHARACTER;
2635
2636 return (0);
2637 }
2638 else if (ch != 0x1a)
2639 {
2640 col ++;
2641
2642 if (col > (PPD_MAX_LINE - 1))
2643 {
2644 /*
2645 * Line is too long...
2646 */
2647
2648 ppd_status = PPD_LINE_TOO_LONG;
2649
2650 return (0);
2651 }
2652 }
2653
2654 break;
2655 }
2656 }
2657 }
2658 }
2659
2660 if (endquote)
2661 {
2662 /*
2663 * Didn't finish this quoted string...
2664 */
2665
2666 while ((ch = getc(fp)) != EOF)
2667 if (ch == '\"')
2668 break;
2669 else if (ch == '\r' || ch == '\n')
2670 {
2671 ppd_line ++;
2672 col = 0;
2673
2674 if (ch == '\r')
2675 {
2676 /*
2677 * Check for a trailing line feed...
2678 */
2679
2680 if ((ch = getc(fp)) == EOF)
2681 break;
2682 if (ch != 0x0a)
2683 ungetc(ch, fp);
2684 }
2685
2686 ch = '\n';
2687 }
2688 else if (ch < ' ' && ch != '\t' && ch != 0x1a)
2689 {
2690 /*
2691 * Other control characters...
2692 */
2693
2694 ppd_status = PPD_ILLEGAL_CHARACTER;
2695
2696 return (0);
2697 }
2698 else if (ch != 0x1a)
2699 {
2700 col ++;
2701
2702 if (col > (PPD_MAX_LINE - 1))
2703 {
2704 /*
2705 * Line is too long...
2706 */
2707
2708 ppd_status = PPD_LINE_TOO_LONG;
2709
2710 return (0);
2711 }
2712 }
2713 }
2714
2715 if (ch != '\n')
2716 {
2717 /*
2718 * Didn't finish this line...
2719 */
2720
2721 while ((ch = getc(fp)) != EOF)
2722 if (ch == '\r' || ch == '\n')
2723 {
2724 /*
2725 * Line feed or carriage return...
2726 */
2727
2728 ppd_line ++;
2729 col = 0;
2730
2731 if (ch == '\r')
2732 {
2733 /*
2734 * Check for a trailing line feed...
2735 */
2736
2737 if ((ch = getc(fp)) == EOF)
2738 break;
2739 if (ch != 0x0a)
2740 ungetc(ch, fp);
2741 }
2742
2743 break;
2744 }
2745 else if (ch < ' ' && ch != '\t' && ch != 0x1a)
2746 {
2747 /*
2748 * Other control characters...
2749 */
2750
2751 ppd_status = PPD_ILLEGAL_CHARACTER;
2752
2753 return (0);
2754 }
2755 else if (ch != 0x1a)
2756 {
2757 col ++;
2758
2759 if (col > (PPD_MAX_LINE - 1))
2760 {
2761 /*
2762 * Line is too long...
2763 */
2764
2765 ppd_status = PPD_LINE_TOO_LONG;
2766
2767 return (0);
2768 }
2769 }
2770 }
2771
2772 if (lineptr > line && lineptr[-1] == '\n')
2773 lineptr --;
2774
2775 *lineptr = '\0';
2776
2777 /* DEBUG_printf(("LINE = \"%s\"\n", line));*/
2778
2779 if (ch == EOF && lineptr == line)
2780 return (0);
2781
2782 /*
2783 * Now parse it...
2784 */
2785
2786 mask = 0;
2787 lineptr = line + 1;
2788
2789 keyword[0] = '\0';
2790 option[0] = '\0';
2791 text[0] = '\0';
2792 *string = NULL;
2793
2794 if (!line[0] || /* Blank line */
2795 strcmp(line, "*") == 0 || /* (Bad) comment line */
2796 strncmp(line, "*%", 2) == 0 || /* Comment line */
2797 strncmp(line, "*?", 2) == 0 || /* Query line */
2798 strcmp(line, "*End") == 0) /* End of multi-line string */
2799 continue;
2800
2801 if (line[0] != '*') /* All lines start with an asterisk */
2802 {
2803 /*
2804 * Allow lines consisting of just whitespace...
2805 */
2806
2807 for (lineptr = line; *lineptr; lineptr ++)
2808 if (!isspace(*lineptr))
2809 break;
2810
2811 if (*lineptr)
2812 {
2813 ppd_status = PPD_MISSING_ASTERISK;
2814 return (0);
2815 }
2816 else
2817 continue;
2818 }
2819
2820 /*
2821 * Get a keyword...
2822 */
2823
2824 keyptr = keyword;
2825
2826 while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr))
2827 {
2828 if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
2829 (keyptr - keyword) >= (PPD_MAX_NAME - 1))
2830 {
2831 ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
2832 return (0);
2833 }
2834
2835 *keyptr++ = *lineptr++;
2836 }
2837
2838 *keyptr = '\0';
2839
2840 if (strcmp(keyword, "End") == 0)
2841 continue;
2842
2843 mask |= PPD_KEYWORD;
2844
2845 /* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
2846
2847 if (isspace(*lineptr))
2848 {
2849 /*
2850 * Get an option name...
2851 */
2852
2853 while (isspace(*lineptr))
2854 lineptr ++;
2855
2856 optptr = option;
2857
2858 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':' &&
2859 *lineptr != '/')
2860 {
2861 if (*lineptr <= ' ' || *lineptr > 126 ||
2862 (optptr - option) >= (PPD_MAX_NAME - 1))
2863 {
2864 ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
2865 return (0);
2866 }
2867
2868 *optptr++ = *lineptr++;
2869 }
2870
2871 *optptr = '\0';
2872 mask |= PPD_OPTION;
2873
2874 /* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
2875
2876 if (*lineptr == '/')
2877 {
2878 /*
2879 * Get human-readable text...
2880 */
2881
2882 lineptr ++;
2883
2884 textptr = text;
2885
2886 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
2887 {
2888 if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
2889 (textptr - text) >= (PPD_MAX_LINE - 1))
2890 {
2891 ppd_status = PPD_ILLEGAL_TRANSLATION;
2892 return (0);
2893 }
2894
2895 *textptr++ = *lineptr++;
2896 }
2897
2898 *textptr = '\0';
2899 ppd_decode(text);
2900
2901 mask |= PPD_TEXT;
2902 }
2903
2904 /* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
2905 }
2906
2907 if (*lineptr == ':')
2908 {
2909 /*
2910 * Get string...
2911 */
2912
2913 *string = malloc(strlen(lineptr) + 1);
2914
2915 while (*lineptr == ':' || isspace(*lineptr))
2916 lineptr ++;
2917
2918 strptr = *string;
2919
2920 for (; *lineptr != '\0'; lineptr ++)
2921 if (*lineptr != '\"')
2922 *strptr++ = *lineptr;
2923
2924 *strptr = '\0';
2925
2926 /* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
2927
2928 mask |= PPD_STRING;
2929 }
2930 }
2931 while (mask == 0);
2932
2933 return (mask);
2934 }
2935
2936
2937 /*
2938 * End of "$Id: ppd.c,v 1.93 2003/02/19 14:46:10 mike Exp $".
2939 */