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