+/*
+ * 'cups_add_dest()' - Add a destination to the array.
+ *
+ * Unlike cupsAddDest(), this function does not check for duplicates.
+ */
+
+static cups_dest_t * /* O - New destination */
+cups_add_dest(const char *name, /* I - Name of destination */
+ const char *instance, /* I - Instance or NULL */
+ int *num_dests, /* IO - Number of destinations */
+ cups_dest_t **dests) /* IO - Destinations */
+{
+ int insert, /* Insertion point */
+ diff; /* Result of comparison */
+ cups_dest_t *dest; /* Destination pointer */
+
+
+ /*
+ * Add new destination...
+ */
+
+ if (*num_dests == 0)
+ dest = malloc(sizeof(cups_dest_t));
+ else
+ dest = realloc(*dests, sizeof(cups_dest_t) * (*num_dests + 1));
+
+ if (!dest)
+ return (NULL);
+
+ *dests = dest;
+
+ /*
+ * Find where to insert the destination...
+ */
+
+ if (*num_dests == 0)
+ insert = 0;
+ else
+ {
+ insert = cups_find_dest(name, instance, *num_dests, *dests, *num_dests - 1,
+ &diff);
+
+ if (diff > 0)
+ insert ++;
+ }
+
+ /*
+ * Move the array elements as needed...
+ */
+
+ if (insert < *num_dests)
+ memmove(*dests + insert + 1, *dests + insert,
+ (*num_dests - insert) * sizeof(cups_dest_t));
+
+ (*num_dests) ++;
+
+ /*
+ * Initialize the destination...
+ */
+
+ dest = *dests + insert;
+ dest->name = _cupsStrAlloc(name);
+ dest->instance = _cupsStrAlloc(instance);
+ dest->is_default = 0;
+ dest->num_options = 0;
+ dest->options = (cups_option_t *)0;
+
+ return (dest);
+}
+
+
+/*
+ * 'cups_compare_dests()' - Compare two destinations.
+ */
+
+static int /* O - Result of comparison */
+cups_compare_dests(cups_dest_t *a, /* I - First destination */
+ cups_dest_t *b) /* I - Second destination */
+{
+ int diff; /* Difference */
+
+
+ if ((diff = strcasecmp(a->name, b->name)) != 0)
+ return (diff);
+ else if (a->instance && b->instance)
+ return (strcasecmp(a->instance, b->instance));
+ else
+ return ((a->instance && !b->instance) - (!a->instance && b->instance));
+}
+
+
+/*
+ * 'cups_find_dest()' - Find a destination using a binary search.
+ */
+
+static int /* O - Index of match */
+cups_find_dest(const char *name, /* I - Destination name */
+ const char *instance, /* I - Instance or NULL */
+ int num_dests, /* I - Number of destinations */
+ cups_dest_t *dests, /* I - Destinations */
+ int prev, /* I - Previous index */
+ int *rdiff) /* O - Difference of match */
+{
+ int left, /* Low mark for binary search */
+ right, /* High mark for binary search */
+ current, /* Current index */
+ diff; /* Result of comparison */
+ cups_dest_t key; /* Search key */
+
+
+ key.name = (char *)name;
+ key.instance = (char *)instance;
+
+ if (prev >= 0)
+ {
+ /*
+ * Start search on either side of previous...
+ */
+
+ if ((diff = cups_compare_dests(&key, dests + prev)) == 0 ||
+ (diff < 0 && prev == 0) ||
+ (diff > 0 && prev == (num_dests - 1)))
+ {
+ *rdiff = diff;
+ return (prev);
+ }
+ else if (diff < 0)
+ {
+ /*
+ * Start with previous on right side...
+ */
+
+ left = 0;
+ right = prev;
+ }
+ else
+ {
+ /*
+ * Start wih previous on left side...
+ */
+
+ left = prev;
+ right = num_dests - 1;
+ }
+ }
+ else
+ {
+ /*
+ * Start search in the middle...
+ */
+
+ left = 0;
+ right = num_dests - 1;
+ }
+
+ do
+ {
+ current = (left + right) / 2;
+ diff = cups_compare_dests(&key, dests + current);
+
+ if (diff == 0)
+ break;
+ else if (diff < 0)
+ right = current;
+ else
+ left = current;
+ }
+ while ((right - left) > 1);
+
+ if (diff != 0)
+ {
+ /*
+ * Check the last 1 or 2 elements...
+ */
+
+ if ((diff = cups_compare_dests(&key, dests + left)) <= 0)
+ current = left;
+ else
+ {
+ diff = cups_compare_dests(&key, dests + right);
+ current = right;
+ }
+ }
+
+ /*
+ * Return the closest destination and the difference...
+ */
+
+ *rdiff = diff;
+
+ return (current);
+}
+
+