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