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