]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/mark.c
Load cups into easysw/current.
[thirdparty/cups.git] / cups / mark.c
1 /*
2 * "$Id: mark.c 6649 2007-07-11 21:46:42Z mike $"
3 *
4 * Option marking routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 *
9 * These coded instructions, statements, and computer programs are the
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/".
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.
25 * ppdFirstOption() - Return the first option in the PPD file.
26 * ppdNextOption() - Return the next option in the PPD file.
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
37 #include "cups.h"
38 #include "string.h"
39 #include "debug.h"
40
41
42 /*
43 * Local functions...
44 */
45
46 static 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
53 int /* O - Number of conflicts found */
54 ppdConflicts(ppd_file_t *ppd) /* I - PPD to check */
55 {
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 */
62
63
64 if (!ppd)
65 return (0);
66
67 /*
68 * Clear all conflicts...
69 */
70
71 conflicts = 0;
72
73 for (o1 = ppdFirstOption(ppd); o1; o1 = ppdNextOption(ppd))
74 o1->conflicted = 0;
75
76 /*
77 * Loop through all of the UI constraints and flag any options
78 * that conflict...
79 */
80
81 for (i = ppd->num_consts, c = ppd->consts, o1 = o2 = NULL, c1 = c2 = NULL;
82 i > 0;
83 i --, c ++)
84 {
85 /*
86 * Grab pointers to the first option...
87 */
88
89 if (!o1 || strcmp(c->option1, o1->keyword))
90 {
91 o1 = ppdFindOption(ppd, c->option1);
92 c1 = NULL;
93 }
94
95 if (!o1)
96 continue;
97 else if (c->choice1[0] && (!c1 || strcmp(c->choice1, c1->choice)))
98 {
99 /*
100 * This constraint maps to a specific choice.
101 */
102
103 key.option = o1;
104
105 if ((c1 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
106 (!c1->marked || strcmp(c->choice1, c1->choice)))
107 c1 = NULL;
108 }
109 else if (!c1)
110 {
111 /*
112 * This constraint applies to any choice for this option.
113 */
114
115 key.option = o1;
116
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")))
120 c1 = NULL;
121 }
122
123 /*
124 * Grab pointers to the second option...
125 */
126
127 if (!o2 || strcmp(c->option2, o2->keyword))
128 {
129 o2 = ppdFindOption(ppd, c->option2);
130 c2 = NULL;
131 }
132
133 if (!o2)
134 continue;
135 else if (c->choice2[0] && (!c2 || strcmp(c->choice2, c2->choice)))
136 {
137 /*
138 * This constraint maps to a specific choice.
139 */
140
141 key.option = o2;
142
143 if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
144 (!c2->marked || strcmp(c->choice2, c2->choice)))
145 c2 = NULL;
146 }
147 else if (!c2)
148 {
149 /*
150 * This constraint applies to any choice for this option.
151 */
152
153 key.option = o2;
154
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")))
158 c2 = NULL;
159 }
160
161 /*
162 * If both options are marked then there is a conflict...
163 */
164
165 if (c1 && c1->marked && c2 && c2->marked)
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
188 ppd_choice_t * /* O - Choice pointer or NULL */
189 ppdFindChoice(ppd_option_t *o, /* I - Pointer to option */
190 const char *choice) /* I - Name of choice */
191 {
192 int i; /* Looping var */
193 ppd_choice_t *c; /* Current choice */
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
211 ppd_choice_t * /* O - Pointer to choice or NULL */
212 ppdFindMarkedChoice(ppd_file_t *ppd, /* I - PPD file */
213 const char *option) /* I - Keyword/option name */
214 {
215 ppd_choice_t key; /* Search key for choice */
216
217
218 if ((key.option = ppdFindOption(ppd, option)) == NULL)
219 return (NULL);
220
221 return ((ppd_choice_t *)cupsArrayFind(ppd->marked, &key));
222 }
223
224
225 /*
226 * 'ppdFindOption()' - Return a pointer to the specified option.
227 */
228
229 ppd_option_t * /* O - Pointer to option or NULL */
230 ppdFindOption(ppd_file_t *ppd, /* I - PPD file data */
231 const char *option) /* I - Option/Keyword name */
232 {
233 /*
234 * Range check input...
235 */
236
237 if (!ppd || !option)
238 return (NULL);
239
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));
250
251 return ((ppd_option_t *)cupsArrayFind(ppd->options, &key));
252 }
253 else
254 {
255 /*
256 * Search in each group...
257 */
258
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 }
273 }
274
275
276 /*
277 * 'ppdIsMarked()' - Check to see if an option is marked...
278 */
279
280 int /* O - Non-zero if option is marked */
281 ppdIsMarked(ppd_file_t *ppd, /* I - PPD file data */
282 const char *option, /* I - Option/Keyword name */
283 const char *choice) /* I - Choice name */
284 {
285 ppd_choice_t key, /* Search key */
286 *c; /* Choice pointer */
287
288
289 if (!ppd)
290 return (0);
291
292 if ((key.option = ppdFindOption(ppd, option)) == NULL)
293 return (0);
294
295 if ((c = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) == NULL)
296 return (0);
297
298 return (!strcmp(c->choice, choice));
299 }
300
301
302 /*
303 * 'ppdMarkDefaults()' - Mark all default options in the PPD file.
304 */
305
306 void
307 ppdMarkDefaults(ppd_file_t *ppd) /* I - PPD file record */
308 {
309 int i; /* Looping variables */
310 ppd_group_t *g; /* Current group */
311 ppd_choice_t *c; /* Current choice */
312
313
314 if (!ppd)
315 return;
316
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
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
344 int /* O - Number of conflicts */
345 ppdMarkOption(ppd_file_t *ppd, /* I - PPD file record */
346 const char *option, /* I - Keyword */
347 const char *choice) /* I - Option name */
348 {
349 int i, j; /* Looping vars */
350 ppd_option_t *o; /* Option pointer */
351 ppd_choice_t *c, /* Choice pointer */
352 *oldc, /* Old choice pointer */
353 key; /* Search key for choice */
354 struct lconv *loc; /* Locale data */
355
356
357 DEBUG_printf(("ppdMarkOption(ppd=%p, option=\"%s\", choice=\"%s\")\n",
358 ppd, option, choice));
359
360 /*
361 * Range check input...
362 */
363
364 if (!ppd || !option || !choice)
365 return (0);
366
367 /*
368 * AP_D_InputSlot is the "default input slot" on MacOS X, and setting
369 * it clears the regular InputSlot choices...
370 */
371
372 if (!strcasecmp(option, "AP_D_InputSlot"))
373 {
374 if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
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 }
383 }
384
385 /*
386 * Check for custom options...
387 */
388
389 if ((o = ppdFindOption(ppd, option)) == NULL)
390 return (0);
391
392 loc = localeconv();
393
394 if (!strncasecmp(choice, "Custom.", 7))
395 {
396 /*
397 * Handle a custom option...
398 */
399
400 if ((c = ppdFindChoice(o, "Custom")) == NULL)
401 return (0);
402
403 if (!strcasecmp(option, "PageSize"))
404 {
405 /*
406 * Handle custom page sizes...
407 */
408
409 ppdPageSize(ppd, choice);
410 }
411 else
412 {
413 /*
414 * Handle other custom options...
415 */
416
417 ppd_coption_t *coption; /* Custom option */
418 ppd_cparam_t *cparam; /* Custom parameter */
419 char *units; /* Custom points units */
420
421
422 if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
423 {
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 :
432 cparam->current.custom_real = (float)_cupsStrScand(choice + 7,
433 NULL, loc);
434 break;
435
436 case PPD_CUSTOM_POINTS :
437 cparam->current.custom_points = (float)_cupsStrScand(choice + 7,
438 &units,
439 loc);
440
441 if (units)
442 {
443 if (!strcasecmp(units, "cm"))
444 cparam->current.custom_points *= 72.0f / 2.54f;
445 else if (!strcasecmp(units, "mm"))
446 cparam->current.custom_points *= 72.0f / 25.4f;
447 else if (!strcasecmp(units, "m"))
448 cparam->current.custom_points *= 72.0f / 0.0254f;
449 else if (!strcasecmp(units, "in"))
450 cparam->current.custom_points *= 72.0f;
451 else if (!strcasecmp(units, "ft"))
452 cparam->current.custom_points *= 12.0f * 72.0f;
453 }
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 }
469 }
470 }
471
472 /*
473 * Make sure that we keep the option marked below...
474 */
475
476 choice = "Custom";
477 }
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 */
486 char *units; /* Custom points units */
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 :
509 cparam->current.custom_real = (float)_cupsStrScand(val->value,
510 NULL, loc);
511 break;
512
513 case PPD_CUSTOM_POINTS :
514 cparam->current.custom_points = (float)_cupsStrScand(val->value,
515 &units,
516 loc);
517
518 if (units)
519 {
520 if (!strcasecmp(units, "cm"))
521 cparam->current.custom_points *= 72.0f / 2.54f;
522 else if (!strcasecmp(units, "mm"))
523 cparam->current.custom_points *= 72.0f / 25.4f;
524 else if (!strcasecmp(units, "m"))
525 cparam->current.custom_points *= 72.0f / 0.0254f;
526 else if (!strcasecmp(units, "in"))
527 cparam->current.custom_points *= 72.0f;
528 else if (!strcasecmp(units, "ft"))
529 cparam->current.custom_points *= 12.0f * 72.0f;
530 }
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 }
551 else
552 {
553 for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
554 if (!strcasecmp(c->choice, choice))
555 break;
556
557 if (!i)
558 return (0);
559 }
560
561 /*
562 * Option found; mark it and then handle unmarking any other options.
563 */
564
565 if (o->ui != PPD_UI_PICKMANY)
566 {
567 /*
568 * Unmark all other choices...
569 */
570
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"))
593 {
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 */
623
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 */
640
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 }
649 }
650 }
651 }
652
653 c->marked = 1;
654
655 cupsArrayAdd(ppd->marked, c);
656
657 /*
658 * Return the number of conflicts...
659 */
660
661 return (ppdConflicts(ppd));
662 }
663
664
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
673 ppd_option_t * /* O - First option or NULL */
674 ppdFirstOption(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
691 ppd_option_t * /* O - Next option or NULL */
692 ppdNextOption(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
701 /*
702 * 'ppd_defaults()' - Set the defaults for this group and all sub-groups.
703 */
704
705 static void
706 ppd_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
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 /*
724 * End of "$Id: mark.c 6649 2007-07-11 21:46:42Z mike $".
725 */