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