]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/mark.c
Merge changes from CUPS 1.5svn-r9602.
[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 (!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"))
261 ppd_mark_option(ppd, cache->sides_option, cache->sides_1sided);
262 else if (!strcmp(sides, "two-sided-long-edge"))
263 ppd_mark_option(ppd, cache->sides_option, cache->sides_2sided_long);
264 else if (!strcmp(sides, "two-sided-short-edge"))
265 ppd_mark_option(ppd, cache->sides_option, cache->sides_2sided_short);
266 }
267 }
268
269 /*
270 * Mark other options...
271 */
272
273 for (i = num_options, optptr = options; i > 0; i --, optptr ++)
274 if (!strcasecmp(optptr->name, "media") ||
275 !strcasecmp(optptr->name, "output-bin") ||
276 !strcasecmp(optptr->name, "output-mode") ||
277 !strcasecmp(optptr->name, "print-quality") ||
278 !strcasecmp(optptr->name, "sides"))
279 continue;
280 else if (!strcasecmp(optptr->name, "resolution") ||
281 !strcasecmp(optptr->name, "printer-resolution"))
282 {
283 ppd_mark_option(ppd, "Resolution", optptr->value);
284 ppd_mark_option(ppd, "SetResolution", optptr->value);
285 /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */
286 ppd_mark_option(ppd, "JCLResolution", optptr->value);
287 /* HP */
288 ppd_mark_option(ppd, "CNRes_PGP", optptr->value);
289 /* Canon */
290 }
291 else if (!strcasecmp(optptr->name, "multiple-document-handling"))
292 {
293 if (!cupsGetOption("Collate", num_options, options) &&
294 ppdFindOption(ppd, "Collate"))
295 {
296 if (strcasecmp(optptr->value, "separate-documents-uncollated-copies"))
297 ppd_mark_option(ppd, "Collate", "True");
298 else
299 ppd_mark_option(ppd, "Collate", "False");
300 }
301 }
302 else if (!strcasecmp(optptr->name, "finishings"))
303 {
304 /*
305 * Lookup cupsIPPFinishings attributes for each value...
306 */
307
308 for (ptr = optptr->value; *ptr;)
309 {
310 /*
311 * Get the next finishings number...
312 */
313
314 if (!isdigit(*ptr & 255))
315 break;
316
317 if ((j = strtol(ptr, &ptr, 10)) < 3)
318 break;
319
320 /*
321 * Skip separator as needed...
322 */
323
324 if (*ptr == ',')
325 ptr ++;
326
327 /*
328 * Look it up in the PPD file...
329 */
330
331 sprintf(s, "%d", j);
332
333 if ((attr = ppdFindAttr(ppd, "cupsIPPFinishings", s)) == NULL)
334 continue;
335
336 /*
337 * Apply "*Option Choice" settings from the attribute value...
338 */
339
340 ppd_mark_choices(ppd, attr->value);
341 }
342 }
343 else if (!strcasecmp(optptr->name, "APPrinterPreset"))
344 {
345 /*
346 * Lookup APPrinterPreset value...
347 */
348
349 if ((attr = ppdFindAttr(ppd, "APPrinterPreset", optptr->value)) != NULL)
350 {
351 /*
352 * Apply "*Option Choice" settings from the attribute value...
353 */
354
355 ppd_mark_choices(ppd, attr->value);
356 }
357 }
358 else if (!strcasecmp(optptr->name, "mirror"))
359 ppd_mark_option(ppd, "MirrorPrint", optptr->value);
360 else
361 ppd_mark_option(ppd, optptr->name, optptr->value);
362
363 ppd_debug_marked(ppd, "After...");
364
365 return (ppdConflicts(ppd) > 0);
366 }
367
368
369 /*
370 * 'ppdFindChoice()' - Return a pointer to an option choice.
371 */
372
373 ppd_choice_t * /* O - Choice pointer or @code NULL@ */
374 ppdFindChoice(ppd_option_t *o, /* I - Pointer to option */
375 const char *choice) /* I - Name of choice */
376 {
377 int i; /* Looping var */
378 ppd_choice_t *c; /* Current choice */
379
380
381 if (!o || !choice)
382 return (NULL);
383
384 if (choice[0] == '{' || !strncasecmp(choice, "Custom.", 7))
385 choice = "Custom";
386
387 for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
388 if (!strcasecmp(c->choice, choice))
389 return (c);
390
391 return (NULL);
392 }
393
394
395 /*
396 * 'ppdFindMarkedChoice()' - Return the marked choice for the specified option.
397 */
398
399 ppd_choice_t * /* O - Pointer to choice or @code NULL@ */
400 ppdFindMarkedChoice(ppd_file_t *ppd, /* I - PPD file */
401 const char *option) /* I - Keyword/option name */
402 {
403 ppd_choice_t key, /* Search key for choice */
404 *marked; /* Marked choice */
405
406
407 DEBUG_printf(("2ppdFindMarkedChoice(ppd=%p, option=\"%s\")", ppd, option));
408
409 if ((key.option = ppdFindOption(ppd, option)) == NULL)
410 {
411 DEBUG_puts("3ppdFindMarkedChoice: Option not found, returning NULL");
412 return (NULL);
413 }
414
415 marked = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key);
416
417 DEBUG_printf(("3ppdFindMarkedChoice: Returning %p(%s)...", marked,
418 marked ? marked->choice : "NULL"));
419
420 return (marked);
421 }
422
423
424 /*
425 * 'ppdFindOption()' - Return a pointer to the specified option.
426 */
427
428 ppd_option_t * /* O - Pointer to option or @code NULL@ */
429 ppdFindOption(ppd_file_t *ppd, /* I - PPD file data */
430 const char *option) /* I - Option/Keyword name */
431 {
432 /*
433 * Range check input...
434 */
435
436 if (!ppd || !option)
437 return (NULL);
438
439 if (ppd->options)
440 {
441 /*
442 * Search in the array...
443 */
444
445 ppd_option_t key; /* Option search key */
446
447
448 strlcpy(key.keyword, option, sizeof(key.keyword));
449
450 return ((ppd_option_t *)cupsArrayFind(ppd->options, &key));
451 }
452 else
453 {
454 /*
455 * Search in each group...
456 */
457
458 int i, j; /* Looping vars */
459 ppd_group_t *group; /* Current group */
460 ppd_option_t *optptr; /* Current option */
461
462
463 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
464 for (j = group->num_options, optptr = group->options;
465 j > 0;
466 j --, optptr ++)
467 if (!strcasecmp(optptr->keyword, option))
468 return (optptr);
469
470 return (NULL);
471 }
472 }
473
474
475 /*
476 * 'ppdIsMarked()' - Check to see if an option is marked.
477 */
478
479 int /* O - Non-zero if option is marked */
480 ppdIsMarked(ppd_file_t *ppd, /* I - PPD file data */
481 const char *option, /* I - Option/Keyword name */
482 const char *choice) /* I - Choice name */
483 {
484 ppd_choice_t key, /* Search key */
485 *c; /* Choice pointer */
486
487
488 if (!ppd)
489 return (0);
490
491 if ((key.option = ppdFindOption(ppd, option)) == NULL)
492 return (0);
493
494 if ((c = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) == NULL)
495 return (0);
496
497 return (!strcmp(c->choice, choice));
498 }
499
500
501 /*
502 * 'ppdMarkDefaults()' - Mark all default options in the PPD file.
503 */
504
505 void
506 ppdMarkDefaults(ppd_file_t *ppd) /* I - PPD file record */
507 {
508 int i; /* Looping variables */
509 ppd_group_t *g; /* Current group */
510 ppd_choice_t *c; /* Current choice */
511
512
513 if (!ppd)
514 return;
515
516 /*
517 * Clean out the marked array...
518 */
519
520 for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
521 c;
522 c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
523 {
524 cupsArrayRemove(ppd->marked, c);
525 c->marked = 0;
526 }
527
528 /*
529 * Then repopulate it with the defaults...
530 */
531
532 for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++)
533 ppd_defaults(ppd, g);
534 }
535
536
537 /*
538 * 'ppdMarkOption()' - Mark an option in a PPD file and return the number of
539 * conflicts.
540 */
541
542 int /* O - Number of conflicts */
543 ppdMarkOption(ppd_file_t *ppd, /* I - PPD file record */
544 const char *option, /* I - Keyword */
545 const char *choice) /* I - Option name */
546 {
547 DEBUG_printf(("ppdMarkOption(ppd=%p, option=\"%s\", choice=\"%s\")",
548 ppd, option, choice));
549
550 /*
551 * Range check input...
552 */
553
554 if (!ppd || !option || !choice)
555 return (0);
556
557 /*
558 * Mark the option...
559 */
560
561 ppd_mark_option(ppd, option, choice);
562
563 /*
564 * Return the number of conflicts...
565 */
566
567 return (ppdConflicts(ppd));
568 }
569
570
571 /*
572 * 'ppdFirstOption()' - Return the first option in the PPD file.
573 *
574 * Options are returned from all groups in ascending alphanumeric order.
575 *
576 * @since CUPS 1.2/Mac OS X 10.5@
577 */
578
579 ppd_option_t * /* O - First option or @code NULL@ */
580 ppdFirstOption(ppd_file_t *ppd) /* I - PPD file */
581 {
582 if (!ppd)
583 return (NULL);
584 else
585 return ((ppd_option_t *)cupsArrayFirst(ppd->options));
586 }
587
588
589 /*
590 * 'ppdNextOption()' - Return the next option in the PPD file.
591 *
592 * Options are returned from all groups in ascending alphanumeric order.
593 *
594 * @since CUPS 1.2/Mac OS X 10.5@
595 */
596
597 ppd_option_t * /* O - Next option or @code NULL@ */
598 ppdNextOption(ppd_file_t *ppd) /* I - PPD file */
599 {
600 if (!ppd)
601 return (NULL);
602 else
603 return ((ppd_option_t *)cupsArrayNext(ppd->options));
604 }
605
606
607 /*
608 * '_ppdParseOptions()' - Parse options from a PPD file.
609 *
610 * This function looks for strings of the form:
611 *
612 * *option choice ... *optionN choiceN
613 * property value ... propertyN valueN
614 *
615 * It stops when it finds a string that doesn't match this format.
616 */
617
618 int /* O - Number of options */
619 _ppdParseOptions(
620 const char *s, /* I - String to parse */
621 int num_options, /* I - Number of options */
622 cups_option_t **options, /* IO - Options */
623 _ppd_parse_t which) /* I - What to parse */
624 {
625 char option[PPD_MAX_NAME * 2 + 1], /* Current option/property */
626 choice[PPD_MAX_NAME], /* Current choice/value */
627 *ptr; /* Pointer into option or choice */
628
629
630 if (!s)
631 return (num_options);
632
633 /*
634 * Read all of the "*Option Choice" and "property value" pairs from the
635 * string, add them to an options array as we go...
636 */
637
638 while (*s)
639 {
640 /*
641 * Skip leading whitespace...
642 */
643
644 while (_cups_isspace(*s))
645 s ++;
646
647 /*
648 * Get the option/property name...
649 */
650
651 ptr = option;
652 while (*s && !_cups_isspace(*s) && ptr < (option + sizeof(option) - 1))
653 *ptr++ = *s++;
654
655 if (ptr == s || !_cups_isspace(*s))
656 break;
657
658 *ptr = '\0';
659
660 /*
661 * Get the choice...
662 */
663
664 while (_cups_isspace(*s))
665 s ++;
666
667 if (!*s)
668 break;
669
670 ptr = choice;
671 while (*s && !_cups_isspace(*s) && ptr < (choice + sizeof(choice) - 1))
672 *ptr++ = *s++;
673
674 if (*s && !_cups_isspace(*s))
675 break;
676
677 *ptr = '\0';
678
679 /*
680 * Add it to the options array...
681 */
682
683 if (option[0] == '*' && which != _PPD_PARSE_PROPERTIES)
684 num_options = cupsAddOption(option + 1, choice, num_options, options);
685 else if (option[0] != '*' && which != _PPD_PARSE_OPTIONS)
686 num_options = cupsAddOption(option, choice, num_options, options);
687 }
688
689 return (num_options);
690 }
691
692
693 #ifdef DEBUG
694 /*
695 * 'ppd_debug_marked()' - Output the marked array to stdout...
696 */
697
698 static void
699 ppd_debug_marked(ppd_file_t *ppd, /* I - PPD file data */
700 const char *title) /* I - Title for list */
701 {
702 ppd_choice_t *c; /* Current choice */
703
704
705 DEBUG_printf(("2cupsMarkOptions: %s", title));
706
707 for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
708 c;
709 c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
710 DEBUG_printf(("2cupsMarkOptions: %s=%s", c->option->keyword, c->choice));
711 }
712 #endif /* DEBUG */
713
714
715 /*
716 * 'ppd_defaults()' - Set the defaults for this group and all sub-groups.
717 */
718
719 static void
720 ppd_defaults(ppd_file_t *ppd, /* I - PPD file */
721 ppd_group_t *g) /* I - Group to default */
722 {
723 int i; /* Looping var */
724 ppd_option_t *o; /* Current option */
725 ppd_group_t *sg; /* Current sub-group */
726
727
728 for (i = g->num_options, o = g->options; i > 0; i --, o ++)
729 if (strcasecmp(o->keyword, "PageRegion") != 0)
730 ppdMarkOption(ppd, o->keyword, o->defchoice);
731
732 for (i = g->num_subgroups, sg = g->subgroups; i > 0; i --, sg ++)
733 ppd_defaults(ppd, sg);
734 }
735
736
737 /*
738 * 'ppd_mark_choices()' - Mark one or more option choices from a string.
739 */
740
741 static void
742 ppd_mark_choices(ppd_file_t *ppd, /* I - PPD file */
743 const char *s) /* I - "*Option Choice ..." string */
744 {
745 int i, /* Looping var */
746 num_options; /* Number of options */
747 cups_option_t *options, /* Options */
748 *option; /* Current option */
749
750
751 if (!s)
752 return;
753
754 options = NULL;
755 num_options = _ppdParseOptions(s, 0, &options, 0);
756
757 for (i = num_options, option = options; i > 0; i --, option ++)
758 ppd_mark_option(ppd, option->name, option->value);
759
760 cupsFreeOptions(num_options, options);
761 }
762
763
764 /*
765 * 'ppd_mark_option()' - Quick mark an option without checking for conflicts.
766 */
767
768 static void
769 ppd_mark_option(ppd_file_t *ppd, /* I - PPD file */
770 const char *option, /* I - Option name */
771 const char *choice) /* I - Choice name */
772 {
773 int i, j; /* Looping vars */
774 ppd_option_t *o; /* Option pointer */
775 ppd_choice_t *c, /* Choice pointer */
776 *oldc, /* Old choice pointer */
777 key; /* Search key for choice */
778 struct lconv *loc; /* Locale data */
779
780
781 DEBUG_printf(("7ppd_mark_option(ppd=%p, option=\"%s\", choice=\"%s\")",
782 ppd, option, choice));
783
784 /*
785 * AP_D_InputSlot is the "default input slot" on MacOS X, and setting
786 * it clears the regular InputSlot choices...
787 */
788
789 if (!strcasecmp(option, "AP_D_InputSlot"))
790 {
791 cupsArraySave(ppd->options);
792
793 if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
794 {
795 key.option = o;
796 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
797 {
798 oldc->marked = 0;
799 cupsArrayRemove(ppd->marked, oldc);
800 }
801 }
802
803 cupsArrayRestore(ppd->options);
804 }
805
806 /*
807 * Check for custom options...
808 */
809
810 cupsArraySave(ppd->options);
811
812 o = ppdFindOption(ppd, option);
813
814 cupsArrayRestore(ppd->options);
815
816 if (!o)
817 return;
818
819 loc = localeconv();
820
821 if (!strncasecmp(choice, "Custom.", 7))
822 {
823 /*
824 * Handle a custom option...
825 */
826
827 if ((c = ppdFindChoice(o, "Custom")) == NULL)
828 return;
829
830 if (!strcasecmp(option, "PageSize"))
831 {
832 /*
833 * Handle custom page sizes...
834 */
835
836 ppdPageSize(ppd, choice);
837 }
838 else
839 {
840 /*
841 * Handle other custom options...
842 */
843
844 ppd_coption_t *coption; /* Custom option */
845 ppd_cparam_t *cparam; /* Custom parameter */
846 char *units; /* Custom points units */
847
848
849 if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
850 {
851 if ((cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params)) == NULL)
852 return;
853
854 switch (cparam->type)
855 {
856 case PPD_CUSTOM_CURVE :
857 case PPD_CUSTOM_INVCURVE :
858 case PPD_CUSTOM_REAL :
859 cparam->current.custom_real = (float)_cupsStrScand(choice + 7,
860 NULL, loc);
861 break;
862
863 case PPD_CUSTOM_POINTS :
864 cparam->current.custom_points = (float)_cupsStrScand(choice + 7,
865 &units,
866 loc);
867
868 if (units)
869 {
870 if (!strcasecmp(units, "cm"))
871 cparam->current.custom_points *= 72.0f / 2.54f;
872 else if (!strcasecmp(units, "mm"))
873 cparam->current.custom_points *= 72.0f / 25.4f;
874 else if (!strcasecmp(units, "m"))
875 cparam->current.custom_points *= 72.0f / 0.0254f;
876 else if (!strcasecmp(units, "in"))
877 cparam->current.custom_points *= 72.0f;
878 else if (!strcasecmp(units, "ft"))
879 cparam->current.custom_points *= 12.0f * 72.0f;
880 }
881 break;
882
883 case PPD_CUSTOM_INT :
884 cparam->current.custom_int = atoi(choice + 7);
885 break;
886
887 case PPD_CUSTOM_PASSCODE :
888 case PPD_CUSTOM_PASSWORD :
889 case PPD_CUSTOM_STRING :
890 if (cparam->current.custom_string)
891 _cupsStrFree(cparam->current.custom_string);
892
893 cparam->current.custom_string = _cupsStrAlloc(choice + 7);
894 break;
895 }
896 }
897 }
898
899 /*
900 * Make sure that we keep the option marked below...
901 */
902
903 choice = "Custom";
904 }
905 else if (choice[0] == '{')
906 {
907 /*
908 * Handle multi-value custom options...
909 */
910
911 ppd_coption_t *coption; /* Custom option */
912 ppd_cparam_t *cparam; /* Custom parameter */
913 char *units; /* Custom points units */
914 int num_vals; /* Number of values */
915 cups_option_t *vals, /* Values */
916 *val; /* Value */
917
918
919 if ((c = ppdFindChoice(o, "Custom")) == NULL)
920 return;
921
922 if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
923 {
924 num_vals = cupsParseOptions(choice, 0, &vals);
925
926 for (i = 0, val = vals; i < num_vals; i ++, val ++)
927 {
928 if ((cparam = ppdFindCustomParam(coption, val->name)) == NULL)
929 continue;
930
931 switch (cparam->type)
932 {
933 case PPD_CUSTOM_CURVE :
934 case PPD_CUSTOM_INVCURVE :
935 case PPD_CUSTOM_REAL :
936 cparam->current.custom_real = (float)_cupsStrScand(val->value,
937 NULL, loc);
938 break;
939
940 case PPD_CUSTOM_POINTS :
941 cparam->current.custom_points = (float)_cupsStrScand(val->value,
942 &units,
943 loc);
944
945 if (units)
946 {
947 if (!strcasecmp(units, "cm"))
948 cparam->current.custom_points *= 72.0f / 2.54f;
949 else if (!strcasecmp(units, "mm"))
950 cparam->current.custom_points *= 72.0f / 25.4f;
951 else if (!strcasecmp(units, "m"))
952 cparam->current.custom_points *= 72.0f / 0.0254f;
953 else if (!strcasecmp(units, "in"))
954 cparam->current.custom_points *= 72.0f;
955 else if (!strcasecmp(units, "ft"))
956 cparam->current.custom_points *= 12.0f * 72.0f;
957 }
958 break;
959
960 case PPD_CUSTOM_INT :
961 cparam->current.custom_int = atoi(val->value);
962 break;
963
964 case PPD_CUSTOM_PASSCODE :
965 case PPD_CUSTOM_PASSWORD :
966 case PPD_CUSTOM_STRING :
967 if (cparam->current.custom_string)
968 _cupsStrFree(cparam->current.custom_string);
969
970 cparam->current.custom_string = _cupsStrRetain(val->value);
971 break;
972 }
973 }
974
975 cupsFreeOptions(num_vals, vals);
976 }
977 }
978 else
979 {
980 for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
981 if (!strcasecmp(c->choice, choice))
982 break;
983
984 if (!i)
985 return;
986 }
987
988 /*
989 * Option found; mark it and then handle unmarking any other options.
990 */
991
992 if (o->ui != PPD_UI_PICKMANY)
993 {
994 /*
995 * Unmark all other choices...
996 */
997
998 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, c)) != NULL)
999 {
1000 oldc->marked = 0;
1001 cupsArrayRemove(ppd->marked, oldc);
1002 }
1003
1004 if (!strcasecmp(option, "PageSize") || !strcasecmp(option, "PageRegion"))
1005 {
1006 /*
1007 * Mark current page size...
1008 */
1009
1010 for (j = 0; j < ppd->num_sizes; j ++)
1011 ppd->sizes[j].marked = !strcasecmp(ppd->sizes[j].name,
1012 choice);
1013
1014 /*
1015 * Unmark the current PageSize or PageRegion setting, as
1016 * appropriate...
1017 */
1018
1019 cupsArraySave(ppd->options);
1020
1021 if (!strcasecmp(option, "PageSize"))
1022 {
1023 if ((o = ppdFindOption(ppd, "PageRegion")) != NULL)
1024 {
1025 key.option = o;
1026 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
1027 {
1028 oldc->marked = 0;
1029 cupsArrayRemove(ppd->marked, oldc);
1030 }
1031 }
1032 }
1033 else
1034 {
1035 if ((o = ppdFindOption(ppd, "PageSize")) != NULL)
1036 {
1037 key.option = o;
1038 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
1039 {
1040 oldc->marked = 0;
1041 cupsArrayRemove(ppd->marked, oldc);
1042 }
1043 }
1044 }
1045
1046 cupsArrayRestore(ppd->options);
1047 }
1048 else if (!strcasecmp(option, "InputSlot"))
1049 {
1050 /*
1051 * Unmark ManualFeed option...
1052 */
1053
1054 cupsArraySave(ppd->options);
1055
1056 if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL)
1057 {
1058 key.option = o;
1059 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
1060 {
1061 oldc->marked = 0;
1062 cupsArrayRemove(ppd->marked, oldc);
1063 }
1064 }
1065
1066 cupsArrayRestore(ppd->options);
1067 }
1068 else if (!strcasecmp(option, "ManualFeed") &&
1069 !strcasecmp(choice, "True"))
1070 {
1071 /*
1072 * Unmark InputSlot option...
1073 */
1074
1075 cupsArraySave(ppd->options);
1076
1077 if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
1078 {
1079 key.option = o;
1080 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
1081 {
1082 oldc->marked = 0;
1083 cupsArrayRemove(ppd->marked, oldc);
1084 }
1085 }
1086
1087 cupsArrayRestore(ppd->options);
1088 }
1089 }
1090
1091 c->marked = 1;
1092
1093 cupsArrayAdd(ppd->marked, c);
1094 }
1095
1096
1097 /*
1098 * End of "$Id: mark.c 9042 2010-03-24 00:45:34Z mike $".
1099 */