]>
git.ipfire.org Git - thirdparty/cups.git/blob - cups/options.c
2 * "$Id: options.c 6943 2007-09-10 23:00:33Z mike $"
4 * Option routines for the Common UNIX Printing System (CUPS).
6 * Copyright 2007 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
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/".
15 * This file is subject to the Apple OS-Developed Software exception.
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.
25 * debug_marked() - Output the marked array to stdout...
26 * ppd_mark_choices() - Mark one or more option choices from a string.
30 * Include necessary headers...
45 static void debug_marked(ppd_file_t
*ppd
, const char *title
);
47 # define debug_marked(ppd,title)
49 static int ppd_mark_choices(ppd_file_t
*ppd
, const char *options
);
53 * 'cupsAddOption()' - Add an option to an option array.
56 int /* O - Number of options */
57 cupsAddOption(const char *name
, /* I - Name of option */
58 const char *value
, /* I - Value of option */
59 int num_options
,/* I - Number of options */
60 cups_option_t
**options
) /* IO - Pointer to options */
62 int i
; /* Looping var */
63 cups_option_t
*temp
; /* Pointer to new option */
66 if (name
== NULL
|| !name
[0] || value
== NULL
||
67 options
== NULL
|| num_options
< 0)
71 * Look for an existing option with the same name...
74 for (i
= 0, temp
= *options
; i
< num_options
; i
++, temp
++)
75 if (!strcasecmp(temp
->name
, name
))
81 * No matching option name...
85 temp
= (cups_option_t
*)malloc(sizeof(cups_option_t
));
87 temp
= (cups_option_t
*)realloc(*options
, sizeof(cups_option_t
) *
95 temp
->name
= _cupsStrAlloc(name
);
101 * Match found; free the old value...
104 _cupsStrFree(temp
->value
);
107 temp
->value
= _cupsStrAlloc(value
);
109 return (num_options
);
114 * 'cupsFreeOptions()' - Free all memory used by options.
119 int num_options
, /* I - Number of options */
120 cups_option_t
*options
) /* I - Pointer to options */
122 int i
; /* Looping var */
125 if (num_options
<= 0 || options
== NULL
)
128 for (i
= 0; i
< num_options
; i
++)
130 _cupsStrFree(options
[i
].name
);
131 _cupsStrFree(options
[i
].value
);
139 * 'cupsGetOption()' - Get an option value.
142 const char * /* O - Option value or NULL */
143 cupsGetOption(const char *name
, /* I - Name of option */
144 int num_options
,/* I - Number of options */
145 cups_option_t
*options
) /* I - Options */
147 int i
; /* Looping var */
150 if (name
== NULL
|| num_options
<= 0 || options
== NULL
)
153 for (i
= 0; i
< num_options
; i
++)
154 if (strcasecmp(options
[i
].name
, name
) == 0)
155 return (options
[i
].value
);
162 * 'cupsMarkOptions()' - Mark command-line options in a PPD file.
165 int /* O - 1 if conflicting */
167 ppd_file_t
*ppd
, /* I - PPD file */
168 int num_options
, /* I - Number of options */
169 cups_option_t
*options
) /* I - Options */
171 int i
, j
, k
; /* Looping vars */
172 int conflict
; /* Option conflicts */
173 char *val
, /* Pointer into value */
174 *ptr
, /* Pointer into string */
175 s
[255]; /* Temporary string */
176 const char *page_size
; /* PageSize option */
177 cups_option_t
*optptr
; /* Current option */
178 ppd_option_t
*option
; /* PPD option */
179 ppd_attr_t
*attr
; /* PPD attribute */
180 static const char * const duplex_options
[] =
181 { /* Duplex option names */
182 "Duplex", /* Adobe */
183 "EFDuplex", /* EFI */
184 "EFDuplexing", /* EFI */
185 "KD03Duplex", /* Kodak */
186 "JCLDuplex" /* Samsung */
188 static const char * const duplex_one
[] =
189 { /* one-sided names */
193 static const char * const duplex_two_long
[] =
194 { /* two-sided-long-edge names */
195 "DuplexNoTumble", /* Adobe */
196 "LongEdge", /* EFI */
199 static const char * const duplex_two_short
[] =
200 { /* two-sided-long-edge names */
201 "DuplexTumble", /* Adobe */
202 "ShortEdge", /* EFI */
211 if (ppd
== NULL
|| num_options
<= 0 || options
== NULL
)
214 debug_marked(ppd
, "Before...");
222 for (i
= num_options
, optptr
= options
; i
> 0; i
--, optptr
++)
223 if (!strcasecmp(optptr
->name
, "media"))
226 * Loop through the option string, separating it at commas and
227 * marking each individual option as long as the corresponding
228 * PPD option (PageSize, InputSlot, etc.) is not also set.
230 * For PageSize, we also check for an empty option value since
231 * some versions of MacOS X use it to specify auto-selection
232 * of the media based solely on the size.
235 page_size
= cupsGetOption("PageSize", num_options
, options
);
237 for (val
= optptr
->value
; *val
;)
240 * Extract the sub-option from the string...
243 for (ptr
= s
; *val
&& *val
!= ',' && (ptr
- s
) < (sizeof(s
) - 1);)
254 if (!page_size
|| !page_size
[0])
255 if (ppdMarkOption(ppd
, "PageSize", s
))
258 if (cupsGetOption("InputSlot", num_options
, options
) == NULL
)
259 if (ppdMarkOption(ppd
, "InputSlot", s
))
262 if (cupsGetOption("MediaType", num_options
, options
) == NULL
)
263 if (ppdMarkOption(ppd
, "MediaType", s
))
266 if (cupsGetOption("EFMediaType", num_options
, options
) == NULL
)
267 if (ppdMarkOption(ppd
, "EFMediaType", s
)) /* EFI */
270 if (cupsGetOption("EFMediaQualityMode", num_options
, options
) == NULL
)
271 if (ppdMarkOption(ppd
, "EFMediaQualityMode", s
)) /* EFI */
274 if (strcasecmp(s
, "manual") == 0 &&
275 cupsGetOption("ManualFeed", num_options
, options
) == NULL
)
276 if (ppdMarkOption(ppd
, "ManualFeed", "True"))
280 else if (!strcasecmp(optptr
->name
, "sides"))
282 for (j
= 0; j
< (int)(sizeof(duplex_options
) / sizeof(duplex_options
[0])); j
++)
283 if (cupsGetOption(duplex_options
[j
], num_options
, options
) != NULL
)
286 if (j
< (int)(sizeof(duplex_options
) / sizeof(duplex_options
[0])))
289 * Don't override the PPD option with the IPP attribute...
295 if (!strcasecmp(optptr
->value
, "one-sided"))
298 * Mark the appropriate duplex option for one-sided output...
301 for (j
= 0; j
< (int)(sizeof(duplex_options
) / sizeof(duplex_options
[0])); j
++)
302 if ((option
= ppdFindOption(ppd
, duplex_options
[j
])) != NULL
)
305 if (j
< (int)(sizeof(duplex_options
) / sizeof(duplex_options
[0])))
307 for (k
= 0; k
< (int)(sizeof(duplex_one
) / sizeof(duplex_one
[0])); k
++)
308 if (ppdFindChoice(option
, duplex_one
[k
]))
310 if (ppdMarkOption(ppd
, duplex_options
[j
], duplex_one
[k
]))
317 else if (!strcasecmp(optptr
->value
, "two-sided-long-edge"))
320 * Mark the appropriate duplex option for two-sided-long-edge output...
323 for (j
= 0; j
< (int)(sizeof(duplex_options
) / sizeof(duplex_options
[0])); j
++)
324 if ((option
= ppdFindOption(ppd
, duplex_options
[j
])) != NULL
)
327 if (j
< (int)(sizeof(duplex_options
) / sizeof(duplex_options
[0])))
329 for (k
= 0; k
< (int)(sizeof(duplex_two_long
) / sizeof(duplex_two_long
[0])); k
++)
330 if (ppdFindChoice(option
, duplex_two_long
[k
]))
332 if (ppdMarkOption(ppd
, duplex_options
[j
], duplex_two_long
[k
]))
339 else if (!strcasecmp(optptr
->value
, "two-sided-short-edge"))
342 * Mark the appropriate duplex option for two-sided-short-edge output...
345 for (j
= 0; j
< (int)(sizeof(duplex_options
) / sizeof(duplex_options
[0])); j
++)
346 if ((option
= ppdFindOption(ppd
, duplex_options
[j
])) != NULL
)
349 if (j
< (int)(sizeof(duplex_options
) / sizeof(duplex_options
[0])))
351 for (k
= 0; k
< (int)(sizeof(duplex_two_short
) / sizeof(duplex_two_short
[0])); k
++)
352 if (ppdFindChoice(option
, duplex_two_short
[k
]))
354 if (ppdMarkOption(ppd
, duplex_options
[j
], duplex_two_short
[k
]))
362 else if (!strcasecmp(optptr
->name
, "resolution") ||
363 !strcasecmp(optptr
->name
, "printer-resolution"))
365 if (ppdMarkOption(ppd
, "Resolution", optptr
->value
))
367 if (ppdMarkOption(ppd
, "SetResolution", optptr
->value
))
368 /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */
370 if (ppdMarkOption(ppd
, "JCLResolution", optptr
->value
)) /* HP */
372 if (ppdMarkOption(ppd
, "CNRes_PGP", optptr
->value
)) /* Canon */
375 else if (!strcasecmp(optptr
->name
, "output-bin"))
377 if (!cupsGetOption("OutputBin", num_options
, options
))
378 if (ppdMarkOption(ppd
, "OutputBin", optptr
->value
))
381 else if (!strcasecmp(optptr
->name
, "multiple-document-handling"))
383 if (!cupsGetOption("Collate", num_options
, options
) &&
384 ppdFindOption(ppd
, "Collate"))
386 if (strcasecmp(optptr
->value
, "separate-documents-uncollated-copies"))
388 if (ppdMarkOption(ppd
, "Collate", "True"))
393 if (ppdMarkOption(ppd
, "Collate", "False"))
398 else if (!strcasecmp(optptr
->name
, "finishings"))
401 * Lookup cupsIPPFinishings attributes for each value...
404 for (ptr
= optptr
->value
; *ptr
;)
407 * Get the next finishings number...
410 if (!isdigit(*ptr
& 255))
413 if ((j
= strtol(ptr
, &ptr
, 10)) < 3)
417 * Skip separator as needed...
424 * Look it up in the PPD file...
429 if ((attr
= ppdFindAttr(ppd
, "cupsIPPFinishings", s
)) == NULL
)
433 * Apply "*Option Choice" settings from the attribute value...
436 if (ppd_mark_choices(ppd
, attr
->value
))
440 else if (!strcasecmp(optptr
->name
, "mirror"))
442 if (ppdMarkOption(ppd
, "MirrorPrint", optptr
->value
))
445 else if (ppdMarkOption(ppd
, optptr
->name
, optptr
->value
))
448 debug_marked(ppd
, "After...");
455 * 'cupsParseOptions()' - Parse options from a command-line argument.
457 * This function converts space-delimited name/value pairs according
458 * to the PAPI text option ABNF specification. Collection values
459 * ("name={a=... b=... c=...}") are stored with the curley brackets
460 * intact - use cupsParseOptions() on the value to extract the collection
464 int /* O - Number of options found */
466 const char *arg
, /* I - Argument to parse */
467 int num_options
, /* I - Number of options */
468 cups_option_t
**options
) /* O - Options found */
470 char *copyarg
, /* Copy of input string */
471 *ptr
, /* Pointer into string */
472 *name
, /* Pointer to name */
473 *value
; /* Pointer to value */
476 if (arg
== NULL
|| options
== NULL
|| num_options
< 0)
480 * Make a copy of the argument string and then divide it up...
483 copyarg
= strdup(arg
);
487 * Skip leading spaces...
490 while (isspace(*ptr
& 255))
494 * Loop through the string...
500 * Get the name up to a SPACE, =, or end-of-string...
504 while (!isspace(*ptr
& 255) && *ptr
!= '=' && *ptr
!= '\0')
508 * Avoid an empty name...
515 * Skip trailing spaces...
518 while (isspace(*ptr
& 255))
524 * Start of another option...
527 if (strncasecmp(name
, "no", 2) == 0)
528 num_options
= cupsAddOption(name
+ 2, "false", num_options
,
531 num_options
= cupsAddOption(name
, "true", num_options
, options
);
537 * Remove = and parse the value...
545 * Quoted string constant...
551 while (*ptr
!= '\'' && *ptr
!= '\0')
554 _cups_strcpy(ptr
, ptr
+ 1);
562 else if (*ptr
== '\"')
565 * Double-quoted string constant...
571 while (*ptr
!= '\"' && *ptr
!= '\0')
574 _cups_strcpy(ptr
, ptr
+ 1);
582 else if (*ptr
== '{')
585 * Collection value...
592 for (depth
= 1; *ptr
; ptr
++)
595 else if (*ptr
== '}')
606 else if (*ptr
== '\\')
607 _cups_strcpy(ptr
, ptr
+ 1);
615 * Normal space-delimited string...
620 while (!isspace(*ptr
& 255) && *ptr
!= '\0')
623 _cups_strcpy(ptr
, ptr
+ 1);
630 * Skip trailing whitespace...
633 while (isspace(*ptr
& 255))
637 * Add the string value...
640 num_options
= cupsAddOption(name
, value
, num_options
, options
);
644 * Free the copy of the argument we made and return the number of options
650 return (num_options
);
655 * 'cupsRemoveOption()' - Remove an option from an option array.
660 int /* O - New number of options */
662 const char *name
, /* I - Option name */
663 int num_options
, /* I - Current number of options */
664 cups_option_t
**options
) /* IO - Options */
666 int i
; /* Looping var */
667 cups_option_t
*option
; /* Current option */
671 * Range check input...
674 if (!name
|| num_options
< 1 || !options
)
675 return (num_options
);
678 * Loop for the option...
681 for (i
= num_options
, option
= *options
; i
> 0; i
--, option
++)
682 if (!strcasecmp(name
, option
->name
))
688 * Remove this option from the array...
694 _cupsStrFree(option
->name
);
695 _cupsStrFree(option
->value
);
698 memmove(option
, option
+ 1, i
* sizeof(cups_option_t
));
702 * Return the new number of options...
705 return (num_options
);
711 * 'debug_marked()' - Output the marked array to stdout...
715 debug_marked(ppd_file_t
*ppd
, /* I - PPD file data */
716 const char *title
) /* I - Title for list */
718 ppd_choice_t
*c
; /* Current choice */
721 printf("cupsMarkOptions: %s\n", title
);
723 for (c
= (ppd_choice_t
*)cupsArrayFirst(ppd
->marked
);
725 c
= (ppd_choice_t
*)cupsArrayNext(ppd
->marked
))
726 printf("cupsMarkOptions: %s=%s\n", c
->option
->keyword
, c
->choice
);
732 * 'ppd_mark_choices()' - Mark one or more option choices from a string.
735 static int /* O - 1 if there are conflicts, 0 otherwise */
736 ppd_mark_choices(ppd_file_t
*ppd
, /* I - PPD file */
737 const char *options
) /* I - "*Option Choice ..." string */
739 char option
[PPD_MAX_NAME
], /* Current option */
740 choice
[PPD_MAX_NAME
], /* Current choice */
741 *ptr
; /* Pointer into option or choice */
742 int conflict
= 0; /* Do we have a conflict? */
749 * Read all of the "*Option Choice" pairs from the string, marking PPD
750 * options as we go...
756 * Skip leading whitespace...
759 while (isspace(*options
& 255))
766 * Get the option name...
771 while (*options
&& !isspace(*options
& 255) &&
772 ptr
< (option
+ sizeof(option
) - 1))
784 while (isspace(*options
& 255))
791 while (*options
&& !isspace(*options
& 255) &&
792 ptr
< (choice
+ sizeof(choice
) - 1))
801 if (ppdMarkOption(ppd
, option
, choice
))
806 * Return whether we had any conflicts...
814 * End of "$Id: options.c 6943 2007-09-10 23:00:33Z mike $".