commit:     7b7eea9df68211a613ac1c375a9f0b1b7f8e35e2
Author:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Sat Jan 10 17:47:51 2026 +0000
Commit:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Sat Jan 10 19:41:59 2026 +0000
URL:        https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=7b7eea9d

libq/array: rewrite with cleaner API

Hide internal details of the list from external consumers.  Require a
flow of array_new() ... array_append() ... array_get() ... array_free()
instead of externally (stack) allocated array structures.

Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>

 applets.h    |   6 +-
 libq/array.c | 222 ++++++++++++++++++++++++++++++++++++++++++++++++-----------
 libq/array.h |  63 +++++++++--------
 libq/dep.c   |   4 +-
 libq/dep.h   |   4 +-
 libq/set.c   |   5 +-
 libq/set.h   |   8 +--
 libq/tree.c  |  10 +--
 main.c       |  49 ++++++-------
 q.c          |  23 ++-----
 qcheck.c     |  13 ++--
 qdepends.c   |  38 ++++------
 qkeyword.c   |  14 ++--
 qlist.c      |   5 +-
 qlop.c       |  60 +++++-----------
 qmanifest.c  |  12 +++-
 qpkg.c       |   5 +-
 qsize.c      |  13 ++--
 qwhich.c     |   8 +--
 19 files changed, 323 insertions(+), 239 deletions(-)

diff --git a/applets.h b/applets.h
index bb8323d..fc4e27c 100644
--- a/applets.h
+++ b/applets.h
@@ -179,9 +179,9 @@ extern set  *features;
 extern set  *ev_use;
 extern char *install_mask;
 extern char *binpkg_format;
-extern array_t *overlays;
-extern array_t *overlay_names;
-extern array_t *overlay_src;
+extern array *overlays;
+extern array *overlay_names;
+extern array *overlay_src;
 extern char *main_overlay;
 extern int twidth;
 extern bool nocolor;

diff --git a/libq/array.c b/libq/array.c
index ac459c9..2c85eb8 100644
--- a/libq/array.c
+++ b/libq/array.c
@@ -17,67 +17,211 @@
 
 #define ARRAY_INC_SIZE 32
 
-void *xarrayget(array_t *arr, size_t idx)
+struct array_t {
+       void **eles;
+       size_t len;
+       size_t siz;
+};
+
+/* allocates a new array */
+array *array_new(void)
+{
+       return xzalloc(sizeof(array));
+}
+
+/* frees an array without freeing any of the data stored in the array */
+void array_free(array *arr)
+{
+       if (arr == NULL)
+               return;
+
+       free(arr->eles);
+       free(arr);
+}
+
+/* frees the array and all the data pointed to by all of its elements
+ * if the callback free function is NULL, free() is used */
+void array_deepfree(array *arr, array_free_cb *func)
 {
-       if (idx >= arr->num)
+       size_t i;
+
+       if (arr == NULL)
+               return;
+
+       if (func == NULL)
+               func = &free;
+
+       for (i = 0; i < arr->len; i++)
+               func(arr->eles[i]);
+
+       array_free(arr);
+}
+
+/* appends the given pointer to the list, no copying of data takes place
+ * returns the pointer */
+void *array_append(array *arr, void *data)
+{
+       size_t n;
+
+       if (arr == NULL)
                return NULL;
-       return arr->eles[idx];
+
+       n = arr->len++;
+
+       if (arr->len > arr->siz)
+       {
+               arr->siz += ARRAY_INC_SIZE;
+               arr->eles = xrealloc(arr->eles, arr->siz * 
sizeof(arr->eles[0]));
+       }
+
+       return arr->eles[n] = data;
 }
 
-/* Push a pointer to memory we already hold and don't want to release.  Do not
- * mix xarraypush_ptr usage with the other push funcs which duplicate memory.
- * The free stage won't know which pointers to release directly.
- */
-void *xarraypush_ptr(array_t *arr, void *ele)
+/* copies data of len bytes and appends to the array
+ * returns the pointer to the copied data */
+void *array_append_copy(array *arr, const void *data, size_t len)
 {
-       size_t n = arr->num++;
-       if (arr->num > arr->len) {
-               arr->len += ARRAY_INC_SIZE;
-               arr->eles = xrealloc_array(arr->eles, arr->len, sizeof(ele));
+       void *ret = NULL;
+
+       if (data != NULL &&
+               len > 0)
+       {
+               ret = xmemdup(data, len);
        }
-       arr->eles[n] = ele;
-       return ele;
+
+       if (array_append(arr, ret) == NULL &&
+               ret != NULL)
+       {
+               free(ret);
+               ret = NULL;
+       }
+
+       return ret;
 }
 
-void *xarraypush(array_t *arr, const void *ele, size_t ele_len)
+/* removes the given element from the array and returns the pointer to
+ * the data removed from the array
+ * the caller should ensure the pointer is freed if necessary */
+void *array_remove(array *arr, size_t elem)
 {
-       return xarraypush_ptr(arr, xmemdup(ele, ele_len));
+       void *ret;
+
+       if (arr == NULL ||
+               elem >= arr->len)
+       {
+               return NULL;
+       }
+
+       ret = arr->eles[elem];
+       arr->len--;
+       if (elem < arr->len)
+       {
+               memmove(&arr->eles[elem], &arr->eles[elem + 1],
+                               sizeof(arr->eles[0]) * (arr->len - elem));
+       }
+
+       return ret;
 }
 
-void xarraysort(array_t *arr, int (*compar)(const void *, const void *))
+/* frees the element at offset elem and removes it from the list, if the
+ * callback free function is NULL, free() is used */
+void array_delete(array *arr, size_t elem, array_free_cb *func)
 {
-       if (arr->num > 1)
-               qsort(arr->eles, arr->num, sizeof(void *), compar);
+       if (arr == NULL)
+               return;
+
+       if (func == NULL)
+               func = &free;
+
+       func(arr->eles[elem]);
+
+       (void)array_remove(arr, elem);
 }
 
-void xarraydelete_ptr(array_t *arr, size_t elem)
+/* returns the number of elements in use */
+size_t array_cnt(array *arr)
 {
-       arr->num--;
-       if (elem < arr->num)
-               memmove(&arr->eles[elem], &arr->eles[elem + 1],
-                               sizeof(arr->eles[0]) * (arr->num - elem));
-       arr->eles[arr->num] = NULL;
+       if (arr == NULL)
+               return 0;
+
+       return arr->len;
 }
 
-void xarraydelete(array_t *arr, size_t elem)
+/* returns the element at the given offset, or NULL when no such element
+ * exists
+ * note that NULL can also be returned if the element has the value of
+ * NULL, so if the caller wants to know the difference, it should check
+ * the input is sane using array_cnt() */
+void *array_get(array *arr, size_t elem)
 {
-       free(arr->eles[elem]);
-       xarraydelete_ptr(arr, elem);
+       if (arr == NULL)
+               return NULL;
+
+       if (arr->len <= elem)
+               return NULL;
+
+       return arr->eles[elem];
 }
 
-/* Useful for people who call xarraypush_ptr as it does not free any of the
- * pointers in the eles list.
- */
-void xarrayfree_int(array_t *arr)
+/* sorts the elements in the array using the given comparator */
+void array_sort(array *arr, int (*compar)(const void *, const void *))
 {
-       free(arr->eles);
-       VALP_CLEAR(arr);
+       if (arr != NULL &&
+               arr->len > 1)
+       {
+               qsort(arr->eles, arr->len, sizeof(void *), compar);
+       }
 }
 
-void xarrayfree(array_t *arr)
+/* binary search over the array, returning the first element for which
+ * compar(needle, elem(N)) returns 0
+ * note that this function assumes the array is sorted in a way
+ * compatible with compar, the caller should ensure this
+ * returns the found element, if any, and its offset in retoff when set
+ * note that if the found element is NULL, the caller should retrieve
+ * and compare the element at retoff to check if the value was found */
+void *array_binsearch
+(
+       array  *arr,
+       void   *needle,
+       int   (*compar)(const void *, const void *),
+       size_t *retoff
+)
 {
-       size_t n;
-       for (n = 0; n < arr->num; ++n)
-               free(arr->eles[n]);
-       xarrayfree_int(arr);
+       size_t low;
+       size_t high;
+       size_t elem;
+       int    cmp;
+
+       if (arr == NULL ||
+               compar == NULL)
+       {
+               return NULL;
+       }
+
+       low  = 0;
+       high = arr->len;
+
+       while (low != high)
+       {
+               elem = low + ((high - low) / 2);
+               cmp  = compar(needle, arr->eles[elem]);
+               if (cmp == 0)
+               {
+                       if (retoff != NULL)
+                               *retoff = elem;
+                       return arr->eles[elem];
+               }
+               else if (cmp < 0)
+               {
+                       high = elem;
+               }
+               else if (cmp > 0)
+               {
+                       low = elem + 1;
+               }
+       }
+
+       *retoff = 0;
+       return NULL;
 }

diff --git a/libq/array.h b/libq/array.h
index cb84d1c..7268019 100644
--- a/libq/array.h
+++ b/libq/array.h
@@ -12,34 +12,43 @@
 
 #include <string.h>  /* strlen in push_str */
 
-typedef struct {
-       void **eles;
-       size_t num;
-       size_t len;
-} array_t;
-
-#define xrealloc_array(ptr, size, ele_size) xrealloc(ptr, (size) * (ele_size))
-/* The assignment after the check is unfortunate as we do a non-NULL check (we
- * already do not permit pushing of NULL pointers), but we can't put it in the
- * increment phase as that will cause a load beyond the bounds of valid memory.
- */
-/* TODO: remove ele = NULL after checking all consumers don't rely on this */
+#define xarrayget(A,I) array_get(A,I)
+#define xarraypush_ptr(A,E) array_append(A,E)
+#define xarraypush(A,E,L) array_append_copy(A,E,L)
+#define xarraypush_str(A,S) array_append_copy(A,S,strlen(S)+1/*NUL*/)
+#define xarraysort(A,C) array_sort(A,C)
+#define xarraydelete_ptr(A,E) array_remove(A,E)
+#define xarraydelete(A,E) array_delete(A,E,NULL)
+#define xarrayfree_int(A) array_free(A)
+#define xarrayfree(A) array_deepfree(A,NULL)
+
+/* new 2026 interface to array */
+typedef struct array_t array;
+typedef void (array_free_cb)(void *priv);
+
+array *array_new(void);
+void   array_free(array *arr);
+void   array_deepfree(array *arr, array_free_cb *func);
+void  *array_append(array *arr, void *data);
+void  *array_append_copy(array *arr, const void *data, size_t len);
+void  *array_remove(array *arr, size_t elem);
+void   array_delete(array *arr, size_t elem, array_free_cb *func);
+size_t array_cnt(array *arr);
+void  *array_get(array *arr, size_t elem);
+void   array_sort(array *arr, int (*compar)(const void *, const void *));
+void  *array_binsearch(array *arr, void *needle, int (*compar)(const void *, 
const void *), size_t *retoff);
+
+#define array_append_strcpy(A,S) array_append_copy(A,S,strlen(S)+1/*NUL*/)
+
 #define array_for_each(arr, n, ele) \
-       for (n = 0, ele = NULL; n < array_cnt(arr) && (ele = (arr)->eles[n]); 
n++)
+       for (n = 0, ele = NULL; \
+                (n < array_cnt(arr) && \
+                 (ele = array_get(arr, n))); \
+                n++)
 #define array_for_each_rev(arr, n, ele) \
-       for (n = array_cnt(arr); n-- > 0 && (ele = (arr)->eles[n]); /*nothing*/)
-#define array_get_elem(arr, n) (arr->eles[n])
-#define array_cnt(arr) (arr)->num
-#define xarraypush_str(arr, ele) xarraypush(arr, ele, strlen(ele) + 1 /*NUL*/)
-#define xarraypush_struct(arr, ele) xarraypush(arr, ele, sizeof(*(ele)))
-
-void *xarrayget(array_t *arr, size_t idx);
-void *xarraypush_ptr(array_t *arr, void *ele);
-void *xarraypush(array_t *arr, const void *ele, size_t ele_len);
-void xarraysort(array_t *arr, int (*compar)(const void *, const void *));
-void xarraydelete_ptr(array_t *arr, size_t elem);
-void xarraydelete(array_t *arr, size_t elem);
-void xarrayfree_int(array_t *arr);
-void xarrayfree(array_t *arr);
+       for (n = array_cnt(arr), ele = NULL; \
+                (n-- > 0 && \
+                 (ele = array_get(arr, n))); \
+                /*nothing*/)
 
 #endif

diff --git a/libq/dep.c b/libq/dep.c
index 6684861..fd9a284 100644
--- a/libq/dep.c
+++ b/libq/dep.c
@@ -230,7 +230,7 @@ dep_print_tree(
                FILE *fp,
                const dep_node *root,
                size_t space,
-               array_t *hlatoms,
+               array *hlatoms,
                const char *hlcolor,
                int verbose)
 {
@@ -377,7 +377,7 @@ dep_resolve_tree(dep_node *root, tree_ctx *t)
 }
 
 void
-dep_flatten_tree(dep_node *root, array_t *out)
+dep_flatten_tree(dep_node *root, array *out)
 {
        if (root->type != DEP_NULL) {
                if (root->type == DEP_NORM) {

diff --git a/libq/dep.h b/libq/dep.h
index abcbaea..18bb903 100644
--- a/libq/dep.h
+++ b/libq/dep.h
@@ -47,10 +47,10 @@ typedef struct _dep_node dep_node;
 #endif
 
 dep_node *dep_grow_tree(const char *depend);
-void dep_print_tree(FILE *fp, const dep_node *root, size_t space, array_t *m, 
const char *c, int verbose);
+void dep_print_tree(FILE *fp, const dep_node *root, size_t space, array *m, 
const char *c, int verbose);
 void dep_resolve_tree(dep_node *root, tree_ctx *t);
 void dep_burn_tree(dep_node *root);
 void dep_prune_use(dep_node *root, set *use);
-void dep_flatten_tree(dep_node *root, array_t *out);
+void dep_flatten_tree(dep_node *root, array *out);
 
 #endif

diff --git a/libq/set.c b/libq/set.c
index d865b63..e198503 100644
--- a/libq/set.c
+++ b/libq/set.c
@@ -16,6 +16,7 @@
 #include <xalloc.h>
 
 #include "set.h"
+#include "array.h"
 
 static unsigned int
 fnv1a32(const char *s)
@@ -284,7 +285,7 @@ list_set(set *q, char ***l)
 }
 
 size_t
-array_set(set *q, array_t *ret)
+array_set(set *q, array *ret)
 {
        int i;
        set_elem *w;
@@ -302,7 +303,7 @@ array_set(set *q, array_t *ret)
 }
 
 size_t
-values_set(set *q, array_t *ret)
+values_set(set *q, array *ret)
 {
        int i;
        set_elem *w;

diff --git a/libq/set.h b/libq/set.h
index 9d321d2..2175b0a 100644
--- a/libq/set.h
+++ b/libq/set.h
@@ -11,10 +11,10 @@
 
 #include "array.h"
 
-typedef struct elem_t set_elem;
+typedef struct setelem_t set_elem;
 typedef struct set_t set;
 
-struct elem_t {
+struct setelem_t {
        char *name;
        unsigned int hash;  /* FNV1a32 */
        void *val;
@@ -35,8 +35,8 @@ const char *contains_set(const char *name, set *q);
 void *get_set(const char *name, set *q);
 void *del_set(const char *s, set *q, bool *removed);
 size_t list_set(set *q, char ***l);
-size_t array_set(set *q, array_t *ret);
-size_t values_set(set *q, array_t *ret);
+size_t array_set(set *q, array *ret);
+size_t values_set(set *q, array *ret);
 size_t cnt_set(set *q);
 void free_set(set *q);
 void clear_set(set *q);

diff --git a/libq/tree.c b/libq/tree.c
index 561ad6a..5d6ba9d 100644
--- a/libq/tree.c
+++ b/libq/tree.c
@@ -246,13 +246,10 @@ void
 tree_close(tree_ctx *ctx)
 {
        if (ctx->cache.categories != NULL) {
-               array_t t_s;
-               array_t *t = &t_s;
+               array *t = array_new();
                size_t n;
                tree_cat_ctx *cat;
 
-               VAL_CLEAR(t_s);
-
                values_set(ctx->cache.categories, t);
                free_set(ctx->cache.categories);
                ctx->cache.categories = NULL;  /* must happen before close_cat 
*/
@@ -2301,12 +2298,9 @@ tree_foreach_pkg_int
        ctx->do_sort = false;
 
        if (postsort) {
-               array_t cats_s;
-               array_t *cats = &cats_s;
+               array *cats = array_new();
                size_t n;
 
-               VAL_CLEAR(cats_s);
-
                /* should never happen, but perhaps a tree implementation
                 * populated something, then don't leak it */
                if (ctx->cache.categories != NULL)

diff --git a/main.c b/main.c
index fcb3fe1..78d550d 100644
--- a/main.c
+++ b/main.c
@@ -46,9 +46,9 @@ set  *features;
 set  *ev_use;
 char *install_mask;
 char *binpkg_format;
-array_t *overlays;
-array_t *overlay_names;
-array_t *overlay_src;
+array *overlays;
+array *overlay_names;
+array *overlay_src;
 
 static char *portedb;
 static char *eprefix;
@@ -935,16 +935,18 @@ read_one_repos_conf(const char *repos_conf, char 
**primary)
                        }
                        if (overlay != NULL) {
                                /* replace overlay */
-                               ele = array_get_elem(overlay_src, n);
-                               free(ele);
-                               array_get_elem(overlay_src, n) = 
xstrdup(repos_conf);
-                               ele = array_get_elem(overlays, n);
-                               free(ele);
-                               ele = array_get_elem(overlays, n) = xstrdup(e);
+                               array_delete(overlay_src, n, NULL);
+                               array_append_strcpy(overlay_src, repos_conf);
+
+                               ele = array_remove(overlay_names, n);
+                               array_append(overlay_names, ele);
+
+                               array_delete(overlays, n, NULL);
+                               ele = array_append_strcpy(overlays, e);
                        } else {
-                               ele = xarraypush_str(overlays, e);
-                               overlay = xarraypush_str(overlay_names, repo);
-                               xarraypush_str(overlay_src, repos_conf);
+                               ele     = array_append_strcpy(overlays, e);
+                               overlay = array_append_strcpy(overlay_names, 
repo);
+                               array_append_strcpy(overlay_src, repos_conf);
                        }
                        if (main_repo && strcmp(repo, main_repo) == 0)
                                *primary = overlay;
@@ -1044,7 +1046,7 @@ initialize_portage_env(void)
                array_for_each(overlay_names, n, overlay) {
                        if (overlay == primary_overlay) {
                                snprintf(pathbuf, sizeof(pathbuf), 
"%s/profiles/package.mask",
-                                               (char 
*)array_get_elem(overlays, n));
+                                               (char *)array_get(overlays, n));
                                read_portage_file(pathbuf + 1, PMASK_FILE, 
package_masks);
                                break;
                        }
@@ -1195,10 +1197,10 @@ initialize_portage_env(void)
                        if (overlay == NULL)
                                i = 0;
                }
-               main_overlay = array_get_elem(overlays, i);
+               main_overlay = array_get(overlays, i);
                /* set source for PORTDIR var */
                free(var->src);
-               var->src = xstrdup((char *)array_get_elem(overlay_src, i));
+               var->src = xstrdup((char *)array_get(overlay_src, i));
        }
 
        /* Make sure ROOT always ends in a slash */
@@ -1221,13 +1223,10 @@ initialize_portage_env(void)
                                        fprintf(stderr, "%s = %s\n", var->name, 
*var->value.s);
                                        break;
                                case _Q_ISET: {
-                                       array_t vals_s;
-                                       array_t *vals = &vals_s;
+                                       array *vals = array_new();
                                        size_t n;
                                        char  *val;
 
-                                       VAL_CLEAR(vals_s);
-
                                        fprintf(stderr, "%s = ", var->name);
                                        array_set(*var->value.t, vals);
                                        array_for_each(vals, n, val) {
@@ -1254,9 +1253,6 @@ int main(int argc, char **argv)
        struct stat st;
        struct winsize winsz;
        int i;
-       array_t overlays_s;
-       array_t overlay_names_s;
-       array_t overlay_src_s;
 
        warnout = stderr;
        IF_DEBUG(init_coredumps());
@@ -1265,12 +1261,9 @@ int main(int argc, char **argv)
        /* ensure any err/warn doesn't use unitialised vars */
        color_clear();
 
-       VAL_CLEAR(overlays_s);
-       VAL_CLEAR(overlay_names_s);
-       VAL_CLEAR(overlay_src_s);
-       overlays      = &overlays_s;
-       overlay_names = &overlay_names_s;
-       overlay_src   = &overlay_src_s;
+       overlays      = array_new();
+       overlay_names = array_new();
+       overlay_src   = array_new();
 
        /* initialise all the properties with their default value */
        for (i = 0; vars_to_read[i].name; ++i) {

diff --git a/q.c b/q.c
index 69b0273..2fd57a5 100644
--- a/q.c
+++ b/q.c
@@ -633,13 +633,10 @@ int q_main(int argc, char **argv)
                                                printf("%s\"%s\"%s", RED, 
*var->value.s, NORM);
                                                break;
                                        case _Q_ISET: {
-                                               array_t vals_s;
-                                               array_t *vals = &vals_s;
+                                               array *vals = array_new();
                                                size_t n;
                                                char  *val;
 
-                                               VAL_CLEAR(vals_s);
-
                                                printf("%s\"", RED);
                                                array_set(*var->value.t, vals);
                                                array_for_each(vals, n, val) {
@@ -673,13 +670,10 @@ int q_main(int argc, char **argv)
                                                printf("%s%s%s", RED, 
*var->value.s, NORM);
                                                break;
                                        case _Q_ISET: {
-                                               array_t vals_s;
-                                               array_t *vals = &vals_s;
+                                               array *vals = array_new();
                                                size_t n;
                                                char  *val;
 
-                                               VAL_CLEAR(vals_s);
-
                                                array_set(*var->value.t, vals);
                                                array_for_each(vals, n, val) {
                                                        printf("%s%s", n == 0 ? 
RED : " ", val);
@@ -699,10 +693,8 @@ int q_main(int argc, char **argv)
        }
 
        if (print_masks) {
-               array_t masks_s;
-               array_t files_s;
-               array_t *masks = &masks_s;
-               array_t *files = &files_s;
+               array *masks = array_new();
+               array *files = array_new();
                char *mask;
                size_t n;
                int j;
@@ -715,9 +707,6 @@ int q_main(int argc, char **argv)
                depend_atom *atom;
                depend_atom *qatom;
 
-               VAL_CLEAR(masks_s);
-               VAL_CLEAR(files_s);
-
                array_set(package_masks, masks);
                values_set(package_masks, files);
 
@@ -741,7 +730,7 @@ int q_main(int argc, char **argv)
                                continue;
 
                        if (verbose > 1) {
-                               char *mfile = (char *)array_get_elem(files, n);
+                               char *mfile = (char *)array_get(files, n);
                                char *l;
                                char *s = NULL;
                                long line = 0;
@@ -790,7 +779,7 @@ int q_main(int argc, char **argv)
                                                atom));
 
                        if (verbose == 1) {
-                               printf(" [%s%s]\n", portroot, (char 
*)array_get_elem(files, n));
+                               printf(" [%s%s]\n", portroot, (char 
*)array_get(files, n));
                        } else {
                                printf("\n");
                        }

diff --git a/qcheck.c b/qcheck.c
index 86707c9..9ca2ed9 100644
--- a/qcheck.c
+++ b/qcheck.c
@@ -59,8 +59,8 @@ static const char * const qcheck_opts_help[] = {
 #define qcprintf(fmt, args...) do { if (!state->bad_only) printf(fmt, ## 
args); } while (0)
 
 struct qcheck_opt_state {
-       array_t *atoms;
-       array_t *regex_arr;
+       array *atoms;
+       array *regex_arr;
        bool bad_only;
        bool qc_update;
        bool chk_afk;
@@ -431,11 +431,9 @@ int qcheck_main(int argc, char **argv)
        int ret;
        tree_ctx *vdb;
        depend_atom *atom;
-       array_t regex_arr;
-       array_t atoms;
        struct qcheck_opt_state state = {
-               .atoms = &atoms,
-               .regex_arr = &regex_arr,
+               .atoms = array_new(),
+               .regex_arr = array_new(),
                .bad_only = false,
                .qc_update = false,
                .chk_afk = true,
@@ -446,9 +444,6 @@ int qcheck_main(int argc, char **argv)
                .fmt = NULL,
        };
 
-       VAL_CLEAR(regex_arr);
-       VAL_CLEAR(atoms);
-
        while ((ret = GETOPT_LONG(QCHECK, qcheck, "")) != -1) {
                switch (ret) {
                COMMON_GETOPTS_CASES(qcheck)

diff --git a/qdepends.c b/qdepends.c
index cb2aec7..3d36c98 100644
--- a/qdepends.c
+++ b/qdepends.c
@@ -58,8 +58,7 @@ static const char * const qdepends_opts_help[] = {
 /* structures / types / etc ... */
 struct qdepends_opt_state {
        unsigned int  qmode;
-       array_t      *atoms;
-       array_t      *deps;
+       array        *atoms;
        set          *udeps;
        char         *depend;
        size_t        depend_len;
@@ -119,6 +118,7 @@ qdepends_results_cb(tree_pkg_ctx *pkg_ctx, void *priv)
        depend_atom *atom;
        depend_atom *datom;
        depend_atom *fatom;
+       array *deps;
        bool firstmatch = false;
        char buf[_Q_PATH_MAX];
        const char **dfile;
@@ -165,7 +165,6 @@ qdepends_results_cb(tree_pkg_ctx *pkg_ctx, void *priv)
                printf("%s:", atom_format(state->format, datom));
        }
 
-       xarrayfree_int(state->deps);
        clear_set(state->udeps);
 
 #define get_depstr(X) \
@@ -193,6 +192,8 @@ qdepends_results_cb(tree_pkg_ctx *pkg_ctx, void *priv)
                if (state->resolve)
                        dep_resolve_tree(dep_tree, state->rtree);
 
+               deps = array_new();
+
                if (state->qmode & QMODE_TREE &&
                        !(state->qmode & QMODE_REVERSE) &&
                        verbose)
@@ -208,7 +209,7 @@ qdepends_results_cb(tree_pkg_ctx *pkg_ctx, void *priv)
                                        if (depstr != NULL) {
                                                dep_node *dep_vdb = 
dep_grow_tree(depstr);
                                                if (dep_vdb != NULL) {
-                                                       
dep_flatten_tree(dep_vdb, state->deps);
+                                                       
dep_flatten_tree(dep_vdb, deps);
                                                        dep_burn_tree(dep_vdb);
                                                } else {
                                                        warn("failed to parse 
VDB depstring from %s\n",
@@ -222,12 +223,12 @@ qdepends_results_cb(tree_pkg_ctx *pkg_ctx, void *priv)
                } else {
                        if (state->qmode & QMODE_FILTERUSE)
                                dep_prune_use(dep_tree, ev_use);
-                       dep_flatten_tree(dep_tree, state->deps);
+                       dep_flatten_tree(dep_tree, deps);
                }
 
                if (verbose) {
                        if (state->qmode & QMODE_REVERSE) {
-                               array_for_each(state->deps, m, atom) {
+                               array_for_each(deps, m, atom) {
                                        array_for_each(state->atoms, n, fatom) {
                                                if (atom_compare(atom, fatom) 
== EQUAL) {
                                                        fatom = NULL;
@@ -255,13 +256,13 @@ qdepends_results_cb(tree_pkg_ctx *pkg_ctx, void *priv)
                                }
                        } else {
                                printf("\n%s=\"\n", *dfile);
-                               dep_print_tree(stdout, dep_tree, 1, state->deps,
+                               dep_print_tree(stdout, dep_tree, 1, deps,
                                                GREEN, verbose > 1);
                                printf("\"");
                        }
                } else {
                        if (state->qmode & QMODE_REVERSE) {
-                               array_for_each(state->deps, m, atom) {
+                               array_for_each(deps, m, atom) {
                                        array_for_each(state->atoms, n, fatom) {
                                                if (atom_compare(atom, fatom) 
== EQUAL) {
                                                        fatom = NULL;
@@ -289,15 +290,13 @@ qdepends_results_cb(tree_pkg_ctx *pkg_ctx, void *priv)
                                        }
                                }
                        } else {
-                               array_for_each(state->deps, m, atom)
+                               array_for_each(deps, m, atom)
                                        state->udeps = 
add_set_unique(atom_to_string(atom),
                                                                                
                  state->udeps, NULL);
                        }
                }
 
-               array_for_each(state->deps, m, atom)
-                       atom_implode(atom);
-               xarrayfree_int(state->deps);
+               array_deepfree(deps, (array_free_cb *)atom_implode);
                dep_burn_tree(dep_tree);
        }
        if (verbose && ret == 1)
@@ -320,11 +319,8 @@ qdepends_results_cb(tree_pkg_ctx *pkg_ctx, void *priv)
 int qdepends_main(int argc, char **argv)
 {
        depend_atom *atom;
-       array_t atoms;
-       array_t deps;
        struct qdepends_opt_state state = {
-               .atoms   = &atoms,
-               .deps    = &deps,
+               .atoms   = array_new(),
                .udeps   = create_set(),
                .qmode   = 0,
                .format  = "%[CATEGORY]%[PF]",
@@ -336,9 +332,6 @@ int qdepends_main(int argc, char **argv)
        int ret;
        bool do_pretty = false;
 
-       VAL_CLEAR(atoms);
-       VAL_CLEAR(deps);
-
        if (quiet)
                state.format = "%[CATEGORY]%[PN]";
 
@@ -382,6 +375,7 @@ int qdepends_main(int argc, char **argv)
 
        if ((argc == optind) && !do_pretty) {
                free_set(state.udeps);
+               array_free(state.atoms);
                qdepends_usage(EXIT_FAILURE);
        }
 
@@ -395,6 +389,7 @@ int qdepends_main(int argc, char **argv)
                        if (optind < argc)
                                fprintf(stdout, "\n");
                }
+               array_free(state.atoms);
                free_set(state.udeps);
                return ret;
        }
@@ -461,10 +456,7 @@ int qdepends_main(int argc, char **argv)
        if (state.depend != NULL)
                free(state.depend);
 
-       array_for_each(state.atoms, i, atom)
-               atom_implode(atom);
-       xarrayfree_int(state.atoms);
-       xarrayfree_int(state.deps);
+       array_deepfree(state.atoms, (array_free_cb *)atom_implode);
        free_set(state.udeps);
 
        if (!ret)

diff --git a/qkeyword.c b/qkeyword.c
index fb14ce3..76bc7cc 100644
--- a/qkeyword.c
+++ b/qkeyword.c
@@ -235,7 +235,7 @@ qkeyword_kw(tree_pkg_ctx *pkg_ctx, void *priv, int what)
 {
        qkeyword_data *data = (qkeyword_data *)priv;
        depend_atom *atom;
-       array_t *masks;
+       array *masks;
 
        if (data->keywordsbuf[qkeyword_test_arch] == what)
        {
@@ -898,23 +898,21 @@ int qkeyword_main(int argc, char **argv)
 
        /* prepare masks for easy(er) matching by key-ing on CAT/PN */
        {
-               array_t masks_s;
-               array_t *masks;
-               array_t *bucket;
-               array_t *ebuck;
+               array *masks;
+               array *bucket;
+               array *ebuck;
                size_t n;
                char *mask;
                depend_atom *atom;
 
-               VAL_CLEAR(masks_s);
-               masks  = &masks_s;
+               masks  = array_new();
                pmasks = create_set();
 
                array_set(package_masks, masks);
                array_for_each(masks, n, mask) {
                        if ((atom = atom_explode(mask)) == NULL)
                                continue;
-                       bucket = xzalloc(sizeof(array_t));
+                       bucket = array_new();
                        xarraypush_ptr(bucket, atom);
                        pmasks = add_set_value(atom_format("%[CAT]%[PN]", atom),
                                                                   bucket, 
(void **)&ebuck, pmasks);

diff --git a/qlist.c b/qlist.c
index 19c8d44..d63c810 100644
--- a/qlist.c
+++ b/qlist.c
@@ -251,15 +251,12 @@ qlist_match(
        }
 
        if (applymasks) {
-               array_t masks_s;
-               array_t *masks = &masks_s;
+               array *masks = array_new();
                depend_atom *matom;
                char *mask;
                size_t n;
                bool match = false;
 
-               VAL_CLEAR(masks_s);
-
                array_set(package_masks, masks);
 
                array_for_each(masks, n, mask) {

diff --git a/qlop.c b/qlop.c
index 5de8e83..b1eb074 100644
--- a/qlop.c
+++ b/qlop.c
@@ -415,7 +415,7 @@ deal with e.g. merging python-3.6 with 3.9 installed as 
well.
 static int do_emerge_log(
                const char *log,
                struct qlop_mode *flags,
-               array_t *atoms,
+               array *atoms,
                time_t tbegin,
                time_t tend)
 {
@@ -435,10 +435,8 @@ static int do_emerge_log(
        depend_atom *atom;
        depend_atom *atomw;
        depend_atom *upgrade_atom = NULL;
-       array_t merge_matches_s;
-       array_t unmerge_matches_s;
-       array_t *merge_matches = &merge_matches_s;
-       array_t *unmerge_matches = &unmerge_matches_s;
+       array *merge_matches = array_new();
+       array *unmerge_matches = array_new();
        set *merge_averages = create_set();
        set *unmerge_averages = create_set();
        set *atomset = NULL;
@@ -451,9 +449,6 @@ static int do_emerge_log(
        struct pkg_match *pkgw;
 #define strpfx(X, Y)  strncmp(X, Y, sizeof(Y) - 1)
 
-       VAL_CLEAR(merge_matches_s);
-       VAL_CLEAR(unmerge_matches_s);
-
        /* support relative path in here and now, when using ROOT, stick to
         * it, turning relative into a moot point */
        if (portroot[1] == '\0')
@@ -523,10 +518,7 @@ static int do_emerge_log(
                                 * "valid" one, such that dummy emerge calls 
(e.g.
                                 * emerge -pv foo) are ignored */
                                if (last_merge != tstart_emerge) {
-                                       array_t vals_s;
-                                       array_t *vals = &vals_s;
-
-                                       VAL_CLEAR(vals_s);
+                                       array *vals = array_new();
 
                                        values_set(atomset, vals);
                                        array_for_each(vals, i, atomw)
@@ -595,15 +587,15 @@ static int do_emerge_log(
                                sync_start = 0;
                                while ((i = array_cnt(merge_matches)) > 0) {
                                        i--;
-                                       pkgw = xarrayget(merge_matches, i);
+                                       pkgw = array_remove(merge_matches, i);
                                        atom_implode(pkgw->atom);
-                                       xarraydelete(merge_matches, i);
+                                       free(pkgw);
                                }
                                while ((i = array_cnt(unmerge_matches)) > 0) {
                                        i--;
-                                       pkgw = xarrayget(unmerge_matches, i);
+                                       pkgw = array_remove(unmerge_matches, i);
                                        atom_implode(pkgw->atom);
-                                       xarraydelete(unmerge_matches, i);
+                                       free(pkgw);
                                }
                        }
                }
@@ -1185,10 +1177,7 @@ static int do_emerge_log(
                size_t total_merges = 0;
                size_t total_unmerges = 0;
                time_t total_time = (time_t)0;
-               array_t avgs_s;
-               array_t *avgs = &avgs_s;
-
-               VAL_CLEAR(avgs_s);
+               array *avgs = array_new();
 
                values_set(merge_averages, avgs);
                xarraysort(avgs, pkg_sort_cb);
@@ -1202,6 +1191,7 @@ static int do_emerge_log(
                }
                xarrayfree_int(avgs);
 
+               avgs = array_new();
                values_set(unmerge_averages, avgs);
                xarraysort(avgs, pkg_sort_cb);
                array_for_each(avgs, i, pkg) {
@@ -1239,15 +1229,12 @@ static int do_emerge_log(
                        printf("\n");
                }
        } else if (flags->do_predict) {
-               array_t avgs_s;
-               array_t *avgs = &avgs_s;
+               array *avgs = array_new();
                enum { P_INIT = 0, P_SREV, P_SRCH } pkgstate;
                size_t j;
                time_t ptime;
                char found;
 
-               VAL_CLEAR(avgs_s);
-
                values_set(merge_averages, avgs);
                xarraysort(avgs, pkg_sort_cb);
                xarraysort(atoms, atom_compar_cb);
@@ -1355,10 +1342,7 @@ static int do_emerge_log(
        }
 
        {
-               array_t t_s;
-               array_t *t = &t_s;
-
-               VAL_CLEAR(t_s);
+               array *t = array_new();
 
                values_set(merge_averages, t);
                array_for_each(t, i, pkgw) {
@@ -1366,6 +1350,7 @@ static int do_emerge_log(
                        free(pkgw);
                }
                xarrayfree_int(t);
+               t = array_new();
                values_set(unmerge_averages, t);
                array_for_each(t, i, pkgw) {
                        atom_implode(pkgw->atom);
@@ -1386,10 +1371,7 @@ static int do_emerge_log(
        }
        xarrayfree(unmerge_matches);
        if (atomset != NULL) {
-               array_t t_s;
-               array_t *t = &t_s;
-
-               VAL_CLEAR(t_s);
+               array *t = array_new();
 
                values_set(atomset, t);
                array_for_each(t, i, atom)
@@ -1402,7 +1384,7 @@ static int do_emerge_log(
 
 /* scan through /proc for running merges, this requires portage user
  * or root */
-static array_t *probe_proc(array_t *atoms)
+static array *probe_proc(array *atoms)
 {
        struct dirent **procs = NULL;
        int procslen;
@@ -1418,14 +1400,11 @@ static array_t *probe_proc(array_t *atoms)
        ssize_t rpathlen;
        char *p;
        depend_atom *atom;
-       array_t ret_atoms_s;
-       array_t *ret_atoms = &ret_atoms_s;
+       array *ret_atoms = array_new();
        size_t i;
        char *cmdline = NULL;
        size_t cmdlinesize = 0;
 
-       VAL_CLEAR(ret_atoms_s);
-
        /* /proc/<pid>/path/<[0-9]+link>
         * /proc/<pid>/fd/<[0-9]+link> */
        if ((procslen = scandir("/proc", &procs, NULL, NULL)) > 0) {
@@ -1608,12 +1587,9 @@ int qlop_main(int argc, char **argv)
        char *p;
        char *q;
        depend_atom *atom;
-       array_t atoms_s;
-       array_t *atoms = &atoms_s;
+       array *atoms = array_new();
        int runningmode = 0;
 
-       VAL_CLEAR(atoms_s);
-
        start_time = -1;
        end_time = -1;
        m.do_time = 0;
@@ -1806,7 +1782,7 @@ int qlop_main(int argc, char **argv)
                end_time = LONG_MAX;
 
        if (m.do_running) {
-               array_t *new_atoms = NULL;
+               array *new_atoms = NULL;
 
                if (runningmode > 1) {
                        warn("running without /proc scanning, heuristics only");

diff --git a/qmanifest.c b/qmanifest.c
index cbf9459..e018d35 100644
--- a/qmanifest.c
+++ b/qmanifest.c
@@ -1775,8 +1775,16 @@ qmanifest_main(int argc, char **argv)
                                repolen = 0;
                                snprintf(path, sizeof(path), 
"%s/profiles/repo_name", overlay);
                                if (eat_file(path, &repo, &repolen)) {
-                                       free(array_get_elem(overlays, n));
-                                       array_get_elem(overlays, n) = repo;
+                                       void *name;
+                                       void *src;
+
+                                       array_delete(overlays, n, NULL);
+                                       name = array_remove(overlay_names, n);
+                                       src  = array_remove(overlay_src, n);
+
+                                       array_append(overlays,      repo);
+                                       array_append(overlay_names, name);
+                                       array_append(overlay_src,   src);
                                } else {
                                        free(repo);
                                }

diff --git a/qpkg.c b/qpkg.c
index da15171..51cb3bc 100644
--- a/qpkg.c
+++ b/qpkg.c
@@ -78,8 +78,7 @@ qpkg_clean(qpkg_cb_args *args)
        uint64_t num_all_bytes = 0;
        set *known_pkgs = NULL;
        set *bin_pkgs = NULL;
-       array_t bins_s;
-       array_t *bins = &bins_s;
+       array *bins = array_new();
        tree_ctx *t;
        tree_ctx *pkgs;
        char *binatomstr;
@@ -90,8 +89,6 @@ qpkg_clean(qpkg_cb_args *args)
        if (pkgs == NULL)
                return 1;
 
-       VAL_CLEAR(bins_s);
-
        bin_pkgs = tree_get_atoms(pkgs, true, bin_pkgs);
        if (bin_pkgs == NULL)
                return 1;

diff --git a/qsize.c b/qsize.c
index d74ebe6..b154d4b 100644
--- a/qsize.c
+++ b/qsize.c
@@ -81,7 +81,7 @@ static const char * const qsize_opts_help[] = {
 #define qsize_usage(ret) usage(ret, QSIZE_FLAGS, qsize_long_opts, 
qsize_opts_help, NULL, lookup_applet_idx("qsize"))
 
 struct qsize_opt_state {
-       array_t *atoms;
+       array *atoms;
        char **argv;
        char search_all;
        char fs_size;
@@ -89,7 +89,7 @@ struct qsize_opt_state {
        char summary_only;
        size_t disp_units;
        const char *str_disp_units;
-       array_t *ignore_regexp;
+       array *ignore_regexp;
        const char *fmt;
        bool need_full_atom:1;
 
@@ -189,18 +189,16 @@ int qsize_main(int argc, char **argv)
        size_t i;
        int ret;
        tree_ctx *vdb;
-       array_t ignore_regexp;
-       array_t atoms;
        depend_atom *atom;
        struct qsize_opt_state state = {
-               .atoms = &atoms,
+               .atoms = array_new(),
                .search_all = 0,
                .fs_size = 0,
                .summary = 0,
                .summary_only = 0,
                .disp_units = 0,
                .str_disp_units = NULL,
-               .ignore_regexp = &ignore_regexp,
+               .ignore_regexp = array_new(),
                .uniq_files = create_set(),
                .num_all_files = 0,
                .num_all_nonfiles = 0,
@@ -210,9 +208,6 @@ int qsize_main(int argc, char **argv)
                .fmt = NULL,
        };
 
-       VAL_CLEAR(ignore_regexp);
-       VAL_CLEAR(atoms);
-
        while ((ret = GETOPT_LONG(QSIZE, qsize, "")) != -1) {
                switch (ret) {
                COMMON_GETOPTS_CASES(qsize)

diff --git a/qwhich.c b/qwhich.c
index 610eb30..7cf691d 100644
--- a/qwhich.c
+++ b/qwhich.c
@@ -71,10 +71,8 @@ struct qwhich_mode {
 int qwhich_main(int argc, char **argv)
 {
        depend_atom *atom;
-       array_t atoms_s;
-       array_t trees_s;
-       array_t *atoms = &atoms_s;
-       array_t *trees = &trees_s;
+       array *atoms = array_new();
+       array *trees = array_new();
        struct qwhich_mode m;
        struct tree_match_ctx *tmc;
        struct tree_match_ctx *tmcw;
@@ -90,8 +88,6 @@ int qwhich_main(int argc, char **argv)
        const char *ext;
 
        VAL_CLEAR(m);
-       VAL_CLEAR(atoms_s);
-       VAL_CLEAR(trees_s);
 
        while ((ret = GETOPT_LONG(QWHICH, qwhich, "")) != -1) {
                switch (ret) {


Reply via email to