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