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