]> 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/*
2 * "$Id: array.c 4921 2006-01-12 21:26:26Z 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 * cupsArrayLast() - Get the last element in the array.
38 * cupsArrayNew() - Create a new array.
39 * cupsArrayNext() - Get the next element in the array.
40 * cupsArrayPrev() - Get the previous element in the array.
41 * cupsArrayRemove() - Remove an element from the array.
42 * cupsArrayRestore() - Reset the current element to the last cupsArraySave.
43 * cupsArraySave() - Mark the current element for a later cupsArrayRestore.
44 * cups_find() - Find an element in the array...
45 */
46
47/*
48 * Include necessary headers...
49 */
50
51#include "array.h"
52#include "string.h"
53#include "debug.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
67struct _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 num_saved, /* Number of saved elements */
81 saved[_CUPS_MAXSAVE];
82 /* Saved elements */
83 void **elements; /* Array elements */
84 cups_array_func_t compare; /* Element comparison function */
85 void *data; /* User data passed to compare */
86};
87
88
89/*
90 * Local functions...
91 */
92
93static int cups_find(cups_array_t *a, void *e, int prev, int *rdiff);
94
95
96/*
97 * 'cupsArrayAdd()' - Add an element to the array.
98 */
99
100int /* O - 1 on success, 0 on failure */
101cupsArrayAdd(cups_array_t *a, /* I - Array */
102 void *e) /* I - Element */
103{
104 int i, /* Looping var */
105 current, /* Current element */
106 diff; /* Comparison with current element */
107
108
109 DEBUG_printf(("cupsArrayAdd(a=%p, e=%p)\n", a, e));
110
111 /*
112 * Range check input...
113 */
114
115 if (!a || !e)
116 {
117 DEBUG_puts("cupsArrayAdd: returning 0");
118 return (0);
119 }
120
121 /*
122 * Verify we have room for the new element...
123 */
124
125 if (a->num_elements >= a->alloc_elements)
126 {
127 /*
128 * Allocate additional elements; start with 16 elements, then
129 * double the size until 1024 elements, then add 1024 elements
130 * thereafter...
131 */
132
133 void **temp; /* New array elements */
134 int count; /* New allocation count */
135
136
137 if (a->alloc_elements == 0)
138 {
139 count = 16;
140 temp = malloc(count * sizeof(void *));
141 }
142 else
143 {
144 if (a->alloc_elements < 1024)
145 count = a->alloc_elements * 2;
146 else
147 count = a->alloc_elements + 1024;
148
149 temp = realloc(a->elements, count * sizeof(void *));
150 }
151
152 DEBUG_printf(("cupsArrayAdd: count=%d\n", count));
153
154 if (!temp)
155 {
156 DEBUG_puts("cupsAddAdd: allocation failed, returning 0");
157 return (0);
158 }
159
160 a->alloc_elements = count;
161 a->elements = temp;
162 }
163
164 /*
165 * Find the insertion point for the new element; if there is no
166 * compare function or elements, just add it to the end...
167 */
168
169 if (!a->num_elements || !a->compare)
170 {
171 /*
172 * Append to the end...
173 */
174
175 current = a->num_elements;
176 }
177 else
178 {
179 /*
180 * Do a binary search for the insertion point...
181 */
182
183 current = cups_find(a, e, a->insert, &diff);
184
185 if (diff > 0)
186 current ++;
187 }
188
189 /*
190 * Insert or append the element...
191 */
192
193 if (current < a->num_elements)
194 {
195 /*
196 * Shift other elements to the right...
197 */
198
199 memmove(a->elements + current + 1, a->elements + current,
200 (a->num_elements - current) * sizeof(void *));
201
202 if (a->current >= current)
203 a->current ++;
204
205 for (i = 0; i < a->num_saved; i ++)
206 if (a->saved[i] >= current)
207 a->saved[i] ++;
208
209 DEBUG_printf(("cupsArrayAdd: insert element at index %d...\n", current));
210 }
211#ifdef DEBUG
212 else
213 printf("cupsArrayAdd: append element at %d...\n", current);
214#endif /* DEBUG */
215
216 a->elements[current] = e;
217 a->num_elements ++;
218 a->insert = current;
219
220#ifdef DEBUG
221 for (current = 0; current < a->num_elements; current ++)
222 printf("cupsArrayAdd: a->elements[%d]=%p\n", current, a->elements[current]);
223#endif /* DEBUG */
224
225 DEBUG_puts("cupsArrayAdd: returning 1");
226
227 return (1);
228}
229
230
231/*
232 * 'cupsArrayClear()' - Clear the array.
233 */
234
235void
236cupsArrayClear(cups_array_t *a) /* I - Array */
237{
238 /*
239 * Range check input...
240 */
241
242 if (!a)
243 return;
244
245 /*
246 * Set the number of elements to 0; we don't actually free the memory
247 * here - that is done in cupsArrayDelete()...
248 */
249
250 a->num_elements = 0;
251 a->current = -1;
252 a->insert = -1;
253 a->num_saved = 0;
254}
255
256
257/*
258 * 'cupsArrayCount()' - Get the number of elements in the array.
259 */
260
261int /* O - Number of elements */
262cupsArrayCount(cups_array_t *a) /* I - Array */
263{
264 /*
265 * Range check input...
266 */
267
268 if (!a)
269 return (0);
270
271 /*
272 * Return the number of elements...
273 */
274
275 return (a->num_elements);
276}
277
278
279/*
280 * 'cupsArrayCurrent()' - Return the current element in the array.
281 */
282
283void * /* O - Element */
284cupsArrayCurrent(cups_array_t *a) /* I - Array */
285{
286 /*
287 * Range check input...
288 */
289
290 if (!a)
291 return (NULL);
292
293 /*
294 * Return the current element...
295 */
296
297 if (a->current >= 0 && a->current < a->num_elements)
298 return (a->elements[a->current]);
299 else
300 return (NULL);
301}
302
303
304/*
305 * 'cupsArrayDelete()' - Free all memory used by the array.
306 */
307
308void
309cupsArrayDelete(cups_array_t *a) /* I - Array */
310{
311 /*
312 * Range check input...
313 */
314
315 if (!a)
316 return;
317
318 /*
319 * Free the array of element pointers - the caller is responsible
320 * for freeing the elements themselves...
321 */
322
323 if (a->alloc_elements)
324 free(a->elements);
325
326 free(a);
327}
328
329
330/*
331 * 'cupsArrayDup()' - Duplicate the array.
332 */
333
334cups_array_t * /* O - Duplicate array */
335cupsArrayDup(cups_array_t *a) /* I - Array */
336{
337 cups_array_t *da; /* Duplicate array */
338
339
340 /*
341 * Range check input...
342 */
343
344 if (!a)
345 return (NULL);
346
347 /*
348 * Allocate memory for the array...
349 */
350
351 da = calloc(1, sizeof(cups_array_t));
352 if (!da)
353 return (NULL);
354
355 da->compare = a->compare;
356 da->data = a->data;
357 da->current = a->current;
358 da->insert = a->insert;
359 da->num_saved = a->num_saved;
360
361 memcpy(da->saved, a->saved, sizeof(a->saved));
362
363 if (a->num_elements)
364 {
365 /*
366 * Allocate memory for the elements...
367 */
368
369 da->elements = malloc(a->num_elements * sizeof(void *));
370 if (!da->elements)
371 {
372 free(da);
373 return (NULL);
374 }
375
376 /*
377 * Copy the element pointers...
378 */
379
380 memcpy(da->elements, a->elements, a->num_elements * sizeof(void *));
381 da->num_elements = a->num_elements;
382 da->alloc_elements = a->num_elements;
383 }
384
385 /*
386 * Return the new array...
387 */
388
389 return (da);
390}
391
392
393/*
394 * 'cupsArrayFind()' - Find an element in the array.
395 */
396
397void * /* O - Element found or NULL */
398cupsArrayFind(cups_array_t *a, /* I - Array */
399 void *e) /* I - Element */
400{
401 int current, /* Current element */
402 diff; /* Difference */
403
404
405 /*
406 * Range check input...
407 */
408
409 if (!a || !e)
410 return (NULL);
411
412 /*
413 * See if we have any elements...
414 */
415
416 if (!a->num_elements)
417 return (NULL);
418
419 /*
420 * Yes, look for a match...
421 */
422
423 current = cups_find(a, e, a->current, &diff);
424 if (!diff)
425 {
426 /*
427 * Found a match...
428 */
429
430 a->current = current;
431
432 return (a->elements[current]);
433 }
434 else
435 {
436 /*
437 * No match...
438 */
439
440 a->current = -1;
441
442 return (NULL);
443 }
444}
445
446
447/*
448 * 'cupsArrayFirst()' - Get the first element in the array.
449 */
450
451void * /* O - First element or NULL */
452cupsArrayFirst(cups_array_t *a) /* I - Array */
453{
454 /*
455 * Range check input...
456 */
457
458 if (!a)
459 return (NULL);
460
461 /*
462 * Return the first element...
463 */
464
465 a->current = 0;
466
467 return (cupsArrayCurrent(a));
468}
469
470
471/*
472 * 'cupsArrayIndex()' - Get the N-th element in the array.
473 */
474
475void * /* O - N-th element or NULL */
476cupsArrayIndex(cups_array_t *a, /* I - Array */
477 int n) /* I - Index into array, starting at 0 */
478{
479 if (!a)
480 return (NULL);
481
482 a->current = n;
483
484 return (cupsArrayCurrent(a));
485}
486
487
488/*
489 * 'cupsArrayLast()' - Get the last element in the array.
490 */
491
492void * /* O - Last element or NULL */
493cupsArrayLast(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 last element...
504 */
505
506 a->current = a->num_elements - 1;
507
508 return (cupsArrayCurrent(a));
509}
510
511
512/*
513 * 'cupsArrayNew()' - Create a new array.
514 */
515
516cups_array_t * /* O - Array */
517cupsArrayNew(cups_array_func_t f, /* I - Comparison function */
518 void *d) /* I - User data */
519{
520 cups_array_t *a; /* Array */
521
522
523 /*
524 * Allocate memory for the array...
525 */
526
527 a = calloc(1, sizeof(cups_array_t));
528 if (!a)
529 return (NULL);
530
531 a->compare = f;
532 a->data = d;
533 a->current = -1;
534 a->insert = -1;
535 a->num_saved = 0;
536
537 return (a);
538}
539
540
541/*
542 * 'cupsArrayNext()' - Get the next element in the array.
543 */
544
545void * /* O - Next element or NULL */
546cupsArrayNext(cups_array_t *a) /* I - Array */
547{
548 /*
549 * Range check input...
550 */
551
552 if (!a)
553 return (NULL);
554
555 /*
556 * Return the next element...
557 */
558
559 if (a->current < a->num_elements)
560 a->current ++;
561
562 return (cupsArrayCurrent(a));
563}
564
565
566/*
567 * 'cupsArrayPrev()' - Get the previous element in the array.
568 */
569
570void * /* O - Previous element or NULL */
571cupsArrayPrev(cups_array_t *a) /* I - Array */
572{
573 /*
574 * Range check input...
575 */
576
577 if (!a)
578 return (NULL);
579
580 /*
581 * Return the previous element...
582 */
583
584 if (a->current >= 0)
585 a->current --;
586
587 return (cupsArrayCurrent(a));
588}
589
590
591/*
592 * 'cupsArrayRemove()' - Remove an element from the array.
593 */
594
595int /* O - 1 on success, 0 on failure */
596cupsArrayRemove(cups_array_t *a, /* I - Array */
597 void *e) /* I - Element */
598{
599 int i, /* Looping var */
600 current, /* Current element */
601 diff; /* Difference */
602
603
604 /*
605 * Range check input...
606 */
607
608 if (!a || !e)
609 return (0);
610
611 /*
612 * See if the element is in the array...
613 */
614
615 if (!a->num_elements)
616 return (0);
617
618 current = cups_find(a, e, a->current, &diff);
619 if (diff)
620 return (0);
621
622 /*
623 * Yes, now remove it...
624 */
625
626 a->num_elements --;
627
628 if (current < a->num_elements)
629 memmove(a->elements + current, a->elements + current + 1,
630 (a->num_elements - current) * sizeof(void *));
631
632 if (current <= a->current)
633 a->current --;
634
635 if (current <= a->insert)
636 a->insert --;
637
638 for (i = 0; i < a->num_saved; i ++)
639 if (current <= a->saved[i])
640 a->saved[i] --;
641
642 return (1);
643}
644
645
646/*
647 * 'cupsArrayRestore()' - Reset the current element to the last cupsArraySave.
648 */
649
650void * /* O - New current element */
651cupsArrayRestore(cups_array_t *a) /* I - Array */
652{
653 if (!a)
654 return (NULL);
655
656 if (a->num_saved <= 0)
657 return (NULL);
658
659 a->num_saved --;
660 a->current = a->saved[a->num_saved];
661
662 if (a->current >= 0 && a->current < a->num_elements)
663 return (a->elements[a->current]);
664 else
665 return (NULL);
666}
667
668
669/*
670 * 'cupsArraySave()' - Mark the current element for a later cupsArrayRestore.
671 *
672 * The save/restore stack is guaranteed to be at least 32 elements deep.
673 */
674
675int /* O - 1 on success, 0 on failure */
676cupsArraySave(cups_array_t *a) /* I - Array */
677{
678 if (!a)
679 return (0);
680
681 if (a->num_saved >= _CUPS_MAXSAVE)
682 return (0);
683
684 a->saved[a->num_saved] = a->current;
685 a->num_saved ++;
686
687 return (1);
688}
689
690
691/*
692 * 'cups_find()' - Find an element in the array...
693 */
694
695static int /* O - Index of match */
696cups_find(cups_array_t *a, /* I - Array */
697 void *e, /* I - Element */
698 int prev, /* I - Previous index */
699 int *rdiff) /* O - Difference of match */
700{
701 int left, /* Left side of search */
702 right, /* Right side of search */
703 current, /* Current element */
704 diff; /* Comparison with current element */
705
706
707 DEBUG_printf(("cups_find(a=%p, e=%p, prev=%d, rdiff=%p)\n", a, e, prev,
708 rdiff));
709
710 if (a->compare)
711 {
712 /*
713 * Do a binary search for the element...
714 */
715
716 DEBUG_puts("cups_find: binary search");
717
718 if (prev >= 0 && prev < a->num_elements)
719 {
720 /*
721 * Start search on either side of previous...
722 */
723
724 if ((diff = (*(a->compare))(e, a->elements[prev], a->data)) == 0 ||
725 (diff < 0 && prev == 0) ||
726 (diff > 0 && prev == (a->num_elements - 1)))
727 {
728 /*
729 * Exact or edge match, return it!
730 */
731
732 DEBUG_printf(("cups_find: Returning %d, diff=%d\n", prev, diff));
733
734 *rdiff = diff;
735
736 return (prev);
737 }
738 else if (diff < 0)
739 {
740 /*
741 * Start with previous on right side...
742 */
743
744 left = 0;
745 right = prev;
746 }
747 else
748 {
749 /*
750 * Start wih previous on left side...
751 */
752
753 left = prev;
754 right = a->num_elements - 1;
755 }
756 }
757 else
758 {
759 /*
760 * Start search in the middle...
761 */
762
763 left = 0;
764 right = a->num_elements - 1;
765 }
766
767 do
768 {
769 current = (left + right) / 2;
770 diff = (*(a->compare))(e, a->elements[current], a->data);
771
772 DEBUG_printf(("cups_find: left=%d, right=%d, current=%d, diff=%d\n",
773 left, right, current, diff));
774
775 if (diff == 0)
776 break;
777 else if (diff < 0)
778 right = current;
779 else
780 left = current;
781 }
782 while ((right - left) > 1);
783
784 if (diff != 0)
785 {
786 /*
787 * Check the last 1 or 2 elements...
788 */
789
790 if ((diff = (*(a->compare))(e, a->elements[left], a->data)) <= 0)
791 current = left;
792 else
793 {
794 diff = (*(a->compare))(e, a->elements[right], a->data);
795 current = right;
796 }
797 }
798 }
799 else
800 {
801 /*
802 * Do a linear pointer search...
803 */
804
805 DEBUG_puts("cups_find: linear search");
806
807 diff = 0;
808
809 for (current = 0; current < a->num_elements; current ++)
810 if (a->elements[current] == e)
811 break;
812 }
813
814 /*
815 * Return the closest element and the difference...
816 */
817
818 DEBUG_printf(("cups_find: Returning %d, diff=%d\n", current, diff));
819
820 *rdiff = diff;
821
822 return (current);
823}
824
825
826/*
827 * End of "$Id: array.c 4921 2006-01-12 21:26:26Z mike $".
828 */