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