]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/options.c
Merge changes from CUPS 1.4svn-r7594.
[thirdparty/cups.git] / cups / options.c
1 /*
2 * "$Id: options.c 7278 2008-01-31 01:23:09Z 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 ptr = copyarg;
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;
248 while (!isspace(*ptr & 255) && *ptr != '=' && *ptr)
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
265 DEBUG_printf(("cupsParseOptions: name=\"%s\"\n", name));
266
267 if (*ptr != '=')
268 {
269 /*
270 * Boolean option...
271 */
272
273 if (!strncasecmp(name, "no", 2))
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';
287 value = ptr;
288
289 while (*ptr && !isspace(*ptr & 255))
290 {
291 if (*ptr == ',')
292 ptr ++;
293 else if (*ptr == '\'' || *ptr == '\"')
294 {
295 /*
296 * Quoted string constant...
297 */
298
299 quote = *ptr;
300 _cups_strcpy(ptr, ptr + 1);
301
302 while (*ptr != quote && *ptr)
303 {
304 if (*ptr == '\\' && ptr[1])
305 _cups_strcpy(ptr, ptr + 1);
306
307 ptr ++;
308 }
309
310 if (*ptr)
311 _cups_strcpy(ptr, ptr + 1);
312 }
313 else if (*ptr == '{')
314 {
315 /*
316 * Collection value...
317 */
318
319 int depth;
320
321 for (depth = 0; *ptr; ptr ++)
322 {
323 if (*ptr == '{')
324 depth ++;
325 else if (*ptr == '}')
326 {
327 depth --;
328 if (!depth)
329 {
330 ptr ++;
331 break;
332 }
333 }
334 else if (*ptr == '\\' && ptr[1])
335 _cups_strcpy(ptr, ptr + 1);
336 }
337 }
338 else
339 {
340 /*
341 * Normal space-delimited string...
342 */
343
344 while (!isspace(*ptr & 255) && *ptr)
345 {
346 if (*ptr == '\\' && ptr[1])
347 _cups_strcpy(ptr, ptr + 1);
348
349 ptr ++;
350 }
351 }
352 }
353
354 if (*ptr != '\0')
355 *ptr++ = '\0';
356
357 DEBUG_printf(("cupsParseOptions: value=\"%s\"\n", value));
358
359 /*
360 * Skip trailing whitespace...
361 */
362
363 while (isspace(*ptr & 255))
364 ptr ++;
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
380 DEBUG_printf(("cupsParseOptions: Returning %d\n", num_options));
381
382 return (num_options);
383 }
384
385
386 /*
387 * 'cupsRemoveOption()' - Remove an option from an option array.
388 *
389 * @since CUPS 1.2@
390 */
391
392 int /* O - New number of options */
393 cupsRemoveOption(
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
402 DEBUG_printf(("cupsRemoveOption(name=\"%s\", num_options=%d, options=%p)\n",
403 name, num_options, options));
404
405 /*
406 * Range check input...
407 */
408
409 if (!name || num_options < 1 || !options)
410 {
411 DEBUG_printf(("cupsRemoveOption: Returning %d\n", num_options));
412 return (num_options);
413 }
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
429 DEBUG_puts("cupsRemoveOption: Found option, removing it...");
430
431 num_options --;
432 i --;
433
434 _cupsStrFree(option->name);
435 _cupsStrFree(option->value);
436
437 if (i > 0)
438 memmove(option, option + 1, i * sizeof(cups_option_t));
439 }
440
441 /*
442 * Return the new number of options...
443 */
444
445 DEBUG_printf(("cupsRemoveOption: Returning %d\n", num_options));
446 return (num_options);
447 }
448
449
450 /*
451 * End of "$Id: options.c 7278 2008-01-31 01:23:09Z mike $".
452 */