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