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