]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/array.c
Import CUPS v2.0b1
[thirdparty/cups.git] / cups / array.c
CommitLineData
ef416fc2 1/*
1a18c85c 2 * "$Id: array.c 12031 2014-07-15 19:57:59Z msweet $"
ef416fc2 3 *
1a18c85c 4 * Sorted array routines for CUPS.
ef416fc2 5 *
1a18c85c
MS
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
ef416fc2 8 *
1a18c85c
MS
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/".
ef416fc2 14 *
1a18c85c 15 * This file is subject to the Apple OS-Developed Software exception.
ef416fc2 16 */
17
18/*
19 * Include necessary headers...
20 */
21
1a18c85c 22#include <cups/cups.h>
71e16022
MS
23#include "string-private.h"
24#include "debug-private.h"
eac3a0a0 25#include "array-private.h"
ef416fc2 26
27
28/*
29 * Limits...
30 */
31
32#define _CUPS_MAXSAVE 32 /**** Maximum number of saves ****/
33
34
35/*
36 * Types and structures...
37 */
38
39struct _cups_array_s /**** CUPS array structure ****/
40{
41 /*
42 * The current implementation uses an insertion sort into an array of
43 * sorted pointers. We leave the array type private/opaque so that we
44 * can change the underlying implementation without affecting the users
45 * of this API.
46 */
47
48 int num_elements, /* Number of array elements */
49 alloc_elements, /* Allocated array elements */
50 current, /* Current element */
51 insert, /* Last inserted element */
bd7854cb 52 unique, /* Are all elements unique? */
ef416fc2 53 num_saved, /* Number of saved elements */
54 saved[_CUPS_MAXSAVE];
55 /* Saved elements */
56 void **elements; /* Array elements */
57 cups_array_func_t compare; /* Element comparison function */
58 void *data; /* User data passed to compare */
b94498cf 59 cups_ahash_func_t hashfunc; /* Hash function */
60 int hashsize, /* Size of hash */
61 *hash; /* Hash array */
10d09e33
MS
62 cups_acopy_func_t copyfunc; /* Copy function */
63 cups_afree_func_t freefunc; /* Free function */
ef416fc2 64};
65
66
67/*
68 * Local functions...
69 */
70
bd7854cb 71static int cups_array_add(cups_array_t *a, void *e, int insert);
72static int cups_array_find(cups_array_t *a, void *e, int prev, int *rdiff);
ef416fc2 73
74
75/*
76 * 'cupsArrayAdd()' - Add an element to the array.
bd7854cb 77 *
78 * When adding an element to a sorted array, non-unique elements are
79e1d494
MS
79 * appended at the end of the run of identical elements. For unsorted arrays,
80 * the element is appended to the end of the array.
5a738aea 81 *
f3c17241 82 * @since CUPS 1.2/OS X 10.5@
ef416fc2 83 */
84
85int /* O - 1 on success, 0 on failure */
86cupsArrayAdd(cups_array_t *a, /* I - Array */
87 void *e) /* I - Element */
88{
e07d4801 89 DEBUG_printf(("2cupsArrayAdd(a=%p, e=%p)", a, e));
ef416fc2 90
91 /*
92 * Range check input...
93 */
94
95 if (!a || !e)
96 {
e07d4801 97 DEBUG_puts("3cupsArrayAdd: returning 0");
ef416fc2 98 return (0);
99 }
100
101 /*
bd7854cb 102 * Append the element...
ef416fc2 103 */
104
bd7854cb 105 return (cups_array_add(a, e, 0));
ef416fc2 106}
107
108
eac3a0a0 109/*
5a9febac 110 * '_cupsArrayAddStrings()' - Add zero or more delimited strings to an array.
eac3a0a0
MS
111 *
112 * Note: The array MUST be created using the @link _cupsArrayNewStrings@
113 * function. Duplicate strings are NOT added. If the string pointer "s" is NULL
114 * or the empty string, no strings are added to the array.
115 */
116
117int /* O - 1 on success, 0 on failure */
118_cupsArrayAddStrings(cups_array_t *a, /* I - Array */
5a9febac
MS
119 const char *s, /* I - Delimited strings or NULL */
120 char delim)/* I - Delimiter character */
eac3a0a0
MS
121{
122 char *buffer, /* Copy of string */
123 *start, /* Start of string */
124 *end; /* End of string */
125 int status = 1; /* Status of add */
126
127
a469f8a5
MS
128 DEBUG_printf(("_cupsArrayAddStrings(a=%p, s=\"%s\", delim='%c')", a, s,
129 delim));
130
eac3a0a0 131 if (!a || !s || !*s)
a469f8a5
MS
132 {
133 DEBUG_puts("1_cupsArrayAddStrings: Returning 0");
eac3a0a0 134 return (0);
a469f8a5 135 }
eac3a0a0 136
5a9febac
MS
137 if (delim == ' ')
138 {
139 /*
140 * Skip leading whitespace...
141 */
142
a469f8a5
MS
143 DEBUG_puts("1_cupsArrayAddStrings: Skipping leading whitespace.");
144
5a9febac
MS
145 while (*s && isspace(*s & 255))
146 s ++;
a469f8a5
MS
147
148 DEBUG_printf(("1_cupsArrayAddStrings: Remaining string \"%s\".", s));
5a9febac
MS
149 }
150
a469f8a5
MS
151 if (!strchr(s, delim) &&
152 (delim != ' ' || (!strchr(s, '\t') && !strchr(s, '\n'))))
eac3a0a0
MS
153 {
154 /*
5a9febac 155 * String doesn't contain a delimiter, so add it as a single value...
eac3a0a0
MS
156 */
157
a469f8a5
MS
158 DEBUG_puts("1_cupsArrayAddStrings: No delimiter seen, adding a single "
159 "value.");
160
eac3a0a0
MS
161 if (!cupsArrayFind(a, (void *)s))
162 status = cupsArrayAdd(a, (void *)s);
163 }
164 else if ((buffer = strdup(s)) == NULL)
a469f8a5
MS
165 {
166 DEBUG_puts("1_cupsArrayAddStrings: Unable to duplicate string.");
eac3a0a0 167 status = 0;
a469f8a5 168 }
eac3a0a0
MS
169 else
170 {
171 for (start = end = buffer; *end; start = end)
172 {
173 /*
174 * Find the end of the current delimited string and see if we need to add
175 * it...
176 */
177
5a9febac
MS
178 if (delim == ' ')
179 {
180 while (*end && !isspace(*end & 255))
181 end ++;
182 while (*end && isspace(*end & 255))
183 *end++ = '\0';
184 }
185 else if ((end = strchr(start, delim)) != NULL)
eac3a0a0
MS
186 *end++ = '\0';
187 else
188 end = start + strlen(start);
189
a469f8a5
MS
190 DEBUG_printf(("1_cupsArrayAddStrings: Adding \"%s\", end=\"%s\"", start,
191 end));
192
eac3a0a0
MS
193 if (!cupsArrayFind(a, start))
194 status &= cupsArrayAdd(a, start);
195 }
196
197 free(buffer);
198 }
199
a469f8a5
MS
200 DEBUG_printf(("1_cupsArrayAddStrings: Returning %d.", status));
201
eac3a0a0
MS
202 return (status);
203}
204
205
ef416fc2 206/*
207 * 'cupsArrayClear()' - Clear the array.
5a738aea 208 *
79e1d494
MS
209 * This function is equivalent to removing all elements in the array.
210 * The caller is responsible for freeing the memory used by the
211 * elements themselves.
212 *
f3c17241 213 * @since CUPS 1.2/OS X 10.5@
ef416fc2 214 */
215
216void
217cupsArrayClear(cups_array_t *a) /* I - Array */
218{
219 /*
220 * Range check input...
221 */
222
223 if (!a)
224 return;
225
10d09e33
MS
226 /*
227 * Free the existing elements as needed..
228 */
229
230 if (a->freefunc)
231 {
232 int i; /* Looping var */
233 void **e; /* Current element */
234
235 for (i = a->num_elements, e = a->elements; i > 0; i --, e ++)
236 (a->freefunc)(*e, a->data);
237 }
238
ef416fc2 239 /*
240 * Set the number of elements to 0; we don't actually free the memory
241 * here - that is done in cupsArrayDelete()...
242 */
243
244 a->num_elements = 0;
245 a->current = -1;
246 a->insert = -1;
bd7854cb 247 a->unique = 1;
ef416fc2 248 a->num_saved = 0;
249}
250
251
252/*
253 * 'cupsArrayCount()' - Get the number of elements in the array.
5a738aea 254 *
f3c17241 255 * @since CUPS 1.2/OS X 10.5@
ef416fc2 256 */
257
258int /* O - Number of elements */
259cupsArrayCount(cups_array_t *a) /* I - Array */
260{
261 /*
262 * Range check input...
263 */
264
265 if (!a)
266 return (0);
267
268 /*
269 * Return the number of elements...
270 */
271
272 return (a->num_elements);
273}
274
275
276/*
277 * 'cupsArrayCurrent()' - Return the current element in the array.
5a738aea 278 *
79e1d494
MS
279 * The current element is undefined until you call @link cupsArrayFind@,
280 * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@.
281 *
f3c17241 282 * @since CUPS 1.2/OS X 10.5@
ef416fc2 283 */
284
285void * /* O - Element */
286cupsArrayCurrent(cups_array_t *a) /* I - Array */
287{
288 /*
289 * Range check input...
290 */
291
292 if (!a)
293 return (NULL);
294
295 /*
296 * Return the current element...
297 */
298
299 if (a->current >= 0 && a->current < a->num_elements)
300 return (a->elements[a->current]);
301 else
302 return (NULL);
303}
304
305
306/*
307 * 'cupsArrayDelete()' - Free all memory used by the array.
5a738aea 308 *
79e1d494
MS
309 * The caller is responsible for freeing the memory used by the
310 * elements themselves.
311 *
f3c17241 312 * @since CUPS 1.2/OS X 10.5@
ef416fc2 313 */
314
315void
316cupsArrayDelete(cups_array_t *a) /* I - Array */
317{
318 /*
319 * Range check input...
320 */
321
322 if (!a)
323 return;
324
325 /*
10d09e33
MS
326 * Free the elements if we have a free function (otherwise the caller is
327 * responsible for doing the dirty work...)
328 */
329
330 if (a->freefunc)
331 {
332 int i; /* Looping var */
333 void **e; /* Current element */
334
335 for (i = a->num_elements, e = a->elements; i > 0; i --, e ++)
336 (a->freefunc)(*e, a->data);
337 }
338
339 /*
340 * Free the array of element pointers...
ef416fc2 341 */
342
343 if (a->alloc_elements)
344 free(a->elements);
345
b94498cf 346 if (a->hashsize)
347 free(a->hash);
348
ef416fc2 349 free(a);
350}
351
352
353/*
354 * 'cupsArrayDup()' - Duplicate the array.
5a738aea 355 *
f3c17241 356 * @since CUPS 1.2/OS X 10.5@
ef416fc2 357 */
358
359cups_array_t * /* O - Duplicate array */
360cupsArrayDup(cups_array_t *a) /* I - Array */
361{
362 cups_array_t *da; /* Duplicate array */
363
364
365 /*
366 * Range check input...
367 */
368
369 if (!a)
370 return (NULL);
371
372 /*
373 * Allocate memory for the array...
374 */
375
376 da = calloc(1, sizeof(cups_array_t));
377 if (!da)
378 return (NULL);
379
380 da->compare = a->compare;
381 da->data = a->data;
382 da->current = a->current;
383 da->insert = a->insert;
bd7854cb 384 da->unique = a->unique;
ef416fc2 385 da->num_saved = a->num_saved;
386
387 memcpy(da->saved, a->saved, sizeof(a->saved));
388
389 if (a->num_elements)
390 {
391 /*
392 * Allocate memory for the elements...
393 */
394
1a18c85c 395 da->elements = malloc((size_t)a->num_elements * sizeof(void *));
ef416fc2 396 if (!da->elements)
397 {
398 free(da);
399 return (NULL);
400 }
401
402 /*
403 * Copy the element pointers...
404 */
405
10d09e33
MS
406 if (a->copyfunc)
407 {
408 /*
409 * Use the copy function to make a copy of each element...
410 */
411
412 int i; /* Looping var */
413
414 for (i = 0; i < a->num_elements; i ++)
415 da->elements[i] = (a->copyfunc)(a->elements[i], a->data);
416 }
417 else
418 {
419 /*
420 * Just copy raw pointers...
421 */
422
1a18c85c 423 memcpy(da->elements, a->elements, (size_t)a->num_elements * sizeof(void *));
10d09e33
MS
424 }
425
ef416fc2 426 da->num_elements = a->num_elements;
427 da->alloc_elements = a->num_elements;
428 }
429
430 /*
431 * Return the new array...
432 */
433
434 return (da);
435}
436
437
438/*
439 * 'cupsArrayFind()' - Find an element in the array.
5a738aea 440 *
f3c17241 441 * @since CUPS 1.2/OS X 10.5@
ef416fc2 442 */
443
5a738aea 444void * /* O - Element found or @code NULL@ */
ef416fc2 445cupsArrayFind(cups_array_t *a, /* I - Array */
446 void *e) /* I - Element */
447{
448 int current, /* Current element */
b94498cf 449 diff, /* Difference */
450 hash; /* Hash index */
ef416fc2 451
452
453 /*
454 * Range check input...
455 */
456
457 if (!a || !e)
458 return (NULL);
459
460 /*
461 * See if we have any elements...
462 */
463
464 if (!a->num_elements)
465 return (NULL);
466
467 /*
468 * Yes, look for a match...
469 */
470
b94498cf 471 if (a->hash)
472 {
473 hash = (*(a->hashfunc))(e, a->data);
474
475 if (hash < 0 || hash >= a->hashsize)
476 {
477 current = a->current;
478 hash = -1;
479 }
480 else
481 {
482 current = a->hash[hash];
483
484 if (current < 0 || current >= a->num_elements)
485 current = a->current;
486 }
487 }
488 else
489 {
490 current = a->current;
491 hash = -1;
492 }
493
494 current = cups_array_find(a, e, current, &diff);
ef416fc2 495 if (!diff)
496 {
497 /*
bd7854cb 498 * Found a match! If the array does not contain unique values, find
499 * the first element that is the same...
ef416fc2 500 */
501
bd7854cb 502 if (!a->unique && a->compare)
503 {
504 /*
505 * The array is not unique, find the first match...
506 */
507
508 while (current > 0 && !(*(a->compare))(e, a->elements[current - 1],
509 a->data))
510 current --;
511 }
512
ef416fc2 513 a->current = current;
514
b94498cf 515 if (hash >= 0)
516 a->hash[hash] = current;
517
ef416fc2 518 return (a->elements[current]);
519 }
520 else
521 {
522 /*
523 * No match...
524 */
525
526 a->current = -1;
527
528 return (NULL);
529 }
530}
531
532
533/*
534 * 'cupsArrayFirst()' - Get the first element in the array.
5a738aea 535 *
f3c17241 536 * @since CUPS 1.2/OS X 10.5@
ef416fc2 537 */
538
79e1d494 539void * /* O - First element or @code NULL@ if the array is empty */
ef416fc2 540cupsArrayFirst(cups_array_t *a) /* I - Array */
541{
542 /*
543 * Range check input...
544 */
545
546 if (!a)
547 return (NULL);
548
549 /*
550 * Return the first element...
551 */
552
553 a->current = 0;
554
555 return (cupsArrayCurrent(a));
556}
557
558
f7deaa1a 559/*
560 * 'cupsArrayGetIndex()' - Get the index of the current element.
561 *
79e1d494
MS
562 * The current element is undefined until you call @link cupsArrayFind@,
563 * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@.
564 *
f3c17241 565 * @since CUPS 1.3/OS X 10.5@
f7deaa1a 566 */
567
79e1d494 568int /* O - Index of the current element, starting at 0 */
f7deaa1a 569cupsArrayGetIndex(cups_array_t *a) /* I - Array */
570{
571 if (!a)
572 return (-1);
573 else
574 return (a->current);
575}
576
577
578/*
579 * 'cupsArrayGetInsert()' - Get the index of the last inserted element.
580 *
f3c17241 581 * @since CUPS 1.3/OS X 10.5@
f7deaa1a 582 */
583
79e1d494 584int /* O - Index of the last inserted element, starting at 0 */
f7deaa1a 585cupsArrayGetInsert(cups_array_t *a) /* I - Array */
586{
587 if (!a)
588 return (-1);
589 else
590 return (a->insert);
591}
592
593
ef416fc2 594/*
595 * 'cupsArrayIndex()' - Get the N-th element in the array.
5a738aea 596 *
f3c17241 597 * @since CUPS 1.2/OS X 10.5@
ef416fc2 598 */
599
5a738aea 600void * /* O - N-th element or @code NULL@ */
ef416fc2 601cupsArrayIndex(cups_array_t *a, /* I - Array */
602 int n) /* I - Index into array, starting at 0 */
603{
604 if (!a)
605 return (NULL);
606
607 a->current = n;
608
609 return (cupsArrayCurrent(a));
610}
611
612
fa73b229 613/*
614 * 'cupsArrayInsert()' - Insert an element in the array.
615 *
bd7854cb 616 * When inserting an element in a sorted array, non-unique elements are
79e1d494
MS
617 * inserted at the beginning of the run of identical elements. For unsorted
618 * arrays, the element is inserted at the beginning of the array.
5a738aea 619 *
f3c17241 620 * @since CUPS 1.2/OS X 10.5@
fa73b229 621 */
622
623int /* O - 0 on failure, 1 on success */
624cupsArrayInsert(cups_array_t *a, /* I - Array */
625 void *e) /* I - Element */
626{
e07d4801 627 DEBUG_printf(("2cupsArrayInsert(a=%p, e=%p)", a, e));
fa73b229 628
629 /*
630 * Range check input...
631 */
632
633 if (!a || !e)
634 {
e07d4801 635 DEBUG_puts("3cupsArrayInsert: returning 0");
fa73b229 636 return (0);
637 }
638
fa73b229 639 /*
640 * Insert the element...
641 */
642
bd7854cb 643 return (cups_array_add(a, e, 1));
fa73b229 644}
645
646
ef416fc2 647/*
648 * 'cupsArrayLast()' - Get the last element in the array.
5a738aea 649 *
f3c17241 650 * @since CUPS 1.2/OS X 10.5@
ef416fc2 651 */
652
79e1d494 653void * /* O - Last element or @code NULL@ if the array is empty */
ef416fc2 654cupsArrayLast(cups_array_t *a) /* I - Array */
655{
656 /*
657 * Range check input...
658 */
659
660 if (!a)
661 return (NULL);
662
663 /*
664 * Return the last element...
665 */
666
667 a->current = a->num_elements - 1;
668
669 return (cupsArrayCurrent(a));
670}
671
672
673/*
674 * 'cupsArrayNew()' - Create a new array.
5a738aea 675 *
79e1d494
MS
676 * The comparison function ("f") is used to create a sorted array. The function
677 * receives pointers to two elements and the user data pointer ("d") - the user
678 * data pointer argument can safely be omitted when not required so functions
679 * like @code strcmp@ can be used for sorted string arrays.
680 *
f3c17241 681 * @since CUPS 1.2/OS X 10.5@
ef416fc2 682 */
683
684cups_array_t * /* O - Array */
79e1d494
MS
685cupsArrayNew(cups_array_func_t f, /* I - Comparison function or @code NULL@ for an unsorted array */
686 void *d) /* I - User data pointer or @code NULL@ */
b94498cf 687{
10d09e33 688 return (cupsArrayNew3(f, d, 0, 0, 0, 0));
b94498cf 689}
690
691
692/*
693 * 'cupsArrayNew2()' - Create a new array with hash.
694 *
79e1d494
MS
695 * The comparison function ("f") is used to create a sorted array. The function
696 * receives pointers to two elements and the user data pointer ("d") - the user
697 * data pointer argument can safely be omitted when not required so functions
698 * like @code strcmp@ can be used for sorted string arrays.
699 *
700 * The hash function ("h") is used to implement cached lookups with the
701 * specified hash size ("hsize").
702 *
f3c17241 703 * @since CUPS 1.3/OS X 10.5@
b94498cf 704 */
705
706cups_array_t * /* O - Array */
79e1d494
MS
707cupsArrayNew2(cups_array_func_t f, /* I - Comparison function or @code NULL@ for an unsorted array */
708 void *d, /* I - User data or @code NULL@ */
709 cups_ahash_func_t h, /* I - Hash function or @code NULL@ for unhashed lookups */
710 int hsize) /* I - Hash size (>= 0) */
10d09e33
MS
711{
712 return (cupsArrayNew3(f, d, h, hsize, 0, 0));
713}
714
715
716/*
717 * 'cupsArrayNew3()' - Create a new array with hash and/or free function.
718 *
719 * The comparison function ("f") is used to create a sorted array. The function
720 * receives pointers to two elements and the user data pointer ("d") - the user
721 * data pointer argument can safely be omitted when not required so functions
722 * like @code strcmp@ can be used for sorted string arrays.
723 *
724 * The hash function ("h") is used to implement cached lookups with the
725 * specified hash size ("hsize").
726 *
727 * The copy function ("cf") is used to automatically copy/retain elements when
728 * added or the array is copied.
729 *
730 * The free function ("cf") is used to automatically free/release elements when
731 * removed or the array is deleted.
732 *
f3c17241 733 * @since CUPS 1.5/OS X 10.7@
10d09e33
MS
734 */
735
736cups_array_t * /* O - Array */
737cupsArrayNew3(cups_array_func_t f, /* I - Comparison function or @code NULL@ for an unsorted array */
738 void *d, /* I - User data or @code NULL@ */
739 cups_ahash_func_t h, /* I - Hash function or @code NULL@ for unhashed lookups */
740 int hsize, /* I - Hash size (>= 0) */
741 cups_acopy_func_t cf, /* I - Copy function */
742 cups_afree_func_t ff) /* I - Free function */
ef416fc2 743{
744 cups_array_t *a; /* Array */
745
746
747 /*
748 * Allocate memory for the array...
749 */
750
751 a = calloc(1, sizeof(cups_array_t));
752 if (!a)
753 return (NULL);
754
755 a->compare = f;
756 a->data = d;
757 a->current = -1;
758 a->insert = -1;
759 a->num_saved = 0;
bd7854cb 760 a->unique = 1;
ef416fc2 761
b94498cf 762 if (hsize > 0 && h)
763 {
764 a->hashfunc = h;
765 a->hashsize = hsize;
1a18c85c 766 a->hash = malloc((size_t)hsize * sizeof(int));
b94498cf 767
768 if (!a->hash)
769 {
770 free(a);
771 return (NULL);
772 }
773
1a18c85c 774 memset(a->hash, -1, (size_t)hsize * sizeof(int));
b94498cf 775 }
776
10d09e33
MS
777 a->copyfunc = cf;
778 a->freefunc = ff;
779
ef416fc2 780 return (a);
781}
782
783
eac3a0a0
MS
784/*
785 * '_cupsArrayNewStrings()' - Create a new array of comma-delimited strings.
786 *
787 * Note: The array automatically manages copies of the strings passed. If the
788 * string pointer "s" is NULL or the empty string, no strings are added to the
789 * newly created array.
790 */
791
792cups_array_t * /* O - Array */
5a9febac
MS
793_cupsArrayNewStrings(const char *s, /* I - Delimited strings or NULL */
794 char delim) /* I - Delimiter character */
eac3a0a0
MS
795{
796 cups_array_t *a; /* Array */
797
798
799 if ((a = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0,
800 (cups_acopy_func_t)_cupsStrAlloc,
801 (cups_afree_func_t)_cupsStrFree)) != NULL)
5a9febac 802 _cupsArrayAddStrings(a, s, delim);
eac3a0a0
MS
803
804 return (a);
805}
806
807
ef416fc2 808/*
809 * 'cupsArrayNext()' - Get the next element in the array.
5a738aea 810 *
79e1d494
MS
811 * This function is equivalent to "cupsArrayIndex(a, cupsArrayGetIndex(a) + 1)".
812 *
813 * The next element is undefined until you call @link cupsArrayFind@,
814 * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@
815 * to set the current element.
816 *
f3c17241 817 * @since CUPS 1.2/OS X 10.5@
ef416fc2 818 */
819
5a738aea 820void * /* O - Next element or @code NULL@ */
ef416fc2 821cupsArrayNext(cups_array_t *a) /* I - Array */
822{
823 /*
824 * Range check input...
825 */
826
827 if (!a)
828 return (NULL);
829
830 /*
831 * Return the next element...
832 */
833
834 if (a->current < a->num_elements)
835 a->current ++;
836
837 return (cupsArrayCurrent(a));
838}
839
840
841/*
842 * 'cupsArrayPrev()' - Get the previous element in the array.
5a738aea 843 *
79e1d494
MS
844 * This function is equivalent to "cupsArrayIndex(a, cupsArrayGetIndex(a) - 1)".
845 *
846 * The previous element is undefined until you call @link cupsArrayFind@,
847 * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@
848 * to set the current element.
849 *
f3c17241 850 * @since CUPS 1.2/OS X 10.5@
ef416fc2 851 */
852
5a738aea 853void * /* O - Previous element or @code NULL@ */
ef416fc2 854cupsArrayPrev(cups_array_t *a) /* I - Array */
855{
856 /*
857 * Range check input...
858 */
859
860 if (!a)
861 return (NULL);
862
863 /*
864 * Return the previous element...
865 */
866
867 if (a->current >= 0)
868 a->current --;
869
870 return (cupsArrayCurrent(a));
871}
872
873
874/*
875 * 'cupsArrayRemove()' - Remove an element from the array.
5a738aea 876 *
79e1d494
MS
877 * If more than one element matches "e", only the first matching element is
878 * removed.
879 *
880 * The caller is responsible for freeing the memory used by the
881 * removed element.
882 *
f3c17241 883 * @since CUPS 1.2/OS X 10.5@
ef416fc2 884 */
885
886int /* O - 1 on success, 0 on failure */
887cupsArrayRemove(cups_array_t *a, /* I - Array */
888 void *e) /* I - Element */
889{
1a18c85c
MS
890 ssize_t i, /* Looping var */
891 current; /* Current element */
892 int diff; /* Difference */
ef416fc2 893
894
895 /*
896 * Range check input...
897 */
898
899 if (!a || !e)
900 return (0);
901
902 /*
903 * See if the element is in the array...
904 */
905
906 if (!a->num_elements)
907 return (0);
908
bd7854cb 909 current = cups_array_find(a, e, a->current, &diff);
ef416fc2 910 if (diff)
911 return (0);
912
913 /*
914 * Yes, now remove it...
915 */
916
917 a->num_elements --;
918
10d09e33
MS
919 if (a->freefunc)
920 (a->freefunc)(a->elements[current], a->data);
921
ef416fc2 922 if (current < a->num_elements)
923 memmove(a->elements + current, a->elements + current + 1,
1a18c85c 924 (size_t)(a->num_elements - current) * sizeof(void *));
ef416fc2 925
926 if (current <= a->current)
927 a->current --;
928
f7deaa1a 929 if (current < a->insert)
ef416fc2 930 a->insert --;
f7deaa1a 931 else if (current == a->insert)
932 a->insert = -1;
ef416fc2 933
934 for (i = 0; i < a->num_saved; i ++)
935 if (current <= a->saved[i])
936 a->saved[i] --;
937
bd7854cb 938 if (a->num_elements <= 1)
939 a->unique = 1;
940
ef416fc2 941 return (1);
942}
943
944
945/*
79e1d494 946 * 'cupsArrayRestore()' - Reset the current element to the last @link cupsArraySave@.
5a738aea 947 *
f3c17241 948 * @since CUPS 1.2/OS X 10.5@
ef416fc2 949 */
950
951void * /* O - New current element */
952cupsArrayRestore(cups_array_t *a) /* I - Array */
953{
954 if (!a)
955 return (NULL);
956
957 if (a->num_saved <= 0)
958 return (NULL);
959
960 a->num_saved --;
961 a->current = a->saved[a->num_saved];
962
963 if (a->current >= 0 && a->current < a->num_elements)
964 return (a->elements[a->current]);
965 else
966 return (NULL);
967}
968
969
970/*
79e1d494
MS
971 * 'cupsArraySave()' - Mark the current element for a later @link cupsArrayRestore@.
972 *
973 * The current element is undefined until you call @link cupsArrayFind@,
974 * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@
975 * to set the current element.
ef416fc2 976 *
977 * The save/restore stack is guaranteed to be at least 32 elements deep.
5a738aea 978 *
f3c17241 979 * @since CUPS 1.2/OS X 10.5@
ef416fc2 980 */
981
982int /* O - 1 on success, 0 on failure */
983cupsArraySave(cups_array_t *a) /* I - Array */
984{
985 if (!a)
986 return (0);
987
988 if (a->num_saved >= _CUPS_MAXSAVE)
989 return (0);
990
991 a->saved[a->num_saved] = a->current;
992 a->num_saved ++;
993
994 return (1);
995}
996
997
e1d6a774 998/*
999 * 'cupsArrayUserData()' - Return the user data for an array.
5a738aea 1000 *
f3c17241 1001 * @since CUPS 1.2/OS X 10.5@
e1d6a774 1002 */
1003
1004void * /* O - User data */
1005cupsArrayUserData(cups_array_t *a) /* I - Array */
1006{
1007 if (a)
1008 return (a->data);
1009 else
1010 return (NULL);
1011}
1012
1013
ef416fc2 1014/*
eac3a0a0 1015 * 'cups_array_add()' - Insert or append an element to the array.
5a738aea 1016 *
f3c17241 1017 * @since CUPS 1.2/OS X 10.5@
bd7854cb 1018 */
1019
1020static int /* O - 1 on success, 0 on failure */
1021cups_array_add(cups_array_t *a, /* I - Array */
1022 void *e, /* I - Element to add */
1023 int insert) /* I - 1 = insert, 0 = append */
1024{
1a18c85c
MS
1025 int i, /* Looping var */
1026 current; /* Current element */
1027 int diff; /* Comparison with current element */
bd7854cb 1028
1029
e07d4801 1030 DEBUG_printf(("7cups_array_add(a=%p, e=%p, insert=%d)", a, e, insert));
bd7854cb 1031
1032 /*
1033 * Verify we have room for the new element...
1034 */
1035
1036 if (a->num_elements >= a->alloc_elements)
1037 {
1038 /*
1039 * Allocate additional elements; start with 16 elements, then
1040 * double the size until 1024 elements, then add 1024 elements
1041 * thereafter...
1042 */
1043
1044 void **temp; /* New array elements */
1045 int count; /* New allocation count */
1046
1047
1048 if (a->alloc_elements == 0)
1049 {
1050 count = 16;
1a18c85c 1051 temp = malloc((size_t)count * sizeof(void *));
bd7854cb 1052 }
1053 else
1054 {
1055 if (a->alloc_elements < 1024)
1056 count = a->alloc_elements * 2;
1057 else
1058 count = a->alloc_elements + 1024;
1059
1a18c85c 1060 temp = realloc(a->elements, (size_t)count * sizeof(void *));
bd7854cb 1061 }
1062
1a18c85c 1063 DEBUG_printf(("9cups_array_add: count=" CUPS_LLFMT, CUPS_LLCAST count));
bd7854cb 1064
1065 if (!temp)
1066 {
e07d4801 1067 DEBUG_puts("9cups_array_add: allocation failed, returning 0");
bd7854cb 1068 return (0);
1069 }
1070
1071 a->alloc_elements = count;
1072 a->elements = temp;
1073 }
1074
1075 /*
1076 * Find the insertion point for the new element; if there is no
1077 * compare function or elements, just add it to the beginning or end...
1078 */
1079
1080 if (!a->num_elements || !a->compare)
1081 {
1082 /*
1083 * No elements or comparison function, insert/append as needed...
1084 */
1085
1086 if (insert)
1087 current = 0; /* Insert at beginning */
1088 else
1089 current = a->num_elements; /* Append to the end */
1090 }
1091 else
1092 {
1093 /*
1094 * Do a binary search for the insertion point...
1095 */
1096
1097 current = cups_array_find(a, e, a->insert, &diff);
1098
1099 if (diff > 0)
1100 {
1101 /*
1102 * Insert after the current element...
1103 */
1104
1105 current ++;
1106 }
1107 else if (!diff)
1108 {
1109 /*
1110 * Compared equal, make sure we add to the begining or end of
1111 * the current run of equal elements...
1112 */
1113
1114 a->unique = 0;
1115
1116 if (insert)
1117 {
1118 /*
1119 * Insert at beginning of run...
1120 */
1121
1122 while (current > 0 && !(*(a->compare))(e, a->elements[current - 1],
1123 a->data))
1124 current --;
1125 }
1126 else
1127 {
1128 /*
1129 * Append at end of run...
1130 */
1131
1132 do
1133 {
1134 current ++;
1135 }
1136 while (current < a->num_elements &&
1137 !(*(a->compare))(e, a->elements[current], a->data));
1138 }
1139 }
1140 }
1141
1142 /*
1143 * Insert or append the element...
1144 */
1145
1146 if (current < a->num_elements)
1147 {
1148 /*
1149 * Shift other elements to the right...
1150 */
1151
1152 memmove(a->elements + current + 1, a->elements + current,
1a18c85c 1153 (size_t)(a->num_elements - current) * sizeof(void *));
bd7854cb 1154
1155 if (a->current >= current)
1156 a->current ++;
1157
1158 for (i = 0; i < a->num_saved; i ++)
1159 if (a->saved[i] >= current)
1160 a->saved[i] ++;
1161
1a18c85c 1162 DEBUG_printf(("9cups_array_add: insert element at index " CUPS_LLFMT, CUPS_LLCAST current));
bd7854cb 1163 }
1164#ifdef DEBUG
1165 else
1a18c85c 1166 DEBUG_printf(("9cups_array_add: append element at " CUPS_LLFMT, CUPS_LLCAST current));
bd7854cb 1167#endif /* DEBUG */
1168
10d09e33
MS
1169 if (a->copyfunc)
1170 {
1171 if ((a->elements[current] = (a->copyfunc)(e, a->data)) == NULL)
1172 {
1173 DEBUG_puts("8cups_array_add: Copy function returned NULL, returning 0");
1174 return (0);
1175 }
1176 }
1177 else
1178 a->elements[current] = e;
1179
bd7854cb 1180 a->num_elements ++;
1181 a->insert = current;
1182
1183#ifdef DEBUG
1184 for (current = 0; current < a->num_elements; current ++)
1a18c85c 1185 DEBUG_printf(("9cups_array_add: a->elements[" CUPS_LLFMT "]=%p", CUPS_LLCAST current, a->elements[current]));
bd7854cb 1186#endif /* DEBUG */
1187
e07d4801 1188 DEBUG_puts("9cups_array_add: returning 1");
bd7854cb 1189
1190 return (1);
1191}
1192
1193
1194/*
eac3a0a0 1195 * 'cups_array_find()' - Find an element in the array.
ef416fc2 1196 */
1197
1198static int /* O - Index of match */
bd7854cb 1199cups_array_find(cups_array_t *a, /* I - Array */
1200 void *e, /* I - Element */
1201 int prev, /* I - Previous index */
1202 int *rdiff) /* O - Difference of match */
ef416fc2 1203{
1204 int left, /* Left side of search */
1205 right, /* Right side of search */
1206 current, /* Current element */
1207 diff; /* Comparison with current element */
1208
1209
e07d4801 1210 DEBUG_printf(("7cups_array_find(a=%p, e=%p, prev=%d, rdiff=%p)", a, e, prev,
ef416fc2 1211 rdiff));
1212
1213 if (a->compare)
1214 {
1215 /*
1216 * Do a binary search for the element...
1217 */
1218
e07d4801 1219 DEBUG_puts("9cups_array_find: binary search");
ef416fc2 1220
1221 if (prev >= 0 && prev < a->num_elements)
1222 {
1223 /*
1224 * Start search on either side of previous...
1225 */
1226
1227 if ((diff = (*(a->compare))(e, a->elements[prev], a->data)) == 0 ||
1228 (diff < 0 && prev == 0) ||
1229 (diff > 0 && prev == (a->num_elements - 1)))
1230 {
1231 /*
1232 * Exact or edge match, return it!
1233 */
1234
e07d4801 1235 DEBUG_printf(("9cups_array_find: Returning %d, diff=%d", prev, diff));
ef416fc2 1236
1237 *rdiff = diff;
1238
1239 return (prev);
1240 }
1241 else if (diff < 0)
1242 {
1243 /*
1244 * Start with previous on right side...
1245 */
1246
1247 left = 0;
1248 right = prev;
1249 }
1250 else
1251 {
1252 /*
1253 * Start wih previous on left side...
1254 */
1255
1256 left = prev;
1257 right = a->num_elements - 1;
1258 }
1259 }
1260 else
1261 {
1262 /*
1263 * Start search in the middle...
1264 */
1265
1266 left = 0;
1267 right = a->num_elements - 1;
1268 }
1269
1270 do
1271 {
1272 current = (left + right) / 2;
1273 diff = (*(a->compare))(e, a->elements[current], a->data);
1274
e07d4801 1275 DEBUG_printf(("9cups_array_find: left=%d, right=%d, current=%d, diff=%d",
ef416fc2 1276 left, right, current, diff));
1277
1278 if (diff == 0)
1279 break;
1280 else if (diff < 0)
1281 right = current;
1282 else
1283 left = current;
1284 }
1285 while ((right - left) > 1);
1286
1287 if (diff != 0)
1288 {
1289 /*
1290 * Check the last 1 or 2 elements...
1291 */
1292
1293 if ((diff = (*(a->compare))(e, a->elements[left], a->data)) <= 0)
1294 current = left;
1295 else
1296 {
1297 diff = (*(a->compare))(e, a->elements[right], a->data);
1298 current = right;
1299 }
1300 }
1301 }
1302 else
1303 {
1304 /*
1305 * Do a linear pointer search...
1306 */
1307
e07d4801 1308 DEBUG_puts("9cups_array_find: linear search");
ef416fc2 1309
a74454a7 1310 diff = 1;
ef416fc2 1311
1312 for (current = 0; current < a->num_elements; current ++)
1313 if (a->elements[current] == e)
a74454a7 1314 {
1315 diff = 0;
ef416fc2 1316 break;
a74454a7 1317 }
ef416fc2 1318 }
1319
1320 /*
1321 * Return the closest element and the difference...
1322 */
1323
e07d4801 1324 DEBUG_printf(("8cups_array_find: Returning %d, diff=%d", current, diff));
ef416fc2 1325
1326 *rdiff = diff;
1327
1328 return (current);
1329}
1330
1331
1332/*
1a18c85c 1333 * End of "$Id: array.c 12031 2014-07-15 19:57:59Z msweet $".
ef416fc2 1334 */