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