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