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