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