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