]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/mark.c
Merge changes from CUPS 1.4svn-r7607.
[thirdparty/cups.git] / cups / mark.c
CommitLineData
ef416fc2 1/*
5a738aea 2 * "$Id: mark.c 7278 2008-01-31 01:23:09Z mike $"
ef416fc2 3 *
4 * Option marking routines for the Common UNIX Printing System (CUPS).
5 *
5a738aea 6 * Copyright 2007-2008 by Apple Inc.
b86bc4cf 7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
ef416fc2 8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 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/".
ef416fc2 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 *
5a738aea
MS
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.
ef416fc2 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.
5a738aea 27 * ppdIsMarked() - Check to see if an option is marked.
ef416fc2 28 * ppdMarkDefaults() - Mark all default options in the PPD file.
29 * ppdMarkOption() - Mark an option in a PPD file.
5a738aea
MS
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...
ef416fc2 33 * ppd_defaults() - Set the defaults for this group and all sub-groups.
5a738aea 34 * ppd_mark_choices() - Mark one or more option choices from a string.
ef416fc2 35 */
36
37/*
38 * Include necessary headers...
39 */
40
b423cd4c 41#include "cups.h"
ef416fc2 42#include "string.h"
43#include "debug.h"
44
45
46/*
47 * Local functions...
48 */
49
5a738aea
MS
50#ifdef DEBUG
51static void debug_marked(ppd_file_t *ppd, const char *title);
52#else
53# define debug_marked(ppd,title)
54#endif /* DEBUG */
ef416fc2 55static void ppd_defaults(ppd_file_t *ppd, ppd_group_t *g);
5a738aea 56static int ppd_mark_choices(ppd_file_t *ppd, const char *options);
ef416fc2 57
58
59/*
5a738aea
MS
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
67int /* O - 1 if conflicting */
68cupsMarkOptions(
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@.
ef416fc2 361 */
362
b94498cf 363int /* O - Number of conflicts found */
364ppdConflicts(ppd_file_t *ppd) /* I - PPD to check */
ef416fc2 365{
b94498cf 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 */
ef416fc2 372
373
2abf387c 374 if (!ppd)
ef416fc2 375 return (0);
376
377 /*
378 * Clear all conflicts...
379 */
380
381 conflicts = 0;
382
2abf387c 383 for (o1 = ppdFirstOption(ppd); o1; o1 = ppdNextOption(ppd))
384 o1->conflicted = 0;
ef416fc2 385
355e94dc
MS
386 cupsArraySave(ppd->marked);
387
ef416fc2 388 /*
389 * Loop through all of the UI constraints and flag any options
390 * that conflict...
391 */
392
b94498cf 393 for (i = ppd->num_consts, c = ppd->consts, o1 = o2 = NULL, c1 = c2 = NULL;
394 i > 0;
395 i --, c ++)
ef416fc2 396 {
397 /*
398 * Grab pointers to the first option...
399 */
400
b94498cf 401 if (!o1 || strcmp(c->option1, o1->keyword))
402 {
403 o1 = ppdFindOption(ppd, c->option1);
404 c1 = NULL;
405 }
ef416fc2 406
2abf387c 407 if (!o1)
ef416fc2 408 continue;
b94498cf 409 else if (c->choice1[0] && (!c1 || strcmp(c->choice1, c1->choice)))
ef416fc2 410 {
411 /*
412 * This constraint maps to a specific choice.
413 */
414
b94498cf 415 key.option = o1;
416
417 if ((c1 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
09a101d6 418 (!c1->marked || strcmp(c->choice1, c1->choice)))
b94498cf 419 c1 = NULL;
ef416fc2 420 }
b94498cf 421 else if (!c1)
ef416fc2 422 {
423 /*
424 * This constraint applies to any choice for this option.
425 */
426
b94498cf 427 key.option = o1;
ef416fc2 428
b94498cf 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")))
ef416fc2 432 c1 = NULL;
433 }
434
435 /*
436 * Grab pointers to the second option...
437 */
438
b94498cf 439 if (!o2 || strcmp(c->option2, o2->keyword))
440 {
441 o2 = ppdFindOption(ppd, c->option2);
442 c2 = NULL;
443 }
ef416fc2 444
2abf387c 445 if (!o2)
ef416fc2 446 continue;
b94498cf 447 else if (c->choice2[0] && (!c2 || strcmp(c->choice2, c2->choice)))
ef416fc2 448 {
449 /*
450 * This constraint maps to a specific choice.
451 */
452
b94498cf 453 key.option = o2;
454
455 if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
09a101d6 456 (!c2->marked || strcmp(c->choice2, c2->choice)))
b94498cf 457 c2 = NULL;
ef416fc2 458 }
b94498cf 459 else if (!c2)
ef416fc2 460 {
461 /*
462 * This constraint applies to any choice for this option.
463 */
464
b94498cf 465 key.option = o2;
ef416fc2 466
b94498cf 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")))
ef416fc2 470 c2 = NULL;
471 }
472
473 /*
474 * If both options are marked then there is a conflict...
475 */
476
2abf387c 477 if (c1 && c1->marked && c2 && c2->marked)
ef416fc2 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
355e94dc
MS
488 cupsArrayRestore(ppd->marked);
489
ef416fc2 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
5a738aea 502ppd_choice_t * /* O - Choice pointer or @code NULL@ */
ef416fc2 503ppdFindChoice(ppd_option_t *o, /* I - Pointer to option */
504 const char *choice) /* I - Name of choice */
505{
b94498cf 506 int i; /* Looping var */
507 ppd_choice_t *c; /* Current choice */
ef416fc2 508
509
bdd6c45b 510 if (!o || !choice)
ef416fc2 511 return (NULL);
512
bdd6c45b
MS
513 if (choice[0] == '{' || !strncasecmp(choice, "Custom.", 7))
514 choice = "Custom";
515
ef416fc2 516 for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
bdd6c45b 517 if (!strcasecmp(c->choice, choice))
ef416fc2 518 return (c);
519
520 return (NULL);
521}
522
523
524/*
525 * 'ppdFindMarkedChoice()' - Return the marked choice for the specified option.
526 */
527
5a738aea 528ppd_choice_t * /* O - Pointer to choice or @code NULL@ */
ef416fc2 529ppdFindMarkedChoice(ppd_file_t *ppd, /* I - PPD file */
530 const char *option) /* I - Keyword/option name */
531{
b94498cf 532 ppd_choice_t key; /* Search key for choice */
ef416fc2 533
534
b94498cf 535 if ((key.option = ppdFindOption(ppd, option)) == NULL)
ef416fc2 536 return (NULL);
537
b94498cf 538 return ((ppd_choice_t *)cupsArrayFind(ppd->marked, &key));
ef416fc2 539}
540
541
542/*
543 * 'ppdFindOption()' - Return a pointer to the specified option.
544 */
545
5a738aea 546ppd_option_t * /* O - Pointer to option or @code NULL@ */
ef416fc2 547ppdFindOption(ppd_file_t *ppd, /* I - PPD file data */
548 const char *option) /* I - Option/Keyword name */
549{
fa73b229 550 /*
551 * Range check input...
552 */
ef416fc2 553
fa73b229 554 if (!ppd || !option)
ef416fc2 555 return (NULL);
556
f301802f 557 if (ppd->options)
558 {
559 /*
560 * Search in the array...
561 */
562
563 ppd_option_t key; /* Option search key */
564
565
566 strlcpy(key.keyword, option, sizeof(key.keyword));
ef416fc2 567
f301802f 568 return ((ppd_option_t *)cupsArrayFind(ppd->options, &key));
569 }
570 else
571 {
572 /*
573 * Search in each group...
574 */
ef416fc2 575
f301802f 576 int i, j; /* Looping vars */
577 ppd_group_t *group; /* Current group */
578 ppd_option_t *optptr; /* Current option */
579
580
581 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
582 for (j = group->num_options, optptr = group->options;
583 j > 0;
584 j --, optptr ++)
585 if (!strcasecmp(optptr->keyword, option))
586 return (optptr);
587
588 return (NULL);
589 }
ef416fc2 590}
591
592
593/*
5a738aea 594 * 'ppdIsMarked()' - Check to see if an option is marked.
ef416fc2 595 */
596
b94498cf 597int /* O - Non-zero if option is marked */
598ppdIsMarked(ppd_file_t *ppd, /* I - PPD file data */
599 const char *option, /* I - Option/Keyword name */
600 const char *choice) /* I - Choice name */
ef416fc2 601{
b94498cf 602 ppd_choice_t key, /* Search key */
603 *c; /* Choice pointer */
ef416fc2 604
605
b94498cf 606 if (!ppd)
ef416fc2 607 return (0);
608
b94498cf 609 if ((key.option = ppdFindOption(ppd, option)) == NULL)
ef416fc2 610 return (0);
611
b94498cf 612 if ((c = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) == NULL)
ef416fc2 613 return (0);
614
b94498cf 615 return (!strcmp(c->choice, choice));
ef416fc2 616}
617
618
619/*
620 * 'ppdMarkDefaults()' - Mark all default options in the PPD file.
621 */
622
623void
b94498cf 624ppdMarkDefaults(ppd_file_t *ppd) /* I - PPD file record */
ef416fc2 625{
b94498cf 626 int i; /* Looping variables */
627 ppd_group_t *g; /* Current group */
628 ppd_choice_t *c; /* Current choice */
ef416fc2 629
630
b94498cf 631 if (!ppd)
ef416fc2 632 return;
633
b94498cf 634 /*
635 * Clean out the marked array...
636 */
637
638 for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
639 c;
640 c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
641 cupsArrayRemove(ppd->marked, c);
642
643 /*
644 * Then repopulate it with the defaults...
645 */
646
ef416fc2 647 for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++)
648 ppd_defaults(ppd, g);
649}
650
651
652/*
653 * 'ppdMarkOption()' - Mark an option in a PPD file.
ef416fc2 654 */
655
656int /* O - Number of conflicts */
657ppdMarkOption(ppd_file_t *ppd, /* I - PPD file record */
658 const char *option, /* I - Keyword */
659 const char *choice) /* I - Option name */
660{
fa73b229 661 int i, j; /* Looping vars */
662 ppd_option_t *o; /* Option pointer */
b94498cf 663 ppd_choice_t *c, /* Choice pointer */
664 *oldc, /* Old choice pointer */
665 key; /* Search key for choice */
757d2cad 666 struct lconv *loc; /* Locale data */
ef416fc2 667
668
bd7854cb 669 DEBUG_printf(("ppdMarkOption(ppd=%p, option=\"%s\", choice=\"%s\")\n",
670 ppd, option, choice));
671
fa73b229 672 /*
673 * Range check input...
674 */
675
676 if (!ppd || !option || !choice)
ef416fc2 677 return (0);
678
fa73b229 679 /*
680 * AP_D_InputSlot is the "default input slot" on MacOS X, and setting
681 * it clears the regular InputSlot choices...
682 */
ef416fc2 683
fa73b229 684 if (!strcasecmp(option, "AP_D_InputSlot"))
685 {
686 if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
b94498cf 687 {
688 key.option = o;
689 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
690 {
691 oldc->marked = 0;
692 cupsArrayRemove(ppd->marked, oldc);
693 }
694 }
ef416fc2 695 }
696
fa73b229 697 /*
698 * Check for custom options...
699 */
700
ef416fc2 701 if ((o = ppdFindOption(ppd, option)) == NULL)
702 return (0);
703
757d2cad 704 loc = localeconv();
ef416fc2 705
b423cd4c 706 if (!strncasecmp(choice, "Custom.", 7))
ef416fc2 707 {
708 /*
fa73b229 709 * Handle a custom option...
ef416fc2 710 */
711
fa73b229 712 if ((c = ppdFindChoice(o, "Custom")) == NULL)
713 return (0);
ef416fc2 714
fa73b229 715 if (!strcasecmp(option, "PageSize"))
716 {
717 /*
718 * Handle custom page sizes...
719 */
ef416fc2 720
fa73b229 721 ppdPageSize(ppd, choice);
722 }
723 else
ef416fc2 724 {
725 /*
fa73b229 726 * Handle other custom options...
ef416fc2 727 */
728
fa73b229 729 ppd_coption_t *coption; /* Custom option */
730 ppd_cparam_t *cparam; /* Custom parameter */
757d2cad 731 char *units; /* Custom points units */
fa73b229 732
8ca02f3c 733
fa73b229 734 if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
ef416fc2 735 {
fa73b229 736 if ((cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params)) == NULL)
737 return (0);
738
739 switch (cparam->type)
740 {
741 case PPD_CUSTOM_CURVE :
742 case PPD_CUSTOM_INVCURVE :
743 case PPD_CUSTOM_REAL :
b86bc4cf 744 cparam->current.custom_real = (float)_cupsStrScand(choice + 7,
745 NULL, loc);
fa73b229 746 break;
747
748 case PPD_CUSTOM_POINTS :
b86bc4cf 749 cparam->current.custom_points = (float)_cupsStrScand(choice + 7,
750 &units,
751 loc);
757d2cad 752
753 if (units)
754 {
755 if (!strcasecmp(units, "cm"))
b86bc4cf 756 cparam->current.custom_points *= 72.0f / 2.54f;
757d2cad 757 else if (!strcasecmp(units, "mm"))
b86bc4cf 758 cparam->current.custom_points *= 72.0f / 25.4f;
757d2cad 759 else if (!strcasecmp(units, "m"))
b86bc4cf 760 cparam->current.custom_points *= 72.0f / 0.0254f;
757d2cad 761 else if (!strcasecmp(units, "in"))
b86bc4cf 762 cparam->current.custom_points *= 72.0f;
757d2cad 763 else if (!strcasecmp(units, "ft"))
b86bc4cf 764 cparam->current.custom_points *= 12.0f * 72.0f;
757d2cad 765 }
fa73b229 766 break;
767
768 case PPD_CUSTOM_INT :
769 cparam->current.custom_int = atoi(choice + 7);
770 break;
771
772 case PPD_CUSTOM_PASSCODE :
773 case PPD_CUSTOM_PASSWORD :
774 case PPD_CUSTOM_STRING :
775 if (cparam->current.custom_string)
2e4ff8af 776 _cupsStrFree(cparam->current.custom_string);
fa73b229 777
2e4ff8af 778 cparam->current.custom_string = _cupsStrAlloc(choice + 7);
fa73b229 779 break;
780 }
ef416fc2 781 }
782 }
8ca02f3c 783
784 /*
785 * Make sure that we keep the option marked below...
786 */
787
788 choice = "Custom";
fa73b229 789 }
b423cd4c 790 else if (choice[0] == '{')
791 {
792 /*
793 * Handle multi-value custom options...
794 */
795
796 ppd_coption_t *coption; /* Custom option */
797 ppd_cparam_t *cparam; /* Custom parameter */
757d2cad 798 char *units; /* Custom points units */
b423cd4c 799 int num_vals; /* Number of values */
800 cups_option_t *vals, /* Values */
801 *val; /* Value */
802
803
804 if ((c = ppdFindChoice(o, "Custom")) == NULL)
805 return (0);
806
807 if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
808 {
809 num_vals = cupsParseOptions(choice + 1, 0, &vals);
810
811 for (i = 0, val = vals; i < num_vals; i ++, val ++)
812 {
813 if ((cparam = ppdFindCustomParam(coption, val->name)) == NULL)
814 continue;
815
816 switch (cparam->type)
817 {
818 case PPD_CUSTOM_CURVE :
819 case PPD_CUSTOM_INVCURVE :
820 case PPD_CUSTOM_REAL :
b86bc4cf 821 cparam->current.custom_real = (float)_cupsStrScand(val->value,
822 NULL, loc);
b423cd4c 823 break;
824
825 case PPD_CUSTOM_POINTS :
b86bc4cf 826 cparam->current.custom_points = (float)_cupsStrScand(val->value,
827 &units,
828 loc);
757d2cad 829
830 if (units)
831 {
832 if (!strcasecmp(units, "cm"))
b86bc4cf 833 cparam->current.custom_points *= 72.0f / 2.54f;
757d2cad 834 else if (!strcasecmp(units, "mm"))
b86bc4cf 835 cparam->current.custom_points *= 72.0f / 25.4f;
757d2cad 836 else if (!strcasecmp(units, "m"))
b86bc4cf 837 cparam->current.custom_points *= 72.0f / 0.0254f;
757d2cad 838 else if (!strcasecmp(units, "in"))
b86bc4cf 839 cparam->current.custom_points *= 72.0f;
757d2cad 840 else if (!strcasecmp(units, "ft"))
b86bc4cf 841 cparam->current.custom_points *= 12.0f * 72.0f;
757d2cad 842 }
b423cd4c 843 break;
844
845 case PPD_CUSTOM_INT :
846 cparam->current.custom_int = atoi(val->value);
847 break;
848
849 case PPD_CUSTOM_PASSCODE :
850 case PPD_CUSTOM_PASSWORD :
851 case PPD_CUSTOM_STRING :
852 if (cparam->current.custom_string)
2e4ff8af 853 _cupsStrFree(cparam->current.custom_string);
b423cd4c 854
2e4ff8af 855 cparam->current.custom_string = _cupsStrAlloc(val->value);
b423cd4c 856 break;
857 }
858 }
859
860 cupsFreeOptions(num_vals, vals);
861 }
862 }
fa73b229 863 else
864 {
865 for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
866 if (!strcasecmp(c->choice, choice))
867 break;
ef416fc2 868
fa73b229 869 if (!i)
870 return (0);
871 }
ef416fc2 872
fa73b229 873 /*
874 * Option found; mark it and then handle unmarking any other options.
875 */
876
fa73b229 877 if (o->ui != PPD_UI_PICKMANY)
878 {
879 /*
880 * Unmark all other choices...
881 */
882
b94498cf 883 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, c)) != NULL)
884 {
885 oldc->marked = 0;
886 cupsArrayRemove(ppd->marked, oldc);
887 }
888
889 if (!strcasecmp(option, "PageSize") || !strcasecmp(option, "PageRegion"))
890 {
891 /*
892 * Mark current page size...
893 */
894
895 for (j = 0; j < ppd->num_sizes; j ++)
896 ppd->sizes[j].marked = !strcasecmp(ppd->sizes[j].name,
897 choice);
898
899 /*
900 * Unmark the current PageSize or PageRegion setting, as
901 * appropriate...
902 */
903
904 if (!strcasecmp(option, "PageSize"))
fa73b229 905 {
b94498cf 906 if ((o = ppdFindOption(ppd, "PageRegion")) != NULL)
907 {
908 key.option = o;
909 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
910 {
911 oldc->marked = 0;
912 cupsArrayRemove(ppd->marked, oldc);
913 }
914 }
915 }
916 else
917 {
918 if ((o = ppdFindOption(ppd, "PageSize")) != NULL)
919 {
920 key.option = o;
921 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
922 {
923 oldc->marked = 0;
924 cupsArrayRemove(ppd->marked, oldc);
925 }
926 }
927 }
928 }
929 else if (!strcasecmp(option, "InputSlot"))
930 {
931 /*
355e94dc 932 * Unmark ManualFeed option...
b94498cf 933 */
fa73b229 934
b94498cf 935 if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL)
936 {
937 key.option = o;
938 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
939 {
940 oldc->marked = 0;
941 cupsArrayRemove(ppd->marked, oldc);
942 }
943 }
944 }
945 else if (!strcasecmp(option, "ManualFeed") &&
946 !strcasecmp(choice, "True"))
947 {
948 /*
949 * Unmark InputSlot option...
950 */
fa73b229 951
b94498cf 952 if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
953 {
954 key.option = o;
955 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
956 {
957 oldc->marked = 0;
958 cupsArrayRemove(ppd->marked, oldc);
959 }
fa73b229 960 }
b94498cf 961 }
ef416fc2 962 }
963
b94498cf 964 c->marked = 1;
965
966 cupsArrayAdd(ppd->marked, c);
967
fa73b229 968 /*
969 * Return the number of conflicts...
970 */
971
ef416fc2 972 return (ppdConflicts(ppd));
973}
974
975
bd7854cb 976/*
977 * 'ppdFirstOption()' - Return the first option in the PPD file.
978 *
5a738aea 979 * Options are returned from all groups in ascending alphanumeric order.
bd7854cb 980 *
981 * @since CUPS 1.2@
982 */
983
5a738aea 984ppd_option_t * /* O - First option or @code NULL@ */
bd7854cb 985ppdFirstOption(ppd_file_t *ppd) /* I - PPD file */
986{
987 if (!ppd)
988 return (NULL);
989 else
990 return ((ppd_option_t *)cupsArrayFirst(ppd->options));
991}
992
993
994/*
995 * 'ppdNextOption()' - Return the next option in the PPD file.
996 *
5a738aea 997 * Options are returned from all groups in ascending alphanumeric order.
bd7854cb 998 *
999 * @since CUPS 1.2@
1000 */
1001
5a738aea 1002ppd_option_t * /* O - Next option or @code NULL@ */
bd7854cb 1003ppdNextOption(ppd_file_t *ppd) /* I - PPD file */
1004{
1005 if (!ppd)
1006 return (NULL);
1007 else
1008 return ((ppd_option_t *)cupsArrayNext(ppd->options));
1009}
1010
1011
5a738aea
MS
1012#ifdef DEBUG
1013/*
1014 * 'debug_marked()' - Output the marked array to stdout...
1015 */
1016
1017static void
1018debug_marked(ppd_file_t *ppd, /* I - PPD file data */
1019 const char *title) /* I - Title for list */
1020{
1021 ppd_choice_t *c; /* Current choice */
1022
1023
ae71f5de 1024 DEBUG_printf(("cupsMarkOptions: %s\n", title));
5a738aea
MS
1025
1026 for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
1027 c;
1028 c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
ae71f5de 1029 DEBUG_printf(("cupsMarkOptions: %s=%s\n", c->option->keyword, c->choice));
5a738aea
MS
1030}
1031#endif /* DEBUG */
1032
1033
ef416fc2 1034/*
1035 * 'ppd_defaults()' - Set the defaults for this group and all sub-groups.
1036 */
1037
1038static void
5a738aea
MS
1039ppd_defaults(ppd_file_t *ppd, /* I - PPD file */
1040 ppd_group_t *g) /* I - Group to default */
ef416fc2 1041{
5a738aea
MS
1042 int i; /* Looping var */
1043 ppd_option_t *o; /* Current option */
1044 ppd_group_t *sg; /* Current sub-group */
ef416fc2 1045
1046
ef416fc2 1047 for (i = g->num_options, o = g->options; i > 0; i --, o ++)
1048 if (strcasecmp(o->keyword, "PageRegion") != 0)
1049 ppdMarkOption(ppd, o->keyword, o->defchoice);
1050
1051 for (i = g->num_subgroups, sg = g->subgroups; i > 0; i --, sg ++)
1052 ppd_defaults(ppd, sg);
1053}
1054
1055
1056/*
5a738aea
MS
1057 * 'ppd_mark_choices()' - Mark one or more option choices from a string.
1058 */
1059
1060static int /* O - 1 if there are conflicts, 0 otherwise */
1061ppd_mark_choices(ppd_file_t *ppd, /* I - PPD file */
1062 const char *options) /* I - "*Option Choice ..." string */
1063{
1064 char option[PPD_MAX_NAME], /* Current option */
1065 choice[PPD_MAX_NAME], /* Current choice */
1066 *ptr; /* Pointer into option or choice */
1067 int conflict = 0; /* Do we have a conflict? */
1068
1069
1070 if (!options)
1071 return (0);
1072
1073 /*
1074 * Read all of the "*Option Choice" pairs from the string, marking PPD
1075 * options as we go...
1076 */
1077
1078 while (*options)
1079 {
1080 /*
1081 * Skip leading whitespace...
1082 */
1083
1084 while (isspace(*options & 255))
1085 options ++;
1086
1087 if (*options != '*')
1088 break;
1089
1090 /*
1091 * Get the option name...
1092 */
1093
1094 options ++;
1095 ptr = option;
1096 while (*options && !isspace(*options & 255) &&
1097 ptr < (option + sizeof(option) - 1))
1098 *ptr++ = *options++;
1099
1100 if (ptr == option)
1101 break;
1102
1103 *ptr = '\0';
1104
1105 /*
1106 * Get the choice...
1107 */
1108
1109 while (isspace(*options & 255))
1110 options ++;
1111
1112 if (!*options)
1113 break;
1114
1115 ptr = choice;
1116 while (*options && !isspace(*options & 255) &&
1117 ptr < (choice + sizeof(choice) - 1))
1118 *ptr++ = *options++;
1119
1120 *ptr = '\0';
1121
1122 /*
1123 * Mark the option...
1124 */
1125
1126 if (ppdMarkOption(ppd, option, choice))
1127 conflict = 1;
1128 }
1129
1130 /*
1131 * Return whether we had any conflicts...
1132 */
1133
1134 return (conflict);
1135}
1136
1137
1138/*
1139 * End of "$Id: mark.c 7278 2008-01-31 01:23:09Z mike $".
ef416fc2 1140 */