]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/options.c
Remove all of the Subversion keywords from various source files.
[thirdparty/cups.git] / cups / options.c
CommitLineData
ef416fc2 1/*
7e86f2f6 2 * Option routines for CUPS.
ef416fc2 3 *
7e86f2f6
MS
4 * Copyright 2007-2014 by Apple Inc.
5 * Copyright 1997-2007 by Easy Software Products.
ef416fc2 6 *
7e86f2f6
MS
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
11 * file is missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 12 *
7e86f2f6 13 * This file is subject to the Apple OS-Developed Software exception.
ef416fc2 14 */
15
16/*
17 * Include necessary headers...
18 */
19
7cf5915e 20#include "cups-private.h"
ef416fc2 21
22
426c6a59
MS
23/*
24 * Local functions...
25 */
26
27static int cups_compare_options(cups_option_t *a, cups_option_t *b);
28static int cups_find_option(const char *name, int num_options,
29 cups_option_t *option, int prev, int *rdiff);
30
31
ef416fc2 32/*
33 * 'cupsAddOption()' - Add an option to an option array.
5a738aea
MS
34 *
35 * New option arrays can be initialized simply by passing 0 for the
36 * "num_options" parameter.
ef416fc2 37 */
38
5a738aea
MS
39int /* O - Number of options */
40cupsAddOption(const char *name, /* I - Name of option */
41 const char *value, /* I - Value of option */
42 int num_options,/* I - Number of options */
ef416fc2 43 cups_option_t **options) /* IO - Pointer to options */
44{
ef416fc2 45 cups_option_t *temp; /* Pointer to new option */
426c6a59
MS
46 int insert, /* Insertion point */
47 diff; /* Result of search */
ef416fc2 48
49
807315e6 50 DEBUG_printf(("2cupsAddOption(name=\"%s\", value=\"%s\", num_options=%d, options=%p)", name, value, num_options, (void *)options));
88f9aafc 51
20fbc903
MS
52 if (!name || !name[0] || !value || !options || num_options < 0)
53 {
f11a948a 54 DEBUG_printf(("3cupsAddOption: Returning %d", num_options));
ef416fc2 55 return (num_options);
20fbc903 56 }
ef416fc2 57
58 /*
59 * Look for an existing option with the same name...
60 */
61
426c6a59
MS
62 if (num_options == 0)
63 {
64 insert = 0;
65 diff = 1;
66 }
67 else
68 {
69 insert = cups_find_option(name, num_options, *options, num_options - 1,
70 &diff);
ef416fc2 71
426c6a59
MS
72 if (diff > 0)
73 insert ++;
74 }
75
76 if (diff)
ef416fc2 77 {
78 /*
79 * No matching option name...
80 */
81
f11a948a 82 DEBUG_printf(("4cupsAddOption: New option inserted at index %d...",
426c6a59 83 insert));
20fbc903 84
ef416fc2 85 if (num_options == 0)
86 temp = (cups_option_t *)malloc(sizeof(cups_option_t));
87 else
7e86f2f6 88 temp = (cups_option_t *)realloc(*options, sizeof(cups_option_t) * (size_t)(num_options + 1));
ef416fc2 89
7e86f2f6 90 if (!temp)
20fbc903 91 {
f11a948a 92 DEBUG_puts("3cupsAddOption: Unable to expand option array, returning 0");
ef416fc2 93 return (0);
20fbc903 94 }
ef416fc2 95
426c6a59
MS
96 *options = temp;
97
98 if (insert < num_options)
99 {
f11a948a 100 DEBUG_printf(("4cupsAddOption: Shifting %d options...",
426c6a59 101 (int)(num_options - insert)));
7e86f2f6 102 memmove(temp + insert + 1, temp + insert, (size_t)(num_options - insert) * sizeof(cups_option_t));
426c6a59
MS
103 }
104
105 temp += insert;
2e4ff8af 106 temp->name = _cupsStrAlloc(name);
ef416fc2 107 num_options ++;
108 }
109 else
110 {
111 /*
112 * Match found; free the old value...
113 */
114
f11a948a 115 DEBUG_printf(("4cupsAddOption: Option already exists at index %d...",
426c6a59
MS
116 insert));
117
118 temp = *options + insert;
2e4ff8af 119 _cupsStrFree(temp->value);
ef416fc2 120 }
121
2e4ff8af 122 temp->value = _cupsStrAlloc(value);
ef416fc2 123
f11a948a 124 DEBUG_printf(("3cupsAddOption: Returning %d", num_options));
20fbc903 125
ef416fc2 126 return (num_options);
127}
128
129
130/*
131 * 'cupsFreeOptions()' - Free all memory used by options.
132 */
133
134void
135cupsFreeOptions(
136 int num_options, /* I - Number of options */
137 cups_option_t *options) /* I - Pointer to options */
138{
139 int i; /* Looping var */
140
141
807315e6 142 DEBUG_printf(("cupsFreeOptions(num_options=%d, options=%p)", num_options, (void *)options));
20fbc903
MS
143
144 if (num_options <= 0 || !options)
ef416fc2 145 return;
146
147 for (i = 0; i < num_options; i ++)
148 {
2e4ff8af
MS
149 _cupsStrFree(options[i].name);
150 _cupsStrFree(options[i].value);
ef416fc2 151 }
152
153 free(options);
154}
155
156
157/*
158 * 'cupsGetOption()' - Get an option value.
159 */
160
5a738aea 161const char * /* O - Option value or @code NULL@ */
ef416fc2 162cupsGetOption(const char *name, /* I - Name of option */
163 int num_options,/* I - Number of options */
164 cups_option_t *options) /* I - Options */
165{
426c6a59
MS
166 int diff, /* Result of comparison */
167 match; /* Matching index */
ef416fc2 168
169
807315e6 170 DEBUG_printf(("2cupsGetOption(name=\"%s\", num_options=%d, options=%p)", name, num_options, (void *)options));
20fbc903
MS
171
172 if (!name || num_options <= 0 || !options)
173 {
e07d4801 174 DEBUG_puts("3cupsGetOption: Returning NULL");
ef416fc2 175 return (NULL);
20fbc903 176 }
ef416fc2 177
426c6a59
MS
178 match = cups_find_option(name, num_options, options, -1, &diff);
179
180 if (!diff)
181 {
e07d4801 182 DEBUG_printf(("3cupsGetOption: Returning \"%s\"", options[match].value));
426c6a59
MS
183 return (options[match].value);
184 }
ef416fc2 185
e07d4801 186 DEBUG_puts("3cupsGetOption: Returning NULL");
ef416fc2 187 return (NULL);
188}
189
190
ef416fc2 191/*
b423cd4c 192 * 'cupsParseOptions()' - Parse options from a command-line argument.
193 *
194 * This function converts space-delimited name/value pairs according
195 * to the PAPI text option ABNF specification. Collection values
196 * ("name={a=... b=... c=...}") are stored with the curley brackets
5a738aea
MS
197 * intact - use @code cupsParseOptions@ on the value to extract the
198 * collection attributes.
b423cd4c 199 */
200
201int /* O - Number of options found */
202cupsParseOptions(
203 const char *arg, /* I - Argument to parse */
204 int num_options, /* I - Number of options */
205 cups_option_t **options) /* O - Options found */
206{
207 char *copyarg, /* Copy of input string */
208 *ptr, /* Pointer into string */
209 *name, /* Pointer to name */
5a738aea 210 *value, /* Pointer to value */
426c6a59 211 sep, /* Separator character */
5a738aea 212 quote; /* Quote character */
b423cd4c 213
214
807315e6 215 DEBUG_printf(("cupsParseOptions(arg=\"%s\", num_options=%d, options=%p)", arg, num_options, (void *)options));
20fbc903 216
91c84a35
MS
217 /*
218 * Range check input...
219 */
220
221 if (!arg)
20fbc903 222 {
e07d4801 223 DEBUG_printf(("1cupsParseOptions: Returning %d", num_options));
91c84a35 224 return (num_options);
20fbc903 225 }
91c84a35
MS
226
227 if (!options || num_options < 0)
20fbc903 228 {
e07d4801 229 DEBUG_puts("1cupsParseOptions: Returning 0");
b423cd4c 230 return (0);
20fbc903 231 }
b423cd4c 232
233 /*
234 * Make a copy of the argument string and then divide it up...
235 */
236
91c84a35 237 if ((copyarg = strdup(arg)) == NULL)
20fbc903 238 {
e07d4801
MS
239 DEBUG_puts("1cupsParseOptions: Unable to copy arg string");
240 DEBUG_printf(("1cupsParseOptions: Returning %d", num_options));
91c84a35 241 return (num_options);
20fbc903 242 }
91c84a35 243
ee571f26
MS
244 if (*copyarg == '{')
245 {
246 /*
247 * Remove surrounding {} so we can parse "{name=value ... name=value}"...
248 */
249
250 if ((ptr = copyarg + strlen(copyarg) - 1) > copyarg && *ptr == '}')
251 {
252 *ptr = '\0';
253 ptr = copyarg + 1;
254 }
255 else
256 ptr = copyarg;
257 }
258 else
259 ptr = copyarg;
b423cd4c 260
261 /*
262 * Skip leading spaces...
263 */
264
7cf5915e 265 while (_cups_isspace(*ptr))
b423cd4c 266 ptr ++;
267
268 /*
269 * Loop through the string...
270 */
271
272 while (*ptr != '\0')
273 {
274 /*
275 * Get the name up to a SPACE, =, or end-of-string...
276 */
277
278 name = ptr;
7cf5915e 279 while (!strchr("\f\n\r\t\v =", *ptr) && *ptr)
b423cd4c 280 ptr ++;
281
282 /*
283 * Avoid an empty name...
284 */
285
286 if (ptr == name)
287 break;
288
289 /*
290 * Skip trailing spaces...
291 */
292
7cf5915e 293 while (_cups_isspace(*ptr))
b423cd4c 294 *ptr++ = '\0';
295
426c6a59
MS
296 if ((sep = *ptr) == '=')
297 *ptr++ = '\0';
298
e07d4801 299 DEBUG_printf(("2cupsParseOptions: name=\"%s\"", name));
20fbc903 300
426c6a59 301 if (sep != '=')
b423cd4c 302 {
303 /*
5a738aea 304 * Boolean option...
b423cd4c 305 */
306
88f9aafc 307 if (!_cups_strncasecmp(name, "no", 2))
b423cd4c 308 num_options = cupsAddOption(name + 2, "false", num_options,
309 options);
310 else
311 num_options = cupsAddOption(name, "true", num_options, options);
312
313 continue;
314 }
315
316 /*
317 * Remove = and parse the value...
318 */
319
426c6a59 320 value = ptr;
b423cd4c 321
7cf5915e 322 while (*ptr && !_cups_isspace(*ptr))
b423cd4c 323 {
20fbc903
MS
324 if (*ptr == ',')
325 ptr ++;
326 else if (*ptr == '\'' || *ptr == '\"')
b423cd4c 327 {
20fbc903
MS
328 /*
329 * Quoted string constant...
330 */
b423cd4c 331
20fbc903
MS
332 quote = *ptr;
333 _cups_strcpy(ptr, ptr + 1);
b423cd4c 334
20fbc903
MS
335 while (*ptr != quote && *ptr)
336 {
337 if (*ptr == '\\' && ptr[1])
338 _cups_strcpy(ptr, ptr + 1);
339
340 ptr ++;
341 }
b423cd4c 342
20fbc903
MS
343 if (*ptr)
344 _cups_strcpy(ptr, ptr + 1);
345 }
346 else if (*ptr == '{')
347 {
348 /*
349 * Collection value...
350 */
b423cd4c 351
20fbc903 352 int depth;
b423cd4c 353
20fbc903 354 for (depth = 0; *ptr; ptr ++)
b423cd4c 355 {
20fbc903
MS
356 if (*ptr == '{')
357 depth ++;
358 else if (*ptr == '}')
b423cd4c 359 {
20fbc903
MS
360 depth --;
361 if (!depth)
362 {
363 ptr ++;
b423cd4c 364 break;
20fbc903 365 }
b423cd4c 366 }
20fbc903
MS
367 else if (*ptr == '\\' && ptr[1])
368 _cups_strcpy(ptr, ptr + 1);
369 }
370 }
371 else
b423cd4c 372 {
20fbc903
MS
373 /*
374 * Normal space-delimited string...
375 */
b423cd4c 376
7cf5915e 377 while (*ptr && !_cups_isspace(*ptr))
20fbc903
MS
378 {
379 if (*ptr == '\\' && ptr[1])
380 _cups_strcpy(ptr, ptr + 1);
381
382 ptr ++;
383 }
b423cd4c 384 }
385 }
386
20fbc903
MS
387 if (*ptr != '\0')
388 *ptr++ = '\0';
389
e07d4801 390 DEBUG_printf(("2cupsParseOptions: value=\"%s\"", value));
20fbc903 391
b423cd4c 392 /*
393 * Skip trailing whitespace...
394 */
395
7cf5915e 396 while (_cups_isspace(*ptr))
20fbc903 397 ptr ++;
b423cd4c 398
399 /*
400 * Add the string value...
401 */
402
403 num_options = cupsAddOption(name, value, num_options, options);
404 }
405
406 /*
407 * Free the copy of the argument we made and return the number of options
408 * found.
409 */
410
411 free(copyarg);
412
e07d4801 413 DEBUG_printf(("1cupsParseOptions: Returning %d", num_options));
20fbc903 414
b423cd4c 415 return (num_options);
416}
417
418
419/*
f7deaa1a 420 * 'cupsRemoveOption()' - Remove an option from an option array.
b423cd4c 421 *
f3c17241 422 * @since CUPS 1.2/OS X 10.5@
b423cd4c 423 */
424
425int /* O - New number of options */
426cupsRemoveOption(
427 const char *name, /* I - Option name */
428 int num_options, /* I - Current number of options */
429 cups_option_t **options) /* IO - Options */
430{
431 int i; /* Looping var */
432 cups_option_t *option; /* Current option */
433
434
807315e6 435 DEBUG_printf(("2cupsRemoveOption(name=\"%s\", num_options=%d, options=%p)", name, num_options, (void *)options));
20fbc903 436
b423cd4c 437 /*
438 * Range check input...
439 */
440
441 if (!name || num_options < 1 || !options)
20fbc903 442 {
f11a948a 443 DEBUG_printf(("3cupsRemoveOption: Returning %d", num_options));
b423cd4c 444 return (num_options);
20fbc903 445 }
b423cd4c 446
447 /*
448 * Loop for the option...
449 */
450
451 for (i = num_options, option = *options; i > 0; i --, option ++)
88f9aafc 452 if (!_cups_strcasecmp(name, option->name))
b423cd4c 453 break;
454
455 if (i)
456 {
457 /*
458 * Remove this option from the array...
459 */
460
f11a948a 461 DEBUG_puts("4cupsRemoveOption: Found option, removing it...");
20fbc903 462
b423cd4c 463 num_options --;
464 i --;
465
2e4ff8af
MS
466 _cupsStrFree(option->name);
467 _cupsStrFree(option->value);
b423cd4c 468
469 if (i > 0)
7e86f2f6 470 memmove(option, option + 1, (size_t)i * sizeof(cups_option_t));
b423cd4c 471 }
472
473 /*
474 * Return the new number of options...
475 */
476
f11a948a 477 DEBUG_printf(("3cupsRemoveOption: Returning %d", num_options));
b423cd4c 478 return (num_options);
479}
480
481
f8b3a85b
MS
482/*
483 * '_cupsGet1284Values()' - Get 1284 device ID keys and values.
484 *
485 * The returned dictionary is a CUPS option array that can be queried with
486 * cupsGetOption and freed with cupsFreeOptions.
487 */
488
489int /* O - Number of key/value pairs */
490_cupsGet1284Values(
491 const char *device_id, /* I - IEEE-1284 device ID string */
492 cups_option_t **values) /* O - Array of key/value pairs */
493{
494 int num_values; /* Number of values */
495 char key[256], /* Key string */
496 value[256], /* Value string */
497 *ptr; /* Pointer into key/value */
498
499
500 /*
501 * Range check input...
502 */
503
504 if (values)
505 *values = NULL;
506
507 if (!device_id || !values)
508 return (0);
509
510 /*
511 * Parse the 1284 device ID value into keys and values. The format is
512 * repeating sequences of:
513 *
514 * [whitespace]key:value[whitespace];
515 */
516
517 num_values = 0;
518 while (*device_id)
519 {
7cf5915e 520 while (_cups_isspace(*device_id))
f8b3a85b
MS
521 device_id ++;
522
523 if (!*device_id)
524 break;
525
526 for (ptr = key; *device_id && *device_id != ':'; device_id ++)
527 if (ptr < (key + sizeof(key) - 1))
528 *ptr++ = *device_id;
529
530 if (!*device_id)
531 break;
532
7cf5915e 533 while (ptr > key && _cups_isspace(ptr[-1]))
f8b3a85b
MS
534 ptr --;
535
536 *ptr = '\0';
537 device_id ++;
538
7cf5915e 539 while (_cups_isspace(*device_id))
f8b3a85b
MS
540 device_id ++;
541
542 if (!*device_id)
543 break;
544
545 for (ptr = value; *device_id && *device_id != ';'; device_id ++)
546 if (ptr < (value + sizeof(value) - 1))
547 *ptr++ = *device_id;
548
549 if (!*device_id)
550 break;
551
7cf5915e 552 while (ptr > value && _cups_isspace(ptr[-1]))
f8b3a85b
MS
553 ptr --;
554
555 *ptr = '\0';
556 device_id ++;
557
558 num_values = cupsAddOption(key, value, num_values, values);
559 }
560
561 return (num_values);
562}
563
564
09a101d6 565/*
426c6a59
MS
566 * 'cups_compare_options()' - Compare two options.
567 */
568
569static int /* O - Result of comparison */
570cups_compare_options(cups_option_t *a, /* I - First option */
571 cups_option_t *b) /* I - Second option */
572{
88f9aafc 573 return (_cups_strcasecmp(a->name, b->name));
426c6a59
MS
574}
575
576
577/*
578 * 'cups_find_option()' - Find an option using a binary search.
579 */
580
581static int /* O - Index of match */
582cups_find_option(
583 const char *name, /* I - Option name */
584 int num_options, /* I - Number of options */
585 cups_option_t *options, /* I - Options */
586 int prev, /* I - Previous index */
587 int *rdiff) /* O - Difference of match */
588{
589 int left, /* Low mark for binary search */
590 right, /* High mark for binary search */
591 current, /* Current index */
592 diff; /* Result of comparison */
593 cups_option_t key; /* Search key */
594
595
807315e6 596 DEBUG_printf(("7cups_find_option(name=\"%s\", num_options=%d, options=%p, prev=%d, rdiff=%p)", name, num_options, (void *)options, prev, (void *)rdiff));
426c6a59
MS
597
598#ifdef DEBUG
599 for (left = 0; left < num_options; left ++)
e07d4801 600 DEBUG_printf(("9cups_find_option: options[%d].name=\"%s\", .value=\"%s\"",
426c6a59
MS
601 left, options[left].name, options[left].value));
602#endif /* DEBUG */
603
604 key.name = (char *)name;
605
606 if (prev >= 0)
607 {
608 /*
609 * Start search on either side of previous...
610 */
611
612 if ((diff = cups_compare_options(&key, options + prev)) == 0 ||
613 (diff < 0 && prev == 0) ||
614 (diff > 0 && prev == (num_options - 1)))
615 {
616 *rdiff = diff;
617 return (prev);
618 }
619 else if (diff < 0)
620 {
621 /*
622 * Start with previous on right side...
623 */
624
625 left = 0;
626 right = prev;
627 }
628 else
629 {
630 /*
631 * Start wih previous on left side...
632 */
633
634 left = prev;
635 right = num_options - 1;
636 }
637 }
638 else
639 {
640 /*
641 * Start search in the middle...
642 */
643
644 left = 0;
645 right = num_options - 1;
646 }
647
648 do
649 {
650 current = (left + right) / 2;
651 diff = cups_compare_options(&key, options + current);
652
653 if (diff == 0)
654 break;
655 else if (diff < 0)
656 right = current;
657 else
658 left = current;
659 }
660 while ((right - left) > 1);
661
662 if (diff != 0)
663 {
664 /*
665 * Check the last 1 or 2 elements...
666 */
667
668 if ((diff = cups_compare_options(&key, options + left)) <= 0)
669 current = left;
670 else
671 {
672 diff = cups_compare_options(&key, options + right);
673 current = right;
674 }
675 }
676
677 /*
678 * Return the closest destination and the difference...
679 */
680
681 *rdiff = diff;
682
683 return (current);
684}