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