]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/options.c
Merge changes from CUPS 1.4svn-r7961.
[thirdparty/cups.git] / cups / options.c
CommitLineData
ef416fc2 1/*
b19ccc9e 2 * "$Id: options.c 7819 2008-08-01 00:27:24Z mike $"
ef416fc2 3 *
4 * Option routines for the Common UNIX Printing System (CUPS).
5 *
91c84a35 6 * Copyright 2007-2008 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 *
5a738aea
MS
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.
ef416fc2 24 */
25
26/*
27 * Include necessary headers...
28 */
29
30#include "cups.h"
31#include <stdlib.h>
32#include <ctype.h>
33#include "string.h"
34#include "debug.h"
35
36
37/*
38 * 'cupsAddOption()' - Add an option to an option array.
5a738aea
MS
39 *
40 * New option arrays can be initialized simply by passing 0 for the
41 * "num_options" parameter.
ef416fc2 42 */
43
5a738aea
MS
44int /* O - Number of options */
45cupsAddOption(const char *name, /* I - Name of option */
46 const char *value, /* I - Value of option */
47 int num_options,/* I - Number of options */
ef416fc2 48 cups_option_t **options) /* IO - Pointer to options */
49{
50 int i; /* Looping var */
51 cups_option_t *temp; /* Pointer to new option */
52
53
20fbc903
MS
54 DEBUG_printf(("cupsAddOption(name=\"%s\", value=\"%s\", num_options=%d, "
55 "options=%p)\n", name, value, num_options, options));
56
57 if (!name || !name[0] || !value || !options || num_options < 0)
58 {
59 DEBUG_printf(("cupsAddOption: Returning %d\n", num_options));
ef416fc2 60 return (num_options);
20fbc903 61 }
ef416fc2 62
63 /*
64 * Look for an existing option with the same name...
65 */
66
67 for (i = 0, temp = *options; i < num_options; i ++, temp ++)
2e4ff8af 68 if (!strcasecmp(temp->name, name))
ef416fc2 69 break;
70
71 if (i >= num_options)
72 {
73 /*
74 * No matching option name...
75 */
76
20fbc903
MS
77 DEBUG_puts("cupsAddOption: New option...");
78
ef416fc2 79 if (num_options == 0)
80 temp = (cups_option_t *)malloc(sizeof(cups_option_t));
81 else
82 temp = (cups_option_t *)realloc(*options, sizeof(cups_option_t) *
83 (num_options + 1));
84
85 if (temp == NULL)
20fbc903
MS
86 {
87 DEBUG_puts("cupsAddOption: Unable to expand option array, returning 0");
ef416fc2 88 return (0);
20fbc903 89 }
ef416fc2 90
91 *options = temp;
92 temp += num_options;
2e4ff8af 93 temp->name = _cupsStrAlloc(name);
ef416fc2 94 num_options ++;
95 }
96 else
97 {
98 /*
99 * Match found; free the old value...
100 */
101
20fbc903 102 DEBUG_puts("cupsAddOption: Option already exists...");
2e4ff8af 103 _cupsStrFree(temp->value);
ef416fc2 104 }
105
2e4ff8af 106 temp->value = _cupsStrAlloc(value);
ef416fc2 107
20fbc903
MS
108 DEBUG_printf(("cupsAddOption: Returning %d\n", num_options));
109
ef416fc2 110 return (num_options);
111}
112
113
114/*
115 * 'cupsFreeOptions()' - Free all memory used by options.
116 */
117
118void
119cupsFreeOptions(
120 int num_options, /* I - Number of options */
121 cups_option_t *options) /* I - Pointer to options */
122{
123 int i; /* Looping var */
124
125
20fbc903
MS
126 DEBUG_printf(("cupsFreeOptions(num_options=%d, options=%p)\n", num_options,
127 options));
128
129 if (num_options <= 0 || !options)
ef416fc2 130 return;
131
132 for (i = 0; i < num_options; i ++)
133 {
2e4ff8af
MS
134 _cupsStrFree(options[i].name);
135 _cupsStrFree(options[i].value);
ef416fc2 136 }
137
138 free(options);
139}
140
141
142/*
143 * 'cupsGetOption()' - Get an option value.
144 */
145
5a738aea 146const char * /* O - Option value or @code NULL@ */
ef416fc2 147cupsGetOption(const char *name, /* I - Name of option */
148 int num_options,/* I - Number of options */
149 cups_option_t *options) /* I - Options */
150{
151 int i; /* Looping var */
152
153
20fbc903
MS
154 DEBUG_printf(("cupsGetOption(name=\"%s\", num_options=%d, options=%p)\n",
155 name, num_options, options));
156
157 if (!name || num_options <= 0 || !options)
158 {
159 DEBUG_puts("cupsGetOption: Returning NULL");
ef416fc2 160 return (NULL);
20fbc903 161 }
ef416fc2 162
163 for (i = 0; i < num_options; i ++)
20fbc903
MS
164 if (!strcasecmp(options[i].name, name))
165 {
166 DEBUG_printf(("cupsGetOption: Returning \"%s\"\n", options[i].value));
ef416fc2 167 return (options[i].value);
20fbc903 168 }
ef416fc2 169
20fbc903 170 DEBUG_puts("cupsGetOption: Returning NULL");
ef416fc2 171 return (NULL);
172}
173
174
ef416fc2 175/*
b423cd4c 176 * 'cupsParseOptions()' - Parse options from a command-line argument.
177 *
178 * This function converts space-delimited name/value pairs according
179 * to the PAPI text option ABNF specification. Collection values
180 * ("name={a=... b=... c=...}") are stored with the curley brackets
5a738aea
MS
181 * intact - use @code cupsParseOptions@ on the value to extract the
182 * collection attributes.
b423cd4c 183 */
184
185int /* O - Number of options found */
186cupsParseOptions(
187 const char *arg, /* I - Argument to parse */
188 int num_options, /* I - Number of options */
189 cups_option_t **options) /* O - Options found */
190{
191 char *copyarg, /* Copy of input string */
192 *ptr, /* Pointer into string */
193 *name, /* Pointer to name */
5a738aea
MS
194 *value, /* Pointer to value */
195 quote; /* Quote character */
b423cd4c 196
197
20fbc903
MS
198 DEBUG_printf(("cupsParseOptions(arg=\"%s\", num_options=%d, options=%p)\n",
199 arg, num_options, options));
200
91c84a35
MS
201 /*
202 * Range check input...
203 */
204
205 if (!arg)
20fbc903
MS
206 {
207 DEBUG_printf(("cupsParseOptions: Returning %d\n", num_options));
91c84a35 208 return (num_options);
20fbc903 209 }
91c84a35
MS
210
211 if (!options || num_options < 0)
20fbc903
MS
212 {
213 DEBUG_puts("cupsParseOptions: Returning 0");
b423cd4c 214 return (0);
20fbc903 215 }
b423cd4c 216
217 /*
218 * Make a copy of the argument string and then divide it up...
219 */
220
91c84a35 221 if ((copyarg = strdup(arg)) == NULL)
20fbc903
MS
222 {
223 DEBUG_puts("cupsParseOptions: Unable to copy arg string");
224 DEBUG_printf(("cupsParseOptions: Returning %d\n", num_options));
91c84a35 225 return (num_options);
20fbc903 226 }
91c84a35 227
ee571f26
MS
228 if (*copyarg == '{')
229 {
230 /*
231 * Remove surrounding {} so we can parse "{name=value ... name=value}"...
232 */
233
234 if ((ptr = copyarg + strlen(copyarg) - 1) > copyarg && *ptr == '}')
235 {
236 *ptr = '\0';
237 ptr = copyarg + 1;
238 }
239 else
240 ptr = copyarg;
241 }
242 else
243 ptr = copyarg;
b423cd4c 244
245 /*
246 * Skip leading spaces...
247 */
248
249 while (isspace(*ptr & 255))
250 ptr ++;
251
252 /*
253 * Loop through the string...
254 */
255
256 while (*ptr != '\0')
257 {
258 /*
259 * Get the name up to a SPACE, =, or end-of-string...
260 */
261
262 name = ptr;
5a738aea 263 while (!isspace(*ptr & 255) && *ptr != '=' && *ptr)
b423cd4c 264 ptr ++;
265
266 /*
267 * Avoid an empty name...
268 */
269
270 if (ptr == name)
271 break;
272
273 /*
274 * Skip trailing spaces...
275 */
276
277 while (isspace(*ptr & 255))
278 *ptr++ = '\0';
279
20fbc903
MS
280 DEBUG_printf(("cupsParseOptions: name=\"%s\"\n", name));
281
b423cd4c 282 if (*ptr != '=')
283 {
284 /*
5a738aea 285 * Boolean option...
b423cd4c 286 */
287
5a738aea 288 if (!strncasecmp(name, "no", 2))
b423cd4c 289 num_options = cupsAddOption(name + 2, "false", num_options,
290 options);
291 else
292 num_options = cupsAddOption(name, "true", num_options, options);
293
294 continue;
295 }
296
297 /*
298 * Remove = and parse the value...
299 */
300
301 *ptr++ = '\0';
20fbc903 302 value = ptr;
b423cd4c 303
20fbc903 304 while (*ptr && !isspace(*ptr & 255))
b423cd4c 305 {
20fbc903
MS
306 if (*ptr == ',')
307 ptr ++;
308 else if (*ptr == '\'' || *ptr == '\"')
b423cd4c 309 {
20fbc903
MS
310 /*
311 * Quoted string constant...
312 */
b423cd4c 313
20fbc903
MS
314 quote = *ptr;
315 _cups_strcpy(ptr, ptr + 1);
b423cd4c 316
20fbc903
MS
317 while (*ptr != quote && *ptr)
318 {
319 if (*ptr == '\\' && ptr[1])
320 _cups_strcpy(ptr, ptr + 1);
321
322 ptr ++;
323 }
b423cd4c 324
20fbc903
MS
325 if (*ptr)
326 _cups_strcpy(ptr, ptr + 1);
327 }
328 else if (*ptr == '{')
329 {
330 /*
331 * Collection value...
332 */
b423cd4c 333
20fbc903 334 int depth;
b423cd4c 335
20fbc903 336 for (depth = 0; *ptr; ptr ++)
b423cd4c 337 {
20fbc903
MS
338 if (*ptr == '{')
339 depth ++;
340 else if (*ptr == '}')
b423cd4c 341 {
20fbc903
MS
342 depth --;
343 if (!depth)
344 {
345 ptr ++;
b423cd4c 346 break;
20fbc903 347 }
b423cd4c 348 }
20fbc903
MS
349 else if (*ptr == '\\' && ptr[1])
350 _cups_strcpy(ptr, ptr + 1);
351 }
352 }
353 else
b423cd4c 354 {
20fbc903
MS
355 /*
356 * Normal space-delimited string...
357 */
b423cd4c 358
20fbc903
MS
359 while (!isspace(*ptr & 255) && *ptr)
360 {
361 if (*ptr == '\\' && ptr[1])
362 _cups_strcpy(ptr, ptr + 1);
363
364 ptr ++;
365 }
b423cd4c 366 }
367 }
368
20fbc903
MS
369 if (*ptr != '\0')
370 *ptr++ = '\0';
371
372 DEBUG_printf(("cupsParseOptions: value=\"%s\"\n", value));
373
b423cd4c 374 /*
375 * Skip trailing whitespace...
376 */
377
378 while (isspace(*ptr & 255))
20fbc903 379 ptr ++;
b423cd4c 380
381 /*
382 * Add the string value...
383 */
384
385 num_options = cupsAddOption(name, value, num_options, options);
386 }
387
388 /*
389 * Free the copy of the argument we made and return the number of options
390 * found.
391 */
392
393 free(copyarg);
394
20fbc903
MS
395 DEBUG_printf(("cupsParseOptions: Returning %d\n", num_options));
396
b423cd4c 397 return (num_options);
398}
399
400
401/*
f7deaa1a 402 * 'cupsRemoveOption()' - Remove an option from an option array.
b423cd4c 403 *
404 * @since CUPS 1.2@
405 */
406
407int /* O - New number of options */
408cupsRemoveOption(
409 const char *name, /* I - Option name */
410 int num_options, /* I - Current number of options */
411 cups_option_t **options) /* IO - Options */
412{
413 int i; /* Looping var */
414 cups_option_t *option; /* Current option */
415
416
20fbc903
MS
417 DEBUG_printf(("cupsRemoveOption(name=\"%s\", num_options=%d, options=%p)\n",
418 name, num_options, options));
419
b423cd4c 420 /*
421 * Range check input...
422 */
423
424 if (!name || num_options < 1 || !options)
20fbc903
MS
425 {
426 DEBUG_printf(("cupsRemoveOption: Returning %d\n", num_options));
b423cd4c 427 return (num_options);
20fbc903 428 }
b423cd4c 429
430 /*
431 * Loop for the option...
432 */
433
434 for (i = num_options, option = *options; i > 0; i --, option ++)
435 if (!strcasecmp(name, option->name))
436 break;
437
438 if (i)
439 {
440 /*
441 * Remove this option from the array...
442 */
443
20fbc903
MS
444 DEBUG_puts("cupsRemoveOption: Found option, removing it...");
445
b423cd4c 446 num_options --;
447 i --;
448
2e4ff8af
MS
449 _cupsStrFree(option->name);
450 _cupsStrFree(option->value);
b423cd4c 451
452 if (i > 0)
f7deaa1a 453 memmove(option, option + 1, i * sizeof(cups_option_t));
b423cd4c 454 }
455
456 /*
457 * Return the new number of options...
458 */
459
20fbc903 460 DEBUG_printf(("cupsRemoveOption: Returning %d\n", num_options));
b423cd4c 461 return (num_options);
462}
463
464
09a101d6 465/*
b19ccc9e 466 * End of "$Id: options.c 7819 2008-08-01 00:27:24Z mike $".
ef416fc2 467 */