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