]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/mark.c
Merge changes from CUPS 1.4svn-r8252.
[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{
b94498cf 464 ppd_choice_t key; /* Search key for choice */
ef416fc2 465
466
b94498cf 467 if ((key.option = ppdFindOption(ppd, option)) == NULL)
ef416fc2 468 return (NULL);
469
b94498cf 470 return ((ppd_choice_t *)cupsArrayFind(ppd->marked, &key));
ef416fc2 471}
472
473
474/*
475 * 'ppdFindOption()' - Return a pointer to the specified option.
476 */
477
5a738aea 478ppd_option_t * /* O - Pointer to option or @code NULL@ */
ef416fc2 479ppdFindOption(ppd_file_t *ppd, /* I - PPD file data */
480 const char *option) /* I - Option/Keyword name */
481{
fa73b229 482 /*
483 * Range check input...
484 */
ef416fc2 485
fa73b229 486 if (!ppd || !option)
ef416fc2 487 return (NULL);
488
f301802f 489 if (ppd->options)
490 {
491 /*
492 * Search in the array...
493 */
494
495 ppd_option_t key; /* Option search key */
496
497
498 strlcpy(key.keyword, option, sizeof(key.keyword));
ef416fc2 499
f301802f 500 return ((ppd_option_t *)cupsArrayFind(ppd->options, &key));
501 }
502 else
503 {
504 /*
505 * Search in each group...
506 */
ef416fc2 507
f301802f 508 int i, j; /* Looping vars */
509 ppd_group_t *group; /* Current group */
510 ppd_option_t *optptr; /* Current option */
511
512
513 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
514 for (j = group->num_options, optptr = group->options;
515 j > 0;
516 j --, optptr ++)
517 if (!strcasecmp(optptr->keyword, option))
518 return (optptr);
519
520 return (NULL);
521 }
ef416fc2 522}
523
524
525/*
5a738aea 526 * 'ppdIsMarked()' - Check to see if an option is marked.
ef416fc2 527 */
528
b94498cf 529int /* O - Non-zero if option is marked */
530ppdIsMarked(ppd_file_t *ppd, /* I - PPD file data */
531 const char *option, /* I - Option/Keyword name */
532 const char *choice) /* I - Choice name */
ef416fc2 533{
b94498cf 534 ppd_choice_t key, /* Search key */
535 *c; /* Choice pointer */
ef416fc2 536
537
b94498cf 538 if (!ppd)
ef416fc2 539 return (0);
540
b94498cf 541 if ((key.option = ppdFindOption(ppd, option)) == NULL)
ef416fc2 542 return (0);
543
b94498cf 544 if ((c = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) == NULL)
ef416fc2 545 return (0);
546
b94498cf 547 return (!strcmp(c->choice, choice));
ef416fc2 548}
549
550
551/*
552 * 'ppdMarkDefaults()' - Mark all default options in the PPD file.
553 */
554
555void
b94498cf 556ppdMarkDefaults(ppd_file_t *ppd) /* I - PPD file record */
ef416fc2 557{
b94498cf 558 int i; /* Looping variables */
559 ppd_group_t *g; /* Current group */
560 ppd_choice_t *c; /* Current choice */
ef416fc2 561
562
b94498cf 563 if (!ppd)
ef416fc2 564 return;
565
b94498cf 566 /*
567 * Clean out the marked array...
568 */
569
570 for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
571 c;
572 c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
573 cupsArrayRemove(ppd->marked, c);
574
575 /*
576 * Then repopulate it with the defaults...
577 */
578
ef416fc2 579 for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++)
580 ppd_defaults(ppd, g);
581}
582
583
584/*
66ab9486
MS
585 * 'ppdMarkOption()' - Mark an option in a PPD file and return the number of
586 * conflicts.
ef416fc2 587 */
588
589int /* O - Number of conflicts */
590ppdMarkOption(ppd_file_t *ppd, /* I - PPD file record */
591 const char *option, /* I - Keyword */
592 const char *choice) /* I - Option name */
593{
bd7854cb 594 DEBUG_printf(("ppdMarkOption(ppd=%p, option=\"%s\", choice=\"%s\")\n",
595 ppd, option, choice));
596
fa73b229 597 /*
598 * Range check input...
599 */
600
601 if (!ppd || !option || !choice)
ef416fc2 602 return (0);
603
66ab9486
MS
604 /*
605 * Mark the option...
606 */
607
608 ppd_mark_option(ppd, option, choice);
609
610 /*
611 * Return the number of conflicts...
612 */
613
614 return (ppdConflicts(ppd));
615}
616
617
618/*
619 * 'ppdFirstOption()' - Return the first option in the PPD file.
620 *
621 * Options are returned from all groups in ascending alphanumeric order.
622 *
426c6a59 623 * @since CUPS 1.2/Mac OS X 10.5@
66ab9486
MS
624 */
625
626ppd_option_t * /* O - First option or @code NULL@ */
627ppdFirstOption(ppd_file_t *ppd) /* I - PPD file */
628{
629 if (!ppd)
630 return (NULL);
631 else
632 return ((ppd_option_t *)cupsArrayFirst(ppd->options));
633}
634
635
636/*
637 * 'ppdNextOption()' - Return the next option in the PPD file.
638 *
639 * Options are returned from all groups in ascending alphanumeric order.
640 *
426c6a59 641 * @since CUPS 1.2/Mac OS X 10.5@
66ab9486
MS
642 */
643
644ppd_option_t * /* O - Next option or @code NULL@ */
645ppdNextOption(ppd_file_t *ppd) /* I - PPD file */
646{
647 if (!ppd)
648 return (NULL);
649 else
650 return ((ppd_option_t *)cupsArrayNext(ppd->options));
651}
652
653
654/*
655 * '_ppdParseOptions()' - Parse options from a PPD file.
656 *
657 * This function looks for strings of the form:
658 *
659 * *option choice ... *optionN choiceN
660 *
661 * It stops when it finds a string that doesn't match this format.
662 */
663
664int /* O - Number of options */
665_ppdParseOptions(
666 const char *s, /* I - String to parse */
667 int num_options, /* I - Number of options */
668 cups_option_t **options) /* IO - Options */
669{
670 char option[PPD_MAX_NAME], /* Current option */
671 choice[PPD_MAX_NAME], /* Current choice */
672 *ptr; /* Pointer into option or choice */
673
674
675 if (!s)
676 return (num_options);
677
678 /*
679 * Read all of the "*Option Choice" pairs from the string, marking PPD
680 * options as we go...
681 */
682
683 while (*s)
684 {
685 /*
686 * Skip leading whitespace...
687 */
688
689 while (isspace(*s & 255))
690 s ++;
691
692 if (*s != '*')
693 break;
694
695 /*
696 * Get the option name...
697 */
698
699 s ++;
700 ptr = option;
701 while (*s && !isspace(*s & 255) && ptr < (option + sizeof(option) - 1))
702 *ptr++ = *s++;
703
704 if (ptr == s)
705 break;
706
707 *ptr = '\0';
708
709 /*
710 * Get the choice...
711 */
712
713 while (isspace(*s & 255))
714 s ++;
715
716 if (!*s)
717 break;
718
719 ptr = choice;
720 while (*s && !isspace(*s & 255) && ptr < (choice + sizeof(choice) - 1))
721 *ptr++ = *s++;
722
723 *ptr = '\0';
724
725 /*
726 * Add it to the options array...
727 */
728
729 num_options = cupsAddOption(option, choice, num_options, options);
730 }
731
732 return (num_options);
733}
734
735
736#ifdef DEBUG
737/*
738 * 'debug_marked()' - Output the marked array to stdout...
739 */
740
741static void
742debug_marked(ppd_file_t *ppd, /* I - PPD file data */
743 const char *title) /* I - Title for list */
744{
745 ppd_choice_t *c; /* Current choice */
746
747
748 DEBUG_printf(("cupsMarkOptions: %s\n", title));
749
750 for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
751 c;
752 c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
753 DEBUG_printf(("cupsMarkOptions: %s=%s\n", c->option->keyword, c->choice));
754}
755#endif /* DEBUG */
756
757
758/*
759 * 'ppd_defaults()' - Set the defaults for this group and all sub-groups.
760 */
761
762static void
763ppd_defaults(ppd_file_t *ppd, /* I - PPD file */
764 ppd_group_t *g) /* I - Group to default */
765{
766 int i; /* Looping var */
767 ppd_option_t *o; /* Current option */
768 ppd_group_t *sg; /* Current sub-group */
769
770
771 for (i = g->num_options, o = g->options; i > 0; i --, o ++)
772 if (strcasecmp(o->keyword, "PageRegion") != 0)
773 ppdMarkOption(ppd, o->keyword, o->defchoice);
774
775 for (i = g->num_subgroups, sg = g->subgroups; i > 0; i --, sg ++)
776 ppd_defaults(ppd, sg);
777}
778
779
780/*
781 * 'ppd_mark_choices()' - Mark one or more option choices from a string.
782 */
783
784static void
785ppd_mark_choices(ppd_file_t *ppd, /* I - PPD file */
786 const char *s) /* I - "*Option Choice ..." string */
787{
788 int i, /* Looping var */
789 num_options; /* Number of options */
790 cups_option_t *options, /* Options */
791 *option; /* Current option */
792
793
5d6412a9 794 if (!s)
66ab9486
MS
795 return;
796
797 options = NULL;
798 num_options = _ppdParseOptions(s, 0, &options);
799
800 for (i = num_options, option = options; i > 0; i --, option ++)
801 ppd_mark_option(ppd, option->name, option->value);
802
803 cupsFreeOptions(num_options, options);
804}
805
806
807/*
808 * 'ppd_mark_option()' - Quick mark an option without checking for conflicts.
809 */
810
811static void
812ppd_mark_option(ppd_file_t *ppd, /* I - PPD file */
813 const char *option, /* I - Option name */
814 const char *choice) /* I - Choice name */
815{
816 int i, j; /* Looping vars */
817 ppd_option_t *o; /* Option pointer */
818 ppd_choice_t *c, /* Choice pointer */
819 *oldc, /* Old choice pointer */
820 key; /* Search key for choice */
821 struct lconv *loc; /* Locale data */
822
823
824 DEBUG_printf(("ppd_mark_option(ppd=%p, option=\"%s\", choice=\"%s\")\n",
825 ppd, option, choice));
826
fa73b229 827 /*
828 * AP_D_InputSlot is the "default input slot" on MacOS X, and setting
829 * it clears the regular InputSlot choices...
830 */
ef416fc2 831
fa73b229 832 if (!strcasecmp(option, "AP_D_InputSlot"))
833 {
834 if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
b94498cf 835 {
836 key.option = o;
837 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
838 {
839 oldc->marked = 0;
840 cupsArrayRemove(ppd->marked, oldc);
841 }
842 }
ef416fc2 843 }
844
fa73b229 845 /*
846 * Check for custom options...
847 */
848
ef416fc2 849 if ((o = ppdFindOption(ppd, option)) == NULL)
66ab9486 850 return;
ef416fc2 851
757d2cad 852 loc = localeconv();
ef416fc2 853
b423cd4c 854 if (!strncasecmp(choice, "Custom.", 7))
ef416fc2 855 {
856 /*
fa73b229 857 * Handle a custom option...
ef416fc2 858 */
859
fa73b229 860 if ((c = ppdFindChoice(o, "Custom")) == NULL)
66ab9486 861 return;
ef416fc2 862
fa73b229 863 if (!strcasecmp(option, "PageSize"))
864 {
865 /*
866 * Handle custom page sizes...
867 */
ef416fc2 868
fa73b229 869 ppdPageSize(ppd, choice);
870 }
871 else
ef416fc2 872 {
873 /*
fa73b229 874 * Handle other custom options...
ef416fc2 875 */
876
fa73b229 877 ppd_coption_t *coption; /* Custom option */
878 ppd_cparam_t *cparam; /* Custom parameter */
757d2cad 879 char *units; /* Custom points units */
fa73b229 880
8ca02f3c 881
fa73b229 882 if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
ef416fc2 883 {
fa73b229 884 if ((cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params)) == NULL)
66ab9486 885 return;
fa73b229 886
887 switch (cparam->type)
888 {
889 case PPD_CUSTOM_CURVE :
890 case PPD_CUSTOM_INVCURVE :
891 case PPD_CUSTOM_REAL :
b86bc4cf 892 cparam->current.custom_real = (float)_cupsStrScand(choice + 7,
893 NULL, loc);
fa73b229 894 break;
895
896 case PPD_CUSTOM_POINTS :
b86bc4cf 897 cparam->current.custom_points = (float)_cupsStrScand(choice + 7,
898 &units,
899 loc);
757d2cad 900
901 if (units)
902 {
903 if (!strcasecmp(units, "cm"))
b86bc4cf 904 cparam->current.custom_points *= 72.0f / 2.54f;
757d2cad 905 else if (!strcasecmp(units, "mm"))
b86bc4cf 906 cparam->current.custom_points *= 72.0f / 25.4f;
757d2cad 907 else if (!strcasecmp(units, "m"))
b86bc4cf 908 cparam->current.custom_points *= 72.0f / 0.0254f;
757d2cad 909 else if (!strcasecmp(units, "in"))
b86bc4cf 910 cparam->current.custom_points *= 72.0f;
757d2cad 911 else if (!strcasecmp(units, "ft"))
b86bc4cf 912 cparam->current.custom_points *= 12.0f * 72.0f;
757d2cad 913 }
fa73b229 914 break;
915
916 case PPD_CUSTOM_INT :
917 cparam->current.custom_int = atoi(choice + 7);
918 break;
919
920 case PPD_CUSTOM_PASSCODE :
921 case PPD_CUSTOM_PASSWORD :
922 case PPD_CUSTOM_STRING :
923 if (cparam->current.custom_string)
2e4ff8af 924 _cupsStrFree(cparam->current.custom_string);
fa73b229 925
2e4ff8af 926 cparam->current.custom_string = _cupsStrAlloc(choice + 7);
fa73b229 927 break;
928 }
ef416fc2 929 }
930 }
8ca02f3c 931
932 /*
933 * Make sure that we keep the option marked below...
934 */
935
936 choice = "Custom";
fa73b229 937 }
b423cd4c 938 else if (choice[0] == '{')
939 {
940 /*
941 * Handle multi-value custom options...
942 */
943
944 ppd_coption_t *coption; /* Custom option */
945 ppd_cparam_t *cparam; /* Custom parameter */
757d2cad 946 char *units; /* Custom points units */
b423cd4c 947 int num_vals; /* Number of values */
948 cups_option_t *vals, /* Values */
949 *val; /* Value */
950
951
952 if ((c = ppdFindChoice(o, "Custom")) == NULL)
66ab9486 953 return;
b423cd4c 954
955 if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
956 {
ee571f26 957 num_vals = cupsParseOptions(choice, 0, &vals);
b423cd4c 958
959 for (i = 0, val = vals; i < num_vals; i ++, val ++)
960 {
961 if ((cparam = ppdFindCustomParam(coption, val->name)) == NULL)
962 continue;
963
964 switch (cparam->type)
965 {
966 case PPD_CUSTOM_CURVE :
967 case PPD_CUSTOM_INVCURVE :
968 case PPD_CUSTOM_REAL :
b86bc4cf 969 cparam->current.custom_real = (float)_cupsStrScand(val->value,
970 NULL, loc);
b423cd4c 971 break;
972
973 case PPD_CUSTOM_POINTS :
b86bc4cf 974 cparam->current.custom_points = (float)_cupsStrScand(val->value,
975 &units,
976 loc);
757d2cad 977
978 if (units)
979 {
980 if (!strcasecmp(units, "cm"))
b86bc4cf 981 cparam->current.custom_points *= 72.0f / 2.54f;
757d2cad 982 else if (!strcasecmp(units, "mm"))
b86bc4cf 983 cparam->current.custom_points *= 72.0f / 25.4f;
757d2cad 984 else if (!strcasecmp(units, "m"))
b86bc4cf 985 cparam->current.custom_points *= 72.0f / 0.0254f;
757d2cad 986 else if (!strcasecmp(units, "in"))
b86bc4cf 987 cparam->current.custom_points *= 72.0f;
757d2cad 988 else if (!strcasecmp(units, "ft"))
b86bc4cf 989 cparam->current.custom_points *= 12.0f * 72.0f;
757d2cad 990 }
b423cd4c 991 break;
992
993 case PPD_CUSTOM_INT :
994 cparam->current.custom_int = atoi(val->value);
995 break;
996
997 case PPD_CUSTOM_PASSCODE :
998 case PPD_CUSTOM_PASSWORD :
999 case PPD_CUSTOM_STRING :
1000 if (cparam->current.custom_string)
2e4ff8af 1001 _cupsStrFree(cparam->current.custom_string);
b423cd4c 1002
426c6a59 1003 cparam->current.custom_string = _cupsStrRetain(val->value);
b423cd4c 1004 break;
1005 }
1006 }
1007
1008 cupsFreeOptions(num_vals, vals);
1009 }
1010 }
fa73b229 1011 else
1012 {
1013 for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
1014 if (!strcasecmp(c->choice, choice))
1015 break;
ef416fc2 1016
fa73b229 1017 if (!i)
66ab9486 1018 return;
fa73b229 1019 }
ef416fc2 1020
fa73b229 1021 /*
1022 * Option found; mark it and then handle unmarking any other options.
1023 */
1024
fa73b229 1025 if (o->ui != PPD_UI_PICKMANY)
1026 {
1027 /*
1028 * Unmark all other choices...
1029 */
1030
b94498cf 1031 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, c)) != NULL)
1032 {
1033 oldc->marked = 0;
1034 cupsArrayRemove(ppd->marked, oldc);
1035 }
1036
1037 if (!strcasecmp(option, "PageSize") || !strcasecmp(option, "PageRegion"))
1038 {
1039 /*
1040 * Mark current page size...
1041 */
1042
1043 for (j = 0; j < ppd->num_sizes; j ++)
1044 ppd->sizes[j].marked = !strcasecmp(ppd->sizes[j].name,
1045 choice);
1046
1047 /*
1048 * Unmark the current PageSize or PageRegion setting, as
1049 * appropriate...
1050 */
1051
1052 if (!strcasecmp(option, "PageSize"))
fa73b229 1053 {
b94498cf 1054 if ((o = ppdFindOption(ppd, "PageRegion")) != NULL)
1055 {
1056 key.option = o;
1057 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
1058 {
1059 oldc->marked = 0;
1060 cupsArrayRemove(ppd->marked, oldc);
1061 }
1062 }
1063 }
1064 else
1065 {
1066 if ((o = ppdFindOption(ppd, "PageSize")) != NULL)
1067 {
1068 key.option = o;
1069 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
1070 {
1071 oldc->marked = 0;
1072 cupsArrayRemove(ppd->marked, oldc);
1073 }
1074 }
1075 }
1076 }
1077 else if (!strcasecmp(option, "InputSlot"))
1078 {
1079 /*
355e94dc 1080 * Unmark ManualFeed option...
b94498cf 1081 */
fa73b229 1082
b94498cf 1083 if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL)
1084 {
1085 key.option = o;
1086 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
1087 {
1088 oldc->marked = 0;
1089 cupsArrayRemove(ppd->marked, oldc);
1090 }
1091 }
1092 }
1093 else if (!strcasecmp(option, "ManualFeed") &&
1094 !strcasecmp(choice, "True"))
1095 {
1096 /*
1097 * Unmark InputSlot option...
1098 */
fa73b229 1099
b94498cf 1100 if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
1101 {
1102 key.option = o;
1103 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
1104 {
1105 oldc->marked = 0;
1106 cupsArrayRemove(ppd->marked, oldc);
1107 }
fa73b229 1108 }
b94498cf 1109 }
ef416fc2 1110 }
1111
b94498cf 1112 c->marked = 1;
1113
1114 cupsArrayAdd(ppd->marked, c);
5a738aea
MS
1115}
1116
1117
1118/*
c168a833
MS
1119 * 'ppd_mark_size()' - Quickly mark a page size without checking for conflicts.
1120 *
1121 * This function is also responsible for mapping PWG/ISO/IPP size names to the
1122 * PPD file...
1123 */
1124
1125static void
1126ppd_mark_size(ppd_file_t *ppd, /* I - PPD file */
1127 const char *size) /* I - Size name */
1128{
1129 int i; /* Looping var */
1130 _cups_pwg_media_t *pwgmedia; /* PWG media information */
1131 ppd_size_t *ppdsize; /* Current PPD size */
1132 double dw, dl; /* Difference in width and height */
1133 double width, /* Width to find */
1134 length; /* Length to find */
1135 char width_str[256], /* Width in size name */
1136 length_str[256],/* Length in size name */
1137 units[256], /* Units in size name */
1138 custom[256]; /* Custom size */
1139 struct lconv *loc; /* Localization data */
1140
1141
1142 /*
1143 * See if this is a PPD size...
1144 */
1145
1146 if (!strncasecmp(size, "Custom.", 7) || ppdPageSize(ppd, size))
1147 {
1148 ppd_mark_option(ppd, "PageSize", size);
1149 return;
1150 }
1151
1152 /*
1153 * Nope, try looking up the PWG or legacy (IPP/ISO) size name...
1154 */
1155
1156 if ((pwgmedia = _cupsPWGMediaByName(size)) == NULL)
1157 pwgmedia = _cupsPWGMediaByLegacy(size);
1158
1159 if (pwgmedia)
1160 {
1161 width = pwgmedia->width;
1162 length = pwgmedia->length;
1163 }
1164 else if (sscanf(size, "%*[^_]_%*[^_]_%255[0-9.]x%255[0-9.]%s", width_str,
1165 length_str, units) == 3)
1166 {
1167 /*
1168 * Got a "self-describing" name that isn't in our table...
1169 */
1170
1171 loc = localeconv();
1172 width = _cupsStrScand(width_str, NULL, loc);
1173 length = _cupsStrScand(length_str, NULL, loc);
1174
1175 if (!strcmp(units, "in"))
1176 {
1177 width *= 72.0;
1178 length *= 72.0;
1179 }
1180 else if (!strcmp(units, "mm"))
1181 {
1182 width *= 25.4 / 72.0;
1183 length *= 25.4 / 72.0;
1184 }
1185 else
1186 return;
1187 }
1188 else
1189 return;
1190
1191 /*
1192 * Search the PPD file for a matching size...
1193 */
1194
1195 for (i = ppd->num_sizes, ppdsize = ppd->sizes; i > 0; i --, ppdsize ++)
1196 {
1197 dw = ppdsize->width - width;
1198 dl = ppdsize->length - length;
1199
1200 if (dw > -5.0 && dw < 5.0 && dl > -5.0 && dl < 5.0)
1201 {
1202 ppd_mark_option(ppd, "PageSize", ppdsize->name);
1203 return;
1204 }
1205 }
1206
1207 /*
1208 * No match found; if custom sizes are supported, set a custom size...
1209 */
1210
1211 if (ppd->variable_sizes)
1212 {
1213 snprintf(custom, sizeof(custom), "Custom.%dx%d", (int)width, (int)length);
1214 ppd_mark_option(ppd, "PageSize", custom);
1215 }
1216}
1217
1218
1219/*
1220 * End of "$Id: mark.c 8210 2009-01-09 02:30:26Z mike $".
ef416fc2 1221 */