]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
66ab9486 | 2 | * "$Id: mark.c 7757 2008-07-18 16:43:43Z mike $" |
ef416fc2 | 3 | * |
4 | * Option marking routines for the Common UNIX Printing System (CUPS). | |
5 | * | |
5a738aea | 6 | * Copyright 2007-2008 by Apple Inc. |
b86bc4cf | 7 | * Copyright 1997-2007 by Easy Software Products, all rights reserved. |
ef416fc2 | 8 | * |
9 | * These coded instructions, statements, and computer programs are the | |
bc44d920 | 10 | * property of Apple Inc. and are protected by Federal copyright |
11 | * law. Distribution and use rights are outlined in the file "LICENSE.txt" | |
12 | * which should have been included with this file. If this file is | |
13 | * file is missing or damaged, see the license at "http://www.cups.org/". | |
ef416fc2 | 14 | * |
15 | * PostScript is a trademark of Adobe Systems, Inc. | |
16 | * | |
17 | * This file is subject to the Apple OS-Developed Software exception. | |
18 | * | |
19 | * Contents: | |
20 | * | |
5a738aea | 21 | * cupsMarkOptions() - Mark command-line options in a PPD file. |
ef416fc2 | 22 | * ppdFindChoice() - Return a pointer to an option choice. |
23 | * ppdFindMarkedChoice() - Return the marked choice for the specified option. | |
24 | * ppdFindOption() - Return a pointer to the specified option. | |
5a738aea | 25 | * ppdIsMarked() - Check to see if an option is marked. |
ef416fc2 | 26 | * ppdMarkDefaults() - Mark all default options in the PPD file. |
66ab9486 MS |
27 | * ppdMarkOption() - Mark an option in a PPD file and return the number |
28 | * of conflicts. | |
5a738aea MS |
29 | * ppdFirstOption() - Return the first option in the PPD file. |
30 | * ppdNextOption() - Return the next option in the PPD file. | |
66ab9486 | 31 | * _ppdParseOptions() - Parse options from a PPD file. |
5a738aea | 32 | * debug_marked() - Output the marked array to stdout... |
ef416fc2 | 33 | * ppd_defaults() - Set the defaults for this group and all sub-groups. |
5a738aea | 34 | * ppd_mark_choices() - Mark one or more option choices from a string. |
66ab9486 MS |
35 | * ppd_mark_option() - Quick mark an option without checking for |
36 | * conflicts. | |
ef416fc2 | 37 | */ |
38 | ||
39 | /* | |
40 | * Include necessary headers... | |
41 | */ | |
42 | ||
b423cd4c | 43 | #include "cups.h" |
ef416fc2 | 44 | #include "string.h" |
45 | #include "debug.h" | |
46 | ||
47 | ||
48 | /* | |
49 | * Local functions... | |
50 | */ | |
51 | ||
5a738aea MS |
52 | #ifdef DEBUG |
53 | static void debug_marked(ppd_file_t *ppd, const char *title); | |
54 | #else | |
66ab9486 | 55 | # define debug_marked(ppd,title) |
5a738aea | 56 | #endif /* DEBUG */ |
ef416fc2 | 57 | static void ppd_defaults(ppd_file_t *ppd, ppd_group_t *g); |
66ab9486 MS |
58 | static void ppd_mark_choices(ppd_file_t *ppd, const char *s); |
59 | static void ppd_mark_option(ppd_file_t *ppd, const char *option, | |
60 | const char *choice); | |
ef416fc2 | 61 | |
62 | ||
63 | /* | |
5a738aea MS |
64 | * 'cupsMarkOptions()' - Mark command-line options in a PPD file. |
65 | * | |
66 | * This function maps the IPP "finishings", "media", "mirror", | |
67 | * "multiple-document-handling", "output-bin", "printer-resolution", and | |
68 | * "sides" attributes to their corresponding PPD options and choices. | |
69 | */ | |
70 | ||
66ab9486 | 71 | int /* O - 1 if conflicts exist, 0 otherwise */ |
5a738aea MS |
72 | cupsMarkOptions( |
73 | ppd_file_t *ppd, /* I - PPD file */ | |
74 | int num_options, /* I - Number of options */ | |
75 | cups_option_t *options) /* I - Options */ | |
76 | { | |
77 | int i, j, k; /* Looping vars */ | |
5a738aea MS |
78 | char *val, /* Pointer into value */ |
79 | *ptr, /* Pointer into string */ | |
80 | s[255]; /* Temporary string */ | |
81 | const char *page_size; /* PageSize option */ | |
82 | cups_option_t *optptr; /* Current option */ | |
83 | ppd_option_t *option; /* PPD option */ | |
84 | ppd_attr_t *attr; /* PPD attribute */ | |
85 | static const char * const duplex_options[] = | |
86 | { /* Duplex option names */ | |
87 | "Duplex", /* Adobe */ | |
88 | "EFDuplex", /* EFI */ | |
89 | "EFDuplexing", /* EFI */ | |
90 | "KD03Duplex", /* Kodak */ | |
91 | "JCLDuplex" /* Samsung */ | |
92 | }; | |
93 | static const char * const duplex_one[] = | |
94 | { /* one-sided names */ | |
95 | "None", | |
96 | "False" | |
97 | }; | |
98 | static const char * const duplex_two_long[] = | |
99 | { /* two-sided-long-edge names */ | |
100 | "DuplexNoTumble", /* Adobe */ | |
101 | "LongEdge", /* EFI */ | |
102 | "Top" /* EFI */ | |
103 | }; | |
104 | static const char * const duplex_two_short[] = | |
105 | { /* two-sided-long-edge names */ | |
106 | "DuplexTumble", /* Adobe */ | |
107 | "ShortEdge", /* EFI */ | |
108 | "Bottom" /* EFI */ | |
109 | }; | |
110 | ||
111 | ||
112 | /* | |
113 | * Check arguments... | |
114 | */ | |
115 | ||
116 | if (!ppd || num_options <= 0 || !options) | |
117 | return (0); | |
118 | ||
119 | debug_marked(ppd, "Before..."); | |
120 | ||
121 | /* | |
122 | * Mark options... | |
123 | */ | |
124 | ||
5a738aea MS |
125 | for (i = num_options, optptr = options; i > 0; i --, optptr ++) |
126 | if (!strcasecmp(optptr->name, "media")) | |
127 | { | |
128 | /* | |
129 | * Loop through the option string, separating it at commas and | |
130 | * marking each individual option as long as the corresponding | |
131 | * PPD option (PageSize, InputSlot, etc.) is not also set. | |
132 | * | |
133 | * For PageSize, we also check for an empty option value since | |
134 | * some versions of MacOS X use it to specify auto-selection | |
135 | * of the media based solely on the size. | |
136 | */ | |
137 | ||
138 | page_size = cupsGetOption("PageSize", num_options, options); | |
139 | ||
140 | for (val = optptr->value; *val;) | |
141 | { | |
142 | /* | |
143 | * Extract the sub-option from the string... | |
144 | */ | |
145 | ||
146 | for (ptr = s; *val && *val != ',' && (ptr - s) < (sizeof(s) - 1);) | |
147 | *ptr++ = *val++; | |
148 | *ptr++ = '\0'; | |
149 | ||
150 | if (*val == ',') | |
151 | val ++; | |
152 | ||
153 | /* | |
154 | * Mark it... | |
155 | */ | |
156 | ||
157 | if (!page_size || !page_size[0]) | |
66ab9486 | 158 | ppd_mark_option(ppd, "PageSize", s); |
5a738aea MS |
159 | |
160 | if (cupsGetOption("InputSlot", num_options, options) == NULL) | |
66ab9486 | 161 | ppd_mark_option(ppd, "InputSlot", s); |
5a738aea MS |
162 | |
163 | if (cupsGetOption("MediaType", num_options, options) == NULL) | |
66ab9486 | 164 | ppd_mark_option(ppd, "MediaType", s); |
5a738aea MS |
165 | |
166 | if (cupsGetOption("EFMediaType", num_options, options) == NULL) | |
66ab9486 | 167 | ppd_mark_option(ppd, "EFMediaType", s); /* EFI */ |
5a738aea MS |
168 | |
169 | if (cupsGetOption("EFMediaQualityMode", num_options, options) == NULL) | |
66ab9486 | 170 | ppd_mark_option(ppd, "EFMediaQualityMode", s); /* EFI */ |
5a738aea | 171 | |
66ab9486 MS |
172 | if (!strcasecmp(s, "manual") && |
173 | !cupsGetOption("ManualFeed", num_options, options)) | |
174 | ppd_mark_option(ppd, "ManualFeed", "True"); | |
5a738aea MS |
175 | } |
176 | } | |
177 | else if (!strcasecmp(optptr->name, "sides")) | |
178 | { | |
66ab9486 MS |
179 | for (j = 0; |
180 | j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); | |
181 | j ++) | |
182 | if (cupsGetOption(duplex_options[j], num_options, options)) | |
5a738aea MS |
183 | break; |
184 | ||
185 | if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) | |
186 | { | |
187 | /* | |
188 | * Don't override the PPD option with the IPP attribute... | |
189 | */ | |
190 | ||
191 | continue; | |
192 | } | |
193 | ||
194 | if (!strcasecmp(optptr->value, "one-sided")) | |
195 | { | |
196 | /* | |
197 | * Mark the appropriate duplex option for one-sided output... | |
198 | */ | |
199 | ||
66ab9486 MS |
200 | for (j = 0; |
201 | j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); | |
202 | j ++) | |
5a738aea MS |
203 | if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL) |
204 | break; | |
205 | ||
206 | if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) | |
207 | { | |
66ab9486 MS |
208 | for (k = 0; |
209 | k < (int)(sizeof(duplex_one) / sizeof(duplex_one[0])); | |
210 | k ++) | |
5a738aea MS |
211 | if (ppdFindChoice(option, duplex_one[k])) |
212 | { | |
66ab9486 | 213 | ppd_mark_option(ppd, duplex_options[j], duplex_one[k]); |
5a738aea MS |
214 | break; |
215 | } | |
216 | } | |
217 | } | |
218 | else if (!strcasecmp(optptr->value, "two-sided-long-edge")) | |
219 | { | |
220 | /* | |
221 | * Mark the appropriate duplex option for two-sided-long-edge output... | |
222 | */ | |
223 | ||
66ab9486 MS |
224 | for (j = 0; |
225 | j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); | |
226 | j ++) | |
5a738aea MS |
227 | if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL) |
228 | break; | |
229 | ||
230 | if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) | |
231 | { | |
66ab9486 MS |
232 | for (k = 0; |
233 | k < (int)(sizeof(duplex_two_long) / sizeof(duplex_two_long[0])); | |
234 | k ++) | |
5a738aea MS |
235 | if (ppdFindChoice(option, duplex_two_long[k])) |
236 | { | |
66ab9486 | 237 | ppd_mark_option(ppd, duplex_options[j], duplex_two_long[k]); |
5a738aea MS |
238 | break; |
239 | } | |
240 | } | |
241 | } | |
242 | else if (!strcasecmp(optptr->value, "two-sided-short-edge")) | |
243 | { | |
244 | /* | |
245 | * Mark the appropriate duplex option for two-sided-short-edge output... | |
246 | */ | |
247 | ||
66ab9486 MS |
248 | for (j = 0; |
249 | j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); | |
250 | j ++) | |
5a738aea MS |
251 | if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL) |
252 | break; | |
253 | ||
254 | if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) | |
255 | { | |
66ab9486 MS |
256 | for (k = 0; |
257 | k < (int)(sizeof(duplex_two_short) / sizeof(duplex_two_short[0])); | |
258 | k ++) | |
5a738aea MS |
259 | if (ppdFindChoice(option, duplex_two_short[k])) |
260 | { | |
66ab9486 | 261 | ppd_mark_option(ppd, duplex_options[j], duplex_two_short[k]); |
5a738aea MS |
262 | break; |
263 | } | |
264 | } | |
265 | } | |
266 | } | |
267 | else if (!strcasecmp(optptr->name, "resolution") || | |
268 | !strcasecmp(optptr->name, "printer-resolution")) | |
269 | { | |
66ab9486 MS |
270 | ppd_mark_option(ppd, "Resolution", optptr->value); |
271 | ppd_mark_option(ppd, "SetResolution", optptr->value); | |
5a738aea | 272 | /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */ |
66ab9486 MS |
273 | ppd_mark_option(ppd, "JCLResolution", optptr->value); |
274 | /* HP */ | |
275 | ppd_mark_option(ppd, "CNRes_PGP", optptr->value); | |
276 | /* Canon */ | |
5a738aea MS |
277 | } |
278 | else if (!strcasecmp(optptr->name, "output-bin")) | |
279 | { | |
280 | if (!cupsGetOption("OutputBin", num_options, options)) | |
66ab9486 | 281 | ppd_mark_option(ppd, "OutputBin", optptr->value); |
5a738aea MS |
282 | } |
283 | else if (!strcasecmp(optptr->name, "multiple-document-handling")) | |
284 | { | |
285 | if (!cupsGetOption("Collate", num_options, options) && | |
286 | ppdFindOption(ppd, "Collate")) | |
287 | { | |
288 | if (strcasecmp(optptr->value, "separate-documents-uncollated-copies")) | |
66ab9486 | 289 | ppd_mark_option(ppd, "Collate", "True"); |
5a738aea | 290 | else |
66ab9486 | 291 | ppd_mark_option(ppd, "Collate", "False"); |
5a738aea MS |
292 | } |
293 | } | |
294 | else if (!strcasecmp(optptr->name, "finishings")) | |
295 | { | |
296 | /* | |
297 | * Lookup cupsIPPFinishings attributes for each value... | |
298 | */ | |
299 | ||
300 | for (ptr = optptr->value; *ptr;) | |
301 | { | |
302 | /* | |
303 | * Get the next finishings number... | |
304 | */ | |
305 | ||
306 | if (!isdigit(*ptr & 255)) | |
307 | break; | |
308 | ||
309 | if ((j = strtol(ptr, &ptr, 10)) < 3) | |
310 | break; | |
311 | ||
312 | /* | |
313 | * Skip separator as needed... | |
314 | */ | |
315 | ||
316 | if (*ptr == ',') | |
317 | ptr ++; | |
318 | ||
319 | /* | |
320 | * Look it up in the PPD file... | |
321 | */ | |
322 | ||
323 | sprintf(s, "%d", j); | |
324 | ||
325 | if ((attr = ppdFindAttr(ppd, "cupsIPPFinishings", s)) == NULL) | |
326 | continue; | |
327 | ||
328 | /* | |
329 | * Apply "*Option Choice" settings from the attribute value... | |
330 | */ | |
331 | ||
66ab9486 | 332 | ppd_mark_choices(ppd, attr->value); |
5a738aea MS |
333 | } |
334 | } | |
66ab9486 | 335 | else if (!strcasecmp(optptr->name, "APPrinterPreset")) |
ef416fc2 | 336 | { |
337 | /* | |
66ab9486 | 338 | * Lookup APPrinterPreset value... |
ef416fc2 | 339 | */ |
340 | ||
66ab9486 MS |
341 | if ((attr = ppdFindAttr(ppd, "APPrinterPreset", optptr->value)) != NULL) |
342 | { | |
343 | /* | |
344 | * Apply "*Option Choice" settings from the attribute value... | |
345 | */ | |
ef416fc2 | 346 | |
66ab9486 MS |
347 | ppd_mark_choices(ppd, attr->value); |
348 | } | |
ef416fc2 | 349 | } |
66ab9486 MS |
350 | else if (!strcasecmp(optptr->name, "mirror")) |
351 | ppd_mark_option(ppd, "MirrorPrint", optptr->value); | |
352 | else | |
353 | ppd_mark_option(ppd, optptr->name, optptr->value); | |
355e94dc | 354 | |
66ab9486 | 355 | debug_marked(ppd, "After..."); |
ef416fc2 | 356 | |
66ab9486 | 357 | return (ppdConflicts(ppd) > 0); |
ef416fc2 | 358 | } |
359 | ||
360 | ||
361 | /* | |
362 | * 'ppdFindChoice()' - Return a pointer to an option choice. | |
363 | */ | |
364 | ||
5a738aea | 365 | ppd_choice_t * /* O - Choice pointer or @code NULL@ */ |
ef416fc2 | 366 | ppdFindChoice(ppd_option_t *o, /* I - Pointer to option */ |
367 | const char *choice) /* I - Name of choice */ | |
368 | { | |
b94498cf | 369 | int i; /* Looping var */ |
370 | ppd_choice_t *c; /* Current choice */ | |
ef416fc2 | 371 | |
372 | ||
bdd6c45b | 373 | if (!o || !choice) |
ef416fc2 | 374 | return (NULL); |
375 | ||
bdd6c45b MS |
376 | if (choice[0] == '{' || !strncasecmp(choice, "Custom.", 7)) |
377 | choice = "Custom"; | |
378 | ||
ef416fc2 | 379 | for (i = o->num_choices, c = o->choices; i > 0; i --, c ++) |
bdd6c45b | 380 | if (!strcasecmp(c->choice, choice)) |
ef416fc2 | 381 | return (c); |
382 | ||
383 | return (NULL); | |
384 | } | |
385 | ||
386 | ||
387 | /* | |
388 | * 'ppdFindMarkedChoice()' - Return the marked choice for the specified option. | |
389 | */ | |
390 | ||
5a738aea | 391 | ppd_choice_t * /* O - Pointer to choice or @code NULL@ */ |
ef416fc2 | 392 | ppdFindMarkedChoice(ppd_file_t *ppd, /* I - PPD file */ |
393 | const char *option) /* I - Keyword/option name */ | |
394 | { | |
b94498cf | 395 | ppd_choice_t key; /* Search key for choice */ |
ef416fc2 | 396 | |
397 | ||
b94498cf | 398 | if ((key.option = ppdFindOption(ppd, option)) == NULL) |
ef416fc2 | 399 | return (NULL); |
400 | ||
b94498cf | 401 | return ((ppd_choice_t *)cupsArrayFind(ppd->marked, &key)); |
ef416fc2 | 402 | } |
403 | ||
404 | ||
405 | /* | |
406 | * 'ppdFindOption()' - Return a pointer to the specified option. | |
407 | */ | |
408 | ||
5a738aea | 409 | ppd_option_t * /* O - Pointer to option or @code NULL@ */ |
ef416fc2 | 410 | ppdFindOption(ppd_file_t *ppd, /* I - PPD file data */ |
411 | const char *option) /* I - Option/Keyword name */ | |
412 | { | |
fa73b229 | 413 | /* |
414 | * Range check input... | |
415 | */ | |
ef416fc2 | 416 | |
fa73b229 | 417 | if (!ppd || !option) |
ef416fc2 | 418 | return (NULL); |
419 | ||
f301802f | 420 | if (ppd->options) |
421 | { | |
422 | /* | |
423 | * Search in the array... | |
424 | */ | |
425 | ||
426 | ppd_option_t key; /* Option search key */ | |
427 | ||
428 | ||
429 | strlcpy(key.keyword, option, sizeof(key.keyword)); | |
ef416fc2 | 430 | |
f301802f | 431 | return ((ppd_option_t *)cupsArrayFind(ppd->options, &key)); |
432 | } | |
433 | else | |
434 | { | |
435 | /* | |
436 | * Search in each group... | |
437 | */ | |
ef416fc2 | 438 | |
f301802f | 439 | int i, j; /* Looping vars */ |
440 | ppd_group_t *group; /* Current group */ | |
441 | ppd_option_t *optptr; /* Current option */ | |
442 | ||
443 | ||
444 | for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) | |
445 | for (j = group->num_options, optptr = group->options; | |
446 | j > 0; | |
447 | j --, optptr ++) | |
448 | if (!strcasecmp(optptr->keyword, option)) | |
449 | return (optptr); | |
450 | ||
451 | return (NULL); | |
452 | } | |
ef416fc2 | 453 | } |
454 | ||
455 | ||
456 | /* | |
5a738aea | 457 | * 'ppdIsMarked()' - Check to see if an option is marked. |
ef416fc2 | 458 | */ |
459 | ||
b94498cf | 460 | int /* O - Non-zero if option is marked */ |
461 | ppdIsMarked(ppd_file_t *ppd, /* I - PPD file data */ | |
462 | const char *option, /* I - Option/Keyword name */ | |
463 | const char *choice) /* I - Choice name */ | |
ef416fc2 | 464 | { |
b94498cf | 465 | ppd_choice_t key, /* Search key */ |
466 | *c; /* Choice pointer */ | |
ef416fc2 | 467 | |
468 | ||
b94498cf | 469 | if (!ppd) |
ef416fc2 | 470 | return (0); |
471 | ||
b94498cf | 472 | if ((key.option = ppdFindOption(ppd, option)) == NULL) |
ef416fc2 | 473 | return (0); |
474 | ||
b94498cf | 475 | if ((c = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) == NULL) |
ef416fc2 | 476 | return (0); |
477 | ||
b94498cf | 478 | return (!strcmp(c->choice, choice)); |
ef416fc2 | 479 | } |
480 | ||
481 | ||
482 | /* | |
483 | * 'ppdMarkDefaults()' - Mark all default options in the PPD file. | |
484 | */ | |
485 | ||
486 | void | |
b94498cf | 487 | ppdMarkDefaults(ppd_file_t *ppd) /* I - PPD file record */ |
ef416fc2 | 488 | { |
b94498cf | 489 | int i; /* Looping variables */ |
490 | ppd_group_t *g; /* Current group */ | |
491 | ppd_choice_t *c; /* Current choice */ | |
ef416fc2 | 492 | |
493 | ||
b94498cf | 494 | if (!ppd) |
ef416fc2 | 495 | return; |
496 | ||
b94498cf | 497 | /* |
498 | * Clean out the marked array... | |
499 | */ | |
500 | ||
501 | for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked); | |
502 | c; | |
503 | c = (ppd_choice_t *)cupsArrayNext(ppd->marked)) | |
504 | cupsArrayRemove(ppd->marked, c); | |
505 | ||
506 | /* | |
507 | * Then repopulate it with the defaults... | |
508 | */ | |
509 | ||
ef416fc2 | 510 | for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++) |
511 | ppd_defaults(ppd, g); | |
512 | } | |
513 | ||
514 | ||
515 | /* | |
66ab9486 MS |
516 | * 'ppdMarkOption()' - Mark an option in a PPD file and return the number of |
517 | * conflicts. | |
ef416fc2 | 518 | */ |
519 | ||
520 | int /* O - Number of conflicts */ | |
521 | ppdMarkOption(ppd_file_t *ppd, /* I - PPD file record */ | |
522 | const char *option, /* I - Keyword */ | |
523 | const char *choice) /* I - Option name */ | |
524 | { | |
bd7854cb | 525 | DEBUG_printf(("ppdMarkOption(ppd=%p, option=\"%s\", choice=\"%s\")\n", |
526 | ppd, option, choice)); | |
527 | ||
fa73b229 | 528 | /* |
529 | * Range check input... | |
530 | */ | |
531 | ||
532 | if (!ppd || !option || !choice) | |
ef416fc2 | 533 | return (0); |
534 | ||
66ab9486 MS |
535 | /* |
536 | * Mark the option... | |
537 | */ | |
538 | ||
539 | ppd_mark_option(ppd, option, choice); | |
540 | ||
541 | /* | |
542 | * Return the number of conflicts... | |
543 | */ | |
544 | ||
545 | return (ppdConflicts(ppd)); | |
546 | } | |
547 | ||
548 | ||
549 | /* | |
550 | * 'ppdFirstOption()' - Return the first option in the PPD file. | |
551 | * | |
552 | * Options are returned from all groups in ascending alphanumeric order. | |
553 | * | |
554 | * @since CUPS 1.2@ | |
555 | */ | |
556 | ||
557 | ppd_option_t * /* O - First option or @code NULL@ */ | |
558 | ppdFirstOption(ppd_file_t *ppd) /* I - PPD file */ | |
559 | { | |
560 | if (!ppd) | |
561 | return (NULL); | |
562 | else | |
563 | return ((ppd_option_t *)cupsArrayFirst(ppd->options)); | |
564 | } | |
565 | ||
566 | ||
567 | /* | |
568 | * 'ppdNextOption()' - Return the next option in the PPD file. | |
569 | * | |
570 | * Options are returned from all groups in ascending alphanumeric order. | |
571 | * | |
572 | * @since CUPS 1.2@ | |
573 | */ | |
574 | ||
575 | ppd_option_t * /* O - Next option or @code NULL@ */ | |
576 | ppdNextOption(ppd_file_t *ppd) /* I - PPD file */ | |
577 | { | |
578 | if (!ppd) | |
579 | return (NULL); | |
580 | else | |
581 | return ((ppd_option_t *)cupsArrayNext(ppd->options)); | |
582 | } | |
583 | ||
584 | ||
585 | /* | |
586 | * '_ppdParseOptions()' - Parse options from a PPD file. | |
587 | * | |
588 | * This function looks for strings of the form: | |
589 | * | |
590 | * *option choice ... *optionN choiceN | |
591 | * | |
592 | * It stops when it finds a string that doesn't match this format. | |
593 | */ | |
594 | ||
595 | int /* O - Number of options */ | |
596 | _ppdParseOptions( | |
597 | const char *s, /* I - String to parse */ | |
598 | int num_options, /* I - Number of options */ | |
599 | cups_option_t **options) /* IO - Options */ | |
600 | { | |
601 | char option[PPD_MAX_NAME], /* Current option */ | |
602 | choice[PPD_MAX_NAME], /* Current choice */ | |
603 | *ptr; /* Pointer into option or choice */ | |
604 | ||
605 | ||
606 | if (!s) | |
607 | return (num_options); | |
608 | ||
609 | /* | |
610 | * Read all of the "*Option Choice" pairs from the string, marking PPD | |
611 | * options as we go... | |
612 | */ | |
613 | ||
614 | while (*s) | |
615 | { | |
616 | /* | |
617 | * Skip leading whitespace... | |
618 | */ | |
619 | ||
620 | while (isspace(*s & 255)) | |
621 | s ++; | |
622 | ||
623 | if (*s != '*') | |
624 | break; | |
625 | ||
626 | /* | |
627 | * Get the option name... | |
628 | */ | |
629 | ||
630 | s ++; | |
631 | ptr = option; | |
632 | while (*s && !isspace(*s & 255) && ptr < (option + sizeof(option) - 1)) | |
633 | *ptr++ = *s++; | |
634 | ||
635 | if (ptr == s) | |
636 | break; | |
637 | ||
638 | *ptr = '\0'; | |
639 | ||
640 | /* | |
641 | * Get the choice... | |
642 | */ | |
643 | ||
644 | while (isspace(*s & 255)) | |
645 | s ++; | |
646 | ||
647 | if (!*s) | |
648 | break; | |
649 | ||
650 | ptr = choice; | |
651 | while (*s && !isspace(*s & 255) && ptr < (choice + sizeof(choice) - 1)) | |
652 | *ptr++ = *s++; | |
653 | ||
654 | *ptr = '\0'; | |
655 | ||
656 | /* | |
657 | * Add it to the options array... | |
658 | */ | |
659 | ||
660 | num_options = cupsAddOption(option, choice, num_options, options); | |
661 | } | |
662 | ||
663 | return (num_options); | |
664 | } | |
665 | ||
666 | ||
667 | #ifdef DEBUG | |
668 | /* | |
669 | * 'debug_marked()' - Output the marked array to stdout... | |
670 | */ | |
671 | ||
672 | static void | |
673 | debug_marked(ppd_file_t *ppd, /* I - PPD file data */ | |
674 | const char *title) /* I - Title for list */ | |
675 | { | |
676 | ppd_choice_t *c; /* Current choice */ | |
677 | ||
678 | ||
679 | DEBUG_printf(("cupsMarkOptions: %s\n", title)); | |
680 | ||
681 | for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked); | |
682 | c; | |
683 | c = (ppd_choice_t *)cupsArrayNext(ppd->marked)) | |
684 | DEBUG_printf(("cupsMarkOptions: %s=%s\n", c->option->keyword, c->choice)); | |
685 | } | |
686 | #endif /* DEBUG */ | |
687 | ||
688 | ||
689 | /* | |
690 | * 'ppd_defaults()' - Set the defaults for this group and all sub-groups. | |
691 | */ | |
692 | ||
693 | static void | |
694 | ppd_defaults(ppd_file_t *ppd, /* I - PPD file */ | |
695 | ppd_group_t *g) /* I - Group to default */ | |
696 | { | |
697 | int i; /* Looping var */ | |
698 | ppd_option_t *o; /* Current option */ | |
699 | ppd_group_t *sg; /* Current sub-group */ | |
700 | ||
701 | ||
702 | for (i = g->num_options, o = g->options; i > 0; i --, o ++) | |
703 | if (strcasecmp(o->keyword, "PageRegion") != 0) | |
704 | ppdMarkOption(ppd, o->keyword, o->defchoice); | |
705 | ||
706 | for (i = g->num_subgroups, sg = g->subgroups; i > 0; i --, sg ++) | |
707 | ppd_defaults(ppd, sg); | |
708 | } | |
709 | ||
710 | ||
711 | /* | |
712 | * 'ppd_mark_choices()' - Mark one or more option choices from a string. | |
713 | */ | |
714 | ||
715 | static void | |
716 | ppd_mark_choices(ppd_file_t *ppd, /* I - PPD file */ | |
717 | const char *s) /* I - "*Option Choice ..." string */ | |
718 | { | |
719 | int i, /* Looping var */ | |
720 | num_options; /* Number of options */ | |
721 | cups_option_t *options, /* Options */ | |
722 | *option; /* Current option */ | |
723 | ||
724 | ||
725 | if (!options) | |
726 | return; | |
727 | ||
728 | options = NULL; | |
729 | num_options = _ppdParseOptions(s, 0, &options); | |
730 | ||
731 | for (i = num_options, option = options; i > 0; i --, option ++) | |
732 | ppd_mark_option(ppd, option->name, option->value); | |
733 | ||
734 | cupsFreeOptions(num_options, options); | |
735 | } | |
736 | ||
737 | ||
738 | /* | |
739 | * 'ppd_mark_option()' - Quick mark an option without checking for conflicts. | |
740 | */ | |
741 | ||
742 | static void | |
743 | ppd_mark_option(ppd_file_t *ppd, /* I - PPD file */ | |
744 | const char *option, /* I - Option name */ | |
745 | const char *choice) /* I - Choice name */ | |
746 | { | |
747 | int i, j; /* Looping vars */ | |
748 | ppd_option_t *o; /* Option pointer */ | |
749 | ppd_choice_t *c, /* Choice pointer */ | |
750 | *oldc, /* Old choice pointer */ | |
751 | key; /* Search key for choice */ | |
752 | struct lconv *loc; /* Locale data */ | |
753 | ||
754 | ||
755 | DEBUG_printf(("ppd_mark_option(ppd=%p, option=\"%s\", choice=\"%s\")\n", | |
756 | ppd, option, choice)); | |
757 | ||
fa73b229 | 758 | /* |
759 | * AP_D_InputSlot is the "default input slot" on MacOS X, and setting | |
760 | * it clears the regular InputSlot choices... | |
761 | */ | |
ef416fc2 | 762 | |
fa73b229 | 763 | if (!strcasecmp(option, "AP_D_InputSlot")) |
764 | { | |
765 | if ((o = ppdFindOption(ppd, "InputSlot")) != NULL) | |
b94498cf | 766 | { |
767 | key.option = o; | |
768 | if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) | |
769 | { | |
770 | oldc->marked = 0; | |
771 | cupsArrayRemove(ppd->marked, oldc); | |
772 | } | |
773 | } | |
ef416fc2 | 774 | } |
775 | ||
fa73b229 | 776 | /* |
777 | * Check for custom options... | |
778 | */ | |
779 | ||
ef416fc2 | 780 | if ((o = ppdFindOption(ppd, option)) == NULL) |
66ab9486 | 781 | return; |
ef416fc2 | 782 | |
757d2cad | 783 | loc = localeconv(); |
ef416fc2 | 784 | |
b423cd4c | 785 | if (!strncasecmp(choice, "Custom.", 7)) |
ef416fc2 | 786 | { |
787 | /* | |
fa73b229 | 788 | * Handle a custom option... |
ef416fc2 | 789 | */ |
790 | ||
fa73b229 | 791 | if ((c = ppdFindChoice(o, "Custom")) == NULL) |
66ab9486 | 792 | return; |
ef416fc2 | 793 | |
fa73b229 | 794 | if (!strcasecmp(option, "PageSize")) |
795 | { | |
796 | /* | |
797 | * Handle custom page sizes... | |
798 | */ | |
ef416fc2 | 799 | |
fa73b229 | 800 | ppdPageSize(ppd, choice); |
801 | } | |
802 | else | |
ef416fc2 | 803 | { |
804 | /* | |
fa73b229 | 805 | * Handle other custom options... |
ef416fc2 | 806 | */ |
807 | ||
fa73b229 | 808 | ppd_coption_t *coption; /* Custom option */ |
809 | ppd_cparam_t *cparam; /* Custom parameter */ | |
757d2cad | 810 | char *units; /* Custom points units */ |
fa73b229 | 811 | |
8ca02f3c | 812 | |
fa73b229 | 813 | if ((coption = ppdFindCustomOption(ppd, option)) != NULL) |
ef416fc2 | 814 | { |
fa73b229 | 815 | if ((cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params)) == NULL) |
66ab9486 | 816 | return; |
fa73b229 | 817 | |
818 | switch (cparam->type) | |
819 | { | |
820 | case PPD_CUSTOM_CURVE : | |
821 | case PPD_CUSTOM_INVCURVE : | |
822 | case PPD_CUSTOM_REAL : | |
b86bc4cf | 823 | cparam->current.custom_real = (float)_cupsStrScand(choice + 7, |
824 | NULL, loc); | |
fa73b229 | 825 | break; |
826 | ||
827 | case PPD_CUSTOM_POINTS : | |
b86bc4cf | 828 | cparam->current.custom_points = (float)_cupsStrScand(choice + 7, |
829 | &units, | |
830 | loc); | |
757d2cad | 831 | |
832 | if (units) | |
833 | { | |
834 | if (!strcasecmp(units, "cm")) | |
b86bc4cf | 835 | cparam->current.custom_points *= 72.0f / 2.54f; |
757d2cad | 836 | else if (!strcasecmp(units, "mm")) |
b86bc4cf | 837 | cparam->current.custom_points *= 72.0f / 25.4f; |
757d2cad | 838 | else if (!strcasecmp(units, "m")) |
b86bc4cf | 839 | cparam->current.custom_points *= 72.0f / 0.0254f; |
757d2cad | 840 | else if (!strcasecmp(units, "in")) |
b86bc4cf | 841 | cparam->current.custom_points *= 72.0f; |
757d2cad | 842 | else if (!strcasecmp(units, "ft")) |
b86bc4cf | 843 | cparam->current.custom_points *= 12.0f * 72.0f; |
757d2cad | 844 | } |
fa73b229 | 845 | break; |
846 | ||
847 | case PPD_CUSTOM_INT : | |
848 | cparam->current.custom_int = atoi(choice + 7); | |
849 | break; | |
850 | ||
851 | case PPD_CUSTOM_PASSCODE : | |
852 | case PPD_CUSTOM_PASSWORD : | |
853 | case PPD_CUSTOM_STRING : | |
854 | if (cparam->current.custom_string) | |
2e4ff8af | 855 | _cupsStrFree(cparam->current.custom_string); |
fa73b229 | 856 | |
2e4ff8af | 857 | cparam->current.custom_string = _cupsStrAlloc(choice + 7); |
fa73b229 | 858 | break; |
859 | } | |
ef416fc2 | 860 | } |
861 | } | |
8ca02f3c | 862 | |
863 | /* | |
864 | * Make sure that we keep the option marked below... | |
865 | */ | |
866 | ||
867 | choice = "Custom"; | |
fa73b229 | 868 | } |
b423cd4c | 869 | else if (choice[0] == '{') |
870 | { | |
871 | /* | |
872 | * Handle multi-value custom options... | |
873 | */ | |
874 | ||
875 | ppd_coption_t *coption; /* Custom option */ | |
876 | ppd_cparam_t *cparam; /* Custom parameter */ | |
757d2cad | 877 | char *units; /* Custom points units */ |
b423cd4c | 878 | int num_vals; /* Number of values */ |
879 | cups_option_t *vals, /* Values */ | |
880 | *val; /* Value */ | |
881 | ||
882 | ||
883 | if ((c = ppdFindChoice(o, "Custom")) == NULL) | |
66ab9486 | 884 | return; |
b423cd4c | 885 | |
886 | if ((coption = ppdFindCustomOption(ppd, option)) != NULL) | |
887 | { | |
888 | num_vals = cupsParseOptions(choice + 1, 0, &vals); | |
889 | ||
890 | for (i = 0, val = vals; i < num_vals; i ++, val ++) | |
891 | { | |
892 | if ((cparam = ppdFindCustomParam(coption, val->name)) == NULL) | |
893 | continue; | |
894 | ||
895 | switch (cparam->type) | |
896 | { | |
897 | case PPD_CUSTOM_CURVE : | |
898 | case PPD_CUSTOM_INVCURVE : | |
899 | case PPD_CUSTOM_REAL : | |
b86bc4cf | 900 | cparam->current.custom_real = (float)_cupsStrScand(val->value, |
901 | NULL, loc); | |
b423cd4c | 902 | break; |
903 | ||
904 | case PPD_CUSTOM_POINTS : | |
b86bc4cf | 905 | cparam->current.custom_points = (float)_cupsStrScand(val->value, |
906 | &units, | |
907 | loc); | |
757d2cad | 908 | |
909 | if (units) | |
910 | { | |
911 | if (!strcasecmp(units, "cm")) | |
b86bc4cf | 912 | cparam->current.custom_points *= 72.0f / 2.54f; |
757d2cad | 913 | else if (!strcasecmp(units, "mm")) |
b86bc4cf | 914 | cparam->current.custom_points *= 72.0f / 25.4f; |
757d2cad | 915 | else if (!strcasecmp(units, "m")) |
b86bc4cf | 916 | cparam->current.custom_points *= 72.0f / 0.0254f; |
757d2cad | 917 | else if (!strcasecmp(units, "in")) |
b86bc4cf | 918 | cparam->current.custom_points *= 72.0f; |
757d2cad | 919 | else if (!strcasecmp(units, "ft")) |
b86bc4cf | 920 | cparam->current.custom_points *= 12.0f * 72.0f; |
757d2cad | 921 | } |
b423cd4c | 922 | break; |
923 | ||
924 | case PPD_CUSTOM_INT : | |
925 | cparam->current.custom_int = atoi(val->value); | |
926 | break; | |
927 | ||
928 | case PPD_CUSTOM_PASSCODE : | |
929 | case PPD_CUSTOM_PASSWORD : | |
930 | case PPD_CUSTOM_STRING : | |
931 | if (cparam->current.custom_string) | |
2e4ff8af | 932 | _cupsStrFree(cparam->current.custom_string); |
b423cd4c | 933 | |
2e4ff8af | 934 | cparam->current.custom_string = _cupsStrAlloc(val->value); |
b423cd4c | 935 | break; |
936 | } | |
937 | } | |
938 | ||
939 | cupsFreeOptions(num_vals, vals); | |
940 | } | |
941 | } | |
fa73b229 | 942 | else |
943 | { | |
944 | for (i = o->num_choices, c = o->choices; i > 0; i --, c ++) | |
945 | if (!strcasecmp(c->choice, choice)) | |
946 | break; | |
ef416fc2 | 947 | |
fa73b229 | 948 | if (!i) |
66ab9486 | 949 | return; |
fa73b229 | 950 | } |
ef416fc2 | 951 | |
fa73b229 | 952 | /* |
953 | * Option found; mark it and then handle unmarking any other options. | |
954 | */ | |
955 | ||
fa73b229 | 956 | if (o->ui != PPD_UI_PICKMANY) |
957 | { | |
958 | /* | |
959 | * Unmark all other choices... | |
960 | */ | |
961 | ||
b94498cf | 962 | if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, c)) != NULL) |
963 | { | |
964 | oldc->marked = 0; | |
965 | cupsArrayRemove(ppd->marked, oldc); | |
966 | } | |
967 | ||
968 | if (!strcasecmp(option, "PageSize") || !strcasecmp(option, "PageRegion")) | |
969 | { | |
970 | /* | |
971 | * Mark current page size... | |
972 | */ | |
973 | ||
974 | for (j = 0; j < ppd->num_sizes; j ++) | |
975 | ppd->sizes[j].marked = !strcasecmp(ppd->sizes[j].name, | |
976 | choice); | |
977 | ||
978 | /* | |
979 | * Unmark the current PageSize or PageRegion setting, as | |
980 | * appropriate... | |
981 | */ | |
982 | ||
983 | if (!strcasecmp(option, "PageSize")) | |
fa73b229 | 984 | { |
b94498cf | 985 | if ((o = ppdFindOption(ppd, "PageRegion")) != NULL) |
986 | { | |
987 | key.option = o; | |
988 | if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) | |
989 | { | |
990 | oldc->marked = 0; | |
991 | cupsArrayRemove(ppd->marked, oldc); | |
992 | } | |
993 | } | |
994 | } | |
995 | else | |
996 | { | |
997 | if ((o = ppdFindOption(ppd, "PageSize")) != NULL) | |
998 | { | |
999 | key.option = o; | |
1000 | if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) | |
1001 | { | |
1002 | oldc->marked = 0; | |
1003 | cupsArrayRemove(ppd->marked, oldc); | |
1004 | } | |
1005 | } | |
1006 | } | |
1007 | } | |
1008 | else if (!strcasecmp(option, "InputSlot")) | |
1009 | { | |
1010 | /* | |
355e94dc | 1011 | * Unmark ManualFeed option... |
b94498cf | 1012 | */ |
fa73b229 | 1013 | |
b94498cf | 1014 | if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL) |
1015 | { | |
1016 | key.option = o; | |
1017 | if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) | |
1018 | { | |
1019 | oldc->marked = 0; | |
1020 | cupsArrayRemove(ppd->marked, oldc); | |
1021 | } | |
1022 | } | |
1023 | } | |
1024 | else if (!strcasecmp(option, "ManualFeed") && | |
1025 | !strcasecmp(choice, "True")) | |
1026 | { | |
1027 | /* | |
1028 | * Unmark InputSlot option... | |
1029 | */ | |
fa73b229 | 1030 | |
b94498cf | 1031 | if ((o = ppdFindOption(ppd, "InputSlot")) != NULL) |
1032 | { | |
1033 | key.option = o; | |
1034 | if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) | |
1035 | { | |
1036 | oldc->marked = 0; | |
1037 | cupsArrayRemove(ppd->marked, oldc); | |
1038 | } | |
fa73b229 | 1039 | } |
b94498cf | 1040 | } |
ef416fc2 | 1041 | } |
1042 | ||
b94498cf | 1043 | c->marked = 1; |
1044 | ||
1045 | cupsArrayAdd(ppd->marked, c); | |
5a738aea MS |
1046 | } |
1047 | ||
1048 | ||
1049 | /* | |
66ab9486 | 1050 | * End of "$Id: mark.c 7757 2008-07-18 16:43:43Z mike $". |
ef416fc2 | 1051 | */ |