]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/array.c
Load cups into easysw/current.
[thirdparty/cups.git] / cups / array.c
1 /*
2 * "$Id: array.c 5119 2006-02-16 15:52:06Z mike $"
3 *
4 * Sorted array routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * cupsArrayAdd() - Add an element to the array.
29 * cupsArrayClear() - Clear the array.
30 * cupsArrayCount() - Get the number of elements in the array.
31 * cupsArrayCurrent() - Return the current element in the array.
32 * cupsArrayDelete() - Free all memory used by the array.
33 * cupsArrayDup() - Duplicate the array.
34 * cupsArrayFind() - Find an element in the array.
35 * cupsArrayFirst() - Get the first element in the array.
36 * cupsArrayIndex() - Get the N-th element in the array.
37 * cupsArrayInsert() - Insert an element in the array.
38 * cupsArrayLast() - Get the last element in the array.
39 * cupsArrayNew() - Create a new array.
40 * cupsArrayNext() - Get the next element in the array.
41 * cupsArrayPrev() - Get the previous element in the array.
42 * cupsArrayRemove() - Remove an element from the array.
43 * cupsArrayRestore() - Reset the current element to the last cupsArraySave.
44 * cupsArraySave() - Mark the current element for a later cupsArrayRestore.
45 * cups_array_find() - Find an element in the array...
46 */
47
48 /*
49 * Include necessary headers...
50 */
51
52 #include "array.h"
53 #include "string.h"
54 #include "debug.h"
55
56
57 /*
58 * Limits...
59 */
60
61 #define _CUPS_MAXSAVE 32 /**** Maximum number of saves ****/
62
63
64 /*
65 * Types and structures...
66 */
67
68 struct _cups_array_s /**** CUPS array structure ****/
69 {
70 /*
71 * The current implementation uses an insertion sort into an array of
72 * sorted pointers. We leave the array type private/opaque so that we
73 * can change the underlying implementation without affecting the users
74 * of this API.
75 */
76
77 int num_elements, /* Number of array elements */
78 alloc_elements, /* Allocated array elements */
79 current, /* Current element */
80 insert, /* Last inserted element */
81 unique, /* Are all elements unique? */
82 num_saved, /* Number of saved elements */
83 saved[_CUPS_MAXSAVE];
84 /* Saved elements */
85 void **elements; /* Array elements */
86 cups_array_func_t compare; /* Element comparison function */
87 void *data; /* User data passed to compare */
88 };
89
90
91 /*
92 * Local functions...
93 */
94
95 static int cups_array_add(cups_array_t *a, void *e, int insert);
96 static int cups_array_find(cups_array_t *a, void *e, int prev, int *rdiff);
97
98
99 /*
100 * 'cupsArrayAdd()' - Add an element to the array.
101 *
102 * When adding an element to a sorted array, non-unique elements are
103 * appended at the end of the run. For unsorted arrays, the element
104 * is inserted at the end of the array.
105 */
106
107 int /* O - 1 on success, 0 on failure */
108 cupsArrayAdd(cups_array_t *a, /* I - Array */
109 void *e) /* I - Element */
110 {
111 DEBUG_printf(("cupsArrayAdd(a=%p, e=%p)\n", a, e));
112
113 /*
114 * Range check input...
115 */
116
117 if (!a || !e)
118 {
119 DEBUG_puts("cupsArrayAdd: returning 0");
120 return (0);
121 }
122
123 /*
124 * Append the element...
125 */
126
127 return (cups_array_add(a, e, 0));
128 }
129
130
131 /*
132 * 'cupsArrayClear()' - Clear the array.
133 */
134
135 void
136 cupsArrayClear(cups_array_t *a) /* I - Array */
137 {
138 /*
139 * Range check input...
140 */
141
142 if (!a)
143 return;
144
145 /*
146 * Set the number of elements to 0; we don't actually free the memory
147 * here - that is done in cupsArrayDelete()...
148 */
149
150 a->num_elements = 0;
151 a->current = -1;
152 a->insert = -1;
153 a->unique = 1;
154 a->num_saved = 0;
155 }
156
157
158 /*
159 * 'cupsArrayCount()' - Get the number of elements in the array.
160 */
161
162 int /* O - Number of elements */
163 cupsArrayCount(cups_array_t *a) /* I - Array */
164 {
165 /*
166 * Range check input...
167 */
168
169 if (!a)
170 return (0);
171
172 /*
173 * Return the number of elements...
174 */
175
176 return (a->num_elements);
177 }
178
179
180 /*
181 * 'cupsArrayCurrent()' - Return the current element in the array.
182 */
183
184 void * /* O - Element */
185 cupsArrayCurrent(cups_array_t *a) /* I - Array */
186 {
187 /*
188 * Range check input...
189 */
190
191 if (!a)
192 return (NULL);
193
194 /*
195 * Return the current element...
196 */
197
198 if (a->current >= 0 && a->current < a->num_elements)
199 return (a->elements[a->current]);
200 else
201 return (NULL);
202 }
203
204
205 /*
206 * 'cupsArrayDelete()' - Free all memory used by the array.
207 */
208
209 void
210 cupsArrayDelete(cups_array_t *a) /* I - Array */
211 {
212 /*
213 * Range check input...
214 */
215
216 if (!a)
217 return;
218
219 /*
220 * Free the array of element pointers - the caller is responsible
221 * for freeing the elements themselves...
222 */
223
224 if (a->alloc_elements)
225 free(a->elements);
226
227 free(a);
228 }
229
230
231 /*
232 * 'cupsArrayDup()' - Duplicate the array.
233 */
234
235 cups_array_t * /* O - Duplicate array */
236 cupsArrayDup(cups_array_t *a) /* I - Array */
237 {
238 cups_array_t *da; /* Duplicate array */
239
240
241 /*
242 * Range check input...
243 */
244
245 if (!a)
246 return (NULL);
247
248 /*
249 * Allocate memory for the array...
250 */
251
252 da = calloc(1, sizeof(cups_array_t));
253 if (!da)
254 return (NULL);
255
256 da->compare = a->compare;
257 da->data = a->data;
258 da->current = a->current;
259 da->insert = a->insert;
260 da->unique = a->unique;
261 da->num_saved = a->num_saved;
262
263 memcpy(da->saved, a->saved, sizeof(a->saved));
264
265 if (a->num_elements)
266 {
267 /*
268 * Allocate memory for the elements...
269 */
270
271 da->elements = malloc(a->num_elements * sizeof(void *));
272 if (!da->elements)
273 {
274 free(da);
275 return (NULL);
276 }
277
278 /*
279 * Copy the element pointers...
280 */
281
282 memcpy(da->elements, a->elements, a->num_elements * sizeof(void *));
283 da->num_elements = a->num_elements;
284 da->alloc_elements = a->num_elements;
285 }
286
287 /*
288 * Return the new array...
289 */
290
291 return (da);
292 }
293
294
295 /*
296 * 'cupsArrayFind()' - Find an element in the array.
297 */
298
299 void * /* O - Element found or NULL */
300 cupsArrayFind(cups_array_t *a, /* I - Array */
301 void *e) /* I - Element */
302 {
303 int current, /* Current element */
304 diff; /* Difference */
305
306
307 /*
308 * Range check input...
309 */
310
311 if (!a || !e)
312 return (NULL);
313
314 /*
315 * See if we have any elements...
316 */
317
318 if (!a->num_elements)
319 return (NULL);
320
321 /*
322 * Yes, look for a match...
323 */
324
325 current = cups_array_find(a, e, a->current, &diff);
326 if (!diff)
327 {
328 /*
329 * Found a match! If the array does not contain unique values, find
330 * the first element that is the same...
331 */
332
333 if (!a->unique && a->compare)
334 {
335 /*
336 * The array is not unique, find the first match...
337 */
338
339 while (current > 0 && !(*(a->compare))(e, a->elements[current - 1],
340 a->data))
341 current --;
342 }
343
344 a->current = current;
345
346 return (a->elements[current]);
347 }
348 else
349 {
350 /*
351 * No match...
352 */
353
354 a->current = -1;
355
356 return (NULL);
357 }
358 }
359
360
361 /*
362 * 'cupsArrayFirst()' - Get the first element in the array.
363 */
364
365 void * /* O - First element or NULL */
366 cupsArrayFirst(cups_array_t *a) /* I - Array */
367 {
368 /*
369 * Range check input...
370 */
371
372 if (!a)
373 return (NULL);
374
375 /*
376 * Return the first element...
377 */
378
379 a->current = 0;
380
381 return (cupsArrayCurrent(a));
382 }
383
384
385 /*
386 * 'cupsArrayIndex()' - Get the N-th element in the array.
387 */
388
389 void * /* O - N-th element or NULL */
390 cupsArrayIndex(cups_array_t *a, /* I - Array */
391 int n) /* I - Index into array, starting at 0 */
392 {
393 if (!a)
394 return (NULL);
395
396 a->current = n;
397
398 return (cupsArrayCurrent(a));
399 }
400
401
402 /*
403 * 'cupsArrayInsert()' - Insert an element in the array.
404 *
405 * When inserting an element in a sorted array, non-unique elements are
406 * inserted at the beginning of the run. For unsorted arrays, the element
407 * is inserted at the beginning of the array.
408 */
409
410 int /* O - 0 on failure, 1 on success */
411 cupsArrayInsert(cups_array_t *a, /* I - Array */
412 void *e) /* I - Element */
413 {
414 DEBUG_printf(("cupsArrayInsert(a=%p, e=%p)\n", a, e));
415
416 /*
417 * Range check input...
418 */
419
420 if (!a || !e)
421 {
422 DEBUG_puts("cupsArrayInsert: returning 0");
423 return (0);
424 }
425
426 /*
427 * Insert the element...
428 */
429
430 return (cups_array_add(a, e, 1));
431 }
432
433
434 /*
435 * 'cupsArrayLast()' - Get the last element in the array.
436 */
437
438 void * /* O - Last element or NULL */
439 cupsArrayLast(cups_array_t *a) /* I - Array */
440 {
441 /*
442 * Range check input...
443 */
444
445 if (!a)
446 return (NULL);
447
448 /*
449 * Return the last element...
450 */
451
452 a->current = a->num_elements - 1;
453
454 return (cupsArrayCurrent(a));
455 }
456
457
458 /*
459 * 'cupsArrayNew()' - Create a new array.
460 */
461
462 cups_array_t * /* O - Array */
463 cupsArrayNew(cups_array_func_t f, /* I - Comparison function */
464 void *d) /* I - User data */
465 {
466 cups_array_t *a; /* Array */
467
468
469 /*
470 * Allocate memory for the array...
471 */
472
473 a = calloc(1, sizeof(cups_array_t));
474 if (!a)
475 return (NULL);
476
477 a->compare = f;
478 a->data = d;
479 a->current = -1;
480 a->insert = -1;
481 a->num_saved = 0;
482 a->unique = 1;
483
484 return (a);
485 }
486
487
488 /*
489 * 'cupsArrayNext()' - Get the next element in the array.
490 */
491
492 void * /* O - Next element or NULL */
493 cupsArrayNext(cups_array_t *a) /* I - Array */
494 {
495 /*
496 * Range check input...
497 */
498
499 if (!a)
500 return (NULL);
501
502 /*
503 * Return the next element...
504 */
505
506 if (a->current < a->num_elements)
507 a->current ++;
508
509 return (cupsArrayCurrent(a));
510 }
511
512
513 /*
514 * 'cupsArrayPrev()' - Get the previous element in the array.
515 */
516
517 void * /* O - Previous element or NULL */
518 cupsArrayPrev(cups_array_t *a) /* I - Array */
519 {
520 /*
521 * Range check input...
522 */
523
524 if (!a)
525 return (NULL);
526
527 /*
528 * Return the previous element...
529 */
530
531 if (a->current >= 0)
532 a->current --;
533
534 return (cupsArrayCurrent(a));
535 }
536
537
538 /*
539 * 'cupsArrayRemove()' - Remove an element from the array.
540 */
541
542 int /* O - 1 on success, 0 on failure */
543 cupsArrayRemove(cups_array_t *a, /* I - Array */
544 void *e) /* I - Element */
545 {
546 int i, /* Looping var */
547 current, /* Current element */
548 diff; /* Difference */
549
550
551 /*
552 * Range check input...
553 */
554
555 if (!a || !e)
556 return (0);
557
558 /*
559 * See if the element is in the array...
560 */
561
562 if (!a->num_elements)
563 return (0);
564
565 current = cups_array_find(a, e, a->current, &diff);
566 if (diff)
567 return (0);
568
569 /*
570 * Yes, now remove it...
571 */
572
573 a->num_elements --;
574
575 if (current < a->num_elements)
576 memmove(a->elements + current, a->elements + current + 1,
577 (a->num_elements - current) * sizeof(void *));
578
579 if (current <= a->current)
580 a->current --;
581
582 if (current <= a->insert)
583 a->insert --;
584
585 for (i = 0; i < a->num_saved; i ++)
586 if (current <= a->saved[i])
587 a->saved[i] --;
588
589 if (a->num_elements <= 1)
590 a->unique = 1;
591
592 return (1);
593 }
594
595
596 /*
597 * 'cupsArrayRestore()' - Reset the current element to the last cupsArraySave.
598 */
599
600 void * /* O - New current element */
601 cupsArrayRestore(cups_array_t *a) /* I - Array */
602 {
603 if (!a)
604 return (NULL);
605
606 if (a->num_saved <= 0)
607 return (NULL);
608
609 a->num_saved --;
610 a->current = a->saved[a->num_saved];
611
612 if (a->current >= 0 && a->current < a->num_elements)
613 return (a->elements[a->current]);
614 else
615 return (NULL);
616 }
617
618
619 /*
620 * 'cupsArraySave()' - Mark the current element for a later cupsArrayRestore.
621 *
622 * The save/restore stack is guaranteed to be at least 32 elements deep.
623 */
624
625 int /* O - 1 on success, 0 on failure */
626 cupsArraySave(cups_array_t *a) /* I - Array */
627 {
628 if (!a)
629 return (0);
630
631 if (a->num_saved >= _CUPS_MAXSAVE)
632 return (0);
633
634 a->saved[a->num_saved] = a->current;
635 a->num_saved ++;
636
637 return (1);
638 }
639
640
641 /*
642 * 'cups_array_add()' - Insert or append an element to the array...
643 */
644
645 static int /* O - 1 on success, 0 on failure */
646 cups_array_add(cups_array_t *a, /* I - Array */
647 void *e, /* I - Element to add */
648 int insert) /* I - 1 = insert, 0 = append */
649 {
650 int i, /* Looping var */
651 current, /* Current element */
652 diff; /* Comparison with current element */
653
654
655 DEBUG_printf(("cups_array_add(a=%p, e=%p, insert=%d)\n", a, e, insert));
656
657 /*
658 * Verify we have room for the new element...
659 */
660
661 if (a->num_elements >= a->alloc_elements)
662 {
663 /*
664 * Allocate additional elements; start with 16 elements, then
665 * double the size until 1024 elements, then add 1024 elements
666 * thereafter...
667 */
668
669 void **temp; /* New array elements */
670 int count; /* New allocation count */
671
672
673 if (a->alloc_elements == 0)
674 {
675 count = 16;
676 temp = malloc(count * sizeof(void *));
677 }
678 else
679 {
680 if (a->alloc_elements < 1024)
681 count = a->alloc_elements * 2;
682 else
683 count = a->alloc_elements + 1024;
684
685 temp = realloc(a->elements, count * sizeof(void *));
686 }
687
688 DEBUG_printf(("cups_array_add: count=%d\n", count));
689
690 if (!temp)
691 {
692 DEBUG_puts("cupsAddAdd: allocation failed, returning 0");
693 return (0);
694 }
695
696 a->alloc_elements = count;
697 a->elements = temp;
698 }
699
700 /*
701 * Find the insertion point for the new element; if there is no
702 * compare function or elements, just add it to the beginning or end...
703 */
704
705 if (!a->num_elements || !a->compare)
706 {
707 /*
708 * No elements or comparison function, insert/append as needed...
709 */
710
711 if (insert)
712 current = 0; /* Insert at beginning */
713 else
714 current = a->num_elements; /* Append to the end */
715 }
716 else
717 {
718 /*
719 * Do a binary search for the insertion point...
720 */
721
722 current = cups_array_find(a, e, a->insert, &diff);
723
724 if (diff > 0)
725 {
726 /*
727 * Insert after the current element...
728 */
729
730 current ++;
731 }
732 else if (!diff)
733 {
734 /*
735 * Compared equal, make sure we add to the begining or end of
736 * the current run of equal elements...
737 */
738
739 a->unique = 0;
740
741 if (insert)
742 {
743 /*
744 * Insert at beginning of run...
745 */
746
747 while (current > 0 && !(*(a->compare))(e, a->elements[current - 1],
748 a->data))
749 current --;
750 }
751 else
752 {
753 /*
754 * Append at end of run...
755 */
756
757 do
758 {
759 current ++;
760 }
761 while (current < a->num_elements &&
762 !(*(a->compare))(e, a->elements[current], a->data));
763 }
764 }
765 }
766
767 /*
768 * Insert or append the element...
769 */
770
771 if (current < a->num_elements)
772 {
773 /*
774 * Shift other elements to the right...
775 */
776
777 memmove(a->elements + current + 1, a->elements + current,
778 (a->num_elements - current) * sizeof(void *));
779
780 if (a->current >= current)
781 a->current ++;
782
783 for (i = 0; i < a->num_saved; i ++)
784 if (a->saved[i] >= current)
785 a->saved[i] ++;
786
787 DEBUG_printf(("cups_array_add: insert element at index %d...\n", current));
788 }
789 #ifdef DEBUG
790 else
791 printf("cups_array_add: append element at %d...\n", current);
792 #endif /* DEBUG */
793
794 a->elements[current] = e;
795 a->num_elements ++;
796 a->insert = current;
797
798 #ifdef DEBUG
799 for (current = 0; current < a->num_elements; current ++)
800 printf("cups_array_add: a->elements[%d]=%p\n", current, a->elements[current]);
801 #endif /* DEBUG */
802
803 DEBUG_puts("cups_array_add: returning 1");
804
805 return (1);
806 }
807
808
809 /*
810 * 'cups_array_find()' - Find an element in the array...
811 */
812
813 static int /* O - Index of match */
814 cups_array_find(cups_array_t *a, /* I - Array */
815 void *e, /* I - Element */
816 int prev, /* I - Previous index */
817 int *rdiff) /* O - Difference of match */
818 {
819 int left, /* Left side of search */
820 right, /* Right side of search */
821 current, /* Current element */
822 diff; /* Comparison with current element */
823
824
825 DEBUG_printf(("cups_array_find(a=%p, e=%p, prev=%d, rdiff=%p)\n", a, e, prev,
826 rdiff));
827
828 if (a->compare)
829 {
830 /*
831 * Do a binary search for the element...
832 */
833
834 DEBUG_puts("cups_array_find: binary search");
835
836 if (prev >= 0 && prev < a->num_elements)
837 {
838 /*
839 * Start search on either side of previous...
840 */
841
842 if ((diff = (*(a->compare))(e, a->elements[prev], a->data)) == 0 ||
843 (diff < 0 && prev == 0) ||
844 (diff > 0 && prev == (a->num_elements - 1)))
845 {
846 /*
847 * Exact or edge match, return it!
848 */
849
850 DEBUG_printf(("cups_array_find: Returning %d, diff=%d\n", prev, diff));
851
852 *rdiff = diff;
853
854 return (prev);
855 }
856 else if (diff < 0)
857 {
858 /*
859 * Start with previous on right side...
860 */
861
862 left = 0;
863 right = prev;
864 }
865 else
866 {
867 /*
868 * Start wih previous on left side...
869 */
870
871 left = prev;
872 right = a->num_elements - 1;
873 }
874 }
875 else
876 {
877 /*
878 * Start search in the middle...
879 */
880
881 left = 0;
882 right = a->num_elements - 1;
883 }
884
885 do
886 {
887 current = (left + right) / 2;
888 diff = (*(a->compare))(e, a->elements[current], a->data);
889
890 DEBUG_printf(("cups_array_find: left=%d, right=%d, current=%d, diff=%d\n",
891 left, right, current, diff));
892
893 if (diff == 0)
894 break;
895 else if (diff < 0)
896 right = current;
897 else
898 left = current;
899 }
900 while ((right - left) > 1);
901
902 if (diff != 0)
903 {
904 /*
905 * Check the last 1 or 2 elements...
906 */
907
908 if ((diff = (*(a->compare))(e, a->elements[left], a->data)) <= 0)
909 current = left;
910 else
911 {
912 diff = (*(a->compare))(e, a->elements[right], a->data);
913 current = right;
914 }
915 }
916 }
917 else
918 {
919 /*
920 * Do a linear pointer search...
921 */
922
923 DEBUG_puts("cups_array_find: linear search");
924
925 diff = 0;
926
927 for (current = 0; current < a->num_elements; current ++)
928 if (a->elements[current] == e)
929 break;
930 }
931
932 /*
933 * Return the closest element and the difference...
934 */
935
936 DEBUG_printf(("cups_array_find: Returning %d, diff=%d\n", current, diff));
937
938 *rdiff = diff;
939
940 return (current);
941 }
942
943
944 /*
945 * End of "$Id: array.c 5119 2006-02-16 15:52:06Z mike $".
946 */