]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/options.c
Merge changes from CUPS 1.4svn-r7994.
[thirdparty/cups.git] / cups / options.c
1 /*
2 * "$Id: options.c 7819 2008-08-01 00:27:24Z mike $"
3 *
4 * Option routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2008 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
8 *
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/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 *
17 * Contents:
18 *
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.
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.
39 *
40 * New option arrays can be initialized simply by passing 0 for the
41 * "num_options" parameter.
42 */
43
44 int /* O - Number of options */
45 cupsAddOption(const char *name, /* I - Name of option */
46 const char *value, /* I - Value of option */
47 int num_options,/* I - Number of options */
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
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));
60 return (num_options);
61 }
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 ++)
68 if (!strcasecmp(temp->name, name))
69 break;
70
71 if (i >= num_options)
72 {
73 /*
74 * No matching option name...
75 */
76
77 DEBUG_puts("cupsAddOption: New option...");
78
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)
86 {
87 DEBUG_puts("cupsAddOption: Unable to expand option array, returning 0");
88 return (0);
89 }
90
91 *options = temp;
92 temp += num_options;
93 temp->name = _cupsStrAlloc(name);
94 num_options ++;
95 }
96 else
97 {
98 /*
99 * Match found; free the old value...
100 */
101
102 DEBUG_puts("cupsAddOption: Option already exists...");
103 _cupsStrFree(temp->value);
104 }
105
106 temp->value = _cupsStrAlloc(value);
107
108 DEBUG_printf(("cupsAddOption: Returning %d\n", num_options));
109
110 return (num_options);
111 }
112
113
114 /*
115 * 'cupsFreeOptions()' - Free all memory used by options.
116 */
117
118 void
119 cupsFreeOptions(
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
126 DEBUG_printf(("cupsFreeOptions(num_options=%d, options=%p)\n", num_options,
127 options));
128
129 if (num_options <= 0 || !options)
130 return;
131
132 for (i = 0; i < num_options; i ++)
133 {
134 _cupsStrFree(options[i].name);
135 _cupsStrFree(options[i].value);
136 }
137
138 free(options);
139 }
140
141
142 /*
143 * 'cupsGetOption()' - Get an option value.
144 */
145
146 const char * /* O - Option value or @code NULL@ */
147 cupsGetOption(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
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");
160 return (NULL);
161 }
162
163 for (i = 0; i < num_options; i ++)
164 if (!strcasecmp(options[i].name, name))
165 {
166 DEBUG_printf(("cupsGetOption: Returning \"%s\"\n", options[i].value));
167 return (options[i].value);
168 }
169
170 DEBUG_puts("cupsGetOption: Returning NULL");
171 return (NULL);
172 }
173
174
175 /*
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
181 * intact - use @code cupsParseOptions@ on the value to extract the
182 * collection attributes.
183 */
184
185 int /* O - Number of options found */
186 cupsParseOptions(
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 */
194 *value, /* Pointer to value */
195 quote; /* Quote character */
196
197
198 DEBUG_printf(("cupsParseOptions(arg=\"%s\", num_options=%d, options=%p)\n",
199 arg, num_options, options));
200
201 /*
202 * Range check input...
203 */
204
205 if (!arg)
206 {
207 DEBUG_printf(("cupsParseOptions: Returning %d\n", num_options));
208 return (num_options);
209 }
210
211 if (!options || num_options < 0)
212 {
213 DEBUG_puts("cupsParseOptions: Returning 0");
214 return (0);
215 }
216
217 /*
218 * Make a copy of the argument string and then divide it up...
219 */
220
221 if ((copyarg = strdup(arg)) == NULL)
222 {
223 DEBUG_puts("cupsParseOptions: Unable to copy arg string");
224 DEBUG_printf(("cupsParseOptions: Returning %d\n", num_options));
225 return (num_options);
226 }
227
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;
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;
263 while (!isspace(*ptr & 255) && *ptr != '=' && *ptr)
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
280 DEBUG_printf(("cupsParseOptions: name=\"%s\"\n", name));
281
282 if (*ptr != '=')
283 {
284 /*
285 * Boolean option...
286 */
287
288 if (!strncasecmp(name, "no", 2))
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';
302 value = ptr;
303
304 while (*ptr && !isspace(*ptr & 255))
305 {
306 if (*ptr == ',')
307 ptr ++;
308 else if (*ptr == '\'' || *ptr == '\"')
309 {
310 /*
311 * Quoted string constant...
312 */
313
314 quote = *ptr;
315 _cups_strcpy(ptr, ptr + 1);
316
317 while (*ptr != quote && *ptr)
318 {
319 if (*ptr == '\\' && ptr[1])
320 _cups_strcpy(ptr, ptr + 1);
321
322 ptr ++;
323 }
324
325 if (*ptr)
326 _cups_strcpy(ptr, ptr + 1);
327 }
328 else if (*ptr == '{')
329 {
330 /*
331 * Collection value...
332 */
333
334 int depth;
335
336 for (depth = 0; *ptr; ptr ++)
337 {
338 if (*ptr == '{')
339 depth ++;
340 else if (*ptr == '}')
341 {
342 depth --;
343 if (!depth)
344 {
345 ptr ++;
346 break;
347 }
348 }
349 else if (*ptr == '\\' && ptr[1])
350 _cups_strcpy(ptr, ptr + 1);
351 }
352 }
353 else
354 {
355 /*
356 * Normal space-delimited string...
357 */
358
359 while (!isspace(*ptr & 255) && *ptr)
360 {
361 if (*ptr == '\\' && ptr[1])
362 _cups_strcpy(ptr, ptr + 1);
363
364 ptr ++;
365 }
366 }
367 }
368
369 if (*ptr != '\0')
370 *ptr++ = '\0';
371
372 DEBUG_printf(("cupsParseOptions: value=\"%s\"\n", value));
373
374 /*
375 * Skip trailing whitespace...
376 */
377
378 while (isspace(*ptr & 255))
379 ptr ++;
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
395 DEBUG_printf(("cupsParseOptions: Returning %d\n", num_options));
396
397 return (num_options);
398 }
399
400
401 /*
402 * 'cupsRemoveOption()' - Remove an option from an option array.
403 *
404 * @since CUPS 1.2@
405 */
406
407 int /* O - New number of options */
408 cupsRemoveOption(
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
417 DEBUG_printf(("cupsRemoveOption(name=\"%s\", num_options=%d, options=%p)\n",
418 name, num_options, options));
419
420 /*
421 * Range check input...
422 */
423
424 if (!name || num_options < 1 || !options)
425 {
426 DEBUG_printf(("cupsRemoveOption: Returning %d\n", num_options));
427 return (num_options);
428 }
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
444 DEBUG_puts("cupsRemoveOption: Found option, removing it...");
445
446 num_options --;
447 i --;
448
449 _cupsStrFree(option->name);
450 _cupsStrFree(option->value);
451
452 if (i > 0)
453 memmove(option, option + 1, i * sizeof(cups_option_t));
454 }
455
456 /*
457 * Return the new number of options...
458 */
459
460 DEBUG_printf(("cupsRemoveOption: Returning %d\n", num_options));
461 return (num_options);
462 }
463
464
465 /*
466 * End of "$Id: options.c 7819 2008-08-01 00:27:24Z mike $".
467 */