]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/ppd.c
Remove unnecessary dependency file.
[thirdparty/cups.git] / cups / ppd.c
CommitLineData
90a24de4 1/*
5f10a00b 2 * "$Id: ppd.c,v 1.51.2.9 2002/04/17 18:07:03 mike Exp $"
90a24de4 3 *
3a193f5e 4 * PPD file routines for the Common UNIX Printing System (CUPS).
90a24de4 5 *
839c43aa 6 * Copyright 1997-2002 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 *
2b85e375 37 * ppdClose() - Free all memory used by the PPD file.
38 * ppd_free_group() - Free a single UI group.
39 * ppd_free_option() - Free a single option.
40 * ppdOpen() - Read a PPD file into memory.
41 * ppdOpenFd() - Read a PPD file into memory.
42 * ppdOpenFile() - Read a PPD file into memory.
43 * ppd_read() - Read a line from a PPD file, skipping comment lines
44 * as necessary.
15166848 45 * compare_strings() - Compare two strings.
caab0820 46 * compare_groups() - Compare two groups.
47 * compare_options() - Compare two options.
48 * compare_choices() - Compare two choices.
90a24de4 49 */
50
51/*
52 * Include necessary headers.
53 */
54
2b85e375 55#include "ppd.h"
3b960317 56#include <stdlib.h>
2456b740 57#include <ctype.h>
3b960317 58#include "string.h"
11b9b0d7 59#include "language.h"
60#include "debug.h"
2b85e375 61
62
63/*
64 * Definitions...
65 */
66
3b960317 67#if defined(WIN32) || defined(__EMX__)
2b85e375 68# define READ_BINARY "rb" /* Open a binary file for reading */
69# define WRITE_BINARY "wb" /* Open a binary file for writing */
70#else
71# define READ_BINARY "r" /* Open a binary file for reading */
72# define WRITE_BINARY "w" /* Open a binary file for writing */
3b960317 73#endif /* WIN32 || __EMX__ */
2b85e375 74
08b247a9 75#define safe_free(p) if (p) free(p) /* Safe free macro */
76
2b85e375 77#define PPD_KEYWORD 1 /* Line contained a keyword */
78#define PPD_OPTION 2 /* Line contained an option name */
79#define PPD_TEXT 4 /* Line contained human-readable text */
80#define PPD_STRING 8 /* Line contained a string or code */
554fab97 81
2b85e375 82
83/*
84 * Local functions...
85 */
86
15166848 87static int compare_strings(char *s, char *t);
caab0820 88static int compare_groups(ppd_group_t *g0, ppd_group_t *g1);
89static int compare_options(ppd_option_t *o0, ppd_option_t *o1);
90static int compare_choices(ppd_choice_t *c0, ppd_choice_t *c1);
6fdf969a 91static int ppd_read(FILE *fp, char *keyword, char *option,
d23a857a 92 char *text, char **string);
93static void ppd_decode(char *string);
2685c8f0 94static void ppd_fix(char *string);
6fdf969a 95static void ppd_free_group(ppd_group_t *group);
96static void ppd_free_option(ppd_option_t *option);
83575f2d 97static ppd_group_t *ppd_get_group(ppd_file_t *ppd, const char *name,
98 const char *text);
99static ppd_option_t *ppd_get_option(ppd_group_t *group, const char *name);
100static ppd_choice_t *ppd_add_choice(ppd_option_t *option, const char *name);
2b85e375 101
102
103/*
104 * 'ppdClose()' - Free all memory used by the PPD file.
105 */
106
107void
108ppdClose(ppd_file_t *ppd) /* I - PPD file record */
109{
110 int i; /* Looping var */
111 ppd_emul_t *emul; /* Current emulation */
112 ppd_group_t *group; /* Current group */
2b85e375 113 char **font; /* Current font */
04de52f8 114 char **filter; /* Current filter */
2b85e375 115
116
117 /*
118 * Range check the PPD file record...
119 */
120
121 if (ppd == NULL)
122 return;
123
124 /*
125 * Free all strings at the top level...
126 */
127
04de52f8 128 safe_free(ppd->patches);
129 safe_free(ppd->jcl_begin);
130 safe_free(ppd->jcl_ps);
131 safe_free(ppd->jcl_end);
08b247a9 132 safe_free(ppd->lang_encoding);
133 safe_free(ppd->lang_version);
134 safe_free(ppd->modelname);
135 safe_free(ppd->ttrasterizer);
136 safe_free(ppd->manufacturer);
137 safe_free(ppd->product);
138 safe_free(ppd->nickname);
139 safe_free(ppd->shortnickname);
2b85e375 140
141 /*
142 * Free any emulations...
143 */
144
145 if (ppd->num_emulations > 0)
146 {
147 for (i = ppd->num_emulations, emul = ppd->emulations; i > 0; i --, emul ++)
148 {
08b247a9 149 safe_free(emul->start);
150 safe_free(emul->stop);
e8fda7b9 151 }
2b85e375 152
08b247a9 153 safe_free(ppd->emulations);
e8fda7b9 154 }
2b85e375 155
2b85e375 156 /*
157 * Free any UI groups, subgroups, and options...
158 */
159
160 if (ppd->num_groups > 0)
161 {
162 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
163 ppd_free_group(group);
164
08b247a9 165 safe_free(ppd->groups);
e8fda7b9 166 }
2b85e375 167
2b85e375 168 /*
169 * Free any page sizes...
170 */
171
172 if (ppd->num_sizes > 0)
08b247a9 173 safe_free(ppd->sizes);
2b85e375 174
175 /*
176 * Free any constraints...
177 */
178
179 if (ppd->num_consts > 0)
08b247a9 180 safe_free(ppd->consts);
2b85e375 181
04de52f8 182 /*
183 * Free any filters...
184 */
185
186 if (ppd->num_filters > 0)
187 {
188 for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++)
189 safe_free(*filter);
190
191 safe_free(ppd->filters);
192 }
193
2b85e375 194 /*
195 * Free any fonts...
196 */
197
198 if (ppd->num_fonts > 0)
199 {
200 for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++)
08b247a9 201 safe_free(*font);
2b85e375 202
08b247a9 203 safe_free(ppd->fonts);
e8fda7b9 204 }
2b85e375 205
b87e43e9 206 /*
207 * Free any profiles...
208 */
209
210 if (ppd->num_profiles > 0)
08b247a9 211 safe_free(ppd->profiles);
b87e43e9 212
2b85e375 213 /*
214 * Free the whole record...
215 */
216
08b247a9 217 safe_free(ppd);
2b85e375 218}
219
220
221/*
222 * 'ppd_free_group()' - Free a single UI group.
223 */
224
225static void
226ppd_free_group(ppd_group_t *group) /* I - Group to free */
227{
228 int i; /* Looping var */
229 ppd_option_t *option; /* Current option */
230 ppd_group_t *subgroup; /* Current sub-group */
231
232
233 if (group->num_options > 0)
234 {
235 for (i = group->num_options, option = group->options;
236 i > 0;
237 i --, option ++)
238 ppd_free_option(option);
239
08b247a9 240 safe_free(group->options);
e8fda7b9 241 }
2b85e375 242
243 if (group->num_subgroups > 0)
244 {
245 for (i = group->num_subgroups, subgroup = group->subgroups;
246 i > 0;
247 i --, subgroup ++)
248 ppd_free_group(subgroup);
249
08b247a9 250 safe_free(group->subgroups);
e8fda7b9 251 }
2b85e375 252}
253
254
255/*
256 * 'ppd_free_option()' - Free a single option.
257 */
258
259static void
260ppd_free_option(ppd_option_t *option) /* I - Option to free */
261{
262 int i; /* Looping var */
263 ppd_choice_t *choice; /* Current choice */
264
265
266 if (option->num_choices > 0)
267 {
268 for (i = option->num_choices, choice = option->choices;
269 i > 0;
270 i --, choice ++)
08b247a9 271 safe_free(choice->code);
2b85e375 272
08b247a9 273 safe_free(option->choices);
e8fda7b9 274 }
2b85e375 275}
276
277
6fdf969a 278/*
279 * 'ppd_get_group()' - Find or create the named group as needed.
280 */
281
282static ppd_group_t * /* O - Named group */
283ppd_get_group(ppd_file_t *ppd, /* I - PPD file */
83575f2d 284 const char *name, /* I - Name of group */
285 const char *text) /* I - Text for group */
6fdf969a 286{
287 int i; /* Looping var */
288 ppd_group_t *group; /* Group */
289
290
753453e4 291 DEBUG_printf(("ppd_get_group(%p, \"%s\")\n", ppd, name));
292
6fdf969a 293 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
83575f2d 294 if (strcmp(group->name, name) == 0)
6fdf969a 295 break;
296
297 if (i == 0)
298 {
753453e4 299 DEBUG_printf(("Adding group %s...\n", name));
300
6fdf969a 301 if (ppd->num_groups == 0)
302 group = malloc(sizeof(ppd_group_t));
303 else
304 group = realloc(ppd->groups,
305 (ppd->num_groups + 1) * sizeof(ppd_group_t));
306
307 if (group == NULL)
308 return (NULL);
309
310 ppd->groups = group;
311 group += ppd->num_groups;
312 ppd->num_groups ++;
313
314 memset(group, 0, sizeof(ppd_group_t));
83575f2d 315 strncpy(group->name, name, sizeof(group->name) - 1);
316 strncpy(group->text, text, sizeof(group->text) - 1);
6fdf969a 317 }
318
319 return (group);
320}
321
322
323/*
324 * 'ppd_get_option()' - Find or create the named option as needed.
325 */
326
327static ppd_option_t * /* O - Named option */
328ppd_get_option(ppd_group_t *group, /* I - Group */
83575f2d 329 const char *name) /* I - Name of option */
6fdf969a 330{
331 int i; /* Looping var */
332 ppd_option_t *option; /* Option */
333
334
335 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
336 if (strcmp(option->keyword, name) == 0)
337 break;
338
339 if (i == 0)
340 {
341 if (group->num_options == 0)
342 option = malloc(sizeof(ppd_option_t));
343 else
344 option = realloc(group->options,
345 (group->num_options + 1) * sizeof(ppd_option_t));
346
347 if (option == NULL)
348 return (NULL);
349
350 group->options = option;
351 option += group->num_options;
352 group->num_options ++;
353
354 memset(option, 0, sizeof(ppd_option_t));
fafbba4f 355 strncpy(option->keyword, name, sizeof(option->keyword) - 1);
6fdf969a 356 }
357
358 return (option);
359}
360
361
362/*
363 * 'ppd_add_choice()' - Add a choice to an option.
364 */
365
366static ppd_choice_t * /* O - Named choice */
367ppd_add_choice(ppd_option_t *option, /* I - Option */
83575f2d 368 const char *name) /* I - Name of choice */
6fdf969a 369{
370 ppd_choice_t *choice; /* Choice */
371
372
373 if (option->num_choices == 0)
374 choice = malloc(sizeof(ppd_choice_t));
375 else
376 choice = realloc(option->choices,
377 sizeof(ppd_choice_t) * (option->num_choices + 1));
378
379 if (choice == NULL)
380 return (NULL);
381
382 option->choices = choice;
383 choice += option->num_choices;
384 option->num_choices ++;
385
386 memset(choice, 0, sizeof(ppd_choice_t));
fafbba4f 387 strncpy(choice->choice, name, sizeof(choice->choice) - 1);
6fdf969a 388
389 return (choice);
390}
391
392
393/*
394 * 'ppd_add_size()' - Add a page size.
395 */
396
397static ppd_size_t * /* O - Named size */
398ppd_add_size(ppd_file_t *ppd, /* I - PPD file */
83575f2d 399 const char *name) /* I - Name of size */
6fdf969a 400{
401 ppd_size_t *size; /* Size */
402
403
404 if (ppd->num_sizes == 0)
405 size = malloc(sizeof(ppd_size_t));
406 else
407 size = realloc(ppd->sizes, sizeof(ppd_size_t) * (ppd->num_sizes + 1));
408
409 if (size == NULL)
410 return (NULL);
411
412 ppd->sizes = size;
413 size += ppd->num_sizes;
414 ppd->num_sizes ++;
415
416 memset(size, 0, sizeof(ppd_size_t));
fafbba4f 417 strncpy(size->name, name, sizeof(size->name) - 1);
6fdf969a 418
419 return (size);
420}
421
422
2b85e375 423/*
424 * 'ppdOpen()' - Read a PPD file into memory.
425 */
426
427ppd_file_t * /* O - PPD file record */
428ppdOpen(FILE *fp) /* I - File to read from */
429{
58ec2a95 430 int i, j, k, m; /* Looping vars */
8c1333e2 431 int count; /* Temporary count */
2b85e375 432 ppd_file_t *ppd; /* PPD file record */
433 ppd_group_t *group, /* Current group */
434 *subgroup; /* Current sub-group */
435 ppd_option_t *option; /* Current option */
436 ppd_choice_t *choice; /* Current choice */
437 ppd_const_t *constraint; /* Current constraint */
438 ppd_size_t *size; /* Current page size */
439 int mask; /* Line data mask */
d2e58bfa 440 char keyword[PPD_MAX_NAME],
441 /* Keyword from file */
442 name[PPD_MAX_NAME],
443 /* Option from file */
444 text[PPD_MAX_TEXT],
445 /* Human-readable text from file */
d23a857a 446 *string, /* Code/text from file */
447 *sptr, /* Pointer into string */
0819478b 448 *nameptr, /* Pointer into name */
449 *temp, /* Temporary string pointer */
450 **tempfonts; /* Temporary fonts pointer */
2b85e375 451 float order; /* Order dependency number */
452 ppd_section_t section; /* Order dependency section */
b87e43e9 453 ppd_profile_t *profile; /* Pointer to color profile */
c493465a 454 char **filter; /* Pointer to filter */
11b9b0d7 455 cups_lang_t *language; /* Default language */
2b85e375 456
457
11b9b0d7 458 /*
459 * Get the default language for the user...
460 */
461
462 language = cupsLangDefault();
463
2b85e375 464 /*
465 * Range check input...
466 */
467
468 if (fp == NULL)
469 return (NULL);
470
471 /*
472 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
473 */
474
554fab97 475 mask = ppd_read(fp, keyword, name, text, &string);
2b85e375 476
477 if (mask == 0 ||
478 strcmp(keyword, "PPD-Adobe") != 0 ||
479 string == NULL || string[0] != '4')
480 {
481 /*
482 * Either this is not a PPD file, or it is not a 4.x PPD file.
483 */
484
08b247a9 485 safe_free(string);
2b85e375 486
487 return (NULL);
e8fda7b9 488 }
2b85e375 489
ba31b514 490 DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword, string));
923e8756 491
08b247a9 492 safe_free(string);
2b85e375 493
494 /*
495 * Allocate memory for the PPD file record...
496 */
497
498 if ((ppd = calloc(sizeof(ppd_file_t), 1)) == NULL)
499 return (NULL);
500
501 ppd->language_level = 1;
502 ppd->color_device = 0;
503 ppd->colorspace = PPD_CS_GRAY;
504 ppd->landscape = 90;
505
506 /*
507 * Read lines from the PPD file and add them to the file record...
508 */
509
510 group = NULL;
511 subgroup = NULL;
512 option = NULL;
513 choice = NULL;
514
554fab97 515 while ((mask = ppd_read(fp, keyword, name, text, &string)) != 0)
2b85e375 516 {
517#ifdef DEBUG
518 printf("mask = %x, keyword = \"%s\"", mask, keyword);
519
520 if (name[0] != '\0')
521 printf(", name = \"%s\"", name);
522
523 if (text[0] != '\0')
524 printf(", text = \"%s\"", text);
525
526 if (string != NULL)
527 {
d23a857a 528 if (strlen(string) > 40)
ba31b514 529 printf(", string = %p", string);
2b85e375 530 else
531 printf(", string = \"%s\"", string);
e8fda7b9 532 }
2b85e375 533
534 puts("");
535#endif /* DEBUG */
536
753453e4 537 if (strcmp(keyword, "CloseUI") != 0 &&
538 strcmp(keyword, "JCLCloseUI") != 0 &&
539 strcmp(keyword, "CloseGroup") != 0 &&
540 strcmp(keyword, "CloseSubGroup") != 0 &&
541 strncmp(keyword, "Default", 7) != 0 &&
542 string == NULL)
543 {
544 /*
545 * Need a string value!
546 */
547
548 ppdClose(ppd);
549 return (NULL);
550 }
551
2b85e375 552 if (strcmp(keyword, "LanguageLevel") == 0)
d23a857a 553 ppd->language_level = atoi(string);
2b85e375 554 else if (strcmp(keyword, "LanguageEncoding") == 0)
555 {
d23a857a 556 ppd->lang_encoding = string;
2b85e375 557 string = NULL; /* Don't free this string below */
558 }
559 else if (strcmp(keyword, "LanguageVersion") == 0)
560 {
d23a857a 561 ppd->lang_version = string;
2b85e375 562 string = NULL; /* Don't free this string below */
563 }
564 else if (strcmp(keyword, "Manufacturer") == 0)
565 {
566 ppd->manufacturer = string;
567 string = NULL; /* Don't free this string below */
568 }
569 else if (strcmp(keyword, "ModelName") == 0)
570 {
d23a857a 571 ppd->modelname = string;
2b85e375 572 string = NULL; /* Don't free this string below */
573 }
1fcd229c 574 else if (strcmp(keyword, "PCFileName") == 0)
575 {
576 ppd->pcfilename = string;
577 string = NULL; /* Don't free this string below */
578 }
2b85e375 579 else if (strcmp(keyword, "NickName") == 0)
580 {
581 ppd->nickname = string;
582 string = NULL; /* Don't free this string below */
583 }
584 else if (strcmp(keyword, "Product") == 0)
585 {
586 ppd->product = string;
587 string = NULL; /* Don't free this string below */
588 }
589 else if (strcmp(keyword, "ShortNickName") == 0)
590 {
591 ppd->shortnickname = string;
592 string = NULL; /* Don't free this string below */
593 }
594 else if (strcmp(keyword, "TTRasterizer") == 0)
595 {
d23a857a 596 ppd->ttrasterizer = string;
2b85e375 597 string = NULL; /* Don't free this string below */
598 }
599 else if (strcmp(keyword, "JCLBegin") == 0)
600 {
601 ppd_decode(string); /* Decode quoted string */
602 ppd->jcl_begin = string;
603 string = NULL; /* Don't free this string below */
604 }
605 else if (strcmp(keyword, "JCLEnd") == 0)
606 {
607 ppd_decode(string); /* Decode quoted string */
608 ppd->jcl_end = string;
609 string = NULL; /* Don't free this string below */
610 }
611 else if (strcmp(keyword, "JCLToPSInterpreter") == 0)
612 {
613 ppd_decode(string); /* Decode quoted string */
614 ppd->jcl_ps = string;
615 string = NULL; /* Don't free this string below */
616 }
617 else if (strcmp(keyword, "AccurateScreensSupport") == 0)
d23a857a 618 ppd->accurate_screens = strcmp(string, "True") == 0;
2b85e375 619 else if (strcmp(keyword, "ColorDevice") == 0)
d23a857a 620 ppd->color_device = strcmp(string, "True") == 0;
2b85e375 621 else if (strcmp(keyword, "ContoneOnly") == 0)
d23a857a 622 ppd->contone_only = strcmp(string, "True") == 0;
2b85e375 623 else if (strcmp(keyword, "DefaultColorSpace") == 0)
624 {
d23a857a 625 if (strcmp(string, "CMY") == 0)
2b85e375 626 ppd->colorspace = PPD_CS_CMY;
d23a857a 627 else if (strcmp(string, "CMYK") == 0)
2b85e375 628 ppd->colorspace = PPD_CS_CMYK;
d23a857a 629 else if (strcmp(string, "RGB") == 0)
2b85e375 630 ppd->colorspace = PPD_CS_RGB;
d23a857a 631 else if (strcmp(string, "RGBK") == 0)
58ec2a95 632 ppd->colorspace = PPD_CS_RGBK;
d23a857a 633 else if (strcmp(string, "N") == 0)
58ec2a95 634 ppd->colorspace = PPD_CS_N;
2b85e375 635 else
636 ppd->colorspace = PPD_CS_GRAY;
637 }
632d3147 638 else if (strcmp(keyword, "cupsFlipDuplex") == 0)
639 ppd->flip_duplex = strcmp(string, "True") == 0;
991a5d0d 640 else if (strcmp(keyword, "cupsManualCopies") == 0)
d23a857a 641 ppd->manual_copies = strcmp(string, "True") == 0;
991a5d0d 642 else if (strcmp(keyword, "cupsModelNumber") == 0)
d23a857a 643 ppd->model_number = atoi(string);
991a5d0d 644 else if (strcmp(keyword, "cupsColorProfile") == 0)
b87e43e9 645 {
646 if (ppd->num_profiles == 0)
647 profile = malloc(sizeof(ppd_profile_t));
648 else
649 profile = realloc(ppd->profiles, sizeof(ppd_profile_t) *
650 (ppd->num_profiles + 1));
651
652 ppd->profiles = profile;
653 profile += ppd->num_profiles;
654 ppd->num_profiles ++;
655
656 memset(profile, 0, sizeof(ppd_profile_t));
fafbba4f 657 strncpy(profile->resolution, name, sizeof(profile->resolution) - 1);
658 strncpy(profile->media_type, text, sizeof(profile->media_type) - 1);
af22b1d1 659 sscanf(string, "%f%f%f%f%f%f%f%f%f%f%f", &(profile->density),
660 &(profile->gamma),
b87e43e9 661 profile->matrix[0] + 0, profile->matrix[0] + 1,
662 profile->matrix[0] + 2, profile->matrix[1] + 0,
663 profile->matrix[1] + 1, profile->matrix[1] + 2,
664 profile->matrix[2] + 0, profile->matrix[2] + 1,
665 profile->matrix[2] + 2);
666 }
c493465a 667 else if (strcmp(keyword, "cupsFilter") == 0)
668 {
669 if (ppd->num_filters == 0)
670 filter = malloc(sizeof(char *));
671 else
672 filter = realloc(ppd->filters, sizeof(char *) * (ppd->num_filters + 1));
673
0819478b 674 if (filter == NULL)
675 {
676 safe_free(filter);
677 ppdClose(ppd);
678 return (NULL);
679 }
680
c493465a 681 ppd->filters = filter;
682 filter += ppd->num_filters;
683 ppd->num_filters ++;
684
685 /*
686 * Copy filter string and prevent it from being freed below...
687 */
688
689 *filter = string;
690 string = NULL;
691 }
7ebf3a09 692 else if (strcmp(keyword, "Throughput") == 0)
693 ppd->throughput = atoi(string);
b03923b8 694 else if (strcmp(keyword, "Font") == 0)
695 {
696 /*
697 * Add this font to the list of available fonts...
698 */
699
700 if (ppd->num_fonts == 0)
0819478b 701 tempfonts = (char **)malloc(sizeof(char *));
b03923b8 702 else
0819478b 703 tempfonts = (char **)realloc(ppd->fonts,
704 sizeof(char *) * (ppd->num_fonts + 1));
b03923b8 705
0819478b 706 if (tempfonts == NULL)
b03923b8 707 {
0819478b 708 safe_free(string);
b03923b8 709 ppdClose(ppd);
710 return (NULL);
711 }
0819478b 712
713 ppd->fonts = tempfonts;
26e73a82 714 ppd->fonts[ppd->num_fonts] = strdup(name);
b03923b8 715 ppd->num_fonts ++;
b03923b8 716 }
6fdf969a 717 else if (strcmp(keyword, "VariablePaperSize") == 0 &&
d1f2b9fe 718 strcmp(string, "True") == 0 &&
719 !ppd->variable_sizes)
6fdf969a 720 {
721 ppd->variable_sizes = 1;
722
723 /*
724 * Add a "Custom" page size entry...
725 */
726
727 ppd_add_size(ppd, "Custom");
728
729 /*
730 * Add a "Custom" page size option...
731 */
732
7d75b814 733 if ((option = ppdFindOption(ppd, "PageSize")) == NULL)
6fdf969a 734 {
7d75b814 735 ppd_group_t *temp;
6fdf969a 736
7d75b814 737
83575f2d 738 if ((temp = ppd_get_group(ppd, "General",
7d75b814 739 cupsLangString(language,
740 CUPS_MSG_GENERAL))) == NULL)
741 {
742 ppdClose(ppd);
743 safe_free(string);
744 return (NULL);
745 }
746
747 if ((option = ppd_get_option(temp, "PageSize")) == NULL)
748 {
749 ppdClose(ppd);
750 safe_free(string);
751 return (NULL);
752 }
6fdf969a 753 }
754
755 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
756 {
757 ppdClose(ppd);
08b247a9 758 safe_free(string);
6fdf969a 759 return (NULL);
760 }
761
fafbba4f 762 strncpy(choice->text, cupsLangString(language, CUPS_MSG_VARIABLE),
763 sizeof(choice->text) - 1);
6fdf969a 764 option = NULL;
765 }
766 else if (strcmp(keyword, "MaxMediaWidth") == 0)
977acbd3 767 ppd->custom_max[0] = (float)atof(string);
6fdf969a 768 else if (strcmp(keyword, "MaxMediaHeight") == 0)
977acbd3 769 ppd->custom_max[1] = (float)atof(string);
6fdf969a 770 else if (strcmp(keyword, "ParamCustomPageSize") == 0)
771 {
772 if (strcmp(name, "Width") == 0)
d23a857a 773 sscanf(string, "%*s%*s%f%f", ppd->custom_min + 0,
6fdf969a 774 ppd->custom_max + 0);
775 else if (strcmp(name, "Height") == 0)
d23a857a 776 sscanf(string, "%*s%*s%f%f", ppd->custom_min + 1,
6fdf969a 777 ppd->custom_max + 1);
778 }
779 else if (strcmp(keyword, "HWMargins") == 0)
d23a857a 780 sscanf(string, "%f%f%f%f", ppd->custom_margins + 0,
6fdf969a 781 ppd->custom_margins + 1, ppd->custom_margins + 2,
782 ppd->custom_margins + 3);
783 else if (strcmp(keyword, "CustomPageSize") == 0 &&
d1f2b9fe 784 strcmp(name, "True") == 0)
6fdf969a 785 {
d1f2b9fe 786 if (!ppd->variable_sizes)
787 {
788 ppd->variable_sizes = 1;
789
790 /*
791 * Add a "Custom" page size entry...
792 */
793
794 ppd_add_size(ppd, "Custom");
795
796 /*
797 * Add a "Custom" page size option...
798 */
799
7d75b814 800 if ((option = ppdFindOption(ppd, "PageSize")) == NULL)
d1f2b9fe 801 {
7d75b814 802 ppd_group_t *temp;
803
804
83575f2d 805 if ((temp = ppd_get_group(ppd, "General",
7d75b814 806 cupsLangString(language,
807 CUPS_MSG_GENERAL))) == NULL)
808 {
809 DEBUG_puts("Unable to get general group!");
810 ppdClose(ppd);
811 safe_free(string);
812 return (NULL);
813 }
814
815 if ((option = ppd_get_option(temp, "PageSize")) == NULL)
816 {
817 DEBUG_puts("Unable to get PageSize option!");
818 ppdClose(ppd);
819 safe_free(string);
820 return (NULL);
821 }
822 }
d1f2b9fe 823
824 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
825 {
7d75b814 826 DEBUG_puts("Unable to add Custom choice!");
d1f2b9fe 827 ppdClose(ppd);
828 safe_free(string);
829 return (NULL);
830 }
831
832 strncpy(choice->text, cupsLangString(language, CUPS_MSG_VARIABLE),
833 sizeof(choice->text) - 1);
d1f2b9fe 834 option = NULL;
835 }
836
6fdf969a 837 if ((option = ppdFindOption(ppd, "PageSize")) == NULL)
838 {
7d75b814 839 DEBUG_puts("Unable to find PageSize option!");
627c58f3 840 ppdClose(ppd);
08b247a9 841 safe_free(string);
6fdf969a 842 return (NULL);
843 }
844
845 if ((choice = ppdFindChoice(option, "Custom")) == NULL)
846 {
7d75b814 847 DEBUG_puts("Unable to find Custom choice!");
6fdf969a 848 ppdClose(ppd);
08b247a9 849 safe_free(string);
6fdf969a 850 return (NULL);
851 }
852
853 choice->code = string;
854 string = NULL;
855 option = NULL;
856 }
2b85e375 857 else if (strcmp(keyword, "LandscapeOrientation") == 0)
858 {
d23a857a 859 if (strcmp(string, "Minus90") == 0)
2b85e375 860 ppd->landscape = -90;
861 else
862 ppd->landscape = 90;
863 }
8c1333e2 864 else if (strcmp(keyword, "Emulators") == 0)
865 {
d23a857a 866 for (count = 1, sptr = string; sptr != NULL;)
8c1333e2 867 if ((sptr = strchr(sptr, ' ')) != NULL)
868 {
869 count ++;
870 while (*sptr == ' ')
871 sptr ++;
e8fda7b9 872 }
8c1333e2 873
874 ppd->num_emulations = count;
875 ppd->emulations = calloc(sizeof(ppd_emul_t), count);
876
d23a857a 877 for (i = 0, sptr = string; i < count; i ++)
8c1333e2 878 {
d2e58bfa 879 for (nameptr = ppd->emulations[i].name;
880 *sptr != '\0' && *sptr != ' ';
881 sptr ++)
882 if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1))
883 *nameptr++ = *sptr;
8c1333e2 884
885 *nameptr = '\0';
886
887 while (*sptr == ' ')
888 sptr ++;
889 }
890 }
891 else if (strncmp(keyword, "StartEmulator_", 14) == 0)
892 {
893 ppd_decode(string);
894
895 for (i = 0; i < ppd->num_emulations; i ++)
896 if (strcmp(keyword + 14, ppd->emulations[i].name) == 0)
897 {
898 ppd->emulations[i].start = string;
899 string = NULL;
900 }
901 }
902 else if (strncmp(keyword, "StopEmulator_", 13) == 0)
903 {
904 ppd_decode(string);
905
906 for (i = 0; i < ppd->num_emulations; i ++)
907 if (strcmp(keyword + 13, ppd->emulations[i].name) == 0)
908 {
909 ppd->emulations[i].stop = string;
910 string = NULL;
911 }
912 }
913 else if (strcmp(keyword, "JobPatchFile") == 0)
914 {
915 if (ppd->patches == NULL)
916 {
917 ppd->patches = string;
918 string = NULL;
919 }
920 else
921 {
0819478b 922 temp = realloc(ppd->patches, strlen(ppd->patches) +
923 strlen(string) + 1);
924 if (temp == NULL)
925 {
926 safe_free(string);
927 ppdClose(ppd);
928 return (NULL);
929 }
930
931 ppd->patches = temp;
8c1333e2 932
d23a857a 933 strcpy(ppd->patches + strlen(ppd->patches), string);
8c1333e2 934 }
935 }
2b85e375 936 else if (strcmp(keyword, "OpenUI") == 0)
937 {
938 /*
939 * Add an option record to the current sub-group, group, or file...
940 */
941
942 if (name[0] == '*')
753453e4 943 strcpy(name, name + 1); /* Eliminate leading asterisk */
2b85e375 944
753453e4 945 for (i = strlen(name) - 1; i > 0 && isspace(name[i]); i --)
946 name[i] = '\0'; /* Eliminate trailing spaces */
947
948 DEBUG_printf(("OpenUI of %s in group %s...\n", name,
949 group ? group->text : "(null)"));
c21064d2 950
652e598f 951 if (subgroup != NULL)
952 option = ppd_get_option(subgroup, name);
953 else if (group == NULL)
954 {
955 if (strcmp(name, "Collate") != 0 &&
956 strcmp(name, "Duplex") != 0 &&
957 strcmp(name, "InputSlot") != 0 &&
958 strcmp(name, "ManualFeed") != 0 &&
959 strcmp(name, "MediaType") != 0 &&
960 strcmp(name, "MediaColor") != 0 &&
961 strcmp(name, "MediaWeight") != 0 &&
962 strcmp(name, "OutputBin") != 0 &&
963 strcmp(name, "OutputMode") != 0 &&
964 strcmp(name, "OutputOrder") != 0 &&
965 strcmp(name, "PageSize") != 0 &&
966 strcmp(name, "PageRegion") != 0)
83575f2d 967 group = ppd_get_group(ppd, "Extra",
968 cupsLangString(language, CUPS_MSG_EXTRA));
caab0820 969 else
83575f2d 970 group = ppd_get_group(ppd, "General",
971 cupsLangString(language, CUPS_MSG_GENERAL));
caab0820 972
652e598f 973 if (group == NULL)
2b85e375 974 {
caab0820 975 ppdClose(ppd);
08b247a9 976 safe_free(string);
caab0820 977 return (NULL);
58ec2a95 978 }
caab0820 979
753453e4 980 DEBUG_printf(("Adding to group %s...\n", group->text));
652e598f 981 option = ppd_get_option(group, name);
982 group = NULL;
983 }
984 else
985 option = ppd_get_option(group, name);
2b85e375 986
652e598f 987 if (option == NULL)
988 {
989 ppdClose(ppd);
990 safe_free(string);
991 return (NULL);
992 }
2b85e375 993
652e598f 994 /*
995 * Now fill in the initial information for the option...
996 */
2b85e375 997
652e598f 998 if (strcmp(string, "PickMany") == 0)
999 option->ui = PPD_UI_PICKMANY;
1000 else if (strcmp(string, "Boolean") == 0)
1001 option->ui = PPD_UI_BOOLEAN;
1002 else
1003 option->ui = PPD_UI_PICKONE;
1004
1005 if (text[0])
1006 {
1007 strncpy(option->text, text, sizeof(option->text) - 1);
1008 ppd_fix(option->text);
1009 }
1010 else
1011 {
1012 if (strcmp(name, "PageSize") == 0)
1013 strncpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_SIZE),
1014 sizeof(option->text) - 1);
1015 else if (strcmp(name, "MediaType") == 0)
1016 strncpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_TYPE),
1017 sizeof(option->text) - 1);
1018 else if (strcmp(name, "InputSlot") == 0)
1019 strncpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_SOURCE),
1020 sizeof(option->text) - 1);
1021 else if (strcmp(name, "ColorModel") == 0)
1022 strncpy(option->text, cupsLangString(language, CUPS_MSG_OUTPUT_MODE),
1023 sizeof(option->text) - 1);
1024 else if (strcmp(name, "Resolution") == 0)
1025 strncpy(option->text, cupsLangString(language, CUPS_MSG_RESOLUTION),
1026 sizeof(option->text) - 1);
1027 else
1028 strncpy(option->text, name, sizeof(option->text) - 1);
caab0820 1029 }
652e598f 1030
1031 option->section = PPD_ORDER_ANY;
2b85e375 1032 }
1033 else if (strcmp(keyword, "JCLOpenUI") == 0)
1034 {
58ec2a95 1035 /*
1036 * Find the JCL group, and add if needed...
1037 */
1038
83575f2d 1039 group = ppd_get_group(ppd, "JCL", "JCL");
58ec2a95 1040
6fdf969a 1041 if (group == NULL)
58ec2a95 1042 {
6fdf969a 1043 ppdClose(ppd);
08b247a9 1044 safe_free(string);
6fdf969a 1045 return (NULL);
58ec2a95 1046 }
1047
2b85e375 1048 /*
1049 * Add an option record to the current JCLs...
1050 */
1051
1052 if (name[0] == '*')
1053 strcpy(name, name + 1);
1054
6fdf969a 1055 option = ppd_get_option(group, name);
2b85e375 1056
1057 if (option == NULL)
1058 {
6fdf969a 1059 ppdClose(ppd);
08b247a9 1060 safe_free(string);
2b85e375 1061 return (NULL);
e8fda7b9 1062 }
2b85e375 1063
2b85e375 1064 /*
1065 * Now fill in the initial information for the option...
1066 */
1067
d23a857a 1068 if (strcmp(string, "PickMany") == 0)
2b85e375 1069 option->ui = PPD_UI_PICKMANY;
d23a857a 1070 else if (strcmp(string, "Boolean") == 0)
2b85e375 1071 option->ui = PPD_UI_BOOLEAN;
1072 else
1073 option->ui = PPD_UI_PICKONE;
1074
fafbba4f 1075 strncpy(option->text, text, sizeof(option->text) - 1);
2b85e375 1076
1077 option->section = PPD_ORDER_JCL;
58ec2a95 1078 group = NULL;
2b85e375 1079 }
1080 else if (strcmp(keyword, "CloseUI") == 0 ||
1081 strcmp(keyword, "JCLCloseUI") == 0)
1082 option = NULL;
1083 else if (strcmp(keyword, "OpenGroup") == 0)
1084 {
1085 /*
1086 * Open a new group...
1087 */
1088
1089 if (group != NULL)
1090 {
1091 ppdClose(ppd);
08b247a9 1092 safe_free(string);
2b85e375 1093 return (NULL);
e8fda7b9 1094 }
2b85e375 1095
83575f2d 1096 /*
1097 * Separate the group name from the text (name/text)...
1098 */
2b85e375 1099
83575f2d 1100 if ((sptr = strchr(string, '/')) != NULL)
1101 *sptr++ = '\0';
1102 else
1103 sptr = string;
1104
1105 /*
1106 * Fix up the text...
1107 */
1108
1109 ppd_decode(sptr);
1110 ppd_fix(sptr);
1111
1112 /*
1113 * Find/add the group...
1114 */
1115
1116 group = ppd_get_group(ppd, string, sptr);
2b85e375 1117 }
1118 else if (strcmp(keyword, "CloseGroup") == 0)
1119 group = NULL;
2b85e375 1120 else if (strcmp(keyword, "OrderDependency") == 0 ||
1121 strcmp(keyword, "NonUIOrderDependency") == 0)
1122 {
04d61d56 1123 if (sscanf(string, "%f%40s%40s", &order, name, keyword) != 3)
2b85e375 1124 {
1125 ppdClose(ppd);
08b247a9 1126 safe_free(string);
2b85e375 1127 return (NULL);
e8fda7b9 1128 }
2b85e375 1129
1130 if (keyword[0] == '*')
1131 strcpy(keyword, keyword + 1);
1132
1133 if (strcmp(name, "ExitServer") == 0)
1134 section = PPD_ORDER_EXIT;
1135 else if (strcmp(name, "Prolog") == 0)
1136 section = PPD_ORDER_PROLOG;
1137 else if (strcmp(name, "DocumentSetup") == 0)
1138 section = PPD_ORDER_DOCUMENT;
1139 else if (strcmp(name, "PageSetup") == 0)
1140 section = PPD_ORDER_PAGE;
1141 else if (strcmp(name, "JCLSetup") == 0)
1142 section = PPD_ORDER_JCL;
1143 else
1144 section = PPD_ORDER_ANY;
1145
1146 if (option == NULL)
1147 {
7d75b814 1148 ppd_group_t *temp;
1149
1150
2b85e375 1151 /*
1152 * Only valid for Non-UI options...
1153 */
1154
7d75b814 1155 for (i = ppd->num_groups, temp = ppd->groups; i > 0; i --, temp ++)
1156 if (temp->text[0] == '\0')
2b85e375 1157 break;
58ec2a95 1158
1159 if (i > 0)
7d75b814 1160 for (i = 0; i < temp->num_options; i ++)
1161 if (strcmp(keyword, temp->options[i].keyword) == 0)
58ec2a95 1162 {
7d75b814 1163 temp->options[i].section = section;
1164 temp->options[i].order = order;
58ec2a95 1165 break;
1166 }
2b85e375 1167 }
1168 else
1169 {
1170 option->section = section;
1171 option->order = order;
e8fda7b9 1172 }
2b85e375 1173 }
1174 else if (strncmp(keyword, "Default", 7) == 0)
1175 {
6c73d44f 1176 if (string == NULL)
1177 continue;
1178
d23a857a 1179 if (strchr(string, '/') != NULL)
1180 *strchr(string, '/') = '\0';
58ec2a95 1181
2b85e375 1182 if (option == NULL)
1183 {
7d75b814 1184 ppd_group_t *temp;
1185
1186
2b85e375 1187 /*
1188 * Only valid for Non-UI options...
1189 */
1190
7d75b814 1191 for (i = ppd->num_groups, temp = ppd->groups; i > 0; i --, temp ++)
1192 if (temp->text[0] == '\0')
2b85e375 1193 break;
58ec2a95 1194
1195 if (i > 0)
7d75b814 1196 for (i = 0; i < temp->num_options; i ++)
1197 if (strcmp(keyword, temp->options[i].keyword) == 0)
58ec2a95 1198 {
7d75b814 1199 strncpy(temp->options[i].defchoice, string,
1200 sizeof(temp->options[i].defchoice) - 1);
58ec2a95 1201 break;
1202 }
2b85e375 1203 }
1204 else
fafbba4f 1205 strncpy(option->defchoice, string, sizeof(option->defchoice) - 1);
2b85e375 1206 }
1207 else if (strcmp(keyword, "UIConstraints") == 0 ||
1208 strcmp(keyword, "NonUIConstraints") == 0)
1209 {
1210 if (ppd->num_consts == 0)
1211 constraint = calloc(sizeof(ppd_const_t), 1);
1212 else
1213 constraint = realloc(ppd->consts,
1214 (ppd->num_consts + 1) * sizeof(ppd_const_t));
1215
1216 if (constraint == NULL)
1217 {
1218 ppdClose(ppd);
08b247a9 1219 safe_free(string);
2b85e375 1220 return (NULL);
e8fda7b9 1221 }
2b85e375 1222
1223 ppd->consts = constraint;
1224 constraint += ppd->num_consts;
1225 ppd->num_consts ++;
1226
fafbba4f 1227 switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1,
8c1333e2 1228 constraint->choice1, constraint->option2,
1229 constraint->choice2))
2b85e375 1230 {
1231 case 0 : /* Error */
1232 case 1 : /* Error */
1233 ppdClose(ppd);
08b247a9 1234 safe_free(string);
2b85e375 1235 break;
1236
8c1333e2 1237 case 2 : /* Two options... */
d2e58bfa 1238 /*
1239 * The following strcpy's are safe, as optionN and
1240 * choiceN are all the same size (size defined by PPD spec...)
1241 */
1242
2b85e375 1243 if (constraint->option1[0] == '*')
8c1333e2 1244 strcpy(constraint->option1, constraint->option1 + 1);
1245
1246 if (constraint->choice1[0] == '*')
1247 strcpy(constraint->option2, constraint->choice1 + 1);
2b85e375 1248 else
8c1333e2 1249 strcpy(constraint->option2, constraint->choice1);
2b85e375 1250
8c1333e2 1251 constraint->choice1[0] = '\0';
1252 constraint->choice2[0] = '\0';
2b85e375 1253 break;
1254
8c1333e2 1255 case 3 : /* Two options, one choice... */
d2e58bfa 1256 /*
1257 * The following strcpy's are safe, as optionN and
1258 * choiceN are all the same size (size defined by PPD spec...)
1259 */
1260
2b85e375 1261 if (constraint->option1[0] == '*')
8c1333e2 1262 strcpy(constraint->option1, constraint->option1 + 1);
1263
1264 if (constraint->choice1[0] == '*')
2b85e375 1265 {
9cbf7321 1266 strcpy(constraint->choice2, constraint->option2);
8c1333e2 1267 strcpy(constraint->option2, constraint->choice1 + 1);
1268 constraint->choice1[0] = '\0';
2b85e375 1269 }
9cbf7321 1270 else
1271 {
1272 if (constraint->option2[0] == '*')
1273 strcpy(constraint->option2, constraint->option2 + 1);
2b85e375 1274
9cbf7321 1275 constraint->choice2[0] = '\0';
1276 }
2b85e375 1277 break;
1278
8c1333e2 1279 case 4 : /* Two options, two choices... */
1280 if (constraint->option1[0] == '*')
1281 strcpy(constraint->option1, constraint->option1 + 1);
2b85e375 1282
8c1333e2 1283 if (constraint->option2[0] == '*')
1284 strcpy(constraint->option2, constraint->option2 + 1);
2b85e375 1285 break;
e8fda7b9 1286 }
2b85e375 1287 }
1288 else if (strcmp(keyword, "PaperDimension") == 0)
1289 {
753453e4 1290 if ((size = ppdPageSize(ppd, name)) == NULL)
1291 size = ppd_add_size(ppd, name);
1292
1293 if (size == NULL)
1294 {
1295 /*
1296 * Unable to add or find size!
1297 */
1298
1299 ppdClose(ppd);
1300 safe_free(string);
1301 return (NULL);
1302 }
1303
1304 sscanf(string, "%f%f", &(size->width), &(size->length));
2b85e375 1305 }
1306 else if (strcmp(keyword, "ImageableArea") == 0)
1307 {
753453e4 1308 if ((size = ppdPageSize(ppd, name)) == NULL)
1309 size = ppd_add_size(ppd, name);
1310
1311 if (size == NULL)
1312 {
1313 /*
1314 * Unable to add or find size!
1315 */
1316
1317 ppdClose(ppd);
1318 safe_free(string);
1319 return (NULL);
1320 }
1321
1322 sscanf(string, "%f%f%f%f", &(size->left), &(size->bottom),
1323 &(size->right), &(size->top));
2b85e375 1324 }
1325 else if (option != NULL &&
1326 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
1327 (PPD_KEYWORD | PPD_OPTION | PPD_STRING))
1328 {
7d75b814 1329 DEBUG_printf(("group = %p, subgroup = %p\n", group, subgroup));
1330
2b85e375 1331 if (strcmp(keyword, "PageSize") == 0)
1332 {
1333 /*
1334 * Add a page size...
1335 */
1336
753453e4 1337 if (ppdPageSize(ppd, name) == NULL)
1338 ppd_add_size(ppd, name);
e8fda7b9 1339 }
2b85e375 1340
1341 /*
1342 * Add the option choice...
1343 */
1344
6fdf969a 1345 choice = ppd_add_choice(option, name);
2b85e375 1346
8c1333e2 1347 if (mask & PPD_TEXT)
2685c8f0 1348 {
fafbba4f 1349 strncpy(choice->text, text, sizeof(choice->text) - 1);
2685c8f0 1350 ppd_fix(choice->text);
1351 }
2b85e375 1352 else if (strcmp(name, "True") == 0)
d23a857a 1353 strcpy(choice->text, "Yes");
2b85e375 1354 else if (strcmp(name, "False") == 0)
d23a857a 1355 strcpy(choice->text, "No");
2b85e375 1356 else
fafbba4f 1357 strncpy(choice->text, name, sizeof(choice->text) - 1);
2b85e375 1358
bbc1bfe5 1359 if (option->section == PPD_ORDER_JCL)
2b85e375 1360 ppd_decode(string); /* Decode quoted string */
1361
1362 choice->code = string;
1363 string = NULL; /* Don't free this string below */
e8fda7b9 1364 }
2b85e375 1365
08b247a9 1366 safe_free(string);
e8fda7b9 1367 }
2b85e375 1368
1369#ifdef DEBUG
1370 if (!feof(fp))
ba31b514 1371 printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp));
2b85e375 1372#endif /* DEBUG */
1373
58ec2a95 1374 /*
1375 * Set the option back-pointer for each choice...
1376 */
1377
caab0820 1378 qsort(ppd->groups, ppd->num_groups, sizeof(ppd_group_t),
1379 (int (*)(const void *, const void *))compare_groups);
1380
58ec2a95 1381 for (i = ppd->num_groups, group = ppd->groups;
1382 i > 0;
1383 i --, group ++)
1384 {
caab0820 1385 qsort(group->options, group->num_options, sizeof(ppd_option_t),
1386 (int (*)(const void *, const void *))compare_options);
1387
58ec2a95 1388 for (j = group->num_options, option = group->options;
1389 j > 0;
1390 j --, option ++)
caab0820 1391 {
1392 qsort(option->choices, option->num_choices, sizeof(ppd_choice_t),
1393 (int (*)(const void *, const void *))compare_choices);
1394
58ec2a95 1395 for (k = 0; k < option->num_choices; k ++)
1396 option->choices[k].option = (void *)option;
caab0820 1397 }
1398
1399 qsort(group->subgroups, group->num_subgroups, sizeof(ppd_group_t),
1400 (int (*)(const void *, const void *))compare_groups);
58ec2a95 1401
1402 for (j = group->num_subgroups, subgroup = group->subgroups;
1403 j > 0;
1404 j --, subgroup ++)
caab0820 1405 {
1406 qsort(subgroup->options, subgroup->num_options, sizeof(ppd_option_t),
1407 (int (*)(const void *, const void *))compare_options);
1408
58ec2a95 1409 for (k = group->num_options, option = group->options;
1410 k > 0;
1411 k --, option ++)
caab0820 1412 {
1413 qsort(option->choices, option->num_choices, sizeof(ppd_choice_t),
1414 (int (*)(const void *, const void *))compare_choices);
1415
58ec2a95 1416 for (m = 0; m < option->num_choices; m ++)
1417 option->choices[m].option = (void *)option;
caab0820 1418 }
1419 }
58ec2a95 1420 }
1421
2b85e375 1422 return (ppd);
1423}
1424
1425
1426/*
1427 * 'ppdOpenFd()' - Read a PPD file into memory.
1428 */
1429
1430ppd_file_t * /* O - PPD file record */
1431ppdOpenFd(int fd) /* I - File to read from */
1432{
1433 FILE *fp; /* File pointer */
1434 ppd_file_t *ppd; /* PPD file record */
1435
1436
1437 /*
1438 * Range check input...
1439 */
1440
1441 if (fd < 0)
1442 return (NULL);
1443
1444 /*
1445 * Try to open the file and parse it...
1446 */
1447
1448 if ((fp = fdopen(fd, "r")) != NULL)
1449 {
1450 setbuf(fp, NULL);
1451
1452 ppd = ppdOpen(fp);
1453
08b247a9 1454 safe_free(fp);
2b85e375 1455 }
1456 else
1457 ppd = NULL;
1458
1459 return (ppd);
1460}
1461
1462
1463/*
1464 * 'ppdOpenFile()' - Read a PPD file into memory.
1465 */
1466
1467ppd_file_t * /* O - PPD file record */
063e1ac7 1468ppdOpenFile(const char *filename) /* I - File to read from */
2b85e375 1469{
1470 FILE *fp; /* File pointer */
1471 ppd_file_t *ppd; /* PPD file record */
1472
1473
1474 /*
1475 * Range check input...
1476 */
1477
1478 if (filename == NULL)
1479 return (NULL);
1480
1481 /*
1482 * Try to open the file and parse it...
1483 */
1484
1485 if ((fp = fopen(filename, "r")) != NULL)
1486 {
1487 ppd = ppdOpen(fp);
1488
1489 fclose(fp);
1490 }
1491 else
1492 ppd = NULL;
1493
1494 return (ppd);
1495}
1496
1497
15166848 1498/*
1499 * 'compare_strings()' - Compare two strings.
1500 */
1501
b5cb0608 1502static int /* O - Result of comparison */
15166848 1503compare_strings(char *s, /* I - First string */
1504 char *t) /* I - Second string */
1505{
1506 int diff, /* Difference between digits */
1507 digits; /* Number of digits */
1508
1509
1510 /*
1511 * Loop through both strings, returning only when a difference is
1512 * seen. Also, compare whole numbers rather than just characters, too!
1513 */
1514
1515 while (*s && *t)
1516 {
1517 if (isdigit(*s) && isdigit(*t))
1518 {
1519 /*
1520 * Got a number; start by skipping leading 0's...
1521 */
1522
1523 while (*s == '0')
1524 s ++;
1525 while (*t == '0')
1526 t ++;
1527
1528 /*
1529 * Skip equal digits...
1530 */
1531
1532 while (isdigit(*s) && *s == *t)
1533 {
1534 s ++;
1535 t ++;
1536 }
1537
1538 /*
1539 * Bounce out if *s and *t aren't both digits...
1540 */
1541
f4d16e74 1542 if (isdigit(*s) && !isdigit(*t))
1543 return (1);
1544 else if (!isdigit(*s) && isdigit(*t))
1545 return (-1);
1546 else if (!isdigit(*s) || !isdigit(*t))
15166848 1547 continue;
1548
1549 if (*s < *t)
1550 diff = -1;
1551 else
1552 diff = 1;
1553
1554 /*
1555 * Figure out how many more digits there are...
1556 */
1557
1558 digits = 0;
1559
1560 while (isdigit(*s))
1561 {
1562 digits ++;
1563 s ++;
1564 }
1565
1566 while (isdigit(*t))
1567 {
1568 digits --;
1569 t ++;
1570 }
1571
1572 /*
1573 * Return if the number or value of the digits is different...
1574 */
1575
1576 if (digits < 0)
1577 return (-1);
1578 else if (digits > 0)
1579 return (1);
1580 else
1581 return (diff);
1582 }
1583 else if (tolower(*s) < tolower(*t))
1584 return (-1);
1585 else if (tolower(*s) > tolower(*t))
1586 return (1);
1587 else
1588 {
1589 s ++;
1590 t ++;
1591 }
1592 }
1593
1594 /*
1595 * Return the results of the final comparison...
1596 */
1597
1598 if (*s)
1599 return (1);
1600 else if (*t)
1601 return (-1);
1602 else
1603 return (0);
1604}
1605
1606
caab0820 1607/*
1608 * 'compare_groups()' - Compare two groups.
1609 */
1610
1611static int /* O - Result of comparison */
1612compare_groups(ppd_group_t *g0, /* I - First group */
1613 ppd_group_t *g1) /* I - Second group */
1614{
15166848 1615 return (compare_strings(g0->text, g1->text));
caab0820 1616}
1617
1618
1619/*
1620 * 'compare_options()' - Compare two options.
1621 */
1622
1623static int /* O - Result of comparison */
1624compare_options(ppd_option_t *o0,/* I - First option */
1625 ppd_option_t *o1)/* I - Second option */
1626{
15166848 1627 return (compare_strings(o0->text, o1->text));
caab0820 1628}
1629
1630
1631/*
1632 * 'compare_choices()' - Compare two choices.
1633 */
1634
1635static int /* O - Result of comparison */
1636compare_choices(ppd_choice_t *c0,/* I - First choice */
1637 ppd_choice_t *c1)/* I - Second choice */
1638{
15166848 1639 return (compare_strings(c0->text, c1->text));
caab0820 1640}
1641
1642
2b85e375 1643/*
1644 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
1645 * necessary.
1646 */
1647
1648static int /* O - Bitmask of fields read */
d23a857a 1649ppd_read(FILE *fp, /* I - File to read from */
1650 char *keyword, /* O - Keyword from line */
1651 char *option, /* O - Option from line */
1652 char *text, /* O - Human-readable text from line */
1653 char **string) /* O - Code/string data */
2b85e375 1654{
1655 int ch, /* Character from file */
753453e4 1656 colon, /* Colon seen? */
2b85e375 1657 endquote, /* Waiting for an end quote */
1658 mask; /* Mask to be returned */
1659 char *keyptr, /* Keyword pointer */
d23a857a 1660 *optptr, /* Option pointer */
1661 *textptr, /* Text pointer */
1662 *strptr, /* Pointer into string */
1663 *lineptr, /* Current position in line buffer */
c5b83b99 1664 line[65536]; /* Line buffer (64k) */
2b85e375 1665
1666
1667 /*
1668 * Range check everything...
1669 */
1670
1671 if (fp == NULL || keyword == NULL || option == NULL || text == NULL ||
554fab97 1672 string == NULL)
2b85e375 1673 return (0);
1674
1675 /*
1676 * Now loop until we have a valid line...
1677 */
1678
c5b83b99 1679 *string = NULL;
1680
2b85e375 1681 do
1682 {
1683 /*
1684 * Read the line...
1685 */
1686
1687 lineptr = line;
1688 endquote = 0;
753453e4 1689 colon = 0;
2b85e375 1690
1691 while ((ch = getc(fp)) != EOF &&
1692 (lineptr - line) < (sizeof(line) - 1))
1693 {
1694 if (ch == '\r' || ch == '\n')
1695 {
1696 /*
1697 * Line feed or carriage return...
1698 */
1699
1700 if (lineptr == line) /* Skip blank lines */
1701 continue;
1702
1703 if (ch == '\r')
1704 {
1705 /*
1706 * Check for a trailing line feed...
1707 */
1708
1709 if ((ch = getc(fp)) == EOF)
1710 break;
1711 if (ch != 0x0a)
1712 ungetc(ch, fp);
e8fda7b9 1713 }
2b85e375 1714
c5b83b99 1715 ch = '\n';
2b85e375 1716
1717 if (!endquote) /* Continue for multi-line text */
1718 break;
c5b83b99 1719
1720 *lineptr++ = '\n';
2b85e375 1721 }
1722 else
1723 {
1724 /*
1725 * Any other character...
1726 */
1727
1728 *lineptr++ = ch;
1729
753453e4 1730 if (ch == ':')
1731 colon = 1;
1732
1733 if (ch == '\"' && colon)
132e0c72 1734 {
1735 endquote = !endquote;
1736
1737 if (!endquote)
1738 {
1739 /*
1740 * End of quoted string; ignore trailing characters...
1741 */
1742
1743 while ((ch = getc(fp)) != EOF)
1744 if (ch == '\n')
1745 break;
1746 else if (ch == '\r')
1747 {
1748 ch = getc(fp);
1749 if (ch != '\n')
1750 ungetc(ch, fp);
1751 break;
1752 }
1753
1754 break;
1755 }
1756 }
e8fda7b9 1757 }
1758 }
2b85e375 1759
c5b83b99 1760 if (endquote)
1761 {
1762 /*
1763 * Didn't finish this quoted string...
1764 */
1765
1766 while ((ch = getc(fp)) != EOF)
1767 if (ch == '\"')
1768 break;
1769 }
1770
1771 if (ch != '\n')
1772 {
1773 /*
1774 * Didn't finish this line...
1775 */
1776
1777 while ((ch = getc(fp)) != EOF)
1778 if (ch == '\r' || ch == '\n')
1779 {
1780 /*
1781 * Line feed or carriage return...
1782 */
1783
1784 if (ch == '\r')
1785 {
1786 /*
1787 * Check for a trailing line feed...
1788 */
1789
1790 if ((ch = getc(fp)) == EOF)
1791 break;
1792 if (ch != 0x0a)
1793 ungetc(ch, fp);
1794 }
1795
1796 break;
1797 }
1798 }
1799
2b85e375 1800 if (lineptr > line && lineptr[-1] == '\n')
1801 lineptr --;
1802
1803 *lineptr = '\0';
1804
753453e4 1805/* DEBUG_printf(("LINE = \"%s\"\n", line));*/
1806
2b85e375 1807 if (ch == EOF && lineptr == line)
1808 return (0);
1809
1810 /*
1811 * Now parse it...
1812 */
1813
1814 mask = 0;
1815 lineptr = line + 1;
1816
1817 keyword[0] = '\0';
1818 option[0] = '\0';
1819 text[0] = '\0';
1820 *string = NULL;
1821
1822 if (line[0] != '*') /* All lines start with an asterisk */
1823 continue;
1824
753453e4 1825 if (strcmp(line, "*") == 0 || /* (Bad) comment line */
1826 strncmp(line, "*%", 2) == 0 || /* Comment line */
d23a857a 1827 strncmp(line, "*?", 2) == 0 || /* Query line */
1828 strcmp(line, "*End") == 0) /* End of multi-line string */
2b85e375 1829 continue;
1830
1831 /*
1832 * Get a keyword...
1833 */
1834
1835 keyptr = keyword;
1836
1837 while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr) &&
d2e58bfa 1838 (keyptr - keyword) < (PPD_MAX_NAME - 1))
2b85e375 1839 *keyptr++ = *lineptr++;
1840
1841 *keyptr = '\0';
753453e4 1842
1843 if (strcmp(keyword, "End") == 0)
1844 continue;
1845
2b85e375 1846 mask |= PPD_KEYWORD;
1847
753453e4 1848/* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
1849
1850 if (isspace(*lineptr))
2b85e375 1851 {
1852 /*
1853 * Get an option name...
1854 */
1855
753453e4 1856 while (isspace(*lineptr))
2b85e375 1857 lineptr ++;
1858
1859 optptr = option;
1860
1861 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':' &&
5f10a00b 1862 *lineptr != '/' && (optptr - option) < (PPD_MAX_NAME - 1))
2b85e375 1863 *optptr++ = *lineptr++;
1864
1865 *optptr = '\0';
1866 mask |= PPD_OPTION;
1867
753453e4 1868/* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
1869
2b85e375 1870 if (*lineptr == '/')
1871 {
1872 /*
1873 * Get human-readable text...
1874 */
1875
1876 lineptr ++;
1877
1878 textptr = text;
1879
1880 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':' &&
d2e58bfa 1881 (textptr - text) < (PPD_MAX_TEXT - 1))
2b85e375 1882 *textptr++ = *lineptr++;
1883
1884 *textptr = '\0';
1885 ppd_decode(text);
1886
1887 mask |= PPD_TEXT;
e8fda7b9 1888 }
753453e4 1889
1890/* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
e8fda7b9 1891 }
2b85e375 1892
1893 if (*lineptr == ':')
1894 {
1895 /*
1896 * Get string...
1897 */
1898
d23a857a 1899 *string = malloc(strlen(lineptr) + 1);
2b85e375 1900
1901 while (*lineptr == ':' || isspace(*lineptr))
1902 lineptr ++;
1903
1904 strptr = *string;
1905
1906 while (*lineptr != '\0')
1907 {
1908 if (*lineptr != '\"')
1909 *strptr++ = *lineptr++;
1910 else
1911 lineptr ++;
e8fda7b9 1912 }
2b85e375 1913
1914 *strptr = '\0';
58ec2a95 1915
753453e4 1916/* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
1917
2b85e375 1918 mask |= PPD_STRING;
e8fda7b9 1919 }
2b85e375 1920 }
1921 while (mask == 0);
1922
1923 return (mask);
1924}
1925
1926
1927/*
1928 * 'ppd_decode()' - Decode a string value...
1929 */
1930
1931static void
d23a857a 1932ppd_decode(char *string) /* I - String to decode */
2b85e375 1933{
d23a857a 1934 char *inptr, /* Input pointer */
1935 *outptr; /* Output pointer */
2b85e375 1936
1937
1938 inptr = string;
1939 outptr = string;
1940
1941 while (*inptr != '\0')
1942 if (*inptr == '<' && isxdigit(inptr[1]))
1943 {
1944 /*
1945 * Convert hex to 8-bit values...
1946 */
1947
1948 inptr ++;
1949 while (isxdigit(*inptr))
1950 {
1951 if (isalpha(*inptr))
0b83a6c8 1952 *outptr = (tolower(*inptr) - 'a' + 10) << 4;
2b85e375 1953 else
0b83a6c8 1954 *outptr = (*inptr - '0') << 4;
2b85e375 1955
1956 inptr ++;
1957
1958 if (isalpha(*inptr))
1959 *outptr |= tolower(*inptr) - 'a' + 10;
1960 else
1961 *outptr |= *inptr - '0';
1962
1963 inptr ++;
1964 outptr ++;
e8fda7b9 1965 }
2b85e375 1966
1967 while (*inptr != '>' && *inptr != '\0')
1968 inptr ++;
1969 while (*inptr == '>')
1970 inptr ++;
1971 }
1972 else
1973 *outptr++ = *inptr++;
1974
1975 *outptr = '\0';
1976}
1977
1978
90a24de4 1979/*
2685c8f0 1980 * 'ppd_fix()' - Fix WinANSI characters in the range 0x80 to 0x9f to be
1981 * valid ISO-8859-1 characters...
1982 */
1983
1984static void
1985ppd_fix(char *string) /* IO - String to fix */
1986{
1987 unsigned char *p; /* Pointer into string */
1988 static unsigned char lut[32] =/* Lookup table for characters */
1989 {
1990 0x20,
1991 0x20,
1992 0x20,
1993 0x20,
1994 0x20,
1995 0x20,
1996 0x20,
1997 0x20,
1998 0x20,
1999 0x20,
2000 0x20,
2001 0x20,
2002 0x20,
2003 0x20,
2004 0x20,
2005 0x20,
2006 'l',
2007 '`',
2008 '\'',
2009 '^',
2010 '~',
2011 0x20, /* bar */
2012 0x20, /* circumflex */
2013 0x20, /* dot */
2014 0x20, /* double dot */
2015 0x20,
2016 0x20, /* circle */
2017 0x20, /* ??? */
2018 0x20,
2019 '\"', /* should be right quotes */
2020 0x20, /* ??? */
2021 0x20 /* accent */
2022 };
2023
2024
2025 for (p = (unsigned char *)string; *p; p ++)
2026 if (*p >= 0x80 && *p < 0xa0)
2027 *p = lut[*p - 0x80];
2028}
2029
2030
2031/*
5f10a00b 2032 * End of "$Id: ppd.c,v 1.51.2.9 2002/04/17 18:07:03 mike Exp $".
90a24de4 2033 */