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