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