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