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