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