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