]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/options.c
Load cups into easysw/current.
[thirdparty/cups.git] / cups / options.c
1 /*
2 * "$Id: options.c 6601 2007-06-22 21:27:22Z mike $"
3 *
4 * Option routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2007 by Easy Software Products.
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 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * cupsAddOption() - Add an option to an option array.
29 * cupsFreeOptions() - Free all memory used by options.
30 * cupsGetOption() - Get an option value.
31 * cupsMarkOptions() - Mark command-line options in a PPD file.
32 * cupsParseOptions() - Parse options from a command-line argument.
33 * cupsRemoveOptions() - Remove an option from an option array.
34 * ppd_mark_choices() - Mark one or more option choices from a string.
35 */
36
37 /*
38 * Include necessary headers...
39 */
40
41 #include "cups.h"
42 #include <stdlib.h>
43 #include <ctype.h>
44 #include "string.h"
45 #include "debug.h"
46
47
48 /*
49 * Local functions...
50 */
51
52 static int ppd_mark_choices(ppd_file_t *ppd, const char *options);
53
54
55 /*
56 * 'cupsAddOption()' - Add an option to an option array.
57 */
58
59 int /* O - Number of options */
60 cupsAddOption(const char *name, /* I - Name of option */
61 const char *value, /* I - Value of option */
62 int num_options,/* I - Number of options */
63 cups_option_t **options) /* IO - Pointer to options */
64 {
65 int i; /* Looping var */
66 cups_option_t *temp; /* Pointer to new option */
67
68
69 if (name == NULL || !name[0] || value == NULL ||
70 options == NULL || num_options < 0)
71 return (num_options);
72
73 /*
74 * Look for an existing option with the same name...
75 */
76
77 for (i = 0, temp = *options; i < num_options; i ++, temp ++)
78 if (strcasecmp(temp->name, name) == 0)
79 break;
80
81 if (i >= num_options)
82 {
83 /*
84 * No matching option name...
85 */
86
87 if (num_options == 0)
88 temp = (cups_option_t *)malloc(sizeof(cups_option_t));
89 else
90 temp = (cups_option_t *)realloc(*options, sizeof(cups_option_t) *
91 (num_options + 1));
92
93 if (temp == NULL)
94 return (0);
95
96 *options = temp;
97 temp += num_options;
98 temp->name = strdup(name);
99 num_options ++;
100 }
101 else
102 {
103 /*
104 * Match found; free the old value...
105 */
106
107 free(temp->value);
108 }
109
110 temp->value = strdup(value);
111
112 return (num_options);
113 }
114
115
116 /*
117 * 'cupsFreeOptions()' - Free all memory used by options.
118 */
119
120 void
121 cupsFreeOptions(
122 int num_options, /* I - Number of options */
123 cups_option_t *options) /* I - Pointer to options */
124 {
125 int i; /* Looping var */
126
127
128 if (num_options <= 0 || options == NULL)
129 return;
130
131 for (i = 0; i < num_options; i ++)
132 {
133 free(options[i].name);
134 free(options[i].value);
135 }
136
137 free(options);
138 }
139
140
141 /*
142 * 'cupsGetOption()' - Get an option value.
143 */
144
145 const char * /* O - Option value or NULL */
146 cupsGetOption(const char *name, /* I - Name of option */
147 int num_options,/* I - Number of options */
148 cups_option_t *options) /* I - Options */
149 {
150 int i; /* Looping var */
151
152
153 if (name == NULL || num_options <= 0 || options == NULL)
154 return (NULL);
155
156 for (i = 0; i < num_options; i ++)
157 if (strcasecmp(options[i].name, name) == 0)
158 return (options[i].value);
159
160 return (NULL);
161 }
162
163
164 /*
165 * 'cupsMarkOptions()' - Mark command-line options in a PPD file.
166 */
167
168 int /* O - 1 if conflicting */
169 cupsMarkOptions(
170 ppd_file_t *ppd, /* I - PPD file */
171 int num_options, /* I - Number of options */
172 cups_option_t *options) /* I - Options */
173 {
174 int i, j, k; /* Looping vars */
175 int conflict; /* Option conflicts */
176 char *val, /* Pointer into value */
177 *ptr, /* Pointer into string */
178 s[255]; /* Temporary string */
179 const char *page_size; /* PageSize option */
180 cups_option_t *optptr; /* Current option */
181 ppd_option_t *option; /* PPD option */
182 ppd_attr_t *attr; /* PPD attribute */
183 static const char * const duplex_options[] =
184 { /* Duplex option names */
185 "Duplex", /* Adobe */
186 "EFDuplex", /* EFI */
187 "EFDuplexing", /* EFI */
188 "KD03Duplex", /* Kodak */
189 "JCLDuplex" /* Samsung */
190 };
191 static const char * const duplex_one[] =
192 { /* one-sided names */
193 "None",
194 "False"
195 };
196 static const char * const duplex_two_long[] =
197 { /* two-sided-long-edge names */
198 "DuplexNoTumble", /* Adobe */
199 "LongEdge", /* EFI */
200 "Top" /* EFI */
201 };
202 static const char * const duplex_two_short[] =
203 { /* two-sided-long-edge names */
204 "DuplexTumble", /* Adobe */
205 "ShortEdge", /* EFI */
206 "Bottom" /* EFI */
207 };
208
209
210 /*
211 * Check arguments...
212 */
213
214 if (ppd == NULL || num_options <= 0 || options == NULL)
215 return (0);
216
217 /*
218 * Mark options...
219 */
220
221 conflict = 0;
222
223 for (i = num_options, optptr = options; i > 0; i --, optptr ++)
224 if (!strcasecmp(optptr->name, "media"))
225 {
226 /*
227 * Loop through the option string, separating it at commas and
228 * marking each individual option as long as the corresponding
229 * PPD option (PageSize, InputSlot, etc.) is not also set.
230 *
231 * For PageSize, we also check for an empty option value since
232 * some versions of MacOS X use it to specify auto-selection
233 * of the media based solely on the size.
234 */
235
236 page_size = cupsGetOption("PageSize", num_options, options);
237
238 for (val = optptr->value; *val;)
239 {
240 /*
241 * Extract the sub-option from the string...
242 */
243
244 for (ptr = s; *val && *val != ',' && (ptr - s) < (sizeof(s) - 1);)
245 *ptr++ = *val++;
246 *ptr++ = '\0';
247
248 if (*val == ',')
249 val ++;
250
251 /*
252 * Mark it...
253 */
254
255 if (!page_size || !page_size[0])
256 if (ppdMarkOption(ppd, "PageSize", s))
257 conflict = 1;
258
259 if (cupsGetOption("InputSlot", num_options, options) == NULL)
260 if (ppdMarkOption(ppd, "InputSlot", s))
261 conflict = 1;
262
263 if (cupsGetOption("MediaType", num_options, options) == NULL)
264 if (ppdMarkOption(ppd, "MediaType", s))
265 conflict = 1;
266
267 if (cupsGetOption("EFMediaType", num_options, options) == NULL)
268 if (ppdMarkOption(ppd, "EFMediaType", s))
269 conflict = 1;
270
271 if (cupsGetOption("EFMediaQualityMode", num_options, options) == NULL)
272 if (ppdMarkOption(ppd, "EFMediaQualityMode", s)) /* EFI */
273 conflict = 1;
274
275 if (strcasecmp(s, "manual") == 0 &&
276 cupsGetOption("ManualFeed", num_options, options) == NULL)
277 if (ppdMarkOption(ppd, "ManualFeed", "True"))
278 conflict = 1;
279 }
280 }
281 else if (!strcasecmp(optptr->name, "sides"))
282 {
283 for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
284 if (cupsGetOption(duplex_options[j], num_options, options) != NULL)
285 break;
286
287 if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
288 {
289 /*
290 * Don't override the PPD option with the IPP attribute...
291 */
292
293 continue;
294 }
295
296 if (!strcasecmp(optptr->value, "one-sided"))
297 {
298 /*
299 * Mark the appropriate duplex option for one-sided output...
300 */
301
302 for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
303 if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL)
304 break;
305
306 if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
307 {
308 for (k = 0; k < (int)(sizeof(duplex_one) / sizeof(duplex_one[0])); k ++)
309 if (ppdFindChoice(option, duplex_one[k]))
310 {
311 if (ppdMarkOption(ppd, duplex_options[j], duplex_one[k]))
312 conflict = 1;
313
314 break;
315 }
316 }
317 }
318 else if (!strcasecmp(optptr->value, "two-sided-long-edge"))
319 {
320 /*
321 * Mark the appropriate duplex option for two-sided-long-edge output...
322 */
323
324 for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
325 if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL)
326 break;
327
328 if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
329 {
330 for (k = 0; k < (int)(sizeof(duplex_two_long) / sizeof(duplex_two_long[0])); k ++)
331 if (ppdFindChoice(option, duplex_two_long[k]))
332 {
333 if (ppdMarkOption(ppd, duplex_options[j], duplex_two_long[k]))
334 conflict = 1;
335
336 break;
337 }
338 }
339 }
340 else if (!strcasecmp(optptr->value, "two-sided-short-edge"))
341 {
342 /*
343 * Mark the appropriate duplex option for two-sided-short-edge output...
344 */
345
346 for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
347 if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL)
348 break;
349
350 if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
351 {
352 for (k = 0; k < (int)(sizeof(duplex_two_short) / sizeof(duplex_two_short[0])); k ++)
353 if (ppdFindChoice(option, duplex_two_short[k]))
354 {
355 if (ppdMarkOption(ppd, duplex_options[j], duplex_two_short[k]))
356 conflict = 1;
357
358 break;
359 }
360 }
361 }
362 }
363 else if (!strcasecmp(optptr->name, "resolution") ||
364 !strcasecmp(optptr->name, "printer-resolution"))
365 {
366 if (ppdMarkOption(ppd, "Resolution", optptr->value))
367 conflict = 1;
368 if (ppdMarkOption(ppd, "SetResolution", optptr->value))
369 /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */
370 conflict = 1;
371 if (ppdMarkOption(ppd, "JCLResolution", optptr->value)) /* HP */
372 conflict = 1;
373 if (ppdMarkOption(ppd, "CNRes_PGP", optptr->value)) /* Canon */
374 conflict = 1;
375 }
376 else if (!strcasecmp(optptr->name, "output-bin"))
377 {
378 if (!cupsGetOption("OutputBin", num_options, options))
379 if (ppdMarkOption(ppd, "OutputBin", optptr->value))
380 conflict = 1;
381 }
382 else if (!strcasecmp(optptr->name, "multiple-document-handling"))
383 {
384 if (!cupsGetOption("Collate", num_options, options) &&
385 ppdFindOption(ppd, "Collate"))
386 {
387 if (strcasecmp(optptr->value, "separate-documents-uncollated-copies"))
388 {
389 if (ppdMarkOption(ppd, "Collate", "True"))
390 conflict = 1;
391 }
392 else
393 {
394 if (ppdMarkOption(ppd, "Collate", "False"))
395 conflict = 1;
396 }
397 }
398 }
399 else if (!strcasecmp(optptr->name, "finishings"))
400 {
401 /*
402 * Lookup cupsIPPFinishings attributes for each value...
403 */
404
405 for (ptr = optptr->value; *ptr;)
406 {
407 /*
408 * Get the next finishings number...
409 */
410
411 if (!isdigit(*ptr & 255))
412 break;
413
414 if ((j = strtol(ptr, &ptr, 10)) < 3)
415 break;
416
417 /*
418 * Skip separator as needed...
419 */
420
421 if (*ptr == ',')
422 ptr ++;
423
424 /*
425 * Look it up in the PPD file...
426 */
427
428 sprintf(s, "%d", j);
429
430 if ((attr = ppdFindAttr(ppd, "cupsIPPFinishings", s)) == NULL)
431 continue;
432
433 /*
434 * Apply "*Option Choice" settings from the attribute value...
435 */
436
437 if (ppd_mark_choices(ppd, attr->value))
438 conflict = 1;
439 }
440 }
441 else if (!strcasecmp(optptr->name, "mirror") &&
442 ppdMarkOption(ppd, "MirrorPrint", optptr->value))
443 conflict = 1;
444 else if (ppdMarkOption(ppd, optptr->name, optptr->value))
445 conflict = 1;
446
447 return (conflict);
448 }
449
450
451 /*
452 * 'cupsParseOptions()' - Parse options from a command-line argument.
453 *
454 * This function converts space-delimited name/value pairs according
455 * to the PAPI text option ABNF specification. Collection values
456 * ("name={a=... b=... c=...}") are stored with the curley brackets
457 * intact - use cupsParseOptions() on the value to extract the collection
458 * attributes.
459 */
460
461 int /* O - Number of options found */
462 cupsParseOptions(
463 const char *arg, /* I - Argument to parse */
464 int num_options, /* I - Number of options */
465 cups_option_t **options) /* O - Options found */
466 {
467 char *copyarg, /* Copy of input string */
468 *ptr, /* Pointer into string */
469 *name, /* Pointer to name */
470 *value; /* Pointer to value */
471
472
473 if (arg == NULL || options == NULL || num_options < 0)
474 return (0);
475
476 /*
477 * Make a copy of the argument string and then divide it up...
478 */
479
480 copyarg = strdup(arg);
481 ptr = copyarg;
482
483 /*
484 * Skip leading spaces...
485 */
486
487 while (isspace(*ptr & 255))
488 ptr ++;
489
490 /*
491 * Loop through the string...
492 */
493
494 while (*ptr != '\0')
495 {
496 /*
497 * Get the name up to a SPACE, =, or end-of-string...
498 */
499
500 name = ptr;
501 while (!isspace(*ptr & 255) && *ptr != '=' && *ptr != '\0')
502 ptr ++;
503
504 /*
505 * Avoid an empty name...
506 */
507
508 if (ptr == name)
509 break;
510
511 /*
512 * Skip trailing spaces...
513 */
514
515 while (isspace(*ptr & 255))
516 *ptr++ = '\0';
517
518 if (*ptr != '=')
519 {
520 /*
521 * Start of another option...
522 */
523
524 if (strncasecmp(name, "no", 2) == 0)
525 num_options = cupsAddOption(name + 2, "false", num_options,
526 options);
527 else
528 num_options = cupsAddOption(name, "true", num_options, options);
529
530 continue;
531 }
532
533 /*
534 * Remove = and parse the value...
535 */
536
537 *ptr++ = '\0';
538
539 if (*ptr == '\'')
540 {
541 /*
542 * Quoted string constant...
543 */
544
545 ptr ++;
546 value = ptr;
547
548 while (*ptr != '\'' && *ptr != '\0')
549 {
550 if (*ptr == '\\')
551 _cups_strcpy(ptr, ptr + 1);
552
553 ptr ++;
554 }
555
556 if (*ptr != '\0')
557 *ptr++ = '\0';
558 }
559 else if (*ptr == '\"')
560 {
561 /*
562 * Double-quoted string constant...
563 */
564
565 ptr ++;
566 value = ptr;
567
568 while (*ptr != '\"' && *ptr != '\0')
569 {
570 if (*ptr == '\\')
571 _cups_strcpy(ptr, ptr + 1);
572
573 ptr ++;
574 }
575
576 if (*ptr != '\0')
577 *ptr++ = '\0';
578 }
579 else if (*ptr == '{')
580 {
581 /*
582 * Collection value...
583 */
584
585 int depth;
586
587 value = ptr;
588
589 for (depth = 1; *ptr; ptr ++)
590 if (*ptr == '{')
591 depth ++;
592 else if (*ptr == '}')
593 {
594 depth --;
595 if (!depth)
596 {
597 ptr ++;
598
599 if (*ptr != ',')
600 break;
601 }
602 }
603 else if (*ptr == '\\')
604 _cups_strcpy(ptr, ptr + 1);
605
606 if (*ptr != '\0')
607 *ptr++ = '\0';
608 }
609 else
610 {
611 /*
612 * Normal space-delimited string...
613 */
614
615 value = ptr;
616
617 while (!isspace(*ptr & 255) && *ptr != '\0')
618 {
619 if (*ptr == '\\')
620 _cups_strcpy(ptr, ptr + 1);
621
622 ptr ++;
623 }
624 }
625
626 /*
627 * Skip trailing whitespace...
628 */
629
630 while (isspace(*ptr & 255))
631 *ptr++ = '\0';
632
633 /*
634 * Add the string value...
635 */
636
637 num_options = cupsAddOption(name, value, num_options, options);
638 }
639
640 /*
641 * Free the copy of the argument we made and return the number of options
642 * found.
643 */
644
645 free(copyarg);
646
647 return (num_options);
648 }
649
650
651 /*
652 * 'cupsRemoveOption()' - Remove an option from an option array.
653 *
654 * @since CUPS 1.2@
655 */
656
657 int /* O - New number of options */
658 cupsRemoveOption(
659 const char *name, /* I - Option name */
660 int num_options, /* I - Current number of options */
661 cups_option_t **options) /* IO - Options */
662 {
663 int i; /* Looping var */
664 cups_option_t *option; /* Current option */
665
666
667 /*
668 * Range check input...
669 */
670
671 if (!name || num_options < 1 || !options)
672 return (num_options);
673
674 /*
675 * Loop for the option...
676 */
677
678 for (i = num_options, option = *options; i > 0; i --, option ++)
679 if (!strcasecmp(name, option->name))
680 break;
681
682 if (i)
683 {
684 /*
685 * Remove this option from the array...
686 */
687
688 num_options --;
689 i --;
690
691 free(option->name);
692 if (option->value)
693 free(option->value);
694
695 if (i > 0)
696 memmove(option, option + 1, i * sizeof(cups_option_t));
697 }
698
699 /*
700 * Return the new number of options...
701 */
702
703 return (num_options);
704 }
705
706
707 /*
708 * 'ppd_mark_choices()' - Mark one or more option choices from a string.
709 */
710
711 static int /* O - 1 if there are conflicts, 0 otherwise */
712 ppd_mark_choices(ppd_file_t *ppd, /* I - PPD file */
713 const char *options) /* I - "*Option Choice ..." string */
714 {
715 char option[PPD_MAX_NAME], /* Current option */
716 choice[PPD_MAX_NAME], /* Current choice */
717 *ptr; /* Pointer into option or choice */
718 int conflict = 0; /* Do we have a conflict? */
719
720
721 if (!options)
722 return (0);
723
724 /*
725 * Read all of the "*Option Choice" pairs from the string, marking PPD
726 * options as we go...
727 */
728
729 while (*options)
730 {
731 /*
732 * Skip leading whitespace...
733 */
734
735 while (isspace(*options & 255))
736 options ++;
737
738 if (*options != '*')
739 break;
740
741 /*
742 * Get the option name...
743 */
744
745 options ++;
746 ptr = option;
747 while (*options && !isspace(*options & 255) &&
748 ptr < (option + sizeof(option) - 1))
749 *ptr++ = *options++;
750
751 if (ptr == option)
752 break;
753
754 *ptr = '\0';
755
756 /*
757 * Get the choice...
758 */
759
760 while (isspace(*options & 255))
761 options ++;
762
763 if (!*options)
764 break;
765
766 ptr = choice;
767 while (*options && !isspace(*options & 255) &&
768 ptr < (choice + sizeof(choice) - 1))
769 *ptr++ = *options++;
770
771 *ptr = '\0';
772
773 /*
774 * Mark the option...
775 */
776
777 if (ppdMarkOption(ppd, option, choice))
778 conflict = 1;
779 }
780
781 /*
782 * Return whether we had any conflicts...
783 */
784
785 return (conflict);
786 }
787
788
789 /*
790 * End of "$Id: options.c 6601 2007-06-22 21:27:22Z mike $".
791 */