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