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