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