]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/options.c
Merge changes from CUPS 1.4svn-r7696.
[thirdparty/cups.git] / cups / options.c
CommitLineData
ef416fc2 1/*
75bd9771 2 * "$Id: options.c 7589 2008-05-19 00:13:23Z 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
MS
227
228 ptr = copyarg;
b423cd4c 229
230 /*
231 * Skip leading spaces...
232 */
233
234 while (isspace(*ptr & 255))
235 ptr ++;
236
237 /*
238 * Loop through the string...
239 */
240
241 while (*ptr != '\0')
242 {
243 /*
244 * Get the name up to a SPACE, =, or end-of-string...
245 */
246
247 name = ptr;
5a738aea 248 while (!isspace(*ptr & 255) && *ptr != '=' && *ptr)
b423cd4c 249 ptr ++;
250
251 /*
252 * Avoid an empty name...
253 */
254
255 if (ptr == name)
256 break;
257
258 /*
259 * Skip trailing spaces...
260 */
261
262 while (isspace(*ptr & 255))
263 *ptr++ = '\0';
264
20fbc903
MS
265 DEBUG_printf(("cupsParseOptions: name=\"%s\"\n", name));
266
b423cd4c 267 if (*ptr != '=')
268 {
269 /*
5a738aea 270 * Boolean option...
b423cd4c 271 */
272
5a738aea 273 if (!strncasecmp(name, "no", 2))
b423cd4c 274 num_options = cupsAddOption(name + 2, "false", num_options,
275 options);
276 else
277 num_options = cupsAddOption(name, "true", num_options, options);
278
279 continue;
280 }
281
282 /*
283 * Remove = and parse the value...
284 */
285
286 *ptr++ = '\0';
20fbc903 287 value = ptr;
b423cd4c 288
20fbc903 289 while (*ptr && !isspace(*ptr & 255))
b423cd4c 290 {
20fbc903
MS
291 if (*ptr == ',')
292 ptr ++;
293 else if (*ptr == '\'' || *ptr == '\"')
b423cd4c 294 {
20fbc903
MS
295 /*
296 * Quoted string constant...
297 */
b423cd4c 298
20fbc903
MS
299 quote = *ptr;
300 _cups_strcpy(ptr, ptr + 1);
b423cd4c 301
20fbc903
MS
302 while (*ptr != quote && *ptr)
303 {
304 if (*ptr == '\\' && ptr[1])
305 _cups_strcpy(ptr, ptr + 1);
306
307 ptr ++;
308 }
b423cd4c 309
20fbc903
MS
310 if (*ptr)
311 _cups_strcpy(ptr, ptr + 1);
312 }
313 else if (*ptr == '{')
314 {
315 /*
316 * Collection value...
317 */
b423cd4c 318
20fbc903 319 int depth;
b423cd4c 320
20fbc903 321 for (depth = 0; *ptr; ptr ++)
b423cd4c 322 {
20fbc903
MS
323 if (*ptr == '{')
324 depth ++;
325 else if (*ptr == '}')
b423cd4c 326 {
20fbc903
MS
327 depth --;
328 if (!depth)
329 {
330 ptr ++;
b423cd4c 331 break;
20fbc903 332 }
b423cd4c 333 }
20fbc903
MS
334 else if (*ptr == '\\' && ptr[1])
335 _cups_strcpy(ptr, ptr + 1);
336 }
337 }
338 else
b423cd4c 339 {
20fbc903
MS
340 /*
341 * Normal space-delimited string...
342 */
b423cd4c 343
20fbc903
MS
344 while (!isspace(*ptr & 255) && *ptr)
345 {
346 if (*ptr == '\\' && ptr[1])
347 _cups_strcpy(ptr, ptr + 1);
348
349 ptr ++;
350 }
b423cd4c 351 }
352 }
353
20fbc903
MS
354 if (*ptr != '\0')
355 *ptr++ = '\0';
356
357 DEBUG_printf(("cupsParseOptions: value=\"%s\"\n", value));
358
b423cd4c 359 /*
360 * Skip trailing whitespace...
361 */
362
363 while (isspace(*ptr & 255))
20fbc903 364 ptr ++;
b423cd4c 365
366 /*
367 * Add the string value...
368 */
369
370 num_options = cupsAddOption(name, value, num_options, options);
371 }
372
373 /*
374 * Free the copy of the argument we made and return the number of options
375 * found.
376 */
377
378 free(copyarg);
379
20fbc903
MS
380 DEBUG_printf(("cupsParseOptions: Returning %d\n", num_options));
381
b423cd4c 382 return (num_options);
383}
384
385
386/*
f7deaa1a 387 * 'cupsRemoveOption()' - Remove an option from an option array.
b423cd4c 388 *
389 * @since CUPS 1.2@
390 */
391
392int /* O - New number of options */
393cupsRemoveOption(
394 const char *name, /* I - Option name */
395 int num_options, /* I - Current number of options */
396 cups_option_t **options) /* IO - Options */
397{
398 int i; /* Looping var */
399 cups_option_t *option; /* Current option */
400
401
20fbc903
MS
402 DEBUG_printf(("cupsRemoveOption(name=\"%s\", num_options=%d, options=%p)\n",
403 name, num_options, options));
404
b423cd4c 405 /*
406 * Range check input...
407 */
408
409 if (!name || num_options < 1 || !options)
20fbc903
MS
410 {
411 DEBUG_printf(("cupsRemoveOption: Returning %d\n", num_options));
b423cd4c 412 return (num_options);
20fbc903 413 }
b423cd4c 414
415 /*
416 * Loop for the option...
417 */
418
419 for (i = num_options, option = *options; i > 0; i --, option ++)
420 if (!strcasecmp(name, option->name))
421 break;
422
423 if (i)
424 {
425 /*
426 * Remove this option from the array...
427 */
428
20fbc903
MS
429 DEBUG_puts("cupsRemoveOption: Found option, removing it...");
430
b423cd4c 431 num_options --;
432 i --;
433
2e4ff8af
MS
434 _cupsStrFree(option->name);
435 _cupsStrFree(option->value);
b423cd4c 436
437 if (i > 0)
f7deaa1a 438 memmove(option, option + 1, i * sizeof(cups_option_t));
b423cd4c 439 }
440
441 /*
442 * Return the new number of options...
443 */
444
20fbc903 445 DEBUG_printf(("cupsRemoveOption: Returning %d\n", num_options));
b423cd4c 446 return (num_options);
447}
448
449
09a101d6 450/*
75bd9771 451 * End of "$Id: options.c 7589 2008-05-19 00:13:23Z mike $".
ef416fc2 452 */