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