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