]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/mark.c
Merge changes from CUPS trunk, r6739.
[thirdparty/cups.git] / cups / mark.c
CommitLineData
ef416fc2 1/*
355e94dc 2 * "$Id: mark.c 6703 2007-07-20 21:28:10Z mike $"
ef416fc2 3 *
4 * Option marking routines for the Common UNIX Printing System (CUPS).
5 *
bc44d920 6 * Copyright 2007 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 *
21 * ppdConflicts() - Check to see if there are any conflicts.
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.
bd7854cb 25 * ppdFirstOption() - Return the first option in the PPD file.
26 * ppdNextOption() - Return the next option in the PPD file.
ef416fc2 27 * ppdIsMarked() - Check to see if an option is marked...
28 * ppdMarkDefaults() - Mark all default options in the PPD file.
29 * ppdMarkOption() - Mark an option in a PPD file.
30 * ppd_defaults() - Set the defaults for this group and all sub-groups.
31 */
32
33/*
34 * Include necessary headers...
35 */
36
b423cd4c 37#include "cups.h"
ef416fc2 38#include "string.h"
39#include "debug.h"
40
41
42/*
43 * Local functions...
44 */
45
46static void ppd_defaults(ppd_file_t *ppd, ppd_group_t *g);
47
48
49/*
50 * 'ppdConflicts()' - Check to see if there are any conflicts.
51 */
52
b94498cf 53int /* O - Number of conflicts found */
54ppdConflicts(ppd_file_t *ppd) /* I - PPD to check */
ef416fc2 55{
b94498cf 56 int i, /* Looping variable */
57 conflicts; /* Number of conflicts */
58 ppd_const_t *c; /* Current constraint */
59 ppd_option_t *o1, *o2; /* Options */
60 ppd_choice_t *c1, *c2; /* Choices */
61 ppd_choice_t key; /* Search key */
ef416fc2 62
63
2abf387c 64 if (!ppd)
ef416fc2 65 return (0);
66
67 /*
68 * Clear all conflicts...
69 */
70
71 conflicts = 0;
72
2abf387c 73 for (o1 = ppdFirstOption(ppd); o1; o1 = ppdNextOption(ppd))
74 o1->conflicted = 0;
ef416fc2 75
355e94dc
MS
76 cupsArraySave(ppd->marked);
77
ef416fc2 78 /*
79 * Loop through all of the UI constraints and flag any options
80 * that conflict...
81 */
82
b94498cf 83 for (i = ppd->num_consts, c = ppd->consts, o1 = o2 = NULL, c1 = c2 = NULL;
84 i > 0;
85 i --, c ++)
ef416fc2 86 {
87 /*
88 * Grab pointers to the first option...
89 */
90
b94498cf 91 if (!o1 || strcmp(c->option1, o1->keyword))
92 {
93 o1 = ppdFindOption(ppd, c->option1);
94 c1 = NULL;
95 }
ef416fc2 96
2abf387c 97 if (!o1)
ef416fc2 98 continue;
b94498cf 99 else if (c->choice1[0] && (!c1 || strcmp(c->choice1, c1->choice)))
ef416fc2 100 {
101 /*
102 * This constraint maps to a specific choice.
103 */
104
b94498cf 105 key.option = o1;
106
107 if ((c1 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
09a101d6 108 (!c1->marked || strcmp(c->choice1, c1->choice)))
b94498cf 109 c1 = NULL;
ef416fc2 110 }
b94498cf 111 else if (!c1)
ef416fc2 112 {
113 /*
114 * This constraint applies to any choice for this option.
115 */
116
b94498cf 117 key.option = o1;
ef416fc2 118
b94498cf 119 if ((c1 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
120 (!strcasecmp(c1->choice, "None") || !strcasecmp(c1->choice, "Off") ||
121 !strcasecmp(c1->choice, "False")))
ef416fc2 122 c1 = NULL;
123 }
124
125 /*
126 * Grab pointers to the second option...
127 */
128
b94498cf 129 if (!o2 || strcmp(c->option2, o2->keyword))
130 {
131 o2 = ppdFindOption(ppd, c->option2);
132 c2 = NULL;
133 }
ef416fc2 134
2abf387c 135 if (!o2)
ef416fc2 136 continue;
b94498cf 137 else if (c->choice2[0] && (!c2 || strcmp(c->choice2, c2->choice)))
ef416fc2 138 {
139 /*
140 * This constraint maps to a specific choice.
141 */
142
b94498cf 143 key.option = o2;
144
145 if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
09a101d6 146 (!c2->marked || strcmp(c->choice2, c2->choice)))
b94498cf 147 c2 = NULL;
ef416fc2 148 }
b94498cf 149 else if (!c2)
ef416fc2 150 {
151 /*
152 * This constraint applies to any choice for this option.
153 */
154
b94498cf 155 key.option = o2;
ef416fc2 156
b94498cf 157 if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
158 (!strcasecmp(c2->choice, "None") || !strcasecmp(c2->choice, "Off") ||
159 !strcasecmp(c2->choice, "False")))
ef416fc2 160 c2 = NULL;
161 }
162
163 /*
164 * If both options are marked then there is a conflict...
165 */
166
2abf387c 167 if (c1 && c1->marked && c2 && c2->marked)
ef416fc2 168 {
169 DEBUG_printf(("%s->%s conflicts with %s->%s (%s %s %s %s)\n",
170 o1->keyword, c1->choice, o2->keyword, c2->choice,
171 c->option1, c->choice1, c->option2, c->choice2));
172 conflicts ++;
173 o1->conflicted = 1;
174 o2->conflicted = 1;
175 }
176 }
177
355e94dc
MS
178 cupsArrayRestore(ppd->marked);
179
ef416fc2 180 /*
181 * Return the number of conflicts found...
182 */
183
184 return (conflicts);
185}
186
187
188/*
189 * 'ppdFindChoice()' - Return a pointer to an option choice.
190 */
191
192ppd_choice_t * /* O - Choice pointer or NULL */
193ppdFindChoice(ppd_option_t *o, /* I - Pointer to option */
194 const char *choice) /* I - Name of choice */
195{
b94498cf 196 int i; /* Looping var */
197 ppd_choice_t *c; /* Current choice */
ef416fc2 198
199
200 if (o == NULL || choice == NULL)
201 return (NULL);
202
203 for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
204 if (strcasecmp(c->choice, choice) == 0)
205 return (c);
206
207 return (NULL);
208}
209
210
211/*
212 * 'ppdFindMarkedChoice()' - Return the marked choice for the specified option.
213 */
214
215ppd_choice_t * /* O - Pointer to choice or NULL */
216ppdFindMarkedChoice(ppd_file_t *ppd, /* I - PPD file */
217 const char *option) /* I - Keyword/option name */
218{
b94498cf 219 ppd_choice_t key; /* Search key for choice */
ef416fc2 220
221
b94498cf 222 if ((key.option = ppdFindOption(ppd, option)) == NULL)
ef416fc2 223 return (NULL);
224
b94498cf 225 return ((ppd_choice_t *)cupsArrayFind(ppd->marked, &key));
ef416fc2 226}
227
228
229/*
230 * 'ppdFindOption()' - Return a pointer to the specified option.
231 */
232
233ppd_option_t * /* O - Pointer to option or NULL */
234ppdFindOption(ppd_file_t *ppd, /* I - PPD file data */
235 const char *option) /* I - Option/Keyword name */
236{
fa73b229 237 /*
238 * Range check input...
239 */
ef416fc2 240
fa73b229 241 if (!ppd || !option)
ef416fc2 242 return (NULL);
243
f301802f 244 if (ppd->options)
245 {
246 /*
247 * Search in the array...
248 */
249
250 ppd_option_t key; /* Option search key */
251
252
253 strlcpy(key.keyword, option, sizeof(key.keyword));
ef416fc2 254
f301802f 255 return ((ppd_option_t *)cupsArrayFind(ppd->options, &key));
256 }
257 else
258 {
259 /*
260 * Search in each group...
261 */
ef416fc2 262
f301802f 263 int i, j; /* Looping vars */
264 ppd_group_t *group; /* Current group */
265 ppd_option_t *optptr; /* Current option */
266
267
268 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
269 for (j = group->num_options, optptr = group->options;
270 j > 0;
271 j --, optptr ++)
272 if (!strcasecmp(optptr->keyword, option))
273 return (optptr);
274
275 return (NULL);
276 }
ef416fc2 277}
278
279
280/*
281 * 'ppdIsMarked()' - Check to see if an option is marked...
282 */
283
b94498cf 284int /* O - Non-zero if option is marked */
285ppdIsMarked(ppd_file_t *ppd, /* I - PPD file data */
286 const char *option, /* I - Option/Keyword name */
287 const char *choice) /* I - Choice name */
ef416fc2 288{
b94498cf 289 ppd_choice_t key, /* Search key */
290 *c; /* Choice pointer */
ef416fc2 291
292
b94498cf 293 if (!ppd)
ef416fc2 294 return (0);
295
b94498cf 296 if ((key.option = ppdFindOption(ppd, option)) == NULL)
ef416fc2 297 return (0);
298
b94498cf 299 if ((c = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) == NULL)
ef416fc2 300 return (0);
301
b94498cf 302 return (!strcmp(c->choice, choice));
ef416fc2 303}
304
305
306/*
307 * 'ppdMarkDefaults()' - Mark all default options in the PPD file.
308 */
309
310void
b94498cf 311ppdMarkDefaults(ppd_file_t *ppd) /* I - PPD file record */
ef416fc2 312{
b94498cf 313 int i; /* Looping variables */
314 ppd_group_t *g; /* Current group */
315 ppd_choice_t *c; /* Current choice */
ef416fc2 316
317
b94498cf 318 if (!ppd)
ef416fc2 319 return;
320
b94498cf 321 /*
322 * Clean out the marked array...
323 */
324
325 for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
326 c;
327 c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
328 cupsArrayRemove(ppd->marked, c);
329
330 /*
331 * Then repopulate it with the defaults...
332 */
333
ef416fc2 334 for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++)
335 ppd_defaults(ppd, g);
336}
337
338
339/*
340 * 'ppdMarkOption()' - Mark an option in a PPD file.
341 *
342 * Notes:
343 *
344 * -1 is returned if the given option would conflict with any currently
345 * selected option.
346 */
347
348int /* O - Number of conflicts */
349ppdMarkOption(ppd_file_t *ppd, /* I - PPD file record */
350 const char *option, /* I - Keyword */
351 const char *choice) /* I - Option name */
352{
fa73b229 353 int i, j; /* Looping vars */
354 ppd_option_t *o; /* Option pointer */
b94498cf 355 ppd_choice_t *c, /* Choice pointer */
356 *oldc, /* Old choice pointer */
357 key; /* Search key for choice */
757d2cad 358 struct lconv *loc; /* Locale data */
ef416fc2 359
360
bd7854cb 361 DEBUG_printf(("ppdMarkOption(ppd=%p, option=\"%s\", choice=\"%s\")\n",
362 ppd, option, choice));
363
fa73b229 364 /*
365 * Range check input...
366 */
367
368 if (!ppd || !option || !choice)
ef416fc2 369 return (0);
370
fa73b229 371 /*
372 * AP_D_InputSlot is the "default input slot" on MacOS X, and setting
373 * it clears the regular InputSlot choices...
374 */
ef416fc2 375
fa73b229 376 if (!strcasecmp(option, "AP_D_InputSlot"))
377 {
378 if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
b94498cf 379 {
380 key.option = o;
381 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
382 {
383 oldc->marked = 0;
384 cupsArrayRemove(ppd->marked, oldc);
385 }
386 }
ef416fc2 387 }
388
fa73b229 389 /*
390 * Check for custom options...
391 */
392
ef416fc2 393 if ((o = ppdFindOption(ppd, option)) == NULL)
394 return (0);
395
757d2cad 396 loc = localeconv();
ef416fc2 397
b423cd4c 398 if (!strncasecmp(choice, "Custom.", 7))
ef416fc2 399 {
400 /*
fa73b229 401 * Handle a custom option...
ef416fc2 402 */
403
fa73b229 404 if ((c = ppdFindChoice(o, "Custom")) == NULL)
405 return (0);
ef416fc2 406
fa73b229 407 if (!strcasecmp(option, "PageSize"))
408 {
409 /*
410 * Handle custom page sizes...
411 */
ef416fc2 412
fa73b229 413 ppdPageSize(ppd, choice);
414 }
415 else
ef416fc2 416 {
417 /*
fa73b229 418 * Handle other custom options...
ef416fc2 419 */
420
fa73b229 421 ppd_coption_t *coption; /* Custom option */
422 ppd_cparam_t *cparam; /* Custom parameter */
757d2cad 423 char *units; /* Custom points units */
fa73b229 424
8ca02f3c 425
fa73b229 426 if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
ef416fc2 427 {
fa73b229 428 if ((cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params)) == NULL)
429 return (0);
430
431 switch (cparam->type)
432 {
433 case PPD_CUSTOM_CURVE :
434 case PPD_CUSTOM_INVCURVE :
435 case PPD_CUSTOM_REAL :
b86bc4cf 436 cparam->current.custom_real = (float)_cupsStrScand(choice + 7,
437 NULL, loc);
fa73b229 438 break;
439
440 case PPD_CUSTOM_POINTS :
b86bc4cf 441 cparam->current.custom_points = (float)_cupsStrScand(choice + 7,
442 &units,
443 loc);
757d2cad 444
445 if (units)
446 {
447 if (!strcasecmp(units, "cm"))
b86bc4cf 448 cparam->current.custom_points *= 72.0f / 2.54f;
757d2cad 449 else if (!strcasecmp(units, "mm"))
b86bc4cf 450 cparam->current.custom_points *= 72.0f / 25.4f;
757d2cad 451 else if (!strcasecmp(units, "m"))
b86bc4cf 452 cparam->current.custom_points *= 72.0f / 0.0254f;
757d2cad 453 else if (!strcasecmp(units, "in"))
b86bc4cf 454 cparam->current.custom_points *= 72.0f;
757d2cad 455 else if (!strcasecmp(units, "ft"))
b86bc4cf 456 cparam->current.custom_points *= 12.0f * 72.0f;
757d2cad 457 }
fa73b229 458 break;
459
460 case PPD_CUSTOM_INT :
461 cparam->current.custom_int = atoi(choice + 7);
462 break;
463
464 case PPD_CUSTOM_PASSCODE :
465 case PPD_CUSTOM_PASSWORD :
466 case PPD_CUSTOM_STRING :
467 if (cparam->current.custom_string)
468 free(cparam->current.custom_string);
469
470 cparam->current.custom_string = strdup(choice + 7);
471 break;
472 }
ef416fc2 473 }
474 }
8ca02f3c 475
476 /*
477 * Make sure that we keep the option marked below...
478 */
479
480 choice = "Custom";
fa73b229 481 }
b423cd4c 482 else if (choice[0] == '{')
483 {
484 /*
485 * Handle multi-value custom options...
486 */
487
488 ppd_coption_t *coption; /* Custom option */
489 ppd_cparam_t *cparam; /* Custom parameter */
757d2cad 490 char *units; /* Custom points units */
b423cd4c 491 int num_vals; /* Number of values */
492 cups_option_t *vals, /* Values */
493 *val; /* Value */
494
495
496 if ((c = ppdFindChoice(o, "Custom")) == NULL)
497 return (0);
498
499 if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
500 {
501 num_vals = cupsParseOptions(choice + 1, 0, &vals);
502
503 for (i = 0, val = vals; i < num_vals; i ++, val ++)
504 {
505 if ((cparam = ppdFindCustomParam(coption, val->name)) == NULL)
506 continue;
507
508 switch (cparam->type)
509 {
510 case PPD_CUSTOM_CURVE :
511 case PPD_CUSTOM_INVCURVE :
512 case PPD_CUSTOM_REAL :
b86bc4cf 513 cparam->current.custom_real = (float)_cupsStrScand(val->value,
514 NULL, loc);
b423cd4c 515 break;
516
517 case PPD_CUSTOM_POINTS :
b86bc4cf 518 cparam->current.custom_points = (float)_cupsStrScand(val->value,
519 &units,
520 loc);
757d2cad 521
522 if (units)
523 {
524 if (!strcasecmp(units, "cm"))
b86bc4cf 525 cparam->current.custom_points *= 72.0f / 2.54f;
757d2cad 526 else if (!strcasecmp(units, "mm"))
b86bc4cf 527 cparam->current.custom_points *= 72.0f / 25.4f;
757d2cad 528 else if (!strcasecmp(units, "m"))
b86bc4cf 529 cparam->current.custom_points *= 72.0f / 0.0254f;
757d2cad 530 else if (!strcasecmp(units, "in"))
b86bc4cf 531 cparam->current.custom_points *= 72.0f;
757d2cad 532 else if (!strcasecmp(units, "ft"))
b86bc4cf 533 cparam->current.custom_points *= 12.0f * 72.0f;
757d2cad 534 }
b423cd4c 535 break;
536
537 case PPD_CUSTOM_INT :
538 cparam->current.custom_int = atoi(val->value);
539 break;
540
541 case PPD_CUSTOM_PASSCODE :
542 case PPD_CUSTOM_PASSWORD :
543 case PPD_CUSTOM_STRING :
544 if (cparam->current.custom_string)
545 free(cparam->current.custom_string);
546
547 cparam->current.custom_string = strdup(val->value);
548 break;
549 }
550 }
551
552 cupsFreeOptions(num_vals, vals);
553 }
554 }
fa73b229 555 else
556 {
557 for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
558 if (!strcasecmp(c->choice, choice))
559 break;
ef416fc2 560
fa73b229 561 if (!i)
562 return (0);
563 }
ef416fc2 564
fa73b229 565 /*
566 * Option found; mark it and then handle unmarking any other options.
567 */
568
fa73b229 569 if (o->ui != PPD_UI_PICKMANY)
570 {
571 /*
572 * Unmark all other choices...
573 */
574
b94498cf 575 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, c)) != NULL)
576 {
577 oldc->marked = 0;
578 cupsArrayRemove(ppd->marked, oldc);
579 }
580
581 if (!strcasecmp(option, "PageSize") || !strcasecmp(option, "PageRegion"))
582 {
583 /*
584 * Mark current page size...
585 */
586
587 for (j = 0; j < ppd->num_sizes; j ++)
588 ppd->sizes[j].marked = !strcasecmp(ppd->sizes[j].name,
589 choice);
590
591 /*
592 * Unmark the current PageSize or PageRegion setting, as
593 * appropriate...
594 */
595
596 if (!strcasecmp(option, "PageSize"))
fa73b229 597 {
b94498cf 598 if ((o = ppdFindOption(ppd, "PageRegion")) != NULL)
599 {
600 key.option = o;
601 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
602 {
603 oldc->marked = 0;
604 cupsArrayRemove(ppd->marked, oldc);
605 }
606 }
607 }
608 else
609 {
610 if ((o = ppdFindOption(ppd, "PageSize")) != NULL)
611 {
612 key.option = o;
613 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
614 {
615 oldc->marked = 0;
616 cupsArrayRemove(ppd->marked, oldc);
617 }
618 }
619 }
620 }
621 else if (!strcasecmp(option, "InputSlot"))
622 {
623 /*
355e94dc 624 * Unmark ManualFeed option...
b94498cf 625 */
fa73b229 626
b94498cf 627 if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL)
628 {
629 key.option = o;
630 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
631 {
632 oldc->marked = 0;
633 cupsArrayRemove(ppd->marked, oldc);
634 }
635 }
636 }
637 else if (!strcasecmp(option, "ManualFeed") &&
638 !strcasecmp(choice, "True"))
639 {
640 /*
641 * Unmark InputSlot option...
642 */
fa73b229 643
b94498cf 644 if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
645 {
646 key.option = o;
647 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
648 {
649 oldc->marked = 0;
650 cupsArrayRemove(ppd->marked, oldc);
651 }
fa73b229 652 }
b94498cf 653 }
ef416fc2 654 }
655
b94498cf 656 c->marked = 1;
657
658 cupsArrayAdd(ppd->marked, c);
659
fa73b229 660 /*
661 * Return the number of conflicts...
662 */
663
ef416fc2 664 return (ppdConflicts(ppd));
665}
666
667
bd7854cb 668/*
669 * 'ppdFirstOption()' - Return the first option in the PPD file.
670 *
671 * Options are returned from all groups in sorted order.
672 *
673 * @since CUPS 1.2@
674 */
675
676ppd_option_t * /* O - First option or NULL */
677ppdFirstOption(ppd_file_t *ppd) /* I - PPD file */
678{
679 if (!ppd)
680 return (NULL);
681 else
682 return ((ppd_option_t *)cupsArrayFirst(ppd->options));
683}
684
685
686/*
687 * 'ppdNextOption()' - Return the next option in the PPD file.
688 *
689 * Options are returned from all groups in sorted order.
690 *
691 * @since CUPS 1.2@
692 */
693
694ppd_option_t * /* O - Next option or NULL */
695ppdNextOption(ppd_file_t *ppd) /* I - PPD file */
696{
697 if (!ppd)
698 return (NULL);
699 else
700 return ((ppd_option_t *)cupsArrayNext(ppd->options));
701}
702
703
ef416fc2 704/*
705 * 'ppd_defaults()' - Set the defaults for this group and all sub-groups.
706 */
707
708static void
709ppd_defaults(ppd_file_t *ppd, /* I - PPD file */
710 ppd_group_t *g) /* I - Group to default */
711{
712 int i; /* Looping var */
713 ppd_option_t *o; /* Current option */
714 ppd_group_t *sg; /* Current sub-group */
715
716
ef416fc2 717 for (i = g->num_options, o = g->options; i > 0; i --, o ++)
718 if (strcasecmp(o->keyword, "PageRegion") != 0)
719 ppdMarkOption(ppd, o->keyword, o->defchoice);
720
721 for (i = g->num_subgroups, sg = g->subgroups; i > 0; i --, sg ++)
722 ppd_defaults(ppd, sg);
723}
724
725
726/*
355e94dc 727 * End of "$Id: mark.c 6703 2007-07-20 21:28:10Z mike $".
ef416fc2 728 */