]>
Commit | Line | Data |
---|---|---|
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 | 83 | static int compare_strings(char *s, char *t); |
caab0820 | 84 | static int compare_groups(ppd_group_t *g0, ppd_group_t *g1); |
85 | static int compare_options(ppd_option_t *o0, ppd_option_t *o1); | |
86 | static int compare_choices(ppd_choice_t *c0, ppd_choice_t *c1); | |
6fdf969a | 87 | static int ppd_read(FILE *fp, char *keyword, char *option, |
d23a857a | 88 | char *text, char **string); |
89 | static void ppd_decode(char *string); | |
2685c8f0 | 90 | static void ppd_fix(char *string); |
6fdf969a | 91 | static void ppd_free_group(ppd_group_t *group); |
92 | static void ppd_free_option(ppd_option_t *option); | |
93 | static ppd_group_t *ppd_get_group(ppd_file_t *ppd, char *name); | |
94 | static ppd_option_t *ppd_get_option(ppd_group_t *group, char *name); | |
95 | static 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 | ||
102 | void | |
103 | ppdClose(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 | ||
203 | static void | |
204 | ppd_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 | ||
237 | static void | |
238 | ppd_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 | ||
260 | static ppd_group_t * /* O - Named group */ | |
261 | ppd_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 | ||
299 | static ppd_option_t * /* O - Named option */ | |
300 | ppd_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 | ||
338 | static ppd_choice_t * /* O - Named choice */ | |
339 | ppd_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 | ||
369 | static ppd_size_t * /* O - Named size */ | |
370 | ppd_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 | ||
399 | ppd_file_t * /* O - PPD file record */ | |
400 | ppdOpen(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 | ||
1245 | ppd_file_t * /* O - PPD file record */ | |
1246 | ppdOpenFd(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 | ||
1282 | ppd_file_t * /* O - PPD file record */ | |
063e1ac7 | 1283 | ppdOpenFile(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 | ||
1317 | int /* O - Result of comparison */ | |
1318 | compare_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 | ||
1422 | static int /* O - Result of comparison */ | |
1423 | compare_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 | ||
1434 | static int /* O - Result of comparison */ | |
1435 | compare_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 | ||
1446 | static int /* O - Result of comparison */ | |
1447 | compare_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 | ||
1459 | static int /* O - Bitmask of fields read */ | |
d23a857a | 1460 | ppd_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 | ||
1656 | static void | |
d23a857a | 1657 | ppd_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 | ||
1709 | static void | |
1710 | ppd_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 | */ |