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