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