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