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