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