]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/array.c
Merge changes from CUPS 1.5svn-r9525
[thirdparty/cups.git] / cups / array.c
1 /*
2 * "$Id: array.c 7616 2008-05-28 00:34:13Z mike $"
3 *
4 * Sorted array routines for CUPS.
5 *
6 * Copyright 2007-2010 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
8 *
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/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 *
17 * Contents:
18 *
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.
33 * cupsArrayNew2() - Create a new array with hash.
34 * cupsArrayNew3() - Create a new array with hash and/or free function.
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.
38 * cupsArrayRestore() - Reset the current element to the last @link
39 * cupsArraySave@.
40 * cupsArraySave() - Mark the current element for a later @link
41 * cupsArrayRestore@.
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...
45 */
46
47 /*
48 * Include necessary headers...
49 */
50
51 #include "string-private.h"
52 #include "debug-private.h"
53 #include "array.h"
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
67 struct _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 */
80 unique, /* Are all elements unique? */
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 */
87 cups_ahash_func_t hashfunc; /* Hash function */
88 int hashsize, /* Size of hash */
89 *hash; /* Hash array */
90 cups_acopy_func_t copyfunc; /* Copy function */
91 cups_afree_func_t freefunc; /* Free function */
92 };
93
94
95 /*
96 * Local functions...
97 */
98
99 static int cups_array_add(cups_array_t *a, void *e, int insert);
100 static int cups_array_find(cups_array_t *a, void *e, int prev, int *rdiff);
101
102
103 /*
104 * 'cupsArrayAdd()' - Add an element to the array.
105 *
106 * When adding an element to a sorted array, non-unique elements are
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.
109 *
110 * @since CUPS 1.2/Mac OS X 10.5@
111 */
112
113 int /* O - 1 on success, 0 on failure */
114 cupsArrayAdd(cups_array_t *a, /* I - Array */
115 void *e) /* I - Element */
116 {
117 DEBUG_printf(("2cupsArrayAdd(a=%p, e=%p)", a, e));
118
119 /*
120 * Range check input...
121 */
122
123 if (!a || !e)
124 {
125 DEBUG_puts("3cupsArrayAdd: returning 0");
126 return (0);
127 }
128
129 /*
130 * Append the element...
131 */
132
133 return (cups_array_add(a, e, 0));
134 }
135
136
137 /*
138 * 'cupsArrayClear()' - Clear the array.
139 *
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 *
144 * @since CUPS 1.2/Mac OS X 10.5@
145 */
146
147 void
148 cupsArrayClear(cups_array_t *a) /* I - Array */
149 {
150 /*
151 * Range check input...
152 */
153
154 if (!a)
155 return;
156
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
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;
178 a->unique = 1;
179 a->num_saved = 0;
180 }
181
182
183 /*
184 * 'cupsArrayCount()' - Get the number of elements in the array.
185 *
186 * @since CUPS 1.2/Mac OS X 10.5@
187 */
188
189 int /* O - Number of elements */
190 cupsArrayCount(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.
209 *
210 * The current element is undefined until you call @link cupsArrayFind@,
211 * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@.
212 *
213 * @since CUPS 1.2/Mac OS X 10.5@
214 */
215
216 void * /* O - Element */
217 cupsArrayCurrent(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.
239 *
240 * The caller is responsible for freeing the memory used by the
241 * elements themselves.
242 *
243 * @since CUPS 1.2/Mac OS X 10.5@
244 */
245
246 void
247 cupsArrayDelete(cups_array_t *a) /* I - Array */
248 {
249 /*
250 * Range check input...
251 */
252
253 if (!a)
254 return;
255
256 /*
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...
272 */
273
274 if (a->alloc_elements)
275 free(a->elements);
276
277 if (a->hashsize)
278 free(a->hash);
279
280 free(a);
281 }
282
283
284 /*
285 * 'cupsArrayDup()' - Duplicate the array.
286 *
287 * @since CUPS 1.2/Mac OS X 10.5@
288 */
289
290 cups_array_t * /* O - Duplicate array */
291 cupsArrayDup(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;
315 da->unique = a->unique;
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
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
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.
371 *
372 * @since CUPS 1.2/Mac OS X 10.5@
373 */
374
375 void * /* O - Element found or @code NULL@ */
376 cupsArrayFind(cups_array_t *a, /* I - Array */
377 void *e) /* I - Element */
378 {
379 int current, /* Current element */
380 diff, /* Difference */
381 hash; /* Hash index */
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
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);
426 if (!diff)
427 {
428 /*
429 * Found a match! If the array does not contain unique values, find
430 * the first element that is the same...
431 */
432
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
444 a->current = current;
445
446 if (hash >= 0)
447 a->hash[hash] = current;
448
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.
466 *
467 * @since CUPS 1.2/Mac OS X 10.5@
468 */
469
470 void * /* O - First element or @code NULL@ if the array is empty */
471 cupsArrayFirst(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
490 /*
491 * 'cupsArrayGetIndex()' - Get the index of the current element.
492 *
493 * The current element is undefined until you call @link cupsArrayFind@,
494 * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@.
495 *
496 * @since CUPS 1.3/Mac OS X 10.5@
497 */
498
499 int /* O - Index of the current element, starting at 0 */
500 cupsArrayGetIndex(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 *
512 * @since CUPS 1.3/Mac OS X 10.5@
513 */
514
515 int /* O - Index of the last inserted element, starting at 0 */
516 cupsArrayGetInsert(cups_array_t *a) /* I - Array */
517 {
518 if (!a)
519 return (-1);
520 else
521 return (a->insert);
522 }
523
524
525 /*
526 * 'cupsArrayIndex()' - Get the N-th element in the array.
527 *
528 * @since CUPS 1.2/Mac OS X 10.5@
529 */
530
531 void * /* O - N-th element or @code NULL@ */
532 cupsArrayIndex(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
544 /*
545 * 'cupsArrayInsert()' - Insert an element in the array.
546 *
547 * When inserting an element in a sorted array, non-unique elements are
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.
550 *
551 * @since CUPS 1.2/Mac OS X 10.5@
552 */
553
554 int /* O - 0 on failure, 1 on success */
555 cupsArrayInsert(cups_array_t *a, /* I - Array */
556 void *e) /* I - Element */
557 {
558 DEBUG_printf(("2cupsArrayInsert(a=%p, e=%p)", a, e));
559
560 /*
561 * Range check input...
562 */
563
564 if (!a || !e)
565 {
566 DEBUG_puts("3cupsArrayInsert: returning 0");
567 return (0);
568 }
569
570 /*
571 * Insert the element...
572 */
573
574 return (cups_array_add(a, e, 1));
575 }
576
577
578 /*
579 * 'cupsArrayLast()' - Get the last element in the array.
580 *
581 * @since CUPS 1.2/Mac OS X 10.5@
582 */
583
584 void * /* O - Last element or @code NULL@ if the array is empty */
585 cupsArrayLast(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.
606 *
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 *
612 * @since CUPS 1.2/Mac OS X 10.5@
613 */
614
615 cups_array_t * /* O - Array */
616 cupsArrayNew(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@ */
618 {
619 return (cupsArrayNew3(f, d, 0, 0, 0, 0));
620 }
621
622
623 /*
624 * 'cupsArrayNew2()' - Create a new array with hash.
625 *
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 *
634 * @since CUPS 1.3/Mac OS X 10.5@
635 */
636
637 cups_array_t * /* O - Array */
638 cupsArrayNew2(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) */
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
667 cups_array_t * /* O - Array */
668 cupsArrayNew3(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 */
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;
691 a->unique = 1;
692
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
708 a->copyfunc = cf;
709 a->freefunc = ff;
710
711 return (a);
712 }
713
714
715 /*
716 * 'cupsArrayNext()' - Get the next element in the array.
717 *
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 *
724 * @since CUPS 1.2/Mac OS X 10.5@
725 */
726
727 void * /* O - Next element or @code NULL@ */
728 cupsArrayNext(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.
750 *
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 *
757 * @since CUPS 1.2/Mac OS X 10.5@
758 */
759
760 void * /* O - Previous element or @code NULL@ */
761 cupsArrayPrev(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.
783 *
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 *
790 * @since CUPS 1.2/Mac OS X 10.5@
791 */
792
793 int /* O - 1 on success, 0 on failure */
794 cupsArrayRemove(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
816 current = cups_array_find(a, e, a->current, &diff);
817 if (diff)
818 return (0);
819
820 /*
821 * Yes, now remove it...
822 */
823
824 a->num_elements --;
825
826 if (a->freefunc)
827 (a->freefunc)(a->elements[current], a->data);
828
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
836 if (current < a->insert)
837 a->insert --;
838 else if (current == a->insert)
839 a->insert = -1;
840
841 for (i = 0; i < a->num_saved; i ++)
842 if (current <= a->saved[i])
843 a->saved[i] --;
844
845 if (a->num_elements <= 1)
846 a->unique = 1;
847
848 return (1);
849 }
850
851
852 /*
853 * 'cupsArrayRestore()' - Reset the current element to the last @link cupsArraySave@.
854 *
855 * @since CUPS 1.2/Mac OS X 10.5@
856 */
857
858 void * /* O - New current element */
859 cupsArrayRestore(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 /*
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.
883 *
884 * The save/restore stack is guaranteed to be at least 32 elements deep.
885 *
886 * @since CUPS 1.2/Mac OS X 10.5@
887 */
888
889 int /* O - 1 on success, 0 on failure */
890 cupsArraySave(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
905 /*
906 * 'cupsArrayUserData()' - Return the user data for an array.
907 *
908 * @since CUPS 1.2/Mac OS X 10.5@
909 */
910
911 void * /* O - User data */
912 cupsArrayUserData(cups_array_t *a) /* I - Array */
913 {
914 if (a)
915 return (a->data);
916 else
917 return (NULL);
918 }
919
920
921 /*
922 * 'cups_array_add()' - Insert or append an element to the array...
923 *
924 * @since CUPS 1.2/Mac OS X 10.5@
925 */
926
927 static int /* O - 1 on success, 0 on failure */
928 cups_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
937 DEBUG_printf(("7cups_array_add(a=%p, e=%p, insert=%d)", a, e, insert));
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
970 DEBUG_printf(("9cups_array_add: count=%d", count));
971
972 if (!temp)
973 {
974 DEBUG_puts("9cups_array_add: allocation failed, returning 0");
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
1069 DEBUG_printf(("9cups_array_add: insert element at index %d...", current));
1070 }
1071 #ifdef DEBUG
1072 else
1073 DEBUG_printf(("9cups_array_add: append element at %d...", current));
1074 #endif /* DEBUG */
1075
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
1087 a->num_elements ++;
1088 a->insert = current;
1089
1090 #ifdef DEBUG
1091 for (current = 0; current < a->num_elements; current ++)
1092 DEBUG_printf(("9cups_array_add: a->elements[%d]=%p", current,
1093 a->elements[current]));
1094 #endif /* DEBUG */
1095
1096 DEBUG_puts("9cups_array_add: returning 1");
1097
1098 return (1);
1099 }
1100
1101
1102 /*
1103 * 'cups_array_find()' - Find an element in the array...
1104 */
1105
1106 static int /* O - Index of match */
1107 cups_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 */
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
1118 DEBUG_printf(("7cups_array_find(a=%p, e=%p, prev=%d, rdiff=%p)", a, e, prev,
1119 rdiff));
1120
1121 if (a->compare)
1122 {
1123 /*
1124 * Do a binary search for the element...
1125 */
1126
1127 DEBUG_puts("9cups_array_find: binary search");
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
1143 DEBUG_printf(("9cups_array_find: Returning %d, diff=%d", prev, diff));
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
1183 DEBUG_printf(("9cups_array_find: left=%d, right=%d, current=%d, diff=%d",
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
1216 DEBUG_puts("9cups_array_find: linear search");
1217
1218 diff = 1;
1219
1220 for (current = 0; current < a->num_elements; current ++)
1221 if (a->elements[current] == e)
1222 {
1223 diff = 0;
1224 break;
1225 }
1226 }
1227
1228 /*
1229 * Return the closest element and the difference...
1230 */
1231
1232 DEBUG_printf(("8cups_array_find: Returning %d, diff=%d", current, diff));
1233
1234 *rdiff = diff;
1235
1236 return (current);
1237 }
1238
1239
1240 /*
1241 * End of "$Id: array.c 7616 2008-05-28 00:34:13Z mike $".
1242 */