]>
git.ipfire.org Git - thirdparty/cups.git/blob - cups/options.c
2 * Option routines for CUPS.
4 * Copyright 2007-2017 by Apple Inc.
5 * Copyright 1997-2007 by Easy Software Products.
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
11 * Include necessary headers...
14 #include "cups-private.h"
15 #include "debug-internal.h"
22 static int cups_compare_options(cups_option_t
*a
, cups_option_t
*b
);
23 static int cups_find_option(const char *name
, int num_options
,
24 cups_option_t
*option
, int prev
, int *rdiff
);
28 * 'cupsAddIntegerOption()' - Add an integer option to an option array.
30 * New option arrays can be initialized simply by passing 0 for the
31 * "num_options" parameter.
33 * @since CUPS 2.2.4/macOS 10.13@
36 int /* O - Number of options */
38 const char *name
, /* I - Name of option */
39 int value
, /* I - Value of option */
40 int num_options
, /* I - Number of options */
41 cups_option_t
**options
) /* IO - Pointer to options */
43 char strvalue
[32]; /* String value */
46 snprintf(strvalue
, sizeof(strvalue
), "%d", value
);
48 return (cupsAddOption(name
, strvalue
, num_options
, options
));
53 * 'cupsAddOption()' - Add an option to an option array.
55 * New option arrays can be initialized simply by passing 0 for the
56 * "num_options" parameter.
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 */
65 cups_option_t
*temp
; /* Pointer to new option */
66 int insert
, /* Insertion point */
67 diff
; /* Result of search */
70 DEBUG_printf(("2cupsAddOption(name=\"%s\", value=\"%s\", num_options=%d, options=%p)", name
, value
, num_options
, (void *)options
));
72 if (!name
|| !name
[0] || !value
|| !options
|| num_options
< 0)
74 DEBUG_printf(("3cupsAddOption: Returning %d", num_options
));
78 if (!_cups_strcasecmp(name
, "cupsPrintQuality"))
79 num_options
= cupsRemoveOption("print-quality", num_options
, options
);
80 else if (!_cups_strcasecmp(name
, "print-quality"))
81 num_options
= cupsRemoveOption("cupsPrintQuality", num_options
, options
);
84 * Look for an existing option with the same name...
94 insert
= cups_find_option(name
, num_options
, *options
, num_options
- 1,
104 * No matching option name...
107 DEBUG_printf(("4cupsAddOption: New option inserted at index %d...",
110 if (num_options
== 0)
111 temp
= (cups_option_t
*)malloc(sizeof(cups_option_t
));
113 temp
= (cups_option_t
*)realloc(*options
, sizeof(cups_option_t
) * (size_t)(num_options
+ 1));
117 DEBUG_puts("3cupsAddOption: Unable to expand option array, returning 0");
123 if (insert
< num_options
)
125 DEBUG_printf(("4cupsAddOption: Shifting %d options...",
126 (int)(num_options
- insert
)));
127 memmove(temp
+ insert
+ 1, temp
+ insert
, (size_t)(num_options
- insert
) * sizeof(cups_option_t
));
131 temp
->name
= _cupsStrAlloc(name
);
137 * Match found; free the old value...
140 DEBUG_printf(("4cupsAddOption: Option already exists at index %d...",
143 temp
= *options
+ insert
;
144 _cupsStrFree(temp
->value
);
147 temp
->value
= _cupsStrAlloc(value
);
149 DEBUG_printf(("3cupsAddOption: Returning %d", num_options
));
151 return (num_options
);
156 * 'cupsFreeOptions()' - Free all memory used by options.
161 int num_options
, /* I - Number of options */
162 cups_option_t
*options
) /* I - Pointer to options */
164 int i
; /* Looping var */
167 DEBUG_printf(("cupsFreeOptions(num_options=%d, options=%p)", num_options
, (void *)options
));
169 if (num_options
<= 0 || !options
)
172 for (i
= 0; i
< num_options
; i
++)
174 _cupsStrFree(options
[i
].name
);
175 _cupsStrFree(options
[i
].value
);
183 * 'cupsGetIntegerOption()' - Get an integer option value.
185 * INT_MIN is returned when the option does not exist, is not an integer, or
186 * exceeds the range of values for the "int" type.
188 * @since CUPS 2.2.4/macOS 10.13@
191 int /* O - Option value or @code INT_MIN@ */
192 cupsGetIntegerOption(
193 const char *name
, /* I - Name of option */
194 int num_options
, /* I - Number of options */
195 cups_option_t
*options
) /* I - Options */
197 const char *value
= cupsGetOption(name
, num_options
, options
);
198 /* String value of option */
199 char *ptr
; /* Pointer into string value */
200 long intvalue
; /* Integer value */
203 if (!value
|| !*value
)
206 intvalue
= strtol(value
, &ptr
, 10);
207 if (intvalue
< INT_MIN
|| intvalue
> INT_MAX
|| *ptr
)
210 return ((int)intvalue
);
215 * 'cupsGetOption()' - Get an option value.
218 const char * /* O - Option value or @code NULL@ */
219 cupsGetOption(const char *name
, /* I - Name of option */
220 int num_options
,/* I - Number of options */
221 cups_option_t
*options
) /* I - Options */
223 int diff
, /* Result of comparison */
224 match
; /* Matching index */
227 DEBUG_printf(("2cupsGetOption(name=\"%s\", num_options=%d, options=%p)", name
, num_options
, (void *)options
));
229 if (!name
|| num_options
<= 0 || !options
)
231 DEBUG_puts("3cupsGetOption: Returning NULL");
235 match
= cups_find_option(name
, num_options
, options
, -1, &diff
);
239 DEBUG_printf(("3cupsGetOption: Returning \"%s\"", options
[match
].value
));
240 return (options
[match
].value
);
243 DEBUG_puts("3cupsGetOption: Returning NULL");
249 * 'cupsParseOptions()' - Parse options from a command-line argument.
251 * This function converts space-delimited name/value pairs according
252 * to the PAPI text option ABNF specification. Collection values
253 * ("name={a=... b=... c=...}") are stored with the curley brackets
254 * intact - use @code cupsParseOptions@ on the value to extract the
255 * collection attributes.
258 int /* O - Number of options found */
260 const char *arg
, /* I - Argument to parse */
261 int num_options
, /* I - Number of options */
262 cups_option_t
**options
) /* O - Options found */
264 char *copyarg
, /* Copy of input string */
265 *ptr
, /* Pointer into string */
266 *name
, /* Pointer to name */
267 *value
, /* Pointer to value */
268 sep
, /* Separator character */
269 quote
; /* Quote character */
272 DEBUG_printf(("cupsParseOptions(arg=\"%s\", num_options=%d, options=%p)", arg
, num_options
, (void *)options
));
275 * Range check input...
280 DEBUG_printf(("1cupsParseOptions: Returning %d", num_options
));
281 return (num_options
);
284 if (!options
|| num_options
< 0)
286 DEBUG_puts("1cupsParseOptions: Returning 0");
291 * Make a copy of the argument string and then divide it up...
294 if ((copyarg
= strdup(arg
)) == NULL
)
296 DEBUG_puts("1cupsParseOptions: Unable to copy arg string");
297 DEBUG_printf(("1cupsParseOptions: Returning %d", num_options
));
298 return (num_options
);
304 * Remove surrounding {} so we can parse "{name=value ... name=value}"...
307 if ((ptr
= copyarg
+ strlen(copyarg
) - 1) > copyarg
&& *ptr
== '}')
319 * Skip leading spaces...
322 while (_cups_isspace(*ptr
))
326 * Loop through the string...
332 * Get the name up to a SPACE, =, or end-of-string...
336 while (!strchr("\f\n\r\t\v =", *ptr
) && *ptr
)
340 * Avoid an empty name...
347 * Skip trailing spaces...
350 while (_cups_isspace(*ptr
))
353 if ((sep
= *ptr
) == '=')
356 DEBUG_printf(("2cupsParseOptions: name=\"%s\"", name
));
364 if (!_cups_strncasecmp(name
, "no", 2))
365 num_options
= cupsAddOption(name
+ 2, "false", num_options
,
368 num_options
= cupsAddOption(name
, "true", num_options
, options
);
374 * Remove = and parse the value...
379 while (*ptr
&& !_cups_isspace(*ptr
))
383 else if (*ptr
== '\'' || *ptr
== '\"')
386 * Quoted string constant...
390 _cups_strcpy(ptr
, ptr
+ 1);
392 while (*ptr
!= quote
&& *ptr
)
394 if (*ptr
== '\\' && ptr
[1])
395 _cups_strcpy(ptr
, ptr
+ 1);
401 _cups_strcpy(ptr
, ptr
+ 1);
403 else if (*ptr
== '{')
406 * Collection value...
411 for (depth
= 0; *ptr
; ptr
++)
415 else if (*ptr
== '}')
424 else if (*ptr
== '\\' && ptr
[1])
425 _cups_strcpy(ptr
, ptr
+ 1);
431 * Normal space-delimited string...
434 while (*ptr
&& !_cups_isspace(*ptr
))
436 if (*ptr
== '\\' && ptr
[1])
437 _cups_strcpy(ptr
, ptr
+ 1);
447 DEBUG_printf(("2cupsParseOptions: value=\"%s\"", value
));
450 * Skip trailing whitespace...
453 while (_cups_isspace(*ptr
))
457 * Add the string value...
460 num_options
= cupsAddOption(name
, value
, num_options
, options
);
464 * Free the copy of the argument we made and return the number of options
470 DEBUG_printf(("1cupsParseOptions: Returning %d", num_options
));
472 return (num_options
);
477 * 'cupsRemoveOption()' - Remove an option from an option array.
479 * @since CUPS 1.2/macOS 10.5@
482 int /* O - New number of options */
484 const char *name
, /* I - Option name */
485 int num_options
, /* I - Current number of options */
486 cups_option_t
**options
) /* IO - Options */
488 int i
; /* Looping var */
489 cups_option_t
*option
; /* Current option */
492 DEBUG_printf(("2cupsRemoveOption(name=\"%s\", num_options=%d, options=%p)", name
, num_options
, (void *)options
));
495 * Range check input...
498 if (!name
|| num_options
< 1 || !options
)
500 DEBUG_printf(("3cupsRemoveOption: Returning %d", num_options
));
501 return (num_options
);
505 * Loop for the option...
508 for (i
= num_options
, option
= *options
; i
> 0; i
--, option
++)
509 if (!_cups_strcasecmp(name
, option
->name
))
515 * Remove this option from the array...
518 DEBUG_puts("4cupsRemoveOption: Found option, removing it...");
523 _cupsStrFree(option
->name
);
524 _cupsStrFree(option
->value
);
527 memmove(option
, option
+ 1, (size_t)i
* sizeof(cups_option_t
));
531 * Return the new number of options...
534 DEBUG_printf(("3cupsRemoveOption: Returning %d", num_options
));
535 return (num_options
);
540 * '_cupsGet1284Values()' - Get 1284 device ID keys and values.
542 * The returned dictionary is a CUPS option array that can be queried with
543 * cupsGetOption and freed with cupsFreeOptions.
546 int /* O - Number of key/value pairs */
548 const char *device_id
, /* I - IEEE-1284 device ID string */
549 cups_option_t
**values
) /* O - Array of key/value pairs */
551 int num_values
; /* Number of values */
552 char key
[256], /* Key string */
553 value
[256], /* Value string */
554 *ptr
; /* Pointer into key/value */
558 * Range check input...
564 if (!device_id
|| !values
)
568 * Parse the 1284 device ID value into keys and values. The format is
569 * repeating sequences of:
571 * [whitespace]key:value[whitespace];
577 while (_cups_isspace(*device_id
))
583 for (ptr
= key
; *device_id
&& *device_id
!= ':'; device_id
++)
584 if (ptr
< (key
+ sizeof(key
) - 1))
590 while (ptr
> key
&& _cups_isspace(ptr
[-1]))
596 while (_cups_isspace(*device_id
))
602 for (ptr
= value
; *device_id
&& *device_id
!= ';'; device_id
++)
603 if (ptr
< (value
+ sizeof(value
) - 1))
609 while (ptr
> value
&& _cups_isspace(ptr
[-1]))
615 num_values
= cupsAddOption(key
, value
, num_values
, values
);
623 * 'cups_compare_options()' - Compare two options.
626 static int /* O - Result of comparison */
627 cups_compare_options(cups_option_t
*a
, /* I - First option */
628 cups_option_t
*b
) /* I - Second option */
630 return (_cups_strcasecmp(a
->name
, b
->name
));
635 * 'cups_find_option()' - Find an option using a binary search.
638 static int /* O - Index of match */
640 const char *name
, /* I - Option name */
641 int num_options
, /* I - Number of options */
642 cups_option_t
*options
, /* I - Options */
643 int prev
, /* I - Previous index */
644 int *rdiff
) /* O - Difference of match */
646 int left
, /* Low mark for binary search */
647 right
, /* High mark for binary search */
648 current
, /* Current index */
649 diff
; /* Result of comparison */
650 cups_option_t key
; /* Search key */
653 DEBUG_printf(("7cups_find_option(name=\"%s\", num_options=%d, options=%p, prev=%d, rdiff=%p)", name
, num_options
, (void *)options
, prev
, (void *)rdiff
));
656 for (left
= 0; left
< num_options
; left
++)
657 DEBUG_printf(("9cups_find_option: options[%d].name=\"%s\", .value=\"%s\"",
658 left
, options
[left
].name
, options
[left
].value
));
661 key
.name
= (char *)name
;
666 * Start search on either side of previous...
669 if ((diff
= cups_compare_options(&key
, options
+ prev
)) == 0 ||
670 (diff
< 0 && prev
== 0) ||
671 (diff
> 0 && prev
== (num_options
- 1)))
679 * Start with previous on right side...
688 * Start wih previous on left side...
692 right
= num_options
- 1;
698 * Start search in the middle...
702 right
= num_options
- 1;
707 current
= (left
+ right
) / 2;
708 diff
= cups_compare_options(&key
, options
+ current
);
717 while ((right
- left
) > 1);
722 * Check the last 1 or 2 elements...
725 if ((diff
= cups_compare_options(&key
, options
+ left
)) <= 0)
729 diff
= cups_compare_options(&key
, options
+ right
);
735 * Return the closest destination and the difference...