]>
git.ipfire.org Git - thirdparty/cups.git/blob - cups/options.c
2 * "$Id: options.c 8181 2008-12-10 17:29:57Z mike $"
4 * Option routines for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2008 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 * cupsParseOptions() - Parse options from a command-line argument.
23 * cupsRemoveOption() - Remove an option from an option array.
27 * Include necessary headers...
41 static int cups_compare_options(cups_option_t
*a
, cups_option_t
*b
);
42 static int cups_find_option(const char *name
, int num_options
,
43 cups_option_t
*option
, int prev
, int *rdiff
);
47 * 'cupsAddOption()' - Add an option to an option array.
49 * New option arrays can be initialized simply by passing 0 for the
50 * "num_options" parameter.
53 int /* O - Number of options */
54 cupsAddOption(const char *name
, /* I - Name of option */
55 const char *value
, /* I - Value of option */
56 int num_options
,/* I - Number of options */
57 cups_option_t
**options
) /* IO - Pointer to options */
59 cups_option_t
*temp
; /* Pointer to new option */
60 int insert
, /* Insertion point */
61 diff
; /* Result of search */
64 DEBUG_printf(("cupsAddOption(name=\"%s\", value=\"%s\", num_options=%d, "
65 "options=%p)\n", name
, value
, num_options
, options
));
67 if (!name
|| !name
[0] || !value
|| !options
|| num_options
< 0)
69 DEBUG_printf(("cupsAddOption: Returning %d\n", num_options
));
74 * Look for an existing option with the same name...
84 insert
= cups_find_option(name
, num_options
, *options
, num_options
- 1,
94 * No matching option name...
97 DEBUG_printf(("cupsAddOption: New option inserted at index %d...\n",
100 if (num_options
== 0)
101 temp
= (cups_option_t
*)malloc(sizeof(cups_option_t
));
103 temp
= (cups_option_t
*)realloc(*options
, sizeof(cups_option_t
) *
108 DEBUG_puts("cupsAddOption: Unable to expand option array, returning 0");
114 if (insert
< num_options
)
116 DEBUG_printf(("cupsAddOption: Shifting %d options...\n",
117 (int)(num_options
- insert
)));
118 memmove(temp
+ insert
+ 1, temp
+ insert
,
119 (num_options
- insert
) * sizeof(cups_option_t
));
123 temp
->name
= _cupsStrAlloc(name
);
129 * Match found; free the old value...
132 DEBUG_printf(("cupsAddOption: Option already exists at index %d...\n",
135 temp
= *options
+ insert
;
136 _cupsStrFree(temp
->value
);
139 temp
->value
= _cupsStrAlloc(value
);
141 DEBUG_printf(("cupsAddOption: Returning %d\n", num_options
));
143 return (num_options
);
148 * 'cupsFreeOptions()' - Free all memory used by options.
153 int num_options
, /* I - Number of options */
154 cups_option_t
*options
) /* I - Pointer to options */
156 int i
; /* Looping var */
159 DEBUG_printf(("cupsFreeOptions(num_options=%d, options=%p)\n", num_options
,
162 if (num_options
<= 0 || !options
)
165 for (i
= 0; i
< num_options
; i
++)
167 _cupsStrFree(options
[i
].name
);
168 _cupsStrFree(options
[i
].value
);
176 * 'cupsGetOption()' - Get an option value.
179 const char * /* O - Option value or @code NULL@ */
180 cupsGetOption(const char *name
, /* I - Name of option */
181 int num_options
,/* I - Number of options */
182 cups_option_t
*options
) /* I - Options */
184 int diff
, /* Result of comparison */
185 match
; /* Matching index */
188 DEBUG_printf(("cupsGetOption(name=\"%s\", num_options=%d, options=%p)\n",
189 name
, num_options
, options
));
191 if (!name
|| num_options
<= 0 || !options
)
193 DEBUG_puts("cupsGetOption: Returning NULL");
197 match
= cups_find_option(name
, num_options
, options
, -1, &diff
);
201 DEBUG_printf(("cupsGetOption: Returning \"%s\"\n", options
[match
].value
));
202 return (options
[match
].value
);
205 DEBUG_puts("cupsGetOption: Returning NULL");
211 * 'cupsParseOptions()' - Parse options from a command-line argument.
213 * This function converts space-delimited name/value pairs according
214 * to the PAPI text option ABNF specification. Collection values
215 * ("name={a=... b=... c=...}") are stored with the curley brackets
216 * intact - use @code cupsParseOptions@ on the value to extract the
217 * collection attributes.
220 int /* O - Number of options found */
222 const char *arg
, /* I - Argument to parse */
223 int num_options
, /* I - Number of options */
224 cups_option_t
**options
) /* O - Options found */
226 char *copyarg
, /* Copy of input string */
227 *ptr
, /* Pointer into string */
228 *name
, /* Pointer to name */
229 *value
, /* Pointer to value */
230 sep
, /* Separator character */
231 quote
; /* Quote character */
234 DEBUG_printf(("cupsParseOptions(arg=\"%s\", num_options=%d, options=%p)\n",
235 arg
, num_options
, options
));
238 * Range check input...
243 DEBUG_printf(("cupsParseOptions: Returning %d\n", num_options
));
244 return (num_options
);
247 if (!options
|| num_options
< 0)
249 DEBUG_puts("cupsParseOptions: Returning 0");
254 * Make a copy of the argument string and then divide it up...
257 if ((copyarg
= strdup(arg
)) == NULL
)
259 DEBUG_puts("cupsParseOptions: Unable to copy arg string");
260 DEBUG_printf(("cupsParseOptions: Returning %d\n", num_options
));
261 return (num_options
);
267 * Remove surrounding {} so we can parse "{name=value ... name=value}"...
270 if ((ptr
= copyarg
+ strlen(copyarg
) - 1) > copyarg
&& *ptr
== '}')
282 * Skip leading spaces...
285 while (isspace(*ptr
& 255))
289 * Loop through the string...
295 * Get the name up to a SPACE, =, or end-of-string...
299 while (!isspace(*ptr
& 255) && *ptr
!= '=' && *ptr
)
303 * Avoid an empty name...
310 * Skip trailing spaces...
313 while (isspace(*ptr
& 255))
316 if ((sep
= *ptr
) == '=')
319 DEBUG_printf(("cupsParseOptions: name=\"%s\"\n", name
));
327 if (!strncasecmp(name
, "no", 2))
328 num_options
= cupsAddOption(name
+ 2, "false", num_options
,
331 num_options
= cupsAddOption(name
, "true", num_options
, options
);
337 * Remove = and parse the value...
342 while (*ptr
&& !isspace(*ptr
& 255))
346 else if (*ptr
== '\'' || *ptr
== '\"')
349 * Quoted string constant...
353 _cups_strcpy(ptr
, ptr
+ 1);
355 while (*ptr
!= quote
&& *ptr
)
357 if (*ptr
== '\\' && ptr
[1])
358 _cups_strcpy(ptr
, ptr
+ 1);
364 _cups_strcpy(ptr
, ptr
+ 1);
366 else if (*ptr
== '{')
369 * Collection value...
374 for (depth
= 0; *ptr
; ptr
++)
378 else if (*ptr
== '}')
387 else if (*ptr
== '\\' && ptr
[1])
388 _cups_strcpy(ptr
, ptr
+ 1);
394 * Normal space-delimited string...
397 while (!isspace(*ptr
& 255) && *ptr
)
399 if (*ptr
== '\\' && ptr
[1])
400 _cups_strcpy(ptr
, ptr
+ 1);
410 DEBUG_printf(("cupsParseOptions: value=\"%s\"\n", value
));
413 * Skip trailing whitespace...
416 while (isspace(*ptr
& 255))
420 * Add the string value...
423 num_options
= cupsAddOption(name
, value
, num_options
, options
);
427 * Free the copy of the argument we made and return the number of options
433 DEBUG_printf(("cupsParseOptions: Returning %d\n", num_options
));
435 return (num_options
);
440 * 'cupsRemoveOption()' - Remove an option from an option array.
442 * @since CUPS 1.2/Mac OS X 10.5@
445 int /* O - New number of options */
447 const char *name
, /* I - Option name */
448 int num_options
, /* I - Current number of options */
449 cups_option_t
**options
) /* IO - Options */
451 int i
; /* Looping var */
452 cups_option_t
*option
; /* Current option */
455 DEBUG_printf(("cupsRemoveOption(name=\"%s\", num_options=%d, options=%p)\n",
456 name
, num_options
, options
));
459 * Range check input...
462 if (!name
|| num_options
< 1 || !options
)
464 DEBUG_printf(("cupsRemoveOption: Returning %d\n", num_options
));
465 return (num_options
);
469 * Loop for the option...
472 for (i
= num_options
, option
= *options
; i
> 0; i
--, option
++)
473 if (!strcasecmp(name
, option
->name
))
479 * Remove this option from the array...
482 DEBUG_puts("cupsRemoveOption: Found option, removing it...");
487 _cupsStrFree(option
->name
);
488 _cupsStrFree(option
->value
);
491 memmove(option
, option
+ 1, i
* sizeof(cups_option_t
));
495 * Return the new number of options...
498 DEBUG_printf(("cupsRemoveOption: Returning %d\n", num_options
));
499 return (num_options
);
504 * 'cups_compare_options()' - Compare two options.
507 static int /* O - Result of comparison */
508 cups_compare_options(cups_option_t
*a
, /* I - First option */
509 cups_option_t
*b
) /* I - Second option */
511 return (strcasecmp(a
->name
, b
->name
));
516 * 'cups_find_option()' - Find an option using a binary search.
519 static int /* O - Index of match */
521 const char *name
, /* I - Option name */
522 int num_options
, /* I - Number of options */
523 cups_option_t
*options
, /* I - Options */
524 int prev
, /* I - Previous index */
525 int *rdiff
) /* O - Difference of match */
527 int left
, /* Low mark for binary search */
528 right
, /* High mark for binary search */
529 current
, /* Current index */
530 diff
; /* Result of comparison */
531 cups_option_t key
; /* Search key */
534 DEBUG_printf(("cups_find_option(name=\"%s\", num_options=%d, options=%p, "
535 "prev=%d, rdiff=%p)\n", name
, num_options
, options
, prev
,
539 for (left
= 0; left
< num_options
; left
++)
540 DEBUG_printf(("cups_find_option: options[%d].name=\"%s\", .value=\"%s\"\n",
541 left
, options
[left
].name
, options
[left
].value
));
544 key
.name
= (char *)name
;
549 * Start search on either side of previous...
552 if ((diff
= cups_compare_options(&key
, options
+ prev
)) == 0 ||
553 (diff
< 0 && prev
== 0) ||
554 (diff
> 0 && prev
== (num_options
- 1)))
562 * Start with previous on right side...
571 * Start wih previous on left side...
575 right
= num_options
- 1;
581 * Start search in the middle...
585 right
= num_options
- 1;
590 current
= (left
+ right
) / 2;
591 diff
= cups_compare_options(&key
, options
+ current
);
600 while ((right
- left
) > 1);
605 * Check the last 1 or 2 elements...
608 if ((diff
= cups_compare_options(&key
, options
+ left
)) <= 0)
612 diff
= cups_compare_options(&key
, options
+ right
);
618 * Return the closest destination and the difference...
628 * End of "$Id: options.c 8181 2008-12-10 17:29:57Z mike $".