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