Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Merge remote-tracking branch 'upstream/main'
Shawn Webb committed 11 months ago
commit ba89bd1e02a4dacd0894a741ca515e507cb22256
parent 89d30c6
67 files changed +1498 -1664
modified .builds/freebsd.yml
@@ -1,6 +1,5 @@
image: freebsd/latest
packages:
-
  - kyua
  - pkgconf
  - python3
sources:
@@ -9,7 +8,7 @@ tasks:
  - configure: |
      mkdir build
      cd build
-
      ../pkg/configure 
+
      ../pkg/configure
  - build: |
      cd build
      make
modified NEWS
@@ -1,3 +1,21 @@
+
Changes from 2.1.99.3 to 2.1.99.4
+
- add a cache file for pkg_add()
+
- fix 32bits issues
+
- improve error message when failing at parsing manifest printing the path of
+
  the manifest.
+

+
Changes from 2.1.99.2 to 2.1.99.3
+
- more work on pkg add performances
+
- pkg(8): document -o options
+
- fix pkg-static issue due to symbols collisions between libmd and libcrypto
+

+
Changes from 2.1.99.1 to 2.1.99.2
+
- fix regression regarding shlibs_required
+

+
Changes from 2.1.99.0 to 2.1.99.1
+
- strong refactoring in internal containers code.
+
- performances improvements in pkg_add
+

Changes from 2.0.99.10 to 2.1.99.0
- pkg.conf(5): mention kmods repo
- validate SHLIB_PROVIDE_PATHS_* options
modified auto.def
@@ -6,7 +6,7 @@ use cc cc-lib cc-shared pkg-config
set maj_ver 2
set med_ver 1
set min_ver 99
-
set dev_ver 0
+
set dev_ver 4
define PKG_API [expr {$maj_ver * 1000000 + $med_ver * 1000 + $min_ver}]
define VERSION $maj_ver.$med_ver.$min_ver[expr {$dev_ver ? ".$dev_ver" : ""}]

modified docs/pkg.8
@@ -40,6 +40,7 @@
.Op Fl d
.Op Fl l
.Op Fl N
+
.Op Fl o Ao option=value Ac
.Op Fl j Ao jail name or id Ac | Fl c Ao chroot path Ac | Fl r Ao root directory Ac
.Op Fl C Ao configuration file Ac
.Op Fl R Ao repository configuration directory Ac
@@ -51,6 +52,7 @@
.Op Cm --debug
.Op Cm --list
.Op Fl N
+
.Op Cm --option Ao option=value Ac
.Op Cm --jail Ao jail name or id Ac | Cm --chroot Ao chroot path Ac | Cm --rootdir Ao root directory Ac
.Op Cm --config Ao configuration file Ac
.Op Cm --repo-conf-dir Ao repository configuration directory Ac
@@ -78,9 +80,9 @@ The following options are supported by
.It Fl v , Cm --version
Display the current version of
.Nm .
-
Specify
-
.Fl v
-
twice to also show
+
Specify twice
+
.Pq Fl vv
+
to also show
.Xr pkg.conf 5
configuration.
.It Fl d , Cm --debug
deleted external/include/tllist.h
@@ -1,254 +0,0 @@
-
#pragma once
-

-
#include <stdlib.h>
-
#include <stddef.h>
-
#include <assert.h>
-

-
#define TLL_PASTE2( a, b) a##b
-
#define TLL_PASTE( a, b) TLL_PASTE2( a, b)
-

-
/* Utility macro to generate a list element struct with a unique struct tag */
-
#define TLL_UNIQUE_INNER_STRUCT(TYPE, ID)      \
-
    struct TLL_PASTE(__tllist_ , ID) {         \
-
        TYPE item;                             \
-
        struct TLL_PASTE(__tllist_, ID) *prev; \
-
        struct TLL_PASTE(__tllist_, ID) *next; \
-
    } *head, *tail;
-

-
/*
-
 * Defines a new typed-list type, or directly instantiate a typed-list variable
-
 *
-
 * Example a, declare a variable (list of integers):
-
 *  tll(int) my_list;
-
 *
-
 * Example b, declare a type, and then use the type:
-
 *   tll(int, my_list_type);
-
 *   struct my_list_type my_list;
-
 */
-
#define tll(TYPE)                                                       \
-
    struct {                                                            \
-
        TLL_UNIQUE_INNER_STRUCT(TYPE, __COUNTER__)                      \
-
        size_t length;                                                  \
-
    }
-

-
/* Initializer: tll(int) my_list = tll_init(); */
-
#define tll_init() {.head = NULL, .tail = NULL, .length = 0}
-

-
/* Length/size of list: printf("size: %zu\n", tll_length(my_list)); */
-
#define tll_length(list) (list).length
-

-
/* Adds a new item to the back of the list */
-
#define tll_push_back(list, new_item)                   \
-
    do {                                                \
-
        tll_insert_after(list, (list).tail, new_item);  \
-
        if ((list).head == NULL)                        \
-
            (list).head = (list).tail;                  \
-
    } while (0)
-

-
/* Adds a new item to the front of the list */
-
#define tll_push_front(list, new_item) \
-
    do {                                                \
-
        tll_insert_before(list, (list).head, new_item); \
-
        if ((list).tail == NULL)                        \
-
            (list).tail = (list).head;                  \
-
    } while (0)
-

-
/*
-
 * Iterates the list. <it> is an iterator pointer. You can access the
-
 * list item with ->item:
-
 *
-
 *   tll(int) my_list = vinit();
-
 *   tll_push_back(my_list, 5);
-
 *
-
 *   tll_foreach(my_list i) {
-
 *       printf("%d\n", i->item);
-
 *   }
-
*/
-
#define tll_foreach(list, it)                                           \
-
    for (__typeof__(*(list).head) *it = (list).head,                    \
-
             *it_next = it != NULL ? it->next : NULL;                   \
-
         it != NULL;                                                    \
-
         it = it_next,                                                  \
-
             it_next = it_next != NULL ? it_next->next : NULL)
-

-
/* Same as tll_foreach(), but iterates backwards */
-
#define tll_rforeach(list, it)                                          \
-
    for (__typeof__(*(list).tail) *it = (list).tail,                    \
-
             *it_prev = it != NULL ? it->prev : NULL;                   \
-
         it != NULL;                                                    \
-
         it = it_prev,                                                  \
-
             it_prev = it_prev != NULL ? it_prev->prev : NULL)
-

-
/*
-
 * Inserts a new item after <it>, which is an iterator. I.e. you can
-
 * only call this from inside a tll_foreach() or tll_rforeach() loop.
-
 */
-
#define tll_insert_after(list, it, new_item) \
-
    do {                                                    \
-
        __typeof__((list).head) __e = malloc(sizeof(*__e)); \
-
        __e->item = (new_item);                             \
-
        __e->prev = (it);                                   \
-
        __e->next = (it) != NULL ? (it)->next : NULL;       \
-
        if ((it) != NULL) {                                 \
-
            if ((it)->next != NULL)                         \
-
                (it)->next->prev = __e;                     \
-
            (it)->next = __e;                               \
-
        }                                                   \
-
        if ((it) == (list).tail)                            \
-
            (list).tail = __e;                              \
-
        (list).length++;                                    \
-
    } while (0)
-

-
/*
-
 * Inserts a new item before <it>, which is an iterator. I.e. you can
-
 * only call this from inside a tll_foreach() or tll_rforeach() loop.
-
 */
-
#define tll_insert_before(list, it, new_item)   \
-
    do {                                                    \
-
        __typeof__((list).head) __e = malloc(sizeof(*__e)); \
-
        __e->item = (new_item);                             \
-
        __e->prev = (it) != NULL ? (it)->prev : NULL;       \
-
        __e->next = (it);                                   \
-
        if ((it) != NULL) {                                 \
-
            if ((it)->prev != NULL)                         \
-
                (it)->prev->next = __e;                     \
-
            (it)->prev = __e;                               \
-
        }                                                   \
-
        if ((it) == (list).head)                            \
-
            (list).head = __e;                              \
-
        (list).length++;                                    \
-
    } while (0)
-

-
/*
-
 * Removes an entry from the list. <it> is an iterator. I.e. you can
-
 * only call this from inside a tll_foreach() or tll_rforeach() loop.
-
 */
-
#define tll_remove(list, it)                              \
-
    do {                                                  \
-
        assert((list).length > 0);                        \
-
        __typeof__((list).head) __prev = it->prev;        \
-
        __typeof__((list).head) __next = it->next;        \
-
        if (__prev != NULL)                               \
-
            __prev->next = __next;                        \
-
        else                                              \
-
            (list).head = __next;                         \
-
        if (__next != NULL)                               \
-
            __next->prev = __prev;                        \
-
        else                                              \
-
            (list).tail = __prev;                         \
-
        free(it);                                         \
-
        (list).length--;                                  \
-
    } while (0)
-

-
/* Same as tll_remove(), but calls free_callback(it->item) */
-
#define tll_remove_and_free(list, it, free_callback)            \
-
    do {                                                        \
-
        free_callback((it)->item);                              \
-
        tll_remove((list), (it));                               \
-
    } while (0)
-

-
#define tll_front(list) (list).head->item
-
#define tll_back(list) (list).tail->item
-

-
/*
-
 * Removes the first element from the list, and returns it (note:
-
 * returns the *actual* item, not an iterator.
-
 */
-
#define tll_pop_front(list) __extension__                  \
-
    ({                                                     \
-
        __typeof__((list).head) it = (list).head;          \
-
        __typeof__((list).head->item) __ret = it->item;    \
-
        tll_remove((list), it);                            \
-
        __ret;                                             \
-
    })
-

-
/* Same as tll_pop_front(), but returns/removes the *last* element */
-
#define tll_pop_back(list) __extension__                                \
-
    ({                                                                  \
-
        __typeof__((list).tail) it = (list).tail;                       \
-
        __typeof__((list).tail->item) __ret = it->item;                 \
-
        tll_remove((list), it);                                         \
-
        __ret;                                                          \
-
    })
-

-
/* Frees the list. This call is *not* needed if the list is already empty. */
-
#define tll_free(list)                          \
-
    do {                                        \
-
        tll_foreach(list, __it)                 \
-
            free(__it);                         \
-
        (list).length = 0;                      \
-
        (list).head = (list).tail = NULL;       \
-
    } while (0)
-

-
/* Same as tll_free(), but also calls free_callback(item) for every item */
-
#define tll_free_and_free(list, free_callback)              \
-
    do {                                                    \
-
        tll_foreach(list, __it) {                           \
-
            free_callback(__it->item);                      \
-
            free(__it);                                     \
-
        }                                                   \
-
        (list).length = 0;                                  \
-
        (list).head = (list).tail = NULL;                   \
-
    } while (0)
-

-
#define tll_sort(list, cmp)                                                 \
-
    do {                                                                    \
-
	__typeof((list).head) __p;                                          \
-
	__typeof((list).head) __q;                                          \
-
	__typeof((list).head) __e;                                          \
-
	__typeof((list).head) __t;                                          \
-
        int __insize, __nmerges, __p_size, __q_size;                        \
-
	if ((list).head == NULL)                                            \
-
	    break;                                                          \
-
        __insize = 1;                                                       \
-
        while (1) {                                                         \
-
		__p = (list).head;                                          \
-
		(list).head = NULL;                                         \
-
                __t = NULL;                                                 \
-
		__nmerges = 0;                                              \
-
		while (__p != NULL) {                                       \
-
	            __nmerges++;                                            \
-
	            __q = __p;                                              \
-
		    __p_size = 0;                                           \
-
		    for (int _i = 0; _i < __insize; _i++) {                 \
-
			    __p_size++;                                     \
-
			    __q = __q->next;                                \
-
			    if (__q == NULL)                                \
-
			        break;                                      \
-
		    }                                                       \
-
	            __q_size = __insize;                                    \
-
		    while (__p_size > 0 || (__q_size > 0 && __q != NULL)) { \
-
			    if (__p_size == 0) {                            \
-
				    __e = __q;                              \
-
				    __q = __q->next;                        \
-
				    __q_size--;                             \
-
			    } else if (__q_size == 0 || __q == NULL) {      \
-
				    __e = __p;                              \
-
				    __p = __p->next;                        \
-
				    __p_size--;                             \
-
			    } else if (cmp(__p->item, __q->item) <= 0) {    \
-
				    __e = __p;                              \
-
				    __p = __p->next;                        \
-
				    __p_size--;                             \
-
			    } else {                                        \
-
				    __e = __q;                              \
-
				    __q = __q->next;                        \
-
				    __q_size--;                             \
-
			    }                                               \
-
			    if (__t != NULL) {                              \
-
				    __t->next = __e;                        \
-
			    } else {                                        \
-
				    (list).head = __e;                      \
-
			    }                                               \
-
			    __e->prev = __t;                                \
-
			    __t = __e;                                      \
-
		    }                                                       \
-
	            __p = __q;                                              \
-
		}                                                           \
-
		(list).tail = __t;                                          \
-
		__t->next = NULL;                                           \
-
		__insize *= 2;                                              \
-
		if (__nmerges <= 1)                                         \
-
			break;                                              \
-
	}                                                                   \
-
    } while (0)
modified external/libcurl/Makefile.autosetup
@@ -48,6 +48,7 @@ SRCS= \
	idn.c \
	if2ip.c \
	llist.c \
+
	macos.c \
	mime.c \
	mprintf.c \
	multi.c \
modified libpkg/Makefile.autosetup
@@ -126,7 +126,9 @@ LOCAL_LDFLAGS+= -ldl
@endif

@if pkgos_darwin
-
LOCAL_LDFLAGS+=	-lresolv
+
LOCAL_LDFLAGS+=	-lresolv -lz \
+
	-framework CoreFoundation -framework CoreServices \
+
	-framework SystemConfiguration
@else
@if pkgos_freebsd
LOCAL_LDFLAGS+=	-Wl,--version-script=$(top_srcdir)/libpkg/libpkg.ver,--undefined-version
modified libpkg/fetch.c
@@ -228,8 +228,8 @@ pkg_fetch_file_to_fd(struct pkg_repo *repo, int dest, struct fetch_item *fi,
    bool silent)
{
	struct pkg_kv	*kv;
-
	kvlist_t	 envtorestore = tll_init();
-
	stringlist_t	 envtounset = tll_init();
+
	kvlist_t	 envtorestore = vec_init();
+
	c_charv_t		 envtounset = vec_init();
	char		*tmp;
	int		 retcode = EPKG_OK;
	struct pkg_repo	*fakerepo = NULL;
@@ -278,16 +278,16 @@ pkg_fetch_file_to_fd(struct pkg_repo *repo, int dest, struct fetch_item *fi,
	}

	repo->silent = silent;
-
	tll_foreach(repo->env, k) {
-
		if ((tmp = getenv(k->item->key)) != NULL) {
+
	vec_foreach(repo->env, i) {
+
		if ((tmp = getenv(repo->env.d[i]->key)) != NULL) {
			kv = xcalloc(1, sizeof(*kv));
-
			kv->key = xstrdup(k->item->key);
+
			kv->key = xstrdup(repo->env.d[i]->key);
			kv->value = xstrdup(tmp);
-
			tll_push_back(envtorestore, kv);
+
			vec_push(&envtorestore, kv);
		} else {
-
			tll_push_back(envtounset, k->item->key);
+
			vec_push(&envtounset, repo->env.d[i]->key);
		}
-
		setenv(k->item->key, k->item->value, 1);
+
		setenv(repo->env.d[i]->key, repo->env.d[i]->value, 1);
	}

	if ((retcode = repo->fetcher->open(repo, fi)) != EPKG_OK)
@@ -299,16 +299,14 @@ pkg_fetch_file_to_fd(struct pkg_repo *repo, int dest, struct fetch_item *fi,
		pkg_emit_fetch_finished(fi->url);

cleanup:
-
	tll_foreach(envtorestore, k) {
-
		setenv(k->item->key, k->item->value, 1);
-
		tll_remove_and_free(envtorestore, k, pkg_kv_free);
+
	vec_foreach(envtorestore, i) {
+
		setenv(envtorestore.d[i]->key, envtorestore.d[i]->value, 1);
+
		vec_remove_and_free(&envtorestore, i, pkg_kv_free);
	}
-
	tll_free(envtorestore);
-
	tll_foreach(envtounset, k) {
-
		unsetenv(k->item);
-
		tll_remove(envtounset, k);
-
	}
-
	tll_free(envtounset);
+
	vec_free(&envtorestore);
+
	while (vec_len(&envtounset) > 0)
+
		unsetenv(vec_pop(&envtounset));
+
	vec_free(&envtounset);

	if (repo->fetcher != NULL && repo->fetcher->close != NULL)
		repo->fetcher->close(repo);
modified libpkg/lua_scripts.c
@@ -1,27 +1,7 @@
/*-
-
 * Copyright (c) 2019 Baptiste Daroussin <bapt@FreeBSD.org>
-
 * All rights reserved.
-
 * 
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 * 
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 * Copyright (c) 2019-2025 Baptiste Daroussin <bapt@FreeBSD.org>
+
 *
+
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include "pkg_config.h"
@@ -60,7 +40,7 @@ pkg_lua_script_run(struct pkg * const pkg, pkg_lua_script type, bool upgrade)
	int cur_pipe[2];
	char *line = NULL;

-
	if (tll_length(pkg->lua_scripts[type]) == 0)
+
	if (vec_len(&pkg->lua_scripts[type]) == 0)
		return (EPKG_OK);

	if (!pkg_object_bool(pkg_config_get("RUN_SCRIPTS"))) {
@@ -72,7 +52,8 @@ pkg_lua_script_run(struct pkg * const pkg, pkg_lua_script type, bool upgrade)
	do_reap = procctl(P_PID, mypid, PROC_REAP_ACQUIRE, NULL) == 0;
#endif

-
	tll_foreach(pkg->lua_scripts[type], s) {
+
	vec_foreach(pkg->lua_scripts[type], i) {
+
		char *script = pkg->lua_scripts[type].d[i];
		if (get_socketpair(cur_pipe) == -1) {
			pkg_emit_errno("pkg_lua_script_script", "socketpair");
			goto cleanup;
@@ -115,13 +96,13 @@ pkg_lua_script_run(struct pkg * const pkg, pkg_lua_script type, bool upgrade)
			lua_override_ios(L, true);

			/* parse and set arguments of the line is in the comments */
-
			if (STARTS_WITH(s->item, "-- args: ")) {
+
			if (STARTS_WITH(script, "-- args: ")) {
				char *walk, *begin, *line = NULL;
				int spaces, argc = 0;
				char **args = NULL;

-
				walk = strchr(s->item, '\n');
-
				begin = s->item + strlen("-- args: ");
+
				walk = strchr(script, '\n');
+
				begin = script + strlen("-- args: ");
				line = xstrndup(begin, walk - begin);
				spaces = pkg_utils_count_spaces(line);
				args = xmalloc((spaces + 1)* sizeof(char *));
@@ -132,8 +113,8 @@ pkg_lua_script_run(struct pkg * const pkg, pkg_lua_script type, bool upgrade)
				lua_args_table(L, args, argc);
			}

-
			pkg_debug(3, "Scripts: executing lua\n--- BEGIN ---\n%s\nScripts: --- END ---", s->item);
-
			if (luaL_dostring(L, s->item)) {
+
			pkg_debug(3, "Scripts: executing lua\n--- BEGIN ---\n%s\nScripts: --- END ---", script);
+
			if (luaL_dostring(L, script)) {
				pkg_emit_error("Failed to execute lua script: %s", lua_tostring(L, -1));
				lua_close(L);
				_exit(1);
@@ -183,14 +164,14 @@ cleanup:
}

ucl_object_t *
-
pkg_lua_script_to_ucl(stringlist_t *scripts)
+
pkg_lua_script_to_ucl(charv_t *scripts)
{
	ucl_object_t *array;

	array = ucl_object_typed_new(UCL_ARRAY);
-
	tll_foreach(*scripts, s)
-
		ucl_array_append(array, ucl_object_fromstring_common(s->item,
-
		    strlen(s->item), UCL_STRING_RAW|UCL_STRING_TRIM));
+
	vec_foreach(*scripts, i)
+
		ucl_array_append(array, ucl_object_fromstring_common(scripts->d[i],
+
		    strlen(scripts->d[i]), UCL_STRING_RAW|UCL_STRING_TRIM));

	return (array);
}
@@ -206,7 +187,7 @@ pkg_lua_script_from_ucl(struct pkg *pkg, const ucl_object_t *obj, pkg_lua_script
			pkg_emit_error("lua scripts be strings");
			return (EPKG_FATAL);
		}
-
		tll_push_back(pkg->lua_scripts[type], xstrdup(ucl_object_tostring(cur)));
+
		vec_push(&pkg->lua_scripts[type], xstrdup(ucl_object_tostring(cur)));
	}
	return (EPKG_OK);
}
modified libpkg/pkg.c
@@ -1,5 +1,5 @@
/*-
-
 * Copyright (c) 2011-2024 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2012 Bryan Drewery <bryan@shatow.net>
 * Copyright (c) 2013 Matthew Seaman <matthew@FreeBSD.org>
@@ -32,6 +32,7 @@ pkg_new(struct pkg **pkg, pkg_t type)
	*pkg = xcalloc(1, sizeof(struct pkg));
	(*pkg)->type = type;
	(*pkg)->rootfd = -1;
+
	(*pkg)->list_sorted = false;

	return (EPKG_OK);
}
@@ -76,7 +77,7 @@ pkg_free(struct pkg *pkg)
	for (int i = 0; i < PKG_NUM_SCRIPTS; i++)
		xstring_free(pkg->scripts[i]);
	for (int i = 0; i < PKG_NUM_LUA_SCRIPTS; i++)
-
		tll_free_and_free(pkg->lua_scripts[i], free);
+
		vec_free_and_free(&pkg->lua_scripts[i], free);

	pkg_list_free(pkg, PKG_DEPS);
	pkg_list_free(pkg, PKG_RDEPS);
@@ -85,27 +86,27 @@ pkg_free(struct pkg *pkg)
	pkg_list_free(pkg, PKG_OPTIONS);
	pkg_list_free(pkg, PKG_CONFIG_FILES);

-
	tll_free_and_free(pkg->users, free);
+
	vec_free_and_free(&pkg->users, free);
	pkg->flags &= ~PKG_LOAD_USERS;
-
	tll_free_and_free(pkg->groups, free);
+
	vec_free_and_free(&pkg->groups, free);
	pkg->flags &= ~PKG_LOAD_GROUPS;
-
	tll_free_and_free(pkg->shlibs_required, free);
+
	vec_free_and_free(&pkg->shlibs_required, free);
	pkg->flags &= ~PKG_LOAD_SHLIBS_REQUIRED;
-
	tll_free_and_free(pkg->shlibs_provided, free);
+
	vec_free_and_free(&pkg->shlibs_provided, free);
	pkg->flags &= ~PKG_LOAD_SHLIBS_REQUIRED;
-
	tll_free_and_free(pkg->provides, free);
+
	vec_free_and_free(&pkg->provides, free);
	pkg->flags &= ~PKG_LOAD_PROVIDES;
-
	tll_free_and_free(pkg->requires, free);
+
	vec_free_and_free(&pkg->requires, free);
	pkg->flags &= ~PKG_LOAD_REQUIRES;
-
	tll_free_and_free(pkg->categories, free);
+
	vec_free_and_free(&pkg->categories, free);
	pkg->flags &= ~PKG_LOAD_CATEGORIES;
-
	tll_free_and_free(pkg->licenses, free);
+
	vec_free_and_free(&pkg->licenses, free);
	pkg->flags &= ~PKG_LOAD_LICENSES;

-
	tll_free_and_free(pkg->message, pkg_message_free);
-
	tll_free_and_free(pkg->annotations, pkg_kv_free);
+
	vec_free_and_free(&pkg->message, pkg_message_free);
+
	vec_free_and_free(&pkg->annotations, pkg_kv_free);

-
	tll_free_and_free(pkg->dir_to_del, free);
+
	vec_free_and_free(&pkg->dir_to_del, free);

	if (pkg->rootfd != -1)
		close(pkg->rootfd);
@@ -246,7 +247,7 @@ pkg_set_s(struct pkg *pkg, pkg_attr attr, const char *str)
		pkg->comment = xstrdup(str);
		break;
	case PKG_ATTR_MESSAGE:
-
		tll_free_and_free(pkg->message, pkg_message_free);
+
		vec_free_and_free(&pkg->message, pkg_message_free);
		if (*str == '[') {
			pkg_message_from_str(pkg, str, strlen(str));
		} else {
@@ -405,45 +406,13 @@ pkg_each(config_files, struct pkg_config_file, config_files);
int
pkg_adduser(struct pkg *pkg, const char *name)
{
-
	assert(pkg != NULL);
-
	assert(name != NULL && name[0] != '\0');
-

-
	tll_foreach(pkg->users, u) {
-
		if (!STREQ(u->item, name))
-
			continue;
-
		if (ctx.developer_mode) {
-
			pkg_emit_error("duplicate user listing: %s, fatal (developer mode)", name);
-
			return (EPKG_FATAL);
-
		}
-
		pkg_emit_error("duplicate user listing: %s, ignoring", name);
-
		return (EPKG_OK);
-
	}
-

-
	tll_push_back(pkg->users, xstrdup(name));
-

-
	return (EPKG_OK);
+
	return (pkg_addstring(&pkg->users, name, "user"));
}

int
pkg_addgroup(struct pkg *pkg, const char *name)
{
-
	assert(pkg != NULL);
-
	assert(name != NULL && name[0] != '\0');
-

-
	tll_foreach(pkg->groups, g) {
-
		if (!STREQ(g->item, name))
-
			continue;
-
		if (ctx.developer_mode) {
-
			pkg_emit_error("duplicate group listing: %s, fatal (developer mode)", name);
-
			return (EPKG_FATAL);
-
		}
-
		pkg_emit_error("duplicate group listing: %s, ignoring", name);
-
		return (EPKG_OK);
-
	}
-

-
	tll_push_back(pkg->groups, xstrdup(name));
-

-
	return (EPKG_OK);
+
	return (pkg_addstring(&pkg->groups, name, "group"));
}

int
@@ -601,14 +570,14 @@ pkg_addconfig_file(struct pkg *pkg, const char *path, const char *content)
}

int
-
pkg_addstring(stringlist_t *list, const char *val, const char *title)
+
pkg_addstring(charv_t *list, const char *val, const char *title)
{
	assert(val != NULL);
	assert(title != NULL);

-
	tll_foreach(*list, v) {
-
		if (!STREQ(v->item, val))
-
			continue;
+
	char *tmp = xstrdup(val);
+
	if (charv_insert_sorted(list, tmp) != NULL) {
+
		free(tmp);
		if (ctx.developer_mode) {
			pkg_emit_error("duplicate %s listing: %s, fatal"
			    " (developer mode)", title, val);
@@ -619,8 +588,6 @@ pkg_addstring(stringlist_t *list, const char *val, const char *title)
		return (EPKG_OK);
	}

-
	tll_push_back(*list, xstrdup(val));
-

	return (EPKG_OK);
}

@@ -696,7 +663,7 @@ pkg_add_lua_script(struct pkg *pkg, const char *data, pkg_lua_script type)
	if (type >= PKG_LUA_UNKNOWN)
		return (EPKG_FATAL);

-
	tll_push_back(pkg->lua_scripts[type], xstrdup(data));
+
	vec_push(&pkg->lua_scripts[type], xstrdup(data));

	return (EPKG_OK);
}
@@ -967,15 +934,11 @@ pkg_addshlib_required(struct pkg *pkg, const char *name,
	char *full_name = pkg_shlib_name_with_flags(name, flags);

	/* silently ignore duplicates in case of shlibs */
-
	tll_foreach(pkg->shlibs_required, s) {
-
		if (STREQ(s->item, full_name)) {
-
			free(full_name);
-
			return (EPKG_OK);
-
		}
+
	if (charv_insert_sorted(&pkg->shlibs_required, full_name) != NULL) {
+
		free(full_name);
+
		return (EPKG_OK);
	}

-
	tll_push_back(pkg->shlibs_required, full_name);
-

	dbg(3, "added shlib deps for %s on %s", pkg->name, full_name);

	return (EPKG_OK);
@@ -991,15 +954,11 @@ pkg_addshlib_provided(struct pkg *pkg, const char *name,
	char *full_name = pkg_shlib_name_with_flags(name, flags);

	/* silently ignore duplicates in case of shlibs */
-
	tll_foreach(pkg->shlibs_provided, s) {
-
		if (STREQ(s->item, full_name)) {
-
			free(full_name);
-
			return (EPKG_OK);
-
		}
+
	if (charv_insert_sorted(&pkg->shlibs_provided, full_name) != NULL) {
+
		free(full_name);
+
		return (EPKG_OK);
	}

-
	tll_push_back(pkg->shlibs_provided, full_name);
-

	dbg(3, "added shlib provide %s for %s", full_name, pkg->name);

	return (EPKG_OK);
@@ -1034,13 +993,13 @@ pkg_addrequire(struct pkg *pkg, const char *name)
	assert(pkg != NULL);
	assert(name != NULL && name[0] != '\0');

-
	/* silently ignore duplicates in case of conflicts */
-
	tll_foreach(pkg->requires, p) {
-
		if (STREQ(p->item, name))
-
			return (EPKG_OK);
-
	}
+
	char *tmp = xstrdup(name);

-
	tll_push_back(pkg->requires, xstrdup(name));
+
	if (charv_insert_sorted(&pkg->requires, tmp) != NULL) {
+
		/* silently ignore duplicates in case of conflicts */
+
		free(tmp);
+
		return (EPKG_OK);
+
	}

	return (EPKG_OK);
}
@@ -1051,13 +1010,13 @@ pkg_addprovide(struct pkg *pkg, const char *name)
	assert(pkg != NULL);
	assert(name != NULL && name[0] != '\0');

-
	/* silently ignore duplicates in case of conflicts */
-
	tll_foreach(pkg->provides, p) {
-
		if (STREQ(p->item, name))
-
			return (EPKG_OK);
-
	}
+
	char *tmp = xstrdup(name);

-
	tll_push_back(pkg->provides, xstrdup(name));
+
	if (charv_insert_sorted(&pkg->provides, tmp) != NULL) {
+
		/* silently ignore duplicates in case of conflicts */
+
		free(tmp);
+
		return (EPKG_OK);
+
	}

	return (EPKG_OK);
}
@@ -1067,9 +1026,9 @@ pkg_kv_get(const kvlist_t *kv, const char *tag)
{
	assert(tag != NULL);

-
	tll_foreach(*kv, k) {
-
		if (STREQ(k->item->key, tag))
-
			return (k->item->value);
+
	vec_foreach(*kv, i) {
+
		if (STREQ(kv->d[i]->key, tag))
+
			return (kv->d[i]->value);
	}

	return (NULL);
@@ -1083,9 +1042,9 @@ pkg_kv_add(kvlist_t *list, const char *key, const char *val, const char *title)
	assert(val != NULL);
	assert(title != NULL);

-
	tll_foreach(*list, k) {
-
		if (!STREQ(k->item->key, key))
-
			continue;
+
	kv = pkg_kv_new(key, val);
+
	if (pkg_kv_insert_sorted(list, kv) != NULL) {
+
		pkg_kv_free(kv);
		if (ctx.developer_mode) {
			pkg_emit_error("duplicate %s: %s, fatal"
				    " (developer mode)", title, key);
@@ -1096,9 +1055,6 @@ pkg_kv_add(kvlist_t *list, const char *key, const char *val, const char *title)
		return (EPKG_OK);
	}

-
	kv = pkg_kv_new(key, val);
-
	tll_push_back(*list, kv);
-

	return (EPKG_OK);
}

@@ -1121,17 +1077,17 @@ pkg_list_count(const struct pkg *pkg, pkg_list list)
	case PKG_CONFIG_FILES:
		return (pkghash_count(pkg->config_files_hash));
	case PKG_USERS:
-
		return (tll_length(pkg->users));
+
		return (vec_len(&pkg->users));
	case PKG_GROUPS:
-
		return (tll_length(pkg->groups));
+
		return (vec_len(&pkg->groups));
	case PKG_SHLIBS_REQUIRED:
-
		return (tll_length(pkg->shlibs_required));
+
		return (vec_len(&pkg->shlibs_required));
	case PKG_SHLIBS_PROVIDED:
-
		return (tll_length(pkg->shlibs_provided));
+
		return (vec_len(&pkg->shlibs_provided));
	case PKG_REQUIRES:
-
		return (tll_length(pkg->requires));
+
		return (vec_len(&pkg->requires));
	case PKG_PROVIDES:
-
		return (tll_length(pkg->provides));
+
		return (vec_len(&pkg->provides));
	}

	return (0);
@@ -1450,7 +1406,7 @@ pkg_is_installed(struct pkgdb *db, const char *name)
bool
pkg_has_message(struct pkg *p)
{
-
	return (tll_length(p->message) > 0);
+
	return (vec_len(&p->message) > 0);
}

bool
@@ -1547,7 +1503,7 @@ pkg_message_from_ucl(struct pkg *pkg, const ucl_object_t *obj)
		msg = xcalloc(1, sizeof(*msg));
		msg->str = xstrdup(ucl_object_tostring(obj));
		msg->type = PKG_MESSAGE_ALWAYS;
-
		tll_push_back(pkg->message, msg);
+
		vec_push(&pkg->message, msg);
		return (EPKG_OK);
	}

@@ -1583,7 +1539,7 @@ pkg_message_from_ucl(struct pkg *pkg, const ucl_object_t *obj)
				    " message will always be printed");
		}
		if (msg->type != PKG_MESSAGE_UPGRADE) {
-
			tll_push_back(pkg->message, msg);
+
			vec_push(&pkg->message, msg);
			continue;
		}

@@ -1597,7 +1553,7 @@ pkg_message_from_ucl(struct pkg *pkg, const ucl_object_t *obj)
			msg->maximum_version = xstrdup(ucl_object_tostring(elt));
		}

-
		tll_push_back(pkg->message, msg);
+
		vec_push(&pkg->message, msg);
	}

	return (EPKG_OK);
@@ -1653,8 +1609,8 @@ pkg_message_to_ucl(const struct pkg *pkg)
	ucl_object_t *obj;

	array = ucl_object_typed_new(UCL_ARRAY);
-
	tll_foreach(pkg->message, t) {
-
		msg = t->item;
+
	vec_foreach(pkg->message, i) {
+
		msg = pkg->message.d[i];
		obj = ucl_object_typed_new (UCL_OBJECT);

		ucl_object_insert_key(obj,
@@ -1703,7 +1659,7 @@ pkg_message_to_str(struct pkg *pkg)
	ucl_object_t *obj;
	char *ret = NULL;

-
	if (tll_length(pkg->message) <= 0)
+
	if (vec_len(&pkg->message) <= 0)
		return (NULL);

	obj = pkg_message_to_ucl(pkg);
@@ -1742,12 +1698,47 @@ pkg_cf_cmp(struct pkg_config_file *a, struct pkg_config_file *b)
{
	return (STREQ(a->path, b->path));
}
+

void
pkg_lists_sort(struct pkg *p)
{
+
	if (p->list_sorted)
+
		return;
+
	p->list_sorted = true;
+

	DL_SORT(p->depends, pkg_dep_cmp);
	DL_SORT(p->files, pkg_file_cmp);
	DL_SORT(p->dirs, pkg_dir_cmp);
	DL_SORT(p->options, pkg_option_cmp);
	DL_SORT(p->config_files, pkg_cf_cmp);
}
+

+
static int
+
pkgs_cmp(const void *a, const void *b)
+
{
+
	struct pkg *pa = *(struct pkg **)a;
+
	struct pkg *pb = *(struct pkg **)b;
+

+
	return (strcmp(pa->name, pb->name));
+
}
+

+
void
+
pkgs_sort(pkgs_t *pkgs)
+
{
+
	if (pkgs->len == 0)
+
		return;
+
	qsort(pkgs->d, pkgs->len, sizeof(pkgs->d[0]), pkgs_cmp);
+
}
+

+
DEFINE_VEC_INSERT_SORTED_FUNC(pkgs_t, pkgs, struct pkg *, pkgs_cmp)
+

+
struct pkg **
+
pkgs_search(pkgs_t *pkgs, char *el)
+
{
+
	struct pkg target = { .name = el };
+
	struct pkg *tgt = &target;
+
	if (pkgs->len == 0)
+
		return (NULL);
+
	struct pkg **res = bsearch(&tgt, pkgs->d, pkgs->len, sizeof(pkgs->d[0]), pkgs_cmp);
+
	return (res);
+
}
modified libpkg/pkg/vec.h
@@ -1,5 +1,5 @@
/*-
-
 * Copyright(c) 2024 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright(c) 2024-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */
@@ -14,23 +14,29 @@
#define vec_t(Type) \
  struct { Type *d; size_t len, cap; }

-
#define vec_init(v) \
-
	memset((v), 0, sizeof(*(v)))
+
#define vec_init() \
+
	{ .d = NULL, .len = 0, .cap = 0 }
+

+
#define vec_foreach(list, __i) \
+
	for (size_t __i = 0; __i < (list).len; __i++)
+

+
/* ssize_t because the value can be negative */
+
#define vec_rforeach(list, __i) \
+
	for (ssize_t __i = ((ssize_t)(list).len) -1 ; __i >= 0; __i--)

#define vec_free(v) \
	do { \
		free((v)->d); \
-
		(v)->d == NULL; \
		memset((v), 0, sizeof(*(v))); \
	} while (0)

-
#define vec_free_and_free(v, free_func)            \
-
	do {                                          \
-
		for (size_t _i=0; _i < (v)->len ; _i++) { \
-
			free_func((v)->d[_i]);          \
-
			(v)->d[_i] = NULL;   \
-
		}                                     \
-
		vec_free((v)); \
+
#define vec_free_and_free(v, free_func)        \
+
	do {                                   \
+
		vec_foreach(*(v), _i) {        \
+
			free_func((v)->d[_i]); \
+
			(v)->d[_i] = NULL;     \
+
		}                              \
+
		vec_free((v));                 \
	} while(0)

#define vec_first(v) \
@@ -42,18 +48,18 @@
#define vec_clear(v) \
	(v)->len = 0

-
#define vec_clear_and_free(v, free_func) \
-
	do {                                          \
-
		for (size_t _i=0; _i < (v)->len ; _i++) { \
-
			free_func((v)->d[_i]);          \
-
			(v)->d[_i] = NULL;   \
-
		}                                     \
-
		(v)->len = 0;                            \
+
#define vec_clear_and_free(v, free_func)       \
+
	do {                                   \
+
		vec_foreach(*(v), _i) {        \
+
			free_func((v)->d[_i]); \
+
			(v)->d[_i] = NULL;     \
+
		}                              \
+
		(v)->len = 0;                  \
	} while (0)

#define vec_push(v, _d)                                            \
	do {                                                          \
-
		if ((v)->len + 1 > (v)->cap) {                            \
+
		if ((v)->len >= (v)->cap) {                            \
			if ((v)->cap == 0)                              \
				(v)->cap = 1;                          \
			else                                          \
@@ -68,6 +74,47 @@
#define vec_pop(v) \
	(v)->d[--(v)->len]

+
#define vec_remove_and_free(v, cnt, free_func) \
+
	do {                                                    \
+
		free_func((v)->d[cnt]);                         \
+
		for (size_t _i = cnt; _i < (v)->len - 1; _i++) {    \
+
			(v)->d[_i] = (v)->d[_i + 1];            \
+
		}                                               \
+
		(v)->len--;                                     \
+
	} while (0)
+

+
#define vec_len(v) \
+
	(v)->len
+

+
#define DEFINE_VEC_INSERT_SORTED_PROTO(type, name, element_type) \
+
	element_type *name##_insert_sorted(type *v, element_type el)
+

+
#define DEFINE_VEC_INSERT_SORTED_FUNC(type, _name, element_type, compare_func) \
+
	element_type *_name##_insert_sorted(type *v, element_type el) { \
+
		/* Verify if the element already exists */ \
+
		if (v->len > 0) { \
+
			element_type *found = bsearch(&el, v->d, v->len, sizeof(element_type), compare_func); \
+
			if (found != NULL){ \
+
				return (found); \
+
			} \
+
		} \
+
		if (v->len >= v->cap) { \
+
			v->cap = (v->cap == 0) ? 1 : v->cap * 2; \
+
			v->d = realloc(v->d, v->cap * sizeof(element_type)); \
+
			if (v->d == NULL) \
+
				abort(); \
+
		} \
+
		/* Find where to insert */ \
+
		size_t i; \
+
		for (i = v->len; i > 0 && compare_func(&v->d[i - 1], &el) > 0; i--) { \
+
			v->d[i] = v->d[i - 1]; \
+
		} \
+
		v->d[i] = el; \
+
		v->len++; \
+
		return (NULL); \
+
	}
+

typedef vec_t(char *) charv_t;
typedef vec_t(const char *) c_charv_t;
+

#endif
modified libpkg/pkg_abi.c
@@ -1,5 +1,5 @@
/*-
-
 * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2012-2013 Matthew Seaman <matthew@FreeBSD.org>
 * Copyright (c) 2024 The FreeBSD Foundation
 *
@@ -440,43 +440,46 @@ pkg_arch_to_legacy(const char *arch, char *dest, size_t sz)
}

void
-
pkg_cleanup_shlibs_required(struct pkg *pkg, stringlist_t *internal_provided)
+
pkg_cleanup_shlibs_required(struct pkg *pkg, charv_t *internal_provided)
{
	struct pkg_file *file = NULL;
	const char *lib;

-
	tll_foreach(pkg->shlibs_required, s)
-
	{
-
		if (stringlist_contains(&pkg->shlibs_provided, s->item) ||
-
		    stringlist_contains(internal_provided, s->item)) {
+
	vec_foreach(pkg->shlibs_required, i) {
+
		const char *s = pkg->shlibs_required.d[i];
+
		if (charv_search(&pkg->shlibs_provided, s) != NULL ||
+
		    charv_search(internal_provided, s) != NULL) {
			pkg_debug(2,
			    "remove %s from required shlibs as the "
			    "package %s provides this library itself",
-
			    s->item, pkg->name);
-
			tll_remove_and_free(pkg->shlibs_required, s, free);
+
			    s, pkg->name);
+
			vec_remove_and_free(&pkg->shlibs_required, i, free);
+
			i--;
			continue;
		}
-
		if (match_ucl_lists(s->item,
+
		if (match_ucl_lists(s,
		    pkg_config_get("SHLIB_REQUIRE_IGNORE_GLOB"),
		    pkg_config_get("SHLIB_REQUIRE_IGNORE_REGEX"))) {
			pkg_debug(2,
			    "remove %s from required shlibs for package %s as it "
			    "is matched by SHLIB_REQUIRE_IGNORE_GLOB/REGEX.",
-
			    s->item, pkg->name);
-
			tll_remove_and_free(pkg->shlibs_required, s, free);
+
			    s, pkg->name);
+
			vec_remove_and_free(&pkg->shlibs_required, i, free);
+
			i--;
			continue;
		}
		file = NULL;
		while (pkg_files(pkg, &file) == EPKG_OK) {
-
			if ((lib = strstr(file->path, s->item)) != NULL &&
-
			    strlen(lib) == strlen(s->item) && lib[-1] == '/') {
+
			if ((lib = strstr(file->path, s)) != NULL &&
+
			    strlen(lib) == strlen(s) && lib[-1] == '/') {
				pkg_debug(2,
				    "remove %s from required shlibs as "
				    "the package %s provides this file itself",
-
				    s->item, pkg->name);
+
				    s, pkg->name);

-
				tll_remove_and_free(pkg->shlibs_required, s,
+
				vec_remove_and_free(&pkg->shlibs_required, i,
				    free);
+
				i--;
				break;
			}
		}
@@ -506,12 +509,12 @@ pkg_analyse_files(struct pkgdb *db __unused, struct pkg *pkg, const char *stage)
		pkg_analyse_close=pkg_analyse_close_elf;
	}

-
	if (tll_length(pkg->shlibs_required) != 0) {
-
		tll_free_and_free(pkg->shlibs_required, free);
+
	if (vec_len(&pkg->shlibs_required) != 0) {
+
		vec_free_and_free(&pkg->shlibs_required, free);
	}

-
	if (tll_length(pkg->shlibs_provided) != 0) {
-
		tll_free_and_free(pkg->shlibs_provided, free);
+
	if (vec_len(&pkg->shlibs_provided) != 0) {
+
		vec_free_and_free(&pkg->shlibs_provided, free);
	}

	ret = pkg_analyse_init(stage);
@@ -527,9 +530,9 @@ pkg_analyse_files(struct pkgdb *db __unused, struct pkg *pkg, const char *stage)
	/* shlibs that are provided by files in the package but not matched by
	   SHLIB_PROVIDE_PATHS_* are still used to filter the shlibs
	   required by the package */
-
	stringlist_t internal_provided = tll_init();
+
	charv_t internal_provided = vec_init();
	/* list of shlibs that are in the path to be evaluated for provided but are symlinks */
-
	stringlist_t maybe_provided = tll_init();
+
	charv_t maybe_provided = vec_init();

	while (pkg_files(pkg, &file) == EPKG_OK) {
		struct stat st;
@@ -579,40 +582,40 @@ pkg_analyse_files(struct pkgdb *db __unused, struct pkg *pkg, const char *stage)
				if (S_ISREG(st.st_mode)) {
					pkg_addshlib_provided(pkg, provided, provided_flags);
				} else {
-
					tll_push_back(maybe_provided, pkg_shlib_name_with_flags(provided, provided_flags));
+
					vec_push(&maybe_provided, pkg_shlib_name_with_flags(provided, provided_flags));
				}
			} else {
-
				tll_push_back(internal_provided, pkg_shlib_name_with_flags(provided, provided_flags));
+
				vec_push(&internal_provided, pkg_shlib_name_with_flags(provided, provided_flags));
			}
			free(provided);
		}
	}

-
	tll_foreach(maybe_provided, s) {
-
		tll_foreach(internal_provided, ip) {
-
			if (STREQ(s->item, ip->item)) {
-
				pkg_addshlib_provided(pkg, s->item, PKG_SHLIB_FLAGS_NONE);
-
				tll_remove_and_free(internal_provided, ip, free);
+
	vec_foreach(maybe_provided, i) {
+
		vec_foreach(internal_provided, j) {
+
			if (STREQ(maybe_provided.d[i], internal_provided.d[j])) {
+
				pkg_addshlib_provided(pkg, maybe_provided.d[i], PKG_SHLIB_FLAGS_NONE);
+
				vec_remove_and_free(&internal_provided, j, free);
			}
		}
-
		tll_remove_and_free(maybe_provided, s, free);
+
		vec_remove_and_free(&maybe_provided, i, free);
	}
-
	tll_free(maybe_provided);
+
	vec_free(&maybe_provided);
	/*
	 * Do not depend on libraries that a package provides itself
	 */
	pkg_cleanup_shlibs_required(pkg, &internal_provided);
-
	tll_free_and_free(internal_provided, free);
+
	vec_free_and_free(&internal_provided, free);

-
	tll_foreach(pkg->shlibs_provided, s) {
-
		if (match_ucl_lists(s->item,
+
	vec_foreach(pkg->shlibs_provided, i) {
+
		if (match_ucl_lists(pkg->shlibs_provided.d[i],
		    pkg_config_get("SHLIB_PROVIDE_IGNORE_GLOB"),
		    pkg_config_get("SHLIB_PROVIDE_IGNORE_REGEX"))) {
			pkg_debug(2,
			    "remove %s from provided shlibs for package %s as it "
			    "is matched by SHLIB_PROVIDE_IGNORE_GLOB/REGEX.",
-
			    s->item, pkg->name);
-
			tll_remove_and_free(pkg->shlibs_provided, s, free);
+
			    pkg->shlibs_provided.d[i], pkg->name);
+
			vec_remove_and_free(&pkg->shlibs_provided, i, free);
			continue;
		}
	}
@@ -622,7 +625,7 @@ pkg_analyse_files(struct pkgdb *db __unused, struct pkg *pkg, const char *stage)
	 * drop the provided one
	 */
	if (pkg_kv_get(&pkg->annotations, "no_provide_shlib") != NULL) {
-
		tll_free_and_free(pkg->shlibs_provided, free);
+
		vec_free_and_free(&pkg->shlibs_provided, free);
	}

	if (failures)
modified libpkg/pkg_add.c
@@ -26,7 +26,6 @@
#include <sys/wait.h>
#include <time.h>
#include <xstring.h>
-
#include <tllist.h>

#include <sys/types.h>
#include <sys/extattr.h>
@@ -46,9 +45,9 @@

struct pkg_add_db {
	struct pkgdb *db;
-
	pkg_chain_t *localpkgs;
-
	struct pkghash *system_shlibs;
-
	bool local_scaned;
+
	pkgs_t localpkgs;
+
	charv_t system_shlibs;
+
	bool local_scanned;
	bool ignore_compat32;
	bool pkgbase;
};
@@ -443,7 +442,7 @@ get_tempdir(struct pkg_add_context *context, const char *path, tempdirs_t *tempd
{
	struct tempdir *tmpdir = NULL;

-
	for (size_t i = 0; i < tempdirs->len; i++) {
+
	vec_foreach(*tempdirs, i) {
		tmpdir = tempdirs->d[i];
		if (strncmp(tmpdir->name, path, tmpdir->len) == 0 && path[tmpdir->len] == '/') {
			reopen_tempdir(context->rootfd, tmpdir);
@@ -666,7 +665,7 @@ create_hardlink(struct pkg_add_context *context, struct pkg_file *f, const char
		return (EPKG_FATAL);
	}
	if (fh->temppath[0] == '\0') {
-
		for (size_t i = 0; i < tempdirs->len; i++) {
+
		vec_foreach(*tempdirs, i) {
			if (strncmp(tempdirs->d[i]->name, fh->path, tempdirs->d[i]->len) == 0 &&
			    fh->path[tempdirs->d[i]->len] == '/' ) {
				tmphdir = tempdirs->d[i];
@@ -1053,7 +1052,7 @@ pkg_extract_finalize(struct pkg *pkg, tempdirs_t *tempdirs)


	if (tempdirs != NULL) {
-
		for (size_t i = 0; i < tempdirs->len; i++) {
+
		vec_foreach(*tempdirs, i) {
			struct tempdir *t = tempdirs->d[i];
			if (renameat(pkg->rootfd, RELATIVE_PATH(t->temp),
			    pkg->rootfd, RELATIVE_PATH(t->name)) != 0) {
@@ -1130,63 +1129,145 @@ pkg_extract_finalize(struct pkg *pkg, tempdirs_t *tempdirs)
}

static bool
-
should_append_pkg(pkg_chain_t *localpkgs, struct pkg *p)
+
should_append_pkg(pkgs_t *localpkgs, struct pkg *p)
{
	/* only keep the highest version is we fine one */
-
	tll_foreach(*localpkgs, lp) {
-
		if (strcmp(lp->item->name, p->name) == 0) {
-
			if (pkg_version_cmp(lp->item->version, p->version) == -1) {
-
				tll_remove_and_free(*localpkgs, lp, pkg_free);
-
				return (true);
-
			}
-
			return (false);
+
	struct pkg **lp = pkgs_insert_sorted(localpkgs, p);
+
	if (lp != NULL) {
+
		if (pkg_version_cmp((*lp)->version, p->version) == -1) {
+
			pkg_free(*lp);
+
			*lp = p;
+
			return (true);
		}
+
		return (false);
	}
-
	/* none found we should append */
	return (true);
}

struct localhashes {
-
	struct pkghash *lpkgs;
-
	struct pkghash *shlibs_provides;
-
	struct pkghash *provides;
+
	kvlist_t shlibs_provides;
+
	kvlist_t provides;
};

+
static FILE *
+
open_cache_read(void)
+
{
+
	FILE *fp;
+
	int cfd, fd;
+

+
	cfd = pkg_get_cachedirfd();
+
	if (cfd == -1)
+
		return (NULL);
+
	if ((fd = openat(cfd, "pkg_add_cache", O_RDONLY)) == -1)
+
		return (NULL);
+
	if ((fp = fdopen(fd, "r")) == NULL)
+
		close(fd);
+
	return (fp);
+
}
+

+
static FILE *
+
open_cache_write(void)
+
{
+
	FILE *fp;
+
	int cfd, fd;
+

+
	cfd = pkg_get_cachedirfd();
+
	if (cfd == -1) {
+
		if (errno == ENOENT) {
+
			if (pkg_mkdirs(ctx.cachedir) != EPKG_OK)
+
				return (NULL);
+
		} else {
+
			return (NULL);
+
		}
+
		cfd = pkg_get_cachedirfd();
+
		if (cfd == -1)
+
			return (NULL);
+
	}
+
	if ((fd = openat(cfd, "pkg_add_cache", O_WRONLY|O_TRUNC)) == -1)
+
		return (NULL);
+
	if ((fp = fdopen(fd, "w")) == NULL)
+
		close(fd);
+
	return (fp);
+
}
+

static void
scan_local_pkgs(struct pkg_add_db *db, bool fromstdin, struct localhashes *l, const char *bd, const char *ext)
{
-
	if (!fromstdin && db->localpkgs != NULL) {
-
		if (!db->local_scaned) {
-
			glob_t g;
-
			char *pattern;
-
			xasprintf(&pattern, "%s/*%s" , bd, ext);
-
			db->local_scaned = true;
-
			if (glob(pattern, 0, NULL, &g) == 0) {
-
				for (int i = 0; i <g.gl_pathc; i++) {
-
					struct pkg *p = NULL;
-
					if (pkg_open(&p, g.gl_pathv[i],
-
					    PKG_OPEN_MANIFEST_COMPACT) == EPKG_OK) {
-
						if (should_append_pkg(db->localpkgs, p)) {
-
							p->repopath = xstrdup(g.gl_pathv[i]);
-
							tll_push_back(*db->localpkgs, p);
+
	if (!fromstdin) {
+
		if (!db->local_scanned) {
+
			bool package_building = (getenv("PACKAGE_BUILDING") != NULL);
+
			bool cache_exist = false;
+
			if (package_building) {
+
				FILE * fp;
+
				if ((fp = open_cache_read()) != NULL) {
+
					cache_exist = true;
+
					char *line = NULL;
+
					size_t linecap = 0;
+
					ssize_t linelen;
+
					while ((linelen = getline(&line, &linecap, fp)) > 0) {
+
						struct pkg * p = NULL;
+
						pkg_new(&p, PKG_FILE);
+
						pkg_parse_manifest(p, line, linelen);
+
						vec_push(&db->localpkgs, p);
+
					}
+
					free(line);
+
				}
+
			}
+
			if (db->localpkgs.len == 0) {
+
				glob_t g;
+
				char *pattern;
+
				xasprintf(&pattern, "%s/*%s" , bd, ext);
+
				db->local_scanned = true;
+
				if (glob(pattern, 0, NULL, &g) == 0) {
+
					for (int i = 0; i <g.gl_pathc; i++) {
+
						struct pkg *p = NULL;
+
						if (pkg_open(&p, g.gl_pathv[i],
+
									PKG_OPEN_MANIFEST_COMPACT) == EPKG_OK) {
+
							if (should_append_pkg(&db->localpkgs, p)) {
+
								p->repopath = xstrdup(g.gl_pathv[i]);
+
							}
						}
					}
				}
+
				globfree(&g);
+
				free(pattern);
+
			}
+
			if (package_building && !cache_exist) {
+
				FILE *fp = fopen("/tmp/pkg_add_cache", "w");
+
				if (fp != NULL) {
+
					vec_foreach(db->localpkgs, i) {
+
						pkg_emit_manifest_file(db->localpkgs.d[i], fp, PKG_MANIFEST_EMIT_COMPACT);
+
						fputs("\n", fp);
+
					}
+
					fclose(fp);
+
				}
			}
-
			globfree(&g);
-
			free(pattern);
		}
-
		tll_foreach(*db->localpkgs, p) {
-
			pkghash_safe_add(l->lpkgs, p->item->name, xstrdup(p->item->repopath), free);
-
			tll_foreach(p->item->shlibs_provided, sp) {
-
				pkghash_safe_add(l->shlibs_provides, sp->item, xstrdup(p->item->repopath), free);
+
		vec_foreach(db->localpkgs, i) {
+
			struct pkg *p = db->localpkgs.d[i];
+
			vec_foreach(p->shlibs_provided, j) {
+
				struct pkg_kv *kv = pkg_kv_new(p->shlibs_provided.d[j], p->repopath);
+
				if (pkg_kv_insert_sorted(&l->shlibs_provides, kv) != NULL)
+
					pkg_kv_free(kv);
			}
-
			tll_foreach(p->item->provides, sp) {
-
				pkghash_safe_add(l->provides, sp->item, xstrdup(p->item->repopath), free);
+
			vec_foreach(p->provides, j) {
+
				struct pkg_kv *kv = pkg_kv_new(p->provides.d[j], p->repopath);
+
				if (pkg_kv_insert_sorted(&l->provides, kv) != NULL)
+
					pkg_kv_free(kv);
			}
		}
	}
}
+

+
static const char *
+
_localpkgs_get(pkgs_t *pkgs, const char *name)
+
{
+
	struct pkg **lp = pkgs_search(pkgs, name);
+
	if (lp != NULL)
+
		return ((*lp)->repopath);
+
	return (NULL);
+
}
+

static int
pkg_add_check_pkg_archive(struct pkg_add_db *db, struct pkg *pkg,
	const char *path, int flags, const char *location)
@@ -1263,7 +1344,7 @@ pkg_add_check_pkg_archive(struct pkg_add_db *db, struct pkg *pkg,
	pkg_emit_add_deps_begin(pkg);

	while (pkg_deps(pkg, &dep) == EPKG_OK) {
-
		pkghash_entry *founddep = NULL;
+
		const char *founddep = NULL;

		if (pkg_is_installed(db->db, dep->name) == EPKG_OK)
			continue;
@@ -1279,7 +1360,7 @@ pkg_add_check_pkg_archive(struct pkg_add_db *db, struct pkg *pkg,
			scan_local_pkgs(db, fromstdin, &l, bd, ext);
			scanned = true;
		}
-
		if ((founddep = pkghash_get(l.lpkgs, dep->name)) == NULL) {
+
		if ((founddep = _localpkgs_get(&db->localpkgs, dep->name)) == NULL) {
			pkg_emit_missing_dep(pkg, dep);
			if ((flags & PKG_ADD_FORCE_MISSING) == 0)
				goto cleanup;
@@ -1287,8 +1368,9 @@ pkg_add_check_pkg_archive(struct pkg_add_db *db, struct pkg *pkg,
		}

		if ((flags & PKG_ADD_UPGRADE) == 0 &&
-
				access(founddep->value, F_OK) == 0) {
-
			ret = pkg_add_common(db, founddep->value, PKG_ADD_AUTOMATIC, location, NULL, NULL, NULL);
+
				access(founddep, F_OK) == 0) {
+
			pkg_debug(2, "Installing %s because of direct dependency: %s", founddep, dep->name);
+
			ret = pkg_add_common(db, founddep, PKG_ADD_AUTOMATIC, location, NULL, NULL, NULL);

			if (ret != EPKG_OK)
				goto cleanup;
@@ -1299,21 +1381,23 @@ pkg_add_check_pkg_archive(struct pkg_add_db *db, struct pkg *pkg,
		}
	}

-
	tll_foreach(pkg->shlibs_required, s) {
-
		if (!db->pkgbase && db->system_shlibs == NULL) {
+
	vec_foreach(pkg->shlibs_required, i) {
+
		char *s = pkg->shlibs_required.d[i];
+
		pkg_debug(2, "%s requires %s", pkg->name, s);
+
		if (!db->pkgbase && db->system_shlibs.len == 0) {
			int ret;
			ret = scan_system_shlibs(&db->system_shlibs, ctx.pkg_rootdir);
			if (ret == EPKG_NOCOMPAT32)
				db->ignore_compat32 = true;
		}
-
		if (pkghash_get(db->system_shlibs, s->item) != NULL)
+
		if (charv_search(&db->system_shlibs, s) != NULL)
			continue;
-
		pkghash_entry *founddep = NULL;
-
		if (pkgdb_is_shlib_provided(db->db, s->item))
+
		const struct pkg_kv *founddep = NULL;
+
		if (pkgdb_is_shlib_provided(db->db, s))
			continue;

		if (fromstdin) {
-
			pkg_emit_error("Missing shlib dependency: %s", s->item);
+
			pkg_emit_error("Missing shlib dependency: %s", s);
			if ((flags & PKG_ADD_FORCE_MISSING) == 0)
				goto cleanup;
			continue;
@@ -1322,14 +1406,15 @@ pkg_add_check_pkg_archive(struct pkg_add_db *db, struct pkg *pkg,
			scan_local_pkgs(db, fromstdin, &l, bd, ext);
			scanned = true;
		}
-
		if ((founddep = pkghash_get(l.shlibs_provides, s->item)) == NULL) {
-
			pkg_emit_error("Missing shlib dependency: %s", s->item);
+
		if ((founddep = pkg_kv_search(&l.shlibs_provides, s)) == NULL) {
+
			pkg_emit_error("Missing shlib dependency: %s", s);
			if ((flags & PKG_ADD_FORCE_MISSING) == 0)
				goto cleanup;
			continue;
		}
		if ((flags & PKG_ADD_UPGRADE) == 0 &&
				access(founddep->value, F_OK) == 0) {
+
			pkg_debug(2, "Installing %s because of shlibs_required: %s", founddep->value, s);
			ret = pkg_add_common(db, founddep->value, PKG_ADD_AUTOMATIC, location, NULL, NULL, NULL);

			if (ret != EPKG_OK)
@@ -1341,13 +1426,14 @@ pkg_add_check_pkg_archive(struct pkg_add_db *db, struct pkg *pkg,
		}
	}

-
	tll_foreach(pkg->requires, s) {
-
		pkghash_entry *founddep = NULL;
-
		if (pkgdb_is_provided(db->db, s->item))
+
	vec_foreach(pkg->requires, i) {
+
		char *s = pkg->requires.d[i];
+
		const struct pkg_kv *founddep = NULL;
+
		if (pkgdb_is_provided(db->db, s))
			continue;

		if (fromstdin) {
-
			pkg_emit_error("Missing require dependency: %s", s->item);
+
			pkg_emit_error("Missing require dependency: %s", s);
			if ((flags & PKG_ADD_FORCE_MISSING) == 0)
				goto cleanup;
			continue;
@@ -1356,14 +1442,15 @@ pkg_add_check_pkg_archive(struct pkg_add_db *db, struct pkg *pkg,
			scan_local_pkgs(db, fromstdin, &l, bd, ext);
			scanned = true;
		}
-
		if ((founddep = pkghash_get(l.provides, s->item)) == NULL) {
-
			pkg_emit_error("Missing require dependency: %s", s->item);
+
		if ((founddep = pkg_kv_search(&l.provides, s)) == NULL) {
+
			pkg_emit_error("Missing require dependency: %s", s);
			if ((flags & PKG_ADD_FORCE_MISSING) == 0)
				goto cleanup;
			continue;
		}
		if ((flags & PKG_ADD_UPGRADE) == 0 &&
				access(founddep->value, F_OK) == 0) {
+
			pkg_debug(2, "Installing %s because of requires: %s", founddep->value, s);
			ret = pkg_add_common(db, founddep->value, PKG_ADD_AUTOMATIC, location, NULL, NULL, NULL);

			if (ret != EPKG_OK)
@@ -1377,9 +1464,8 @@ pkg_add_check_pkg_archive(struct pkg_add_db *db, struct pkg *pkg,

	retcode = EPKG_OK;
cleanup:
-
	pkghash_destroy(l.lpkgs);
-
	pkghash_destroy(l.provides);
-
	pkghash_destroy(l.shlibs_provides);
+
	vec_free_and_free(&l.shlibs_provides, pkg_kv_free);
+
	vec_free_and_free(&l.provides, pkg_kv_free);
	pkg_emit_add_deps_finished(pkg);

	return (retcode);
@@ -1424,7 +1510,7 @@ pkg_add_cleanup_old(struct pkgdb *db, struct pkg *old, struct pkg *new, struct t
					const char *libname;
					libname = strrchr(f->path, '/');
					if (libname != NULL &&
-
					    stringlist_contains(&old->shlibs_provided, libname+1)) {
+
					    charv_search(&old->shlibs_provided, libname+1) != NULL) {
						backup_library(db, old, f->path);
					}
				}
@@ -1484,15 +1570,13 @@ pkg_add_common(struct pkg_add_db *db, const char *path, unsigned flags,
	int			 retcode = EPKG_OK;
	int			 ret;
	int			 nfiles;
-
	tempdirs_t		 tempdirs;
+
	tempdirs_t		 tempdirs = vec_init();
	struct pkg_add_context	 context;

	memset(&context, 0, sizeof(context));

	assert(path != NULL);

-
	vec_init(&tempdirs);
-

	/*
	 * Open the package archive file, read all the meta files and set the
	 * current archive_entry to the first non-meta file.
@@ -1657,8 +1741,8 @@ pkg_add_common(struct pkg_add_db *db, const char *path, unsigned flags,
	else
		pkg_emit_upgrade_finished(pkg, local);

-
	tll_foreach(pkg->message, m) {
-
		msg = m->item;
+
	vec_foreach(pkg->message, i) {
+
		msg = pkg->message.d[i];
		msgstr = NULL;
		if (msg->type == PKG_MESSAGE_ALWAYS) {
			msgstr = msg->str;
@@ -1716,19 +1800,17 @@ pkg_add(struct pkgdb *db, const char *path, unsigned flags,
    const char *location)
{
	struct pkg_add_db padb;
-
	pkg_chain_t localpkgs = tll_init();
	int ret;

	memset(&padb, 0, sizeof(padb));
	padb.db = db;
-
	padb.localpkgs = &localpkgs;
-
	padb.local_scaned = false;
+
	padb.local_scanned = false;
	padb.ignore_compat32 = false;
	padb.pkgbase = pkgdb_file_exists(db, "/usr/bin/uname");

	ret = pkg_add_common(&padb, path, flags, location, NULL, NULL, NULL);
-
	tll_free_and_free(localpkgs, pkg_free);
-
	pkghash_destroy(padb.system_shlibs);
+
	vec_free_and_free(&padb.localpkgs, pkg_free);
+
	vec_free_and_free(&padb.system_shlibs, free);
	return (ret);
}

@@ -1818,18 +1900,16 @@ pkg_add_fromdir(struct pkg *pkg, const char *src, struct pkgdb *db __unused)
	struct group *gr, grent;
	int err, fd, fromfd;
	int retcode;
-
	hardlinks_t hardlinks;
+
	hardlinks_t hardlinks = vec_init();
	const char *path;
	char buffer[1024];
	size_t link_len;
	bool install_as_user;
-
	tempdirs_t tempdirs;
+
	tempdirs_t tempdirs = vec_init();
	struct pkg_add_context context;

	memset(&context, 0, sizeof(context));

-
	vec_init(&hardlinks);
-
	vec_init(&tempdirs);
	install_as_user = (getenv("INSTALL_AS_USER") != NULL);

	fromfd = open(src, O_DIRECTORY);
@@ -1971,7 +2051,7 @@ pkg_add_fromdir(struct pkg *pkg, const char *src, struct pkgdb *db __unused)
				    " '%s'", RELATIVE_PATH(f->path));
			}
			path = NULL;
-
			for (size_t i = 0; i < hardlinks.len; i++) {
+
			vec_foreach(hardlinks, i) {
				struct hardlink *hit = hardlinks.d[i];
				if (hit->ino == st.st_ino &&
				    hit->dev == st.st_dev) {
modified libpkg/pkg_attributes.c
@@ -1,29 +1,9 @@
/*-
-
 * Copyright (c) 2011-2013 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2013 Matthew Seaman <matthew@FreeBSD.org>
-
 * All rights reserved.
 *
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 *
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <assert.h>
@@ -173,6 +153,37 @@ pkg_kv_free(struct pkg_kv *c)
	free(c);
}

+
static int
+
kv_cmp(const void *a, const void *b) {
+
	struct pkg_kv *ka = *(struct pkg_kv **)a;
+
	struct pkg_kv *kb = *(struct pkg_kv **)b;
+

+
	return (strcmp(ka->key, kb->key));
+
}
+

+
struct pkg_kv *
+
pkg_kv_search(kvlist_t *kv, char *el)
+
{
+
	struct pkg_kv target =  { .key = el, .value = NULL };
+
	struct pkg_kv *tgt = &target;
+
	if (kv->len == 0)
+
		return (NULL);
+
	struct pkg_kv **res = bsearch(&tgt, kv->d, kv->len, sizeof(kv->d[0]), kv_cmp);
+
	if (res == NULL)
+
		return (NULL);
+
	return (*res);
+
}
+

+
DEFINE_VEC_INSERT_SORTED_FUNC(kvlist_t, pkg_kv, struct pkg_kv *, kv_cmp)
+

+
void
+
pkg_kv_sort(kvlist_t *kv)
+
{
+
	if (kv->len == 0)
+
		return;
+
	qsort(kv->d, kv->len, sizeof(kv->d[0]), kv_cmp);
+
}
+

struct pkg_kvlist_iterator *
pkg_kvlist_iterator(struct pkg_kvlist *l)
{
@@ -184,13 +195,9 @@ pkg_kvlist_iterator(struct pkg_kvlist *l)
struct pkg_kv *
pkg_kvlist_next(struct pkg_kvlist_iterator *it)
{
-
	if (it->cur == NULL)
-
		it->cur = it->list->head;
-
	else
-
		it->cur = ((__typeof__(it->list->head))it->cur)->next;
-
	if (it->cur == NULL)
+
	if (it->pos >= it->list->len)
		return (NULL);
-
	return (((__typeof__(it->list->head))it->cur)->item);
+
	return (it->list->d[it->pos++]);
}

struct pkg_stringlist_iterator *
@@ -204,13 +211,9 @@ pkg_stringlist_iterator(struct pkg_stringlist *l)
const char *
pkg_stringlist_next(struct pkg_stringlist_iterator *it)
{
-
	if (it->cur == NULL)
-
		it->cur = it->list->head;
-
	else
-
		it->cur = ((__typeof__(it->list->head))it->cur)->next;
-
	if (it->cur == NULL)
+
	if (it->pos >= it->list->len)
		return (NULL);
-
	return (((__typeof__(it->list->head))it->cur)->item);
+
	return (it->list->d[it->pos++]);
}

struct pkg_el *
@@ -352,13 +355,3 @@ pkg_get_element(struct pkg *p, pkg_attr a)

	return (e);
}
-

-
bool
-
stringlist_contains(stringlist_t *l, const char *name)
-
{
-
	tll_foreach(*l, e) {
-
		if (STREQ(e->item, name))
-
			return (true);
-
	}
-
	return (false);
-
}
modified libpkg/pkg_checksum.c
@@ -202,13 +202,11 @@ pkg_checksum_generate(struct pkg *pkg, char *dest, size_t destlen,
	char *olduid;
	size_t blen;
	struct kv *entries = NULL;
-
	charv_t tofree;
+
	charv_t tofree = vec_init();
	struct pkg_option *option = NULL;
	struct pkg_dep *dep = NULL;
	struct pkg_file *f = NULL;
-
	int i;
	bool is_group = false;
-
	vec_init(&tofree);

	if (pkg == NULL || type >= PKG_HASH_TYPE_UNKNOWN ||
					destlen < checksum_types[type].hlen)
@@ -228,20 +226,20 @@ pkg_checksum_generate(struct pkg *pkg, char *dest, size_t destlen,
		LL_APPEND(entries, kv_new(option->key, option->value));
	}

-
	tll_foreach(pkg->shlibs_required, s) {
-
		LL_APPEND(entries, kv_new("required_shlib", s->item));
+
	vec_foreach(pkg->shlibs_required, i) {
+
		LL_APPEND(entries, kv_new("required_shlib", pkg->shlibs_required.d[i]));
	}

-
	tll_foreach(pkg->shlibs_provided, s) {
-
		LL_APPEND(entries, kv_new("provided_shlib", s->item));
+
	vec_foreach(pkg->shlibs_provided, i) {
+
		LL_APPEND(entries, kv_new("provided_shlib", pkg->shlibs_provided.d[i]));
	}

-
	tll_foreach(pkg->users, u) {
-
		LL_APPEND(entries, kv_new("user", u->item));
+
	vec_foreach(pkg->users, i) {
+
		LL_APPEND(entries, kv_new("user", pkg->users.d[i]));
	}

-
	tll_foreach(pkg->groups, g) {
-
		LL_APPEND(entries, kv_new("group", g->item));
+
	vec_foreach(pkg->groups, i) {
+
		LL_APPEND(entries, kv_new("group", pkg->groups.d[i]));
	}

	while (pkg_deps(pkg, &dep) == EPKG_OK) {
@@ -254,12 +252,12 @@ pkg_checksum_generate(struct pkg *pkg, char *dest, size_t destlen,
		}
	}

-
	tll_foreach(pkg->provides, p) {
-
		LL_APPEND(entries, kv_new("provide", p->item));
+
	vec_foreach(pkg->provides, i) {
+
		LL_APPEND(entries, kv_new("provide", pkg->provides.d[i]));
	}

-
	tll_foreach(pkg->requires, r) {
-
		LL_APPEND(entries, kv_new("require", r->item));
+
	vec_foreach(pkg->requires, i) {
+
		LL_APPEND(entries, kv_new("require", pkg->requires.d[i]));
	}

	if (inc_scripts) {
@@ -270,8 +268,8 @@ pkg_checksum_generate(struct pkg *pkg, char *dest, size_t destlen,
			}
		}
		for (int i = 0; i < PKG_NUM_LUA_SCRIPTS; i++) {
-
			tll_foreach(pkg->lua_scripts[i], s)
-
				LL_APPEND(entries, kv_new("lua_script", s->item));
+
			vec_foreach(pkg->lua_scripts[i], j)
+
				LL_APPEND(entries, kv_new("lua_script", pkg->lua_scripts[i].d[j]));
		}
	}

@@ -290,7 +288,7 @@ pkg_checksum_generate(struct pkg *pkg, char *dest, size_t destlen,
	}

	if (checksum_types[type].encfunc) {
-
		i = snprintf(dest, destlen, "%d%c%d%c", PKG_CHECKSUM_CUR_VERSION,
+
		size_t i = snprintf(dest, destlen, "%d%c%d%c", PKG_CHECKSUM_CUR_VERSION,
				PKG_CKSUM_SEPARATOR, type, PKG_CKSUM_SEPARATOR);
		assert(i < destlen);
		checksum_types[type].encfunc(bdigest, blen, dest + i, destlen - i);
modified libpkg/pkg_config.c
@@ -780,7 +780,7 @@ add_repo(const ucl_object_t *obj, struct pkg_repo *r, const char *rname, pkg_ini
		while ((cur = ucl_iterate_object(env, &it, true))) {
			kv = pkg_kv_new(ucl_object_key(cur),
			    ucl_object_tostring_forced(cur));
-
			tll_push_back(r->env, kv);
+
			vec_push(&r->env, kv);
		}
	}
}
@@ -1711,7 +1711,7 @@ pkg_repo_free(struct pkg_repo *r)
	pkg_repo_meta_free(r->meta);
	if (r->fetcher != NULL && r->fetcher->cleanup != NULL)
		r->fetcher->cleanup(r);
-
	tll_free_and_free(r->env, pkg_kv_free);
+
	vec_free_and_free(&r->env, pkg_kv_free);
	free(r->dbpath);
	free(r);
}
modified libpkg/pkg_create.c
@@ -68,9 +68,8 @@ pkg_create_from_dir(struct pkg *pkg, const char *root,
	const char	*relocation;
	char		*manifest;
	ucl_object_t	*obj;
-
	hardlinks_t	 hardlinks;
+
	hardlinks_t	 hardlinks = vec_init();

-
	vec_init(&hardlinks);
	if (pkg_is_valid(pkg) != EPKG_OK) {
		pkg_emit_error("the package is not valid");
		return (EPKG_FATAL);
@@ -501,6 +500,7 @@ load_metadata(struct pkg *pkg, const char *metadata, const char *plist,
	}

	if ((pkg_parse_manifest_fileat(fd, pkg, "+MANIFEST")) != EPKG_OK) {
+
		pkg_emit_error("Error parsing %s/+MANIFEST", metadata);
		close(fd);
		return (EPKG_FATAL);
	}
modified libpkg/pkg_cudf.c
@@ -136,12 +136,12 @@ cudf_emit_pkg(struct pkg *pkg, int version, FILE *f,
	}

	column = 0;
-
	if (tll_length(pkg->provides) > 0) {
+
	if (vec_len(&pkg->provides) > 0) {
		if (fprintf(f, "provides: ") < 0)
			return (EPKG_FATAL);
-
		tll_foreach(pkg->provides, p) {
-
			if (cudf_print_element(f, p->item,
-
			    column + 1 == tll_length(pkg->provides), &column) < 0) {
+
		vec_foreach(pkg->provides, i) {
+
			if (cudf_print_element(f, pkg->provides.d[i],
+
			    column + 1 == vec_len(&pkg->provides), &column) < 0) {
				return (EPKG_FATAL);
			}
		}
@@ -350,7 +350,7 @@ pkg_jobs_cudf_insert_res_job (pkg_solved_list *target,
	if (it_old != NULL)
		res->items[1] = it_old;

-
	tll_push_back(*target, res);
+
	vec_push(target, res);
}

struct pkg_cudf_entry {
modified libpkg/pkg_delete.c
@@ -120,14 +120,14 @@ pkg_delete(struct pkg *pkg, struct pkg *rpkg, struct pkgdb *db, int flags,

	if ((flags & PKG_DELETE_UPGRADE) == 0) {
		pkg_emit_deinstall_finished(pkg);
-
		tll_foreach(pkg->message, m) {
-
			if (m->item->type == PKG_MESSAGE_REMOVE) {
+
		vec_foreach(pkg->message, i) {
+
			if (pkg->message.d[i]->type == PKG_MESSAGE_REMOVE) {
				if (message == NULL) {
					message = xstring_new();
					pkg_fprintf(message->fp, "Message from "
					    "%n-%v:\n", pkg, pkg);
				}
-
				fprintf(message->fp, "%s\n", m->item->str);
+
				fprintf(message->fp, "%s\n", pkg->message.d[i]->str);
			}
		}
		if (pkg_has_message(pkg) && message != NULL) {
@@ -167,21 +167,22 @@ pkg_add_dir_to_del(struct pkg *pkg, const char *file, const char *dir)
		path[len] = '\0';
	}

-
	tll_foreach(pkg->dir_to_del, d) {
-
		len2 = strlen(d->item);
-
		if (len2 >= len && strncmp(path, d->item, len) == 0)
+
	vec_foreach(pkg->dir_to_del, i) {
+
		len2 = strlen(pkg->dir_to_del.d[i]);
+
		if (len2 >= len && strncmp(path, pkg->dir_to_del.d[i], len) == 0)
			return;

-
		if (strncmp(path, d->item, len2) == 0) {
+
		if (strncmp(path, pkg->dir_to_del.d[i], len2) == 0) {
			pkg_debug(1, "Replacing in deletion %s with %s",
-
			    d->item, path);
-
			tll_remove_and_free(pkg->dir_to_del, d, free);
-
			break;
+
			    pkg->dir_to_del.d[i], path);
+
			free(pkg->dir_to_del.d[i]);
+
			pkg->dir_to_del.d[i] = xstrdup(path);
+
			return;
		}
	}

	pkg_debug(1, "Adding to deletion %s", path);
-
	tll_push_back(pkg->dir_to_del, xstrdup(path));
+
	vec_push(&pkg->dir_to_del, xstrdup(path));
}

static void
@@ -272,9 +273,8 @@ pkg_effective_rmdir(struct pkgdb *db, struct pkg *pkg)
	char prefix_r[MAXPATHLEN];

	snprintf(prefix_r, sizeof(prefix_r), "%s", pkg->prefix[0] ? pkg->prefix + 1 : "");
-
	tll_foreach(pkg->dir_to_del, d) {
-
		rmdir_p(db, pkg, d->item, prefix_r);
-
		tll_remove_and_free(pkg->dir_to_del, d, free);
+
	vec_foreach(pkg->dir_to_del, i) {
+
		rmdir_p(db, pkg, pkg->dir_to_del.d[i], prefix_r);
	}
}

@@ -408,7 +408,7 @@ pkg_delete_dir(struct pkg *pkg, struct pkg_dir *dir)
	if ((strncmp(prefix_rel, path, len) == 0) && path[len] == '/') {
		pkg_add_dir_to_del(pkg, NULL, path);
	} else {
-
		tll_push_back(pkg->dir_to_del, xstrdup(path));
+
		vec_push(&pkg->dir_to_del, xstrdup(path));
	}
}

modified libpkg/pkg_jobs.c
@@ -67,7 +67,6 @@
#include "private/pkg.h"
#include "private/pkgdb.h"
#include "private/pkg_jobs.h"
-
#include "tllist.h"

extern struct pkg_ctx ctx;

@@ -81,7 +80,7 @@ struct pkg_jobs_locked {
	void *context;
};
static __thread struct pkg_jobs_locked *pkgs_job_lockedpkg;
-
typedef tll(int64_t) candidates_t;
+
typedef vec_t(int64_t) candidates_t;

#define IS_DELETE(j) ((j)->type == PKG_JOBS_DEINSTALL || (j)->type == PKG_JOBS_AUTOREMOVE)

@@ -119,8 +118,7 @@ pkg_jobs_set_flags(struct pkg_jobs *j, pkg_flags flags)
int
pkg_jobs_set_repository(struct pkg_jobs *j, const char *ident)
{
-
	c_charv_t idents;
-
	vec_init(&idents);
+
	c_charv_t idents = vec_init();
	if (ident != NULL)
		vec_push(&idents, ident);
	return (pkg_jobs_set_repositories(j, &idents));
@@ -206,10 +204,10 @@ pkg_jobs_free(struct pkg_jobs *j)
	j->request_delete = NULL;

	pkg_jobs_universe_free(j->universe);
-
	tll_free_and_free(j->jobs, free);
+
	vec_free_and_free(&j->jobs, free);
	LL_FREE(j->patterns, pkg_jobs_pattern_free);
	if (j->triggers.cleanup != NULL) {
-
		tll_free_and_free(*j->triggers.cleanup, trigger_free);
+
		vec_free_and_free(j->triggers.cleanup, trigger_free);
		free(j->triggers.cleanup);
	}
	if (j->triggers.dfd != -1)
@@ -218,7 +216,7 @@ pkg_jobs_free(struct pkg_jobs *j)
		ucl_object_unref(j->triggers.schema);
	pkghash_destroy(j->orphaned);
	pkghash_destroy(j->notorphaned);
-
	pkghash_destroy(j->system_shlibs);
+
	vec_free_and_free(&j->system_shlibs, free);
	free(j);
}

@@ -308,26 +306,28 @@ pkg_jobs_iter(struct pkg_jobs *j, void **iter,
{
	struct pkg_solved *s;
	struct {
-
		typeof(*(j->jobs.head)) *it;
+
		pkg_solved_list *list;
+
		size_t pos;
	} *t;
	t = *iter;
	if (*iter == NULL) {
		t = xcalloc(1, sizeof(*t));
		*iter = t;
-
	} else if (t->it == NULL) {
+
	} else if (t->pos >= t->list->len) {
			free(t);
			return (false);
	}

-
	if (tll_length(j->jobs) == 0)
+
	if (j->jobs.len == 0)
		return (false);
-
	if (t->it == NULL)
-
		t->it = j->jobs.head;
-
	s = t->it->item;
+
	if (t->list == NULL) {
+
		t->list = &j->jobs;
+
		t->pos = 0;
+
	}
+
	s = t->list->d[t->pos++];
	*new = s->items[0]->pkg;
	*old = s->items[1] ? s->items[1]->pkg : NULL;
	*type = s->type;
-
	t->it = t->it->next;
	return (true);
}

@@ -456,7 +456,7 @@ pkg_jobs_add_req(struct pkg_jobs *j, struct pkg *pkg)
}

static bool
-
append_to_del_request(struct pkg_jobs *j, pkg_chain_t *to_process, const char *uid, const char *reqname)
+
append_to_del_request(struct pkg_jobs *j, pkgs_t *to_process, const char *uid, const char *reqname)
{
	struct pkg *p;

@@ -468,7 +468,7 @@ append_to_del_request(struct pkg_jobs *j, pkg_chain_t *to_process, const char *u
		   reqname);
		return (false);
	}
-
	tll_push_back(*to_process, p);
+
	vec_push(to_process, p);
	return (true);
}

@@ -476,7 +476,7 @@ bool
delete_process_provides(struct pkg_jobs *j, struct pkg *lp, const char *provide,
    struct pkgdb_it *(*provideq)(struct pkgdb *db, const char *req),
    struct pkgdb_it *(*requireq)(struct pkgdb *db, const char *req),
-
    pkg_chain_t *to_process)
+
    pkgs_t *to_process)
{
	struct pkgdb_it *lit, *rit;
	struct pkg *pkg;
@@ -484,7 +484,7 @@ delete_process_provides(struct pkg_jobs *j, struct pkg *lp, const char *provide,
	bool ret = true;

	/* check for pkgbase shlibs and provides */
-
	if (pkghash_get(j->system_shlibs, provide) != NULL)
+
	if (charv_search(&j->system_shlibs, provide) != NULL)
		return (ret);
	/* if something else to provide the same thing we can safely delete */
	lit = provideq(j->db, provide);
@@ -537,7 +537,7 @@ pkg_jobs_process_delete_request(struct pkg_jobs *j)
	struct pkg_dep *d = NULL;
	struct pkg *lp;
	int rc = EPKG_OK;
-
	pkg_chain_t to_process = tll_init();
+
	pkgs_t to_process = vec_init();
	pkghash_it it;

	if (force)
@@ -560,15 +560,15 @@ pkg_jobs_process_delete_request(struct pkg_jobs *j)
				rc = EPKG_FATAL;
		}

-
		tll_foreach(lp->provides, i) {
-
			if (!delete_process_provides(j, lp, i->item,
+
		vec_foreach(lp->provides, i) {
+
			if (!delete_process_provides(j, lp, lp->provides.d[i],
			    pkgdb_query_provide, pkgdb_query_require,
			    &to_process))
				rc = EPKG_FATAL;
		}

-
		tll_foreach(lp->shlibs_provided, i) {
-
			if (!delete_process_provides(j, lp, i->item,
+
		vec_foreach(lp->shlibs_provided, i) {
+
			if (!delete_process_provides(j, lp, lp->shlibs_provided.d[i],
			    pkgdb_query_shlib_provide,
			    pkgdb_query_shlib_require, &to_process))
				rc = EPKG_FATAL;
@@ -578,17 +578,17 @@ pkg_jobs_process_delete_request(struct pkg_jobs *j)
	if (rc == EPKG_FATAL)
		return (rc);

-
	tll_foreach(to_process, pit) {
-
		lp = pit->item;
+
	vec_foreach(to_process, pit) {
+
		lp = to_process.d[pit];
		if (pkg_jobs_add_req(j, lp) == NULL) {
-
			tll_free(to_process);
+
			vec_free(&to_process);
			return (EPKG_FATAL);
		}
	}

-
	if (tll_length(to_process) > 0)
+
	if (vec_len(&to_process) > 0)
		rc = pkg_jobs_process_delete_request(j);
-
	tll_free(to_process);
+
	vec_free(&to_process);

	return (rc);
}
@@ -661,8 +661,8 @@ pkg_jobs_test_automatic(struct pkg_jobs *j, struct pkg *p)
			return (false);
	}

-
	tll_foreach(p->provides, i) {
-
		it = pkgdb_query_require(j->db, i->item);
+
	vec_foreach(p->provides, i) {
+
		it = pkgdb_query_require(j->db, p->provides.d[i]);
		if (it == NULL)
			continue;
		npkg = NULL;
@@ -676,8 +676,8 @@ pkg_jobs_test_automatic(struct pkg_jobs *j, struct pkg *p)
		pkgdb_it_free(it);
	}

-
	tll_foreach(p->shlibs_provided, i) {
-
		it = pkgdb_query_shlib_require(j->db, i->item);
+
	vec_foreach(p->shlibs_provided, i) {
+
		it = pkgdb_query_shlib_require(j->db, p->shlibs_provided.d[i]);
		if (it == NULL)
			continue;
		npkg = NULL;
@@ -1050,14 +1050,12 @@ pkg_jobs_find_remote_pattern(struct pkg_jobs *j, struct job_pattern *jp)
}

bool
-
pkg_jobs_need_upgrade(struct pkghash *system_shlibs, struct pkg *rp, struct pkg *lp)
+
pkg_jobs_need_upgrade(charv_t *system_shlibs, struct pkg *rp, struct pkg *lp)
{
	int ret, ret1, ret2;
	struct pkg_option *lo = NULL, *ro = NULL;
	struct pkg_dep *ld = NULL, *rd = NULL;
	struct pkg_conflict *lc = NULL, *rc = NULL;
-
	const char **l1;
-
	size_t i;

	/* If no local package, then rp is obviously need to be added */
	if (lp == NULL)
@@ -1178,116 +1176,77 @@ pkg_jobs_need_upgrade(struct pkghash *system_shlibs, struct pkg *rp, struct pkg
	}

	/* Provides */
-
	if (tll_length(rp->provides) != tll_length(lp->provides)) {
+
	if (vec_len(&rp->provides) != vec_len(&lp->provides)) {
		free(rp->reason);
		rp->reason = xstrdup("provides changed");
		return (true);
	}
-
	l1 = xcalloc(tll_length(lp->provides), sizeof (char*));
-
	i = 0;
-
	tll_foreach(lp->provides, l) {
-
		l1[i++] = l->item;
-
	}
-
	i = 0;
-
	tll_foreach(rp->provides, r) {
-
		if (!STREQ(r->item, l1[i])) {
+
	pkg_lists_sort(lp);
+
	pkg_lists_sort(rp);
+

+
	vec_foreach(lp->provides, i) {
+
		if (!STREQ(lp->provides.d[i], rp->provides.d[i])) {
			free(rp->reason);
			rp->reason = xstrdup("provides changed");
-
			free(l1);
			return (true);
		}
	}
-
	free(l1);

	/* Requires */
-
	if (tll_length(rp->requires) != tll_length(lp->requires)) {
+
	if (vec_len(&rp->requires) != vec_len(&lp->requires)) {
		free(rp->reason);
		rp->reason = xstrdup("requires changed");
		return (true);
	}
-
	l1 = xcalloc(tll_length(lp->requires), sizeof (char*));
-
	i = 0;
-
	tll_foreach(lp->requires, l) {
-
		l1[i++] = l->item;
-
	}
-
	i = 0;
-
	tll_foreach(rp->requires, r) {
-
		if (!STREQ(r->item, l1[i])) {
+
	vec_foreach(lp->requires, i) {
+
		if (!STREQ(lp->requires.d[i], rp->requires.d[i])) {
			free(rp->reason);
			rp->reason = xstrdup("requires changed");
-
			free(l1);
			return (true);
		}
	}
-
	free(l1);

	/* Finish by the shlibs */
-
	if (tll_length(rp->shlibs_provided) != tll_length(lp->shlibs_provided)) {
+
	if (vec_len(&rp->shlibs_provided) != vec_len(&lp->shlibs_provided)) {
		free(rp->reason);
		rp->reason = xstrdup("provided shared library changed");
		return (true);
	}
-
	l1 = xcalloc(tll_length(lp->shlibs_provided), sizeof (char*));
-
	i = 0;
-
	tll_foreach(lp->shlibs_provided, l) {
-
		l1[i++] = l->item;
-
	}
-
	i = 0;
-
	tll_foreach(rp->shlibs_provided, r) {
-
		if (!STREQ(r->item, l1[i])) {
+
	vec_foreach(lp->shlibs_provided, i) {
+
		if (!STREQ(lp->shlibs_provided.d[i], rp->shlibs_provided.d[i])) {
			free(rp->reason);
			rp->reason = xstrdup("provided shared library changed");
-
			free(l1);
			return (true);
		}
-
		i++;
	}
-
	free(l1);

-
	size_t cntr = tll_length(rp->shlibs_required);
-
	size_t cntl = tll_length(lp->shlibs_required);
-
	if (cntr != cntl) {
+
	size_t cntr = vec_len(&rp->shlibs_required);
+
	size_t cntl = vec_len(&lp->shlibs_required);
+
	if (cntr != cntl & system_shlibs == NULL) {
+
		free(rp->reason);
+
		rp->reason = xstrdup("required shared library changed");
+
		return (true);
+
	}
+
	size_t i, j;
+

+
	for (i = 0, j = 0; i < cntl && j < cntr; i++, j++) {
+
		if (STREQ(lp->shlibs_required.d[i], rp->shlibs_required.d[j]))
+
				continue;
		if (system_shlibs != NULL) {
-
		/*
-
		 * before considering shlibs we need to check if we are running
-
		 * pkgbase
-
		 */
-
			tll_foreach(rp->shlibs_required, r) {
-
				if (pkghash_get(system_shlibs, r->item) != NULL)
-
					cntr--;
+
			if (charv_search(system_shlibs, lp->shlibs_required.d[i]) != NULL) {
+
				j--;
+
				continue;
			}
-
			tll_foreach(lp->shlibs_required, l) {
-
				if (pkghash_get(system_shlibs, l->item) != NULL)
-
					cntl--;
+
			if (charv_search(system_shlibs, rp->shlibs_required.d[j]) != NULL) {
+
				i++;
+
				continue;
			}
		}
-
		if (cntr != cntl) {
-
			free(rp->reason);
-
			rp->reason = xstrdup("required shared library changed");
-
			return (true);
-
		}
-
	}
-
	l1 = xcalloc(tll_length(lp->shlibs_required), sizeof (char*));
-
	i = 0;
-
	tll_foreach(lp->shlibs_required, l) {
-
		if (pkghash_get(system_shlibs, l->item) != NULL)
-
			continue;
-
		l1[i++] = l->item;
-
	}
-
	i = 0;
-
	tll_foreach(rp->shlibs_required, r) {
-
		if (pkghash_get(system_shlibs, r->item) != NULL)
-
			continue;
-
		if (!STREQ(r->item, l1[i])) {
-
			free(rp->reason);
-
			rp->reason = xstrdup("required shared library changed");
-
			free(l1);
-
			return (true);
-
		}
-
		i++;
+
		free(rp->reason);
+
		rp->reason = xstrdup("required shared library changed");
+
		return (true);
+
		break;
	}
-
	free(l1);
-

	return (false);
}

@@ -1405,8 +1364,8 @@ pkg_jobs_set_deinstall_reasons(struct pkg_jobs *j)
	struct pkg_job_request *jreq;
	struct pkg *req_pkg, *pkg;

-
	tll_foreach(j->jobs, it) {
-
		sit = it->item;
+
	vec_foreach(j->jobs, i) {
+
		sit = j->jobs.d[i];
		jreq = pkg_jobs_find_deinstall_request(sit->items[0], j, 0);
		if (jreq != NULL && jreq->item->unit != sit->items[0]) {
			req_pkg = jreq->item->pkg;
@@ -1546,7 +1505,7 @@ pkg_jobs_find_install_candidates(struct pkg_jobs *j)

		if ((j->flags & PKG_FLAG_FORCE) ||
						pkg_jobs_check_remote_candidate(j, pkg)) {
-
			tll_push_front(*candidates, pkg->id);
+
			vec_push(candidates, pkg->id);
		}
		pkg_free(pkg);
		pkg = NULL;
@@ -1573,15 +1532,15 @@ jobs_solve_full_upgrade(struct pkg_jobs *j)
	assert(!j->solved);

	candidates = pkg_jobs_find_install_candidates(j);
-
	jcount = tll_length(*candidates);
+
	jcount = candidates->len;

	pkg_emit_progress_start("Checking for upgrades (%zd candidates)",
			jcount);

-
	tll_foreach(*candidates, c) {
+
	vec_foreach(*candidates, i) {
		pkg_emit_progress_tick(++elt_num, jcount);
		sqlite3_snprintf(sizeof(sqlbuf), sqlbuf, " WHERE p.id=%" PRId64,
-
		    c->item);
+
		    candidates->d[i]);
		if ((it = pkgdb_query_cond(j->db, sqlbuf, NULL, MATCH_ALL)) == NULL)
			return (EPKG_FATAL);

@@ -1593,7 +1552,7 @@ jobs_solve_full_upgrade(struct pkg_jobs *j)
		pkg_free(pkg);
		pkgdb_it_free(it);
	}
-
	tll_free(*candidates);
+
	vec_free(candidates);
	free(candidates);
	pkg_emit_progress_tick(jcount, jcount);

@@ -1919,7 +1878,7 @@ pkg_jobs_solve(struct pkg_jobs *j)
{
	int ret;

-
	if (j->system_shlibs == NULL) {
+
	if (j->system_shlibs.len == 0) {
		/* If /usr/bin/uname is in the pkg database, we are targeting
		 * a pkgbase system and should rely on the pkgbase packages to
		 * provide system shlibs. */
@@ -1942,10 +1901,10 @@ pkg_jobs_solve(struct pkg_jobs *j)
	 * conflicts if we can check for and solve conflicts without first
	 * needing to fetch.
	 */
-
	tll_foreach(j->jobs, job) {
+
	vec_foreach(j->jobs, i) {
		struct pkg *p;

-
		p = ((struct pkg_solved *)job->item)->items[0]->pkg;
+
		p = ((struct pkg_solved *)j->jobs.d[i])->items[0]->pkg;
		if (p->type != PKG_REMOTE)
			continue;

@@ -1964,7 +1923,7 @@ pkg_jobs_solve(struct pkg_jobs *j)
			rc = pkg_jobs_check_conflicts(j);
			if (rc == EPKG_CONFLICT) {
				/* Cleanup results */
-
				tll_free_and_free(j->jobs, free);
+
				vec_free_and_free(&j->jobs, free);
				has_conflicts = true;
				pkg_jobs_solve(j);
			}
@@ -1982,7 +1941,7 @@ pkg_jobs_count(struct pkg_jobs *j)
{
	assert(j != NULL);

-
	return (tll_length(j->jobs));
+
	return (j->jobs.len);
}

int
@@ -2128,9 +2087,9 @@ pkg_jobs_execute(struct pkg_jobs *j)
	if (retcode != EPKG_OK)
		return (retcode);

-
	total_actions = tll_length(j->jobs);
-
	tll_foreach(j->jobs, _p) {
-
		struct pkg_solved *ps = _p->item;
+
	total_actions = j->jobs.len;
+
	vec_foreach(j->jobs, i) {
+
		struct pkg_solved *ps = j->jobs.d[i];

		pkg_emit_new_action(++current_action, total_actions);
		switch (ps->type) {
@@ -2222,7 +2181,7 @@ pkg_jobs_apply(struct pkg_jobs *j)
						rc = pkg_jobs_check_conflicts(j);
						if (rc == EPKG_CONFLICT) {
							/* Cleanup results */
-
							tll_free_and_free(j->jobs, free);
+
							vec_free_and_free(&j->jobs, free);
							has_conflicts = true;
							rc = pkg_jobs_solve(j);
						}
@@ -2283,8 +2242,8 @@ pkg_jobs_fetch(struct pkg_jobs *j)
		cachedir = j->destdir;

	/* check for available size to fetch */
-
	tll_foreach(j->jobs, _p) {
-
		struct pkg_solved *ps = _p->item;
+
	vec_foreach(j->jobs, i) {
+
		struct pkg_solved *ps = j->jobs.d[i];
		if (ps->type != PKG_SOLVED_DELETE && ps->type != PKG_SOLVED_UPGRADE_REMOVE) {
			p = ps->items[0]->pkg;
			if (p->type != PKG_REMOTE)
@@ -2349,8 +2308,8 @@ pkg_jobs_fetch(struct pkg_jobs *j)
		return (EPKG_OK); /* don't download anything */

	/* Fetch */
-
	tll_foreach(j->jobs, _p) {
-
		struct pkg_solved *ps = _p->item;
+
	vec_foreach(j->jobs, i) {
+
		struct pkg_solved *ps = j->jobs.d[i];
		if (ps->type != PKG_SOLVED_DELETE && ps->type != PKG_SOLVED_UPGRADE_REMOVE) {
			p = ps->items[0]->pkg;
			if (p->type != PKG_REMOTE)
@@ -2381,8 +2340,8 @@ pkg_jobs_check_conflicts(struct pkg_jobs *j)
	pkg_emit_integritycheck_begin();
	j->conflicts_registered = 0;

-
	tll_foreach(j->jobs, _p) {
-
		struct pkg_solved *ps = _p->item;
+
	vec_foreach(j->jobs, i) {
+
		struct pkg_solved *ps = j->jobs.d[i];
		if (ps->type == PKG_SOLVED_DELETE || ps->type == PKG_SOLVED_UPGRADE_REMOVE) {
			continue;
		}
modified libpkg/pkg_jobs_conflicts.c
@@ -37,7 +37,7 @@
#include "private/pkg_jobs.h"
#include "siphash.h"

-
typedef tll(struct pkg_job_request *) conflict_chain_t;
+
typedef vec_t(struct pkg_job_request *) conflict_chain_t;

TREE_DEFINE(pkg_jobs_conflict_item, entry);

@@ -55,8 +55,10 @@ pkg_conflicts_sipkey_init(void)
}

static int
-
pkg_conflicts_chain_cmp_cb(struct pkg_job_request *a, struct pkg_job_request *b)
+
pkg_conflicts_chain_cmp(const void *jra, const void *jrb)
{
+
	const struct pkg_job_request *a = *(const struct pkg_job_request **)jra;
+
	const struct pkg_job_request *b = *(const struct pkg_job_request **)jrb;
	const char *vera, *verb;

	if (a->skip || b->skip) {
@@ -80,11 +82,11 @@ pkg_conflicts_request_resolve_chain(struct pkg *req, conflict_chain_t *chain)
	 * First of all prefer pure origins, where the last element of
	 * an origin is pkg name
	 */
-
	tll_foreach(*chain, e) {
-
		slash_pos = strrchr(e->item->item->pkg->origin, '/');
+
	vec_foreach(*chain, i) {
+
		slash_pos = strrchr(chain->d[i]->item->pkg->origin, '/');
		if (slash_pos != NULL) {
			if (STREQ(slash_pos + 1, req->name)) {
-
				selected = e->item;
+
				selected = chain->d[i];
				break;
			}
		}
@@ -93,16 +95,16 @@ pkg_conflicts_request_resolve_chain(struct pkg *req, conflict_chain_t *chain)
	if (selected == NULL) {
		/* XXX: add manual selection here */
		/* Sort list by version of package */
-
		tll_sort(*chain, pkg_conflicts_chain_cmp_cb);
-
		selected = tll_front(*chain);
+
		qsort(chain->d, chain->len, sizeof(chain->d[0]), pkg_conflicts_chain_cmp);
+
		selected = chain->d[0];
	}

	pkg_debug(2, "select %s in the chain of conflicts for %s",
	    selected->item->pkg->name, req->name);
	/* Disable conflicts from a request */
-
	tll_foreach(*chain, e) {
-
		if (e->item != selected)
-
			e->item->skip = true;
+
	vec_foreach(*chain, i) {
+
		if (chain->d[i] != selected)
+
			chain->d[i]->skip = true;
	}

	return (EPKG_OK);
@@ -119,7 +121,7 @@ pkg_conflicts_request_resolve(struct pkg_jobs *j)
	it = pkghash_iterator(j->request_add);
	while (pkghash_next(&it)) {
		req = it.value;
-
		conflict_chain_t  chain = tll_init();
+
		conflict_chain_t  chain = vec_init();
		if (req->skip)
			continue;

@@ -128,20 +130,20 @@ pkg_conflicts_request_resolve(struct pkg_jobs *j)
			if (unit != NULL) {
				found = pkghash_get_value(j->request_add, unit->pkg->uid);
				if (found != NULL && !found->skip) {
-
					tll_push_front(chain, found);
+
					vec_push(&chain, found);
				}
			}
		}
-
		if (tll_length(chain) > 0) {
+
		if (chain.len > 0) {
			/* Add package itself */
-
			tll_push_front(chain, req);
+
			vec_push(&chain, req);

			if (pkg_conflicts_request_resolve_chain(req->item->pkg, &chain) != EPKG_OK) {
-
				tll_free(chain);
+
				vec_free(&chain);
				return (EPKG_FATAL);
			}
		}
-
		tll_free(chain);
+
		vec_free(&chain);
	}

	return (EPKG_OK);
modified libpkg/pkg_jobs_schedule.c
@@ -26,7 +26,6 @@
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include <assert.h>
-
#include <tllist.h>

#include "pkg.h"
#include "private/event.h"
@@ -200,8 +199,10 @@ pkg_jobs_schedule_dbg_job(pkg_solved_list *jobs, struct pkg_solved *job)
	    job->items[0]->pkg->uid);

	debug_edges = true;
-
	tll_foreach(*jobs, it) {
-
		pkg_jobs_schedule_graph_edge(job, it->item);
+
	vec_foreach(*jobs, i) {
+
		if (jobs->d[i] == NULL)
+
			continue;
+
		pkg_jobs_schedule_graph_edge(job, jobs->d[i]);
	}
	debug_edges = false;
}
@@ -210,8 +211,10 @@ static bool
pkg_jobs_schedule_has_incoming_edge(pkg_solved_list *nodes,
    struct pkg_solved *node)
{
-
	tll_foreach(*nodes, it) {
-
		if (pkg_jobs_schedule_graph_edge(it->item, node)) {
+
	vec_foreach(*nodes, i) {
+
		if (nodes->d[i] == NULL)
+
			continue;
+
		if (pkg_jobs_schedule_graph_edge(nodes->d[i], node)) {
			return (true);
		}
	}
@@ -238,13 +241,16 @@ pkg_jobs_schedule_priority(struct pkg_solved *node)

/* This comparison function is used as a tiebreaker in the topological sort. */
static int
-
pkg_jobs_schedule_cmp_available(struct pkg_solved *a, struct pkg_solved *b)
+
pkg_jobs_schedule_cmp_available(const void *va, const void *vb)
{
+
	struct pkg_solved *a = *(struct pkg_solved **)va;
+
	struct pkg_solved *b = *(struct pkg_solved **)vb;
+

	int ret = pkg_jobs_schedule_priority(b) - pkg_jobs_schedule_priority(a);
	if (ret == 0) {
		/* Falling back to lexicographical ordering ensures that job execution
		 * order is always consistent and makes testing easier. */
-
		return strcmp(a->items[0]->pkg->uid, b->items[0]->pkg->uid);
+
		return strcmp(b->items[0]->pkg->uid, a->items[0]->pkg->uid);
	} else {
		return ret;
	}
@@ -254,34 +260,39 @@ pkg_jobs_schedule_cmp_available(struct pkg_solved *a, struct pkg_solved *b)
static void
pkg_jobs_schedule_topological_sort(pkg_solved_list *jobs)
{
-
	pkg_solved_list sorted = tll_init();
-
	pkg_solved_list available = tll_init();
+
	pkg_solved_list sorted = vec_init();
+
	pkg_solved_list available = vec_init();
+
	size_t left = jobs->len;

	/* Place all job nodes with no incoming edges in available */
-
	tll_foreach(*jobs, it) {
-
		if (!pkg_jobs_schedule_has_incoming_edge(jobs, it->item) &&
-
		    !pkg_jobs_schedule_has_incoming_edge(&available, it->item)) {
-
			tll_push_front(available, it->item);
-
			tll_remove(*jobs, it);
+
	vec_foreach(*jobs, i) {
+
		if (!pkg_jobs_schedule_has_incoming_edge(jobs, jobs->d[i]) &&
+
		    !pkg_jobs_schedule_has_incoming_edge(&available, jobs->d[i])) {
+
			vec_push(&available, jobs->d[i]);
+
			jobs->d[i] = NULL;
+
			left--;
		}
	}

-
	while (tll_length(available) > 0) {
+
	while (available.len > 0) {
		/* Add the highest priority job from the set of available jobs
		 * to the sorted list */
-
		tll_sort(available, pkg_jobs_schedule_cmp_available);
-
		struct pkg_solved *node = tll_pop_front(available);
-
		tll_push_back(sorted, node);
+
		qsort(available.d, available.len, sizeof(available.d[0]), pkg_jobs_schedule_cmp_available);
+
		struct pkg_solved *node = vec_pop(&available);
+
		vec_push(&sorted, node);

		/* Again, place all job nodes with no incoming edges in the set
		 * of available jobs, ignoring any incoming edges from job nodes
		 * already added to the sorted list */
-
		tll_foreach(*jobs, it) {
-
			if (pkg_jobs_schedule_graph_edge(node, it->item)) {
-
				if (!pkg_jobs_schedule_has_incoming_edge(jobs, it->item) &&
-
				    !pkg_jobs_schedule_has_incoming_edge(&available, it->item)) {
-
					tll_push_front(available, it->item);
-
					tll_remove(*jobs, it);
+
		vec_foreach(*jobs, i) {
+
			if (jobs->d[i] == NULL)
+
				continue;
+
			if (pkg_jobs_schedule_graph_edge(node, jobs->d[i])) {
+
				if (!pkg_jobs_schedule_has_incoming_edge(jobs, jobs->d[i]) &&
+
				    !pkg_jobs_schedule_has_incoming_edge(&available, jobs->d[i])) {
+
					vec_push(&available, jobs->d[i]);
+
					jobs->d[i] = NULL;
+
					left--;
				}
			}
		}
@@ -290,9 +301,11 @@ pkg_jobs_schedule_topological_sort(pkg_solved_list *jobs)
	/* The jobs list will only be non-empty at this point if there is a
	 * cycle in the graph and all cycles must be eliminated by splitting
	 * upgrade jobs before calling this function. */
-
	assert(tll_length(*jobs) == 0);
+
	assert(left == 0);

-
	*jobs = sorted;
+
	vec_free(&available);
+
	free(jobs->d);
+
	jobs->d = sorted.d;
}

/*
@@ -311,12 +324,12 @@ pkg_jobs_schedule_find_cycle(pkg_solved_list *jobs,
	node->path_next = *path;
	*path = node;

-
	tll_foreach(*jobs, it) {
-
		if (pkg_jobs_schedule_graph_edge(node, it->item)) {
-
			switch (it->item->mark){
+
	vec_foreach(*jobs, i) {
+
		if (pkg_jobs_schedule_graph_edge(node, jobs->d[i])) {
+
			switch (jobs->d[i]->mark){
			case PKG_SOLVED_CYCLE_MARK_NONE:;
				struct pkg_solved *cycle =
-
				    pkg_jobs_schedule_find_cycle(jobs, path, it->item);
+
				    pkg_jobs_schedule_find_cycle(jobs, path, jobs->d[i]);
				if (cycle != NULL) {
					return (cycle);
				}
@@ -324,7 +337,7 @@ pkg_jobs_schedule_find_cycle(pkg_solved_list *jobs,
			case PKG_SOLVED_CYCLE_MARK_DONE:
				break;
			case PKG_SOLVED_CYCLE_MARK_PATH:
-
				return (it->item); /* Found a cycle */
+
				return (jobs->d[i]); /* Found a cycle */
			default:
				assert(false);
			}
@@ -345,21 +358,21 @@ int pkg_jobs_schedule(struct pkg_jobs *j)
	while (true) {
		dbg(3, "checking job scheduling graph for cycles...");

-
		tll_foreach(j->jobs, it) {
-
			it->item->mark = PKG_SOLVED_CYCLE_MARK_NONE;
-
			it->item->path_next = NULL;
+
		vec_foreach(j->jobs, i) {
+
			j->jobs.d[i]->mark = PKG_SOLVED_CYCLE_MARK_NONE;
+
			j->jobs.d[i]->path_next = NULL;

-
			pkg_jobs_schedule_dbg_job(&j->jobs, it->item);
+
			pkg_jobs_schedule_dbg_job(&j->jobs, j->jobs.d[i]);
		}

		/* The graph may not be connected, in which case it is necessary to
		 * run multiple searches for cycles from different start nodes. */
		struct pkg_solved *path = NULL;
		struct pkg_solved *cycle = NULL;
-
		tll_foreach(j->jobs, it) {
-
			switch (it->item->mark) {
+
		vec_foreach(j->jobs, i) {
+
			switch (j->jobs.d[i]->mark) {
			case PKG_SOLVED_CYCLE_MARK_NONE:
-
				cycle = pkg_jobs_schedule_find_cycle(&j->jobs, &path, it->item);
+
				cycle = pkg_jobs_schedule_find_cycle(&j->jobs, &path, j->jobs.d[i]);
				break;
			case PKG_SOLVED_CYCLE_MARK_DONE:
				break;
@@ -409,7 +422,7 @@ int pkg_jobs_schedule(struct pkg_jobs *j)
		path->type = PKG_SOLVED_UPGRADE_INSTALL;
		path->items[1] = NULL;
		path->xlink = new;
-
		tll_push_back(j->jobs, new);
+
		vec_push(&j->jobs, new);
	}

	pkg_jobs_schedule_topological_sort(&j->jobs);
modified libpkg/pkg_jobs_universe.c
@@ -45,7 +45,6 @@
#include "private/pkg.h"
#include "private/pkgdb.h"
#include "private/pkg_jobs.h"
-
#include "tllist.h"

#define IS_DELETE(j) ((j)->type == PKG_JOBS_DEINSTALL || (j)->type == PKG_JOBS_AUTOREMOVE)

@@ -95,12 +94,12 @@ pkg_jobs_universe_get_local(struct pkg_jobs_universe *universe,
	return (pkg);
}

-
static pkg_chain_t *
+
static pkgs_t *
pkg_jobs_universe_get_remote(struct pkg_jobs_universe *universe,
	const char *uid, unsigned flag)
{
	struct pkg *pkg = NULL;
-
	pkg_chain_t *result = NULL;
+
	pkgs_t *result = NULL;
	struct pkgdb_it *it;
	struct pkg_job_universe_item *unit, *cur, *found;

@@ -136,8 +135,8 @@ pkg_jobs_universe_get_remote(struct pkg_jobs_universe *universe,

	while (pkgdb_it_next(it, &pkg, flag) == EPKG_OK) {
		if (result == NULL)
-
			result = xcalloc(1, sizeof(pkg_chain_t));
-
		tll_push_front(*result, pkg);
+
			result = xcalloc(1, sizeof(pkgs_t));
+
		vec_push(result, pkg);
		pkg = NULL;
	}

@@ -241,7 +240,7 @@ pkg_jobs_universe_process_deps(struct pkg_jobs_universe *universe,
	int rc;
	struct pkg_job_universe_item *unit;
	struct pkg *npkg, *rpkg, *lpkg;
-
	pkg_chain_t *rpkgs = NULL;
+
	pkgs_t *rpkgs = NULL;
	bool found = false;

	rpkg = NULL;
@@ -317,8 +316,8 @@ pkg_jobs_universe_process_deps(struct pkg_jobs_universe *universe,

		found = false;
		/* Iteration one */
-
		tll_foreach(*rpkgs, rit) {
-
			rpkg = rit->item;
+
		vec_rforeach(*rpkgs, i) {
+
			rpkg = rpkgs->d[i];

			if (pkg->reponame && rpkg->reponame &&
					STREQ(pkg->reponame, rpkg->reponame)) {
@@ -329,12 +328,12 @@ pkg_jobs_universe_process_deps(struct pkg_jobs_universe *universe,

		/* Fallback if a dependency is not found in the same repo */
		if (!found) {
-
			tll_foreach(*rpkgs, rit) {
-
				rpkg = rit->item;
+
			vec_rforeach(*rpkgs, i) {
+
				rpkg = rpkgs->d[i];

				if (npkg != NULL) {
					/* Set reason for upgrades */
-
					if (!pkg_jobs_need_upgrade(universe->j->system_shlibs, rpkg, npkg))
+
					if (!pkg_jobs_need_upgrade(&universe->j->system_shlibs, rpkg, npkg))
						continue;
					/* Save automatic flag */
					rpkg->automatic = npkg->automatic;
@@ -344,7 +343,7 @@ pkg_jobs_universe_process_deps(struct pkg_jobs_universe *universe,

				/* Special case if we cannot find any package */
				if (npkg == NULL && rc != EPKG_OK) {
-
					tll_free(*rpkgs);
+
					vec_free(rpkgs);
					free(rpkgs);
					return (rc);
				}
@@ -355,7 +354,7 @@ pkg_jobs_universe_process_deps(struct pkg_jobs_universe *universe,

			if (npkg != NULL) {
				/* Set reason for upgrades */
-
				if (!pkg_jobs_need_upgrade(universe->j->system_shlibs, rpkg, npkg))
+
				if (!pkg_jobs_need_upgrade(&universe->j->system_shlibs, rpkg, npkg))
					continue;
				/* Save automatic flag */
				rpkg->automatic = npkg->automatic;
@@ -363,13 +362,13 @@ pkg_jobs_universe_process_deps(struct pkg_jobs_universe *universe,

			rc = pkg_jobs_universe_process_item(universe, rpkg, NULL);
			if (npkg == NULL && rc != EPKG_OK) {
-
				tll_free(*rpkgs);
+
				vec_free(rpkgs);
				free(rpkgs);
				return (rc);
			}
		}

-
		tll_free(*rpkgs);
+
		vec_free(rpkgs);
		free(rpkgs);
	}

@@ -472,37 +471,38 @@ pkg_jobs_universe_process_shlibs(struct pkg_jobs_universe *universe,
	struct pkgdb_it *it;
	int rc;

-
	tll_foreach(pkg->shlibs_required, s) {
-
		if (pkghash_get(universe->j->system_shlibs, s->item) != NULL)
+
	vec_foreach(pkg->shlibs_required, i) {
+
		const char *s = pkg->shlibs_required.d[i];
+
		if (charv_search(&universe->j->system_shlibs, s) != NULL)
			continue;
-
		if (pkghash_get(universe->provides, s->item) != NULL)
+
		if (pkghash_get(universe->provides, s) != NULL)
			continue;

		/* Check for local provides */
-
		it = pkgdb_query_shlib_provide(universe->j->db, s->item);
+
		it = pkgdb_query_shlib_provide(universe->j->db, s);
		if (it != NULL) {
			rc = pkg_jobs_universe_handle_provide(universe, it,
-
			    s->item, true, pkg);
+
			    s, true, pkg);
			pkgdb_it_free(it);

			if (rc != EPKG_OK) {
				dbg(1, "cannot find local packages that provide library %s "
						"required for %s",
-
						s->item, pkg->name);
+
						s, pkg->name);
			}
		}
		/* Not found, search in the repos */
		it = pkgdb_repo_shlib_provide(universe->j->db,
-
			s->item, universe->j->reponames);
+
			s, universe->j->reponames);

		if (it != NULL) {
-
			rc = pkg_jobs_universe_handle_provide(universe, it, s->item, true, pkg);
+
			rc = pkg_jobs_universe_handle_provide(universe, it, s, true, pkg);
			pkgdb_it_free(it);

			if (rc != EPKG_OK) {
				dbg(1, "cannot find remote packages that provide library %s "
						"required for %s",
-
				    s->item, pkg->name);
+
				    s, pkg->name);
			}
		}
	}
@@ -517,35 +517,36 @@ pkg_jobs_universe_process_provides_requires(struct pkg_jobs_universe *universe,
	struct pkgdb_it *it;
	int rc;

-
	tll_foreach(pkg->requires, r) {
-
		if (pkghash_get(universe->provides, r->item) != NULL)
+
	vec_foreach(pkg->requires, i) {
+
		const char *r = pkg->requires.d[i];
+
		if (pkghash_get(universe->provides, r) != NULL)
			continue;

		/* Check for local provides */
-
		it = pkgdb_query_provide(universe->j->db, r->item);
+
		it = pkgdb_query_provide(universe->j->db, r);
		if (it != NULL) {
-
			rc = pkg_jobs_universe_handle_provide(universe, it, r->item, false, pkg);
+
			rc = pkg_jobs_universe_handle_provide(universe, it, r, false, pkg);
			pkgdb_it_free(it);

			if (rc != EPKG_OK) {
				dbg(1, "cannot find local packages that provide %s "
						"required for %s",
-
						r->item, pkg->name);
+
						r, pkg->name);
			}
		}

		/* Not found, search in the repos */
		it = pkgdb_repo_provide(universe->j->db,
-
			r->item, universe->j->reponames);
+
			r, universe->j->reponames);

		if (it != NULL) {
-
			rc = pkg_jobs_universe_handle_provide(universe, it, r->item, false, pkg);
+
			rc = pkg_jobs_universe_handle_provide(universe, it, r, false, pkg);
			pkgdb_it_free(it);

			if (rc != EPKG_OK) {
				dbg(1, "cannot find remote packages that provide %s "
						"required for %s",
-
				    r->item, pkg->name);
+
				    r, pkg->name);
				return (rc);
			}
		}
@@ -980,7 +981,7 @@ pkg_jobs_universe_get_upgrade_candidates(struct pkg_jobs_universe *universe,
					PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES|
					PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|
					PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
-
	tll(struct pkg *) candidates = tll_init();
+
	pkgs_t candidates = vec_init();

	unit = pkghash_get_value(universe->items, uid);
	if (unit != NULL) {
@@ -1019,12 +1020,12 @@ pkg_jobs_universe_get_upgrade_candidates(struct pkg_jobs_universe *universe,
		}
		else {
			if (selected == lp &&
-
					(lp == NULL || pkg_jobs_need_upgrade(universe->j->system_shlibs, pkg, lp)))
+
					(lp == NULL || pkg_jobs_need_upgrade(&universe->j->system_shlibs, pkg, lp)))
				selected = pkg;
			else if (pkg_version_change_between(pkg, selected) == PKG_UPGRADE)
				selected = pkg;
		}
-
		tll_push_front(candidates, pkg);
+
		vec_push(&candidates, pkg);
		pkg = NULL;
	}

@@ -1036,17 +1037,17 @@ pkg_jobs_universe_get_upgrade_candidates(struct pkg_jobs_universe *universe,
	}
	if (selected != lp) {
		/* We need to add the whole chain of upgrade candidates */
-
		tll_foreach(candidates, cit) {
-
			pkg_jobs_universe_add_pkg(universe, cit->item, force, NULL);
+
		vec_rforeach(candidates, i) {
+
			pkg_jobs_universe_add_pkg(universe, candidates.d[i], force, NULL);
		}
	}
	else {
-
		tll_free_and_free(candidates, pkg_free);
+
		vec_free_and_free(&candidates, pkg_free);
		return (NULL);
	}

	unit = pkghash_get_value(universe->items, uid);
-
	tll_free(candidates);
+
	vec_free(&candidates);

	return (unit);
}
modified libpkg/pkg_manifest.c
@@ -1,29 +1,9 @@
/*-
-
 * Copyright (c) 2011-2023 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2013-2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
-
 * All rights reserved.
 *
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 *
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <sys/types.h>
@@ -983,10 +963,10 @@ pkg_emit_object(struct pkg *pkg, short flags)

	dbg(4, "Emitting licenses");
	seq = NULL;
-
	tll_foreach(pkg->licenses, l) {
+
	vec_foreach(pkg->licenses, i) {
		if (seq == NULL)
			seq = ucl_object_typed_new(UCL_ARRAY);
-
		ucl_array_append(seq, ucl_object_fromstring(l->item));
+
		ucl_array_append(seq, ucl_object_fromstring(pkg->licenses.d[i]));
	}
	if (seq)
		ucl_object_insert_key(top, seq, "licenses", 8, false);
@@ -1018,50 +998,50 @@ pkg_emit_object(struct pkg *pkg, short flags)

	dbg(4, "Emitting categories");
	seq = NULL;
-
	tll_foreach(pkg->categories, c) {
+
	vec_foreach(pkg->categories, i) {
		if (seq == NULL)
			seq = ucl_object_typed_new(UCL_ARRAY);
-
		ucl_array_append(seq, ucl_object_fromstring(c->item));
+
		ucl_array_append(seq, ucl_object_fromstring(pkg->categories.d[i]));
	}
	if (seq)
		ucl_object_insert_key(top, seq, "categories", 10, false);

	dbg(4, "Emitting users");
	seq = NULL;
-
	tll_foreach(pkg->users, u) {
+
	vec_foreach(pkg->users, i) {
		if (seq == NULL)
			seq = ucl_object_typed_new(UCL_ARRAY);
-
		ucl_array_append(seq, ucl_object_fromstring(u->item));
+
		ucl_array_append(seq, ucl_object_fromstring(pkg->users.d[i]));
	}
	if (seq)
		ucl_object_insert_key(top, seq, "users", 5, false);

	dbg(4, "Emitting groups");
	seq = NULL;
-
	tll_foreach(pkg->groups, g) {
+
	vec_foreach(pkg->groups, i) {
		if (seq == NULL)
			seq = ucl_object_typed_new(UCL_ARRAY);
-
		ucl_array_append(seq, ucl_object_fromstring(g->item));
+
		ucl_array_append(seq, ucl_object_fromstring(pkg->groups.d[i]));
	}
	if (seq)
		ucl_object_insert_key(top, seq, "groups", 6, false);

	dbg(4, "Emitting shibs_required");
	seq = NULL;
-
	tll_foreach(pkg->shlibs_required, s) {
+
	vec_foreach(pkg->shlibs_required, i) {
		if (seq == NULL)
			seq = ucl_object_typed_new(UCL_ARRAY);
-
		ucl_array_append(seq, ucl_object_fromstring(s->item));
+
		ucl_array_append(seq, ucl_object_fromstring(pkg->shlibs_required.d[i]));
	}
	if (seq)
		ucl_object_insert_key(top, seq, "shlibs_required", 15, false);

	dbg(4, "Emitting shlibs_provided");
	seq = NULL;
-
	tll_foreach(pkg->shlibs_provided, s) {
+
	vec_foreach(pkg->shlibs_provided, i) {
		if (seq == NULL)
			seq = ucl_object_typed_new(UCL_ARRAY);
-
		ucl_array_append(seq, ucl_object_fromstring(s->item));
+
		ucl_array_append(seq, ucl_object_fromstring(pkg->shlibs_provided.d[i]));
	}
	if (seq)
		ucl_object_insert_key(top, seq, "shlibs_provided", 15, false);
@@ -1078,20 +1058,20 @@ pkg_emit_object(struct pkg *pkg, short flags)

	dbg(4, "Emitting provides");
	seq = NULL;
-
	tll_foreach(pkg->provides, p) {
+
	vec_foreach(pkg->provides, i) {
		if (seq == NULL)
			seq = ucl_object_typed_new(UCL_ARRAY);
-
		ucl_array_append(seq, ucl_object_fromstring(p->item));
+
		ucl_array_append(seq, ucl_object_fromstring(pkg->provides.d[i]));
	}
	if (seq)
		ucl_object_insert_key(top, seq, "provides", 8, false);

	dbg(4, "Emitting requires");
	seq = NULL;
-
	tll_foreach(pkg->requires, r) {
+
	vec_foreach(pkg->requires, i) {
		if (seq == NULL)
			seq = ucl_object_typed_new(UCL_ARRAY);
-
		ucl_array_append(seq, ucl_object_fromstring(r->item));
+
		ucl_array_append(seq, ucl_object_fromstring(pkg->requires.d[i]));
	}
	if (seq)
		ucl_object_insert_key(top, seq, "requires", 8, false);
@@ -1110,8 +1090,8 @@ pkg_emit_object(struct pkg *pkg, short flags)
		ucl_object_insert_key(top, map, "options", 7, false);

	map = NULL;
-
	tll_foreach(pkg->annotations, k) {
-
		kv = k->item;
+
	vec_foreach(pkg->annotations, i) {
+
		kv = pkg->annotations.d[i];
		if (map == NULL)
			map = ucl_object_typed_new(UCL_OBJECT);
		/* Add annotations except for internal ones. */
@@ -1220,7 +1200,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
		dbg(4, "Emitting lua scripts");
		map = NULL;
		for (i = 0; i < PKG_NUM_LUA_SCRIPTS; i++) {
-
			if (tll_length(pkg->lua_scripts[i]) == 0)
+
			if (vec_len(&pkg->lua_scripts[i]) == 0)
				continue;
			switch(i) {
			case PKG_LUA_PRE_INSTALL:
modified libpkg/pkg_ports.c
@@ -518,7 +518,7 @@ populate_keywords(struct plist *p)
		a = xmalloc(sizeof(struct action));
		k->keyword = xstrdup(keyacts[i].key);
		a->perform = keyacts[i].action;
-
		tll_push_back(k->actions, a);
+
		vec_push(&k->actions, a);
		pkghash_safe_add(p->keywords, k->keyword, k, NULL);
	}
}
@@ -527,7 +527,7 @@ static void
keyword_free(struct keyword *k)
{
	free(k->keyword);
-
	tll_free_and_free(k->actions, free);
+
	vec_free_and_free(&k->actions, free);
	free(k);
}

@@ -707,7 +707,7 @@ apply_keyword_file(ucl_object_t *obj, struct plist *p, char *line, struct file_a
				else if (STRIEQ(ucl_object_tostring(elt), "upgrade"))
					msg->type = PKG_MESSAGE_UPGRADE;
			}
-
			tll_push_back(p->pkg->message, msg);
+
			vec_push(&p->pkg->message, msg);
		}
	}

@@ -907,8 +907,8 @@ parse_keywords(struct plist *plist, char *keyword,

	k = pkghash_get_value(plist->keywords, keyword);
	if (k != NULL) {
-
		tll_foreach(k->actions, a) {
-
			ret = a->item->perform(plist, line, attr);
+
		vec_foreach(k->actions, i) {
+
			ret = k->actions.d[i]->perform(plist, line, attr);
			if (ret != EPKG_OK)
				break;
		}
@@ -1048,7 +1048,6 @@ plist_new(struct pkg *pkg, const char *stage)
	p->post_install_buf = xstring_new();
	p->pre_deinstall_buf = xstring_new();
	p->post_deinstall_buf = xstring_new();
-
	vec_init(&p->hardlinks);

	populate_keywords(p);

@@ -1091,7 +1090,7 @@ expand_plist_variables(const char *in, kvlist_t *vars)
	const char *cp;
	size_t len;

-
	if (tll_length(*vars) == 0)
+
	if (vec_len(vars) == 0)
		return (xstrdup(in));

	buf = xstring_new();
@@ -1129,10 +1128,10 @@ expand_plist_variables(const char *in, kvlist_t *vars)
		len = in - cp -1;
		/* we have a variable */
		bool found = false;
-
		tll_foreach(*vars, i) {
-
			if (strncmp(cp, i->item->key, len) != 0)
+
		vec_foreach(*vars, i) {
+
			if (strncmp(cp, vars->d[i]->key, len) != 0)
				continue;
-
			fputs(i->item->value, buf->fp);
+
			fputs(vars->d[i]->value, buf->fp);
			found = true;
			in++;
			break;
@@ -1209,15 +1208,15 @@ add_variable(struct plist *p, char *line, struct file_attr *a __unused)
	while (*val != '\0' && isspace(*val))
		val++;

-
	tll_foreach(p->variables, v) {
-
		if (STREQ(v->item->key, key)) {
-
			free(v->item->value);
-
			v->item->value = xstrdup(val);
+
	vec_foreach(p->variables, i) {
+
		if (STREQ(p->variables.d[i]->key, key)) {
+
			free(p->variables.d[i]->value);
+
			p->variables.d[i]->value = xstrdup(val);
			return (EPKG_OK);
		}
	}
	struct pkg_kv *kv = pkg_kv_new(key, val);
-
	tll_push_back(p->variables, kv);
+
	vec_push(&p->variables, kv);
	return (EPKG_OK);
}

@@ -1355,10 +1354,10 @@ pkg_add_port(struct pkgdb *db, struct pkg *pkg, const char *input_path,
		pkg_emit_install_finished(pkg, NULL);
		if (pkg_has_message(pkg))
			message = xstring_new();
-
		tll_foreach(pkg->message, m) {
-
			if (m->item->type == PKG_MESSAGE_ALWAYS ||
-
			    m->item->type == PKG_MESSAGE_INSTALL) {
-
				fprintf(message->fp, "%s\n", m->item->str);
+
		vec_foreach(pkg->message, i) {
+
			if (pkg->message.d[i]->type == PKG_MESSAGE_ALWAYS ||
+
			    pkg->message.d[i]->type == PKG_MESSAGE_INSTALL) {
+
				fprintf(message->fp, "%s\n", pkg->message.d[i]->str);
			}
		}
		if (pkg_has_message(pkg)) {
modified libpkg/pkg_printf.c
@@ -860,20 +860,20 @@ format_annotations(xstring *buf, const void *data, struct percent_esc *p)
	int			count;

	if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) {
-
		return (list_count(buf, tll_length(pkg->annotations), p));
+
		return (list_count(buf, vec_len(&pkg->annotations), p));
	} else {
		set_list_defaults(p, "%An: %Av\n", "");

		count = 1;
		fflush(p->sep_fmt->fp);
		fflush(p->item_fmt->fp);
-
		tll_foreach(pkg->annotations, k) {
+
		vec_foreach(pkg->annotations, i) {
			if (count > 1)
				iterate_item(buf, pkg, p->sep_fmt->buf,
-
					     k->item, count, PP_A);
+
					     pkg->annotations.d[i], count, PP_A);

			iterate_item(buf, pkg, p->item_fmt->buf,
-
				     k->item, count, PP_A);
+
				     pkg->annotations.d[i], count, PP_A);
			count++;
		}
	}
@@ -913,7 +913,7 @@ format_shlibs_required(xstring *buf, const void *data, struct percent_esc *p)
	const struct pkg	*pkg = data;

	if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
-
		return (list_count(buf, tll_length(pkg->shlibs_required), p));
+
		return (list_count(buf, vec_len(&pkg->shlibs_required), p));
	else {
		int			 count;

@@ -922,13 +922,13 @@ format_shlibs_required(xstring *buf, const void *data, struct percent_esc *p)
		count = 1;
		fflush(p->sep_fmt->fp);
		fflush(p->item_fmt->fp);
-
		tll_foreach(pkg->shlibs_required, r) {
+
		vec_foreach(pkg->shlibs_required, i) {
			if (count > 1)
				iterate_item(buf, pkg, p->sep_fmt->buf,
-
					     r->item, count, PP_B);
+
					     pkg->shlibs_required.d[i], count, PP_B);

			iterate_item(buf, pkg, p->item_fmt->buf,
-
				     r->item, count, PP_B);
+
				     pkg->shlibs_required.d[i], count, PP_B);
			count++;
		}
	}
@@ -960,19 +960,19 @@ format_categories(xstring *buf, const void *data, struct percent_esc *p)
	int			 count = 0;

	if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) {
-
		return (list_count(buf, tll_length(pkg->categories), p));
+
		return (list_count(buf, vec_len(&pkg->categories), p));
	} else {
		set_list_defaults(p, "%Cn", ", ");

		count = 1;
		fflush(p->sep_fmt->fp);
		fflush(p->item_fmt->fp);
-
		tll_foreach(pkg->categories, c) {
+
		vec_foreach(pkg->categories, i) {
			if (count > 1)
				iterate_item(buf, pkg, p->sep_fmt->buf,
-
				    c->item, count, PP_C);
+
				    pkg->categories.d[i], count, PP_C);

-
			iterate_item(buf, pkg, p->item_fmt->buf, c->item,
+
			iterate_item(buf, pkg, p->item_fmt->buf, pkg->categories.d[i],
			    count, PP_C);
			count++;
		}
@@ -1175,7 +1175,7 @@ format_groups(xstring *buf, const void *data, struct percent_esc *p)
	const struct pkg	*pkg = data;

	if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
-
		return (list_count(buf, tll_length(pkg->groups), p));
+
		return (list_count(buf, vec_len(&pkg->groups), p));
	else {
		int	 count;

@@ -1184,13 +1184,13 @@ format_groups(xstring *buf, const void *data, struct percent_esc *p)
		count = 1;
		fflush(p->sep_fmt->fp);
		fflush(p->item_fmt->fp);
-
		tll_foreach(pkg->groups, g) {
+
		vec_foreach(pkg->groups, i) {
			if (count > 1)
				iterate_item(buf, pkg, p->sep_fmt->buf,
-
					     g->item, count, PP_G);
+
					     pkg->groups.d[i], count, PP_G);

			iterate_item(buf, pkg,p->item_fmt->buf,
-
				     g->item, count, PP_G);
+
				     pkg->groups.d[i], count, PP_G);
			count++;
		}
	}
@@ -1231,19 +1231,19 @@ format_licenses(xstring *buf, const void *data, struct percent_esc *p)
	int			 count = 0;

	if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) {
-
		return (list_count(buf, tll_length(pkg->licenses), p));
+
		return (list_count(buf, vec_len(&pkg->licenses), p));
	} else {
		set_list_defaults(p, "%Ln", " %l ");

		count = 1;
		fflush(p->sep_fmt->fp);
		fflush(p->item_fmt->fp);
-
		tll_foreach(pkg->licenses, l) {
+
		vec_foreach(pkg->licenses, i) {
			if (count > 1)
				iterate_item(buf, pkg, p->sep_fmt->buf,
-
				    l->item, count, PP_L);
+
				    pkg->licenses.d[i], count, PP_L);

-
			iterate_item(buf, pkg, p->item_fmt->buf, l->item,
+
			iterate_item(buf, pkg, p->item_fmt->buf, pkg->licenses.d[i],
			    count, PP_L);
			count++;
		}
@@ -1273,8 +1273,8 @@ format_message(xstring *buffer, const void *data, struct percent_esc *p)
	struct pkg_message	*msg;
	char			*message;

-
	tll_foreach(pkg->message, m) {
-
		msg = m->item;
+
	vec_foreach(pkg->message, i) {
+
		msg = pkg->message.d[i];
		if (bufmsg == NULL) {
			bufmsg = xstring_new();
		} else {
@@ -1461,7 +1461,7 @@ format_users(xstring *buf, const void *data, struct percent_esc *p)
	const struct pkg	*pkg = data;

	if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
-
		return (list_count(buf, tll_length(pkg->users), p));
+
		return (list_count(buf, vec_len(&pkg->users), p));
	else {
		int	 count;

@@ -1470,13 +1470,13 @@ format_users(xstring *buf, const void *data, struct percent_esc *p)
		count = 1;
		fflush(p->sep_fmt->fp);
		fflush(p->item_fmt->fp);
-
		tll_foreach(pkg->users, u) {
+
		vec_foreach(pkg->users, i) {
			if (count > 1)
				iterate_item(buf, pkg, p->sep_fmt->buf,
-
					     u->item, count, PP_U);
+
					     pkg->users.d[i], count, PP_U);

			iterate_item(buf, pkg, p->item_fmt->buf,
-
				     u->item, count, PP_U);
+
				     pkg->users.d[i], count, PP_U);
			count++;
		}
	}
@@ -1527,7 +1527,7 @@ format_required(xstring *buf, const void *data, struct percent_esc *p)
	const struct pkg	*pkg = data;

	if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
-
		return (list_count(buf, tll_length(pkg->requires), p));
+
		return (list_count(buf, vec_len(&pkg->requires), p));
	else {
		int	 count;

@@ -1536,13 +1536,13 @@ format_required(xstring *buf, const void *data, struct percent_esc *p)
		count = 1;
		fflush(p->sep_fmt->fp);
		fflush(p->item_fmt->fp);
-
		tll_foreach(pkg->requires, r) {
+
		vec_foreach(pkg->requires, i) {
			if (count > 1)
				iterate_item(buf, pkg, p->sep_fmt->buf,
-
					     r->item, count, PP_Y);
+
					     pkg->requires.d[i], count, PP_Y);

			iterate_item(buf, pkg, p->item_fmt->buf,
-
				     r->item, count, PP_Y);
+
				     pkg->requires.d[i], count, PP_Y);
			count++;
		}
	}
@@ -1584,7 +1584,7 @@ format_shlibs_provided(xstring *buf, const void *data, struct percent_esc *p)
	const struct pkg	*pkg = data;

	if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
-
		return (list_count(buf, tll_length(pkg->shlibs_provided), p));
+
		return (list_count(buf, vec_len(&pkg->shlibs_provided), p));
	else {
		int	 count;

@@ -1593,13 +1593,13 @@ format_shlibs_provided(xstring *buf, const void *data, struct percent_esc *p)
		count = 1;
		fflush(p->sep_fmt->fp);
		fflush(p->item_fmt->fp);
-
		tll_foreach(pkg->shlibs_provided, r) {
+
		vec_foreach(pkg->shlibs_provided, i) {
			if (count > 1)
				iterate_item(buf, pkg, p->sep_fmt->buf,
-
					     r->item, count, PP_b);
+
					     pkg->shlibs_provided.d[i], count, PP_b);

			iterate_item(buf, pkg, p->item_fmt->buf,
-
				     r->item, count, PP_b);
+
				     pkg->shlibs_provided.d[i], count, PP_b);
			count++;
		}
	}
@@ -1925,7 +1925,7 @@ format_provided(xstring *buf, const void *data, struct percent_esc *p)
	const struct pkg	*pkg = data;

	if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
-
		return (list_count(buf, tll_length(pkg->provides), p));
+
		return (list_count(buf, vec_len(&pkg->provides), p));
	else {
		int	 count;

@@ -1934,13 +1934,13 @@ format_provided(xstring *buf, const void *data, struct percent_esc *p)
		count = 1;
		fflush(p->sep_fmt->fp);
		fflush(p->item_fmt->fp);
-
		tll_foreach(pkg->provides, r) {
+
		vec_foreach(pkg->provides, i) {
			if (count > 1)
				iterate_item(buf, pkg, p->sep_fmt->buf,
-
					     r->item, count, PP_y);
+
					     pkg->provides.d[i], count, PP_y);

			iterate_item(buf, pkg, p->item_fmt->buf,
-
				     r->item, count, PP_y);
+
				     pkg->provides.d[i], count, PP_y);
			count++;
		}
	}
modified libpkg/pkg_repo_create.c
@@ -1,5 +1,5 @@
/*-
-
 * Copyright (c) 2011-2024 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
 * Copyright (c) 2012-2013 Matthew Seaman <matthew@FreeBSD.org>
@@ -7,27 +7,9 @@
 * Copyright (c) 2023-2024 Serenity Cyber Security, LLC
 *                         Author: Gleb Popov <arrowd@FreeBSD.org>
 *
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 *
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 * SPDX-License-Identifier: BSD-2-Clause
 */
+

#include "pkg_config.h"

#include <sys/types.h>
@@ -52,7 +34,6 @@
#include <fcntl.h>
#include <dirent.h>

-
#include "tllist.h"
#include "pkg.h"
#include "private/event.h"
#include "private/utils.h"
@@ -156,7 +137,7 @@ struct pkg_fts_item {
	off_t fts_size;
	int fts_info;
};
-
typedef tll(struct pkg_fts_item *) fts_item_t;
+
typedef vec_t(struct pkg_fts_item *) fts_item_t;

static struct pkg_fts_item*
pkg_create_repo_fts_new(FTSENT *fts, const char *root_path)
@@ -274,7 +255,7 @@ pkg_create_repo_read_fts(fts_item_t *items, FTS *fts,
		if (fts_cur == NULL)
			return (EPKG_FATAL);

-
		tll_push_front(*items, fts_cur);
+
		vec_push(items, fts_cur);
		(*plen) ++;
	}

@@ -321,11 +302,11 @@ pkg_create_repo_thread(void *arg)
		if (items != NULL)
			pkg_create_repo_fts_free(items);
		pthread_mutex_lock(&te->llock);
-
		if (tll_length(te->fts_items) == 0) {
+
		if (te->fts_items.len == 0) {
			pthread_mutex_unlock(&te->llock);
			goto cleanup;
		}
-
		items = tll_pop_front(te->fts_items);
+
		items = vec_pop(&te->fts_items);
		pthread_mutex_unlock(&te->llock);
		path = items->fts_accpath;
		repopath = items->pkg_path;
@@ -935,7 +916,7 @@ cleanup:
	if (fts != NULL)
		fts_close(fts);

-
	tll_free_and_free(te.fts_items, pkg_create_repo_fts_free);
+
	vec_free_and_free(&te.fts_items, pkg_create_repo_fts_free);

	if (retcode != EPKG_OK)
		return (retcode);
modified libpkg/pkg_solve.c
@@ -37,7 +37,6 @@
#include <string.h>
#include <ctype.h>
#include <math.h>
-
#include <tllist.h>

#include "pkg.h"
#include "pkghash.h"
@@ -105,7 +104,7 @@ struct pkg_solve_rule {

struct pkg_solve_problem {
	struct pkg_jobs *j;
-
	tll(struct pkg_solve_rule *) rules;
+
	vec_t(struct pkg_solve_rule *) rules;
	pkghash *variables_by_uid;
	struct pkg_solve_variable *variables;
	PicoSAT *sat;
@@ -179,7 +178,7 @@ pkg_solve_rule_free(struct pkg_solve_rule *rule)
void
pkg_solve_problem_free(struct pkg_solve_problem *problem)
{
-
	tll_free_and_free(problem->rules, pkg_solve_rule_free);
+
	vec_free_and_free(&problem->rules, pkg_solve_rule_free);
	pkghash_destroy(problem->variables_by_uid);
	picosat_reset(problem->sat);
	free(problem->variables);
@@ -308,7 +307,7 @@ pkg_solve_handle_provide (struct pkg_solve_problem *problem,
		pkg = curvar->unit->pkg;

		if (pr->is_shlib) {
-
			libfound = stringlist_contains(&pkg->shlibs_provided, pr->provide);
+
			libfound = (charv_search(&pkg->shlibs_provided, pr->provide) != NULL);
			/* Skip incompatible ABI as well */
			if (libfound && !STREQ(pkg->abi, orig->abi)) {
				dbg(2, "require %s: package %s-%s(%c) provides wrong ABI %s, "
@@ -318,7 +317,7 @@ pkg_solve_handle_provide (struct pkg_solve_problem *problem,
			}
		}
		else {
-
			providefound = stringlist_contains(&pkg->provides, pr->provide);
+
			providefound = (charv_search(&pkg->provides, pr->provide) != NULL);
		}

		if (!providefound && !libfound) {
@@ -389,7 +388,7 @@ pkg_solve_add_depend_rule(struct pkg_solve_problem *problem,
		return (EPKG_FATAL);
	}

-
	tll_push_front(problem->rules, rule);
+
	vec_push(&problem->rules, rule);

	return (EPKG_OK);
}
@@ -449,7 +448,7 @@ pkg_solve_add_conflict_rule(struct pkg_solve_problem *problem,
		/* !Bx */
		pkg_solve_item_new(rule, curvar, -1);

-
		tll_push_front(problem->rules, rule);
+
		vec_push(&problem->rules, rule);
	}

	return (EPKG_OK);
@@ -488,7 +487,7 @@ pkg_solve_add_require_rule(struct pkg_solve_problem *problem,
		}

		if (cnt > 1) {
-
			tll_push_front(problem->rules, rule);
+
			vec_push(&problem->rules, rule);
		}
		else {
			/* Missing dependencies... */
@@ -543,7 +542,7 @@ pkg_solve_add_vital_rule(struct pkg_solve_problem *problem,
	}

	if (rule)
-
		tll_push_front(problem->rules, rule);
+
		vec_push(&problem->rules, rule);

	return (EPKG_OK);
}
@@ -608,7 +607,7 @@ pkg_solve_add_request_rule(struct pkg_solve_problem *problem,
	}

	if (cnt > 1 && var->unit->inhash != 0) {
-
		tll_push_front(problem->rules, rule);
+
		vec_push(&problem->rules, rule);
		/* Also need to add pairs of conflicts */
		LL_FOREACH(req->item, item) {
			curvar = pkg_solve_find_var_in_chain(var, item->unit);
@@ -625,7 +624,7 @@ pkg_solve_add_request_rule(struct pkg_solve_problem *problem,
				/* !Bx */
				pkg_solve_item_new(rule, confvar, -1);

-
				tll_push_front(problem->rules, rule);
+
				vec_push(&problem->rules, rule);
			}
		}
	}
@@ -667,7 +666,7 @@ pkg_solve_add_chain_rule(struct pkg_solve_problem *problem,
			/* !Ay */
			pkg_solve_item_new(rule, confvar, -1);

-
			tll_push_front(problem->rules, rule);
+
			vec_push(&problem->rules, rule);
		}
	}

@@ -721,22 +720,23 @@ pkg_solve_process_universe_variable(struct pkg_solve_problem *problem,
		}

		/* Shlibs */
-
		tll_foreach(pkg->shlibs_required, s) {
+
		vec_foreach(pkg->shlibs_required, i) {
+
			const char *s = pkg->shlibs_required.d[i];
			/* Ignore 32 bit libraries */
-
			if (j->ignore_compat32 && str_ends_with(s->item, ":32"))
+
			if (j->ignore_compat32 && str_ends_with(s, ":32"))
				continue;
-
			if (pkghash_get(j->system_shlibs, s->item) != NULL) {
+
			if (charv_search(&j->system_shlibs, s) != NULL) {
				/* The shlib is provided by the system */
				continue;
			}
			if (pkg_solve_add_require_rule(problem, cur_var,
-
			    s->item, cur_var->assumed_reponame) != EPKG_OK) {
+
			    s, cur_var->assumed_reponame) != EPKG_OK) {
				continue;
			}
		}
-
		tll_foreach(pkg->requires, r) {
+
		vec_foreach(pkg->requires, i) {
			if (pkg_solve_add_require_rule(problem, cur_var,
-
			    r->item, cur_var->assumed_reponame) != EPKG_OK) {
+
			    pkg->requires.d[i], cur_var->assumed_reponame) != EPKG_OK) {
				continue;
			}
		}
@@ -842,7 +842,7 @@ pkg_solve_jobs_to_sat(struct pkg_jobs *j)
		        return (NULL);
	}

-
	if (tll_length(problem->rules) == 0)
+
	if (problem->rules.len == 0)
		dbg(1, "problem has no requests");

	return (problem);
@@ -986,7 +986,7 @@ pkg_solve_set_initial_assumption(struct pkg_solve_problem *problem,
			    conservative, assumed_reponame, true);

			if (local && (STREQ(selected->pkg->digest, local->pkg->digest) ||
-
				      !pkg_jobs_need_upgrade(problem->j->system_shlibs, selected->pkg, local->pkg))) {
+
				      !pkg_jobs_need_upgrade(&problem->j->system_shlibs, selected->pkg, local->pkg))) {
				selected = local;
			}
		}
@@ -1035,8 +1035,8 @@ pkg_solve_sat_problem(struct pkg_solve_problem *problem)
	int attempt = 0;
	struct pkg_solve_variable *var;

-
	tll_foreach(problem->rules, it) {
-
		rule = it->item;
+
	vec_rforeach(problem->rules, j) {
+
		rule = problem->rules.d[j];

		LL_FOREACH(rule->items, item) {
			picosat_add(problem->sat, item->var->order * item->inverse);
@@ -1046,8 +1046,8 @@ pkg_solve_sat_problem(struct pkg_solve_problem *problem)
		pkg_debug_print_rule(rule);
	}

-
	tll_foreach(problem->rules, it) {
-
		rule = it->item;
+
	vec_rforeach(problem->rules, j) {
+
		rule = problem->rules.d[j];
		pkg_solve_set_initial_assumption(problem, rule);
	}

@@ -1079,8 +1079,8 @@ reiterate:

			while (*failed) {
				var = &problem->variables[abs(*failed) - 1];
-
				tll_foreach(problem->rules, it) {
-
					rule = it->item;
+
				vec_rforeach(problem->rules, j) {
+
					rule = problem->rules.d[j];

					if (rule->reason != PKG_RULE_DEPEND) {
						LL_FOREACH(rule->items, item) {
@@ -1226,8 +1226,8 @@ pkg_solve_dot_export(struct pkg_solve_problem *problem, FILE *file)

	/* Print all variables as nodes */

-
	tll_foreach(problem->rules, rit) {
-
		rule = rit->item;
+
	vec_rforeach(problem->rules, j) {
+
		rule = problem->rules.d[j];
		struct pkg_solve_item *it = rule->items, *key_elt = NULL;

		switch(rule->reason) {
@@ -1283,10 +1283,10 @@ pkg_solve_dimacs_export(struct pkg_solve_problem *problem, FILE *f)
	struct pkg_solve_rule *rule;
	struct pkg_solve_item *it;

-
	fprintf(f, "p cnf %d %zu\n", (int)problem->nvars, tll_length(problem->rules));
+
	fprintf(f, "p cnf %d %zu\n", (int)problem->nvars, problem->rules.len);

-
	tll_foreach(problem->rules, rit) {
-
		rule = rit->item;
+
	vec_rforeach(problem->rules, i) {
+
		rule = problem->rules.d[i];
		LL_FOREACH(rule->items, it) {
			size_t order = it->var - problem->variables;
			if (order < problem->nvars)
@@ -1332,7 +1332,7 @@ pkg_solve_insert_res_job (struct pkg_solve_variable *var,
				res->items[0] = add_var->unit;
				res->type = (j->type == PKG_JOBS_FETCH) ?
								PKG_SOLVED_FETCH : PKG_SOLVED_INSTALL;
-
				tll_push_back(j->jobs, res);
+
				vec_push(&j->jobs, res);
				dbg(3, "pkg_solve: schedule installation of %s %s",
					add_var->uid, add_var->digest);
			}
@@ -1341,7 +1341,7 @@ pkg_solve_insert_res_job (struct pkg_solve_variable *var,
				res->items[0] = add_var->unit;
				res->items[1] = del_var->unit;
				res->type = PKG_SOLVED_UPGRADE;
-
				tll_push_back(j->jobs, res);
+
				vec_push(&j->jobs, res);
				dbg(3, "pkg_solve: schedule upgrade of %s from %s to %s",
					del_var->uid, del_var->digest, add_var->digest);
			}
@@ -1361,7 +1361,7 @@ pkg_solve_insert_res_job (struct pkg_solve_variable *var,
				res = xcalloc(1, sizeof(struct pkg_solved));
				res->items[0] = cur_var->unit;
				res->type = PKG_SOLVED_DELETE;
-
				tll_push_back(j->jobs, res);
+
				vec_push(&j->jobs, res);
				dbg(3, "schedule deletion of %s %s",
					cur_var->uid, cur_var->digest);
			}
modified libpkg/pkgbase.c
@@ -24,17 +24,17 @@
#include "xmalloc.h"

struct pkgbase {
-
	struct pkghash *system_shlibs;
+
	charv_t system_shlibs;
	/*
	 * unused yet but will be in the future when we will start using
	 * provides/requires in pkgbase
	 */
-
	struct pkghash *provides;
+
	charv_t provides;
	bool ignore_compat32;
};

static int
-
scan_dir_for_shlibs(pkghash **shlib_list, const char *dir,
+
scan_dir_for_shlibs(charv_t *shlib_list, const char *dir,
    enum pkg_shlib_flags flags)
{
	DIR *dirp= opendir(dir);
@@ -74,9 +74,8 @@ scan_dir_for_shlibs(pkghash **shlib_list, const char *dir,

		/* We have a valid shared library name. */
		char *full = pkg_shlib_name_with_flags(dp->d_name, flags);
-
		pkghash_safe_add(*shlib_list, full, NULL, NULL);
+
		vec_push(shlib_list, full);
		cnt++;
-
		free(full);
	}
	if (cnt == 0)
		errno = ENOENT;
@@ -96,7 +95,7 @@ static struct {
};

int
-
scan_system_shlibs(pkghash **system_shlibs, const char *rootdir)
+
scan_system_shlibs(charv_t *system_shlibs, const char *rootdir)
{
	int r = EPKG_OK;
	for (int i = 0; i < NELEM(system_shlib_table); i++) {
@@ -115,6 +114,8 @@ scan_system_shlibs(pkghash **system_shlibs, const char *rootdir)
			return (ret);
		}
	}
+
	if (system_shlibs->d)
+
		qsort(system_shlibs->d, system_shlibs->len, sizeof(char *), char_cmp);

	return (r);
}
@@ -136,8 +137,8 @@ pkgbase_free(struct pkgbase *pb)
{
	if (pb == NULL)
		return;
-
	pkghash_destroy(pb->system_shlibs);
-
	pkghash_destroy(pb->provides);
+
	vec_free_and_free(&pb->system_shlibs, free);
+
	vec_free_and_free(&pb->provides, free);
	free(pb);
}

@@ -146,11 +147,11 @@ pkgbase_provide_shlib(struct pkgbase *pb, const char *shlib)
{
	if (pb->ignore_compat32 && str_ends_with(shlib, ":32"))
		return (true);
-
	return (pkghash_get(pb->system_shlibs, shlib) != NULL);
+
	return (charv_search(&pb->system_shlibs, shlib) != NULL);
}

bool
pkgbase_provide(struct pkgbase *pb, const char *provide)
{
-
	return (pkghash_get(pb->provides, provide) != NULL);
+
	return (charv_search(&pb->provides, provide) != NULL);
}
modified libpkg/pkgdb.c
@@ -1,5 +1,5 @@
/*-
-
 * Copyright (c) 2011-2024 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2011 Will Andrews <will@FreeBSD.org>
 * Copyright (c) 2011 Philippe Pepiot <phil@philpep.org>
@@ -50,7 +50,6 @@
#include "private/pkgdb.h"
#include "private/utils.h"
#include "private/pkg_deps.h"
-
#include "tllist.h"
#include "pkg/vec.h"

#include "private/db_upgrades.h"
@@ -847,7 +846,7 @@ pkgdb_open_repos(struct pkgdb *db, const char *reponame)
			/* We need read only access here */
			if (r->ops->open(r, R_OK) == EPKG_OK) {
				r->ops->init(r);
-
				tll_push_front(db->repos, r);
+
				vec_push(&db->repos, r);
			} else
				pkg_emit_error("Repository %s cannot be opened."
				    " 'pkg update' required", r->name);
@@ -993,10 +992,9 @@ pkgdb_nfs_corruption(sqlite3 *db)
int
pkgdb_open_all(struct pkgdb **db_p, pkgdb_t type, const char *reponame)
{
-
	c_charv_t r;
+
	c_charv_t r = vec_init();
	int ret;

-
	vec_init(&r);
	if (reponame != NULL)
		vec_push(&r, reponame);

@@ -1147,7 +1145,7 @@ pkgdb_close(struct pkgdb *db)

	if (db->sqlite != NULL) {

-
		tll_free_and_free(db->repos, pkgdb_free_repo);
+
		vec_free_and_free(&db->repos, pkgdb_free_repo);

		if (!sqlite3_db_readonly(db->sqlite, "main"))
			pkg_plugins_hook_run(PKG_PLUGIN_HOOK_PKGDB_CLOSE_RW, NULL, db);
@@ -1818,7 +1816,7 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg, int forced,
			goto cleanup;
		}
		if ((ret = run_prstmt(DIRS2, package_id, dir->path,
-
		    true)) != SQLITE_DONE) {
+
		    (int64_t)true)) != SQLITE_DONE) {
			if (ret == SQLITE_CONSTRAINT) {
				pkg_emit_error("Another package is already "
				    "providing directory: %s",
@@ -1833,10 +1831,10 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg, int forced,
	 * Insert categories
	 */

-
	tll_foreach(pkg->categories, c) {
-
		ret = run_prstmt(CATEGORY1, c->item);
+
	vec_foreach(pkg->categories, i) {
+
		ret = run_prstmt(CATEGORY1, pkg->categories.d[i]);
		if (ret == SQLITE_DONE)
-
			ret = run_prstmt(CATEGORY2, package_id, c->item);
+
			ret = run_prstmt(CATEGORY2, package_id, pkg->categories.d[i]);
		if (ret != SQLITE_DONE) {
			ERROR_STMT_SQLITE(s, STMT(CATEGORY2));
			goto cleanup;
@@ -1847,11 +1845,11 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg, int forced,
	 * Insert licenses
	 */

-
	tll_foreach(pkg->licenses, l) {
-
		if (run_prstmt(LICENSES1, l->item)
+
	vec_foreach(pkg->licenses, i) {
+
		if (run_prstmt(LICENSES1, pkg->licenses.d[i])
		    != SQLITE_DONE
		    ||
-
		    run_prstmt(LICENSES2, package_id, l->item)
+
		    run_prstmt(LICENSES2, package_id, pkg->licenses.d[i])
		    != SQLITE_DONE) {
			ERROR_STMT_SQLITE(s, STMT(LICENSES2));
			goto cleanup;
@@ -1862,11 +1860,11 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg, int forced,
	 * Insert users
	 */

-
	tll_foreach(pkg->users, u) {
-
		if (run_prstmt(USERS1, u->item)
+
	vec_foreach(pkg->users, i) {
+
		if (run_prstmt(USERS1, pkg->users.d[i])
		    != SQLITE_DONE
		    ||
-
		    run_prstmt(USERS2, package_id, u->item)
+
		    run_prstmt(USERS2, package_id, pkg->users.d[i])
		    != SQLITE_DONE) {
			ERROR_STMT_SQLITE(s, STMT(USERS2));
			goto cleanup;
@@ -1877,11 +1875,11 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg, int forced,
	 * Insert groups
	 */

-
	tll_foreach(pkg->groups, g) {
-
		if (run_prstmt(GROUPS1, g->item)
+
	vec_foreach(pkg->groups, i) {
+
		if (run_prstmt(GROUPS1, pkg->groups.d[i])
		    != SQLITE_DONE
		    ||
-
		    run_prstmt(GROUPS2, package_id, g->item)
+
		    run_prstmt(GROUPS2, package_id, pkg->groups.d[i])
		    != SQLITE_DONE) {
			ERROR_STMT_SQLITE(s, STMT(GROUPS2));
			goto cleanup;
@@ -1986,10 +1984,10 @@ pkgdb_insert_lua_scripts(struct pkg *pkg, int64_t package_id, sqlite3 *s)
	int64_t			 i;

	for (i = 0; i < PKG_NUM_LUA_SCRIPTS; i++) {
-
		tll_foreach(pkg->lua_scripts[i], script) {
-
			if (run_prstmt(LUASCRIPT1, script->item) != SQLITE_DONE
+
		vec_foreach(pkg->lua_scripts[i], j) {
+
			if (run_prstmt(LUASCRIPT1, pkg->lua_scripts[i].d[j]) != SQLITE_DONE
			    ||
-
			    run_prstmt(LUASCRIPT2, script->item, package_id, i) != SQLITE_DONE) {
+
			    run_prstmt(LUASCRIPT2, pkg->lua_scripts[i].d[j], package_id, i) != SQLITE_DONE) {
				ERROR_STMT_SQLITE(s, STMT(LUASCRIPT2));
				return (EPKG_FATAL);
			}
@@ -2001,11 +1999,11 @@ pkgdb_insert_lua_scripts(struct pkg *pkg, int64_t package_id, sqlite3 *s)
int
pkgdb_update_shlibs_required(struct pkg *pkg, int64_t package_id, sqlite3 *s)
{
-
	tll_foreach(pkg->shlibs_required, r) {
-
		if (run_prstmt(SHLIBS1, r->item)
+
	vec_foreach(pkg->shlibs_required, i) {
+
		if (run_prstmt(SHLIBS1, pkg->shlibs_required.d[i])
		    != SQLITE_DONE
		    ||
-
		    run_prstmt(SHLIBS_REQD, package_id, r->item)
+
		    run_prstmt(SHLIBS_REQD, package_id, pkg->shlibs_required.d[i])
		    != SQLITE_DONE) {
			ERROR_STMT_SQLITE(s, STMT(SHLIBS_REQD));
			return (EPKG_FATAL);
@@ -2034,11 +2032,11 @@ pkgdb_update_config_file_content(struct pkg *p, sqlite3 *s)
int
pkgdb_update_shlibs_provided(struct pkg *pkg, int64_t package_id, sqlite3 *s)
{
-
	tll_foreach(pkg->shlibs_provided, r) {
-
		if (run_prstmt(SHLIBS1, r->item)
+
	vec_foreach(pkg->shlibs_provided, i) {
+
		if (run_prstmt(SHLIBS1, pkg->shlibs_provided.d[i])
		    != SQLITE_DONE
		    ||
-
		    run_prstmt(SHLIBS_PROV, package_id, r->item)
+
		    run_prstmt(SHLIBS_PROV, package_id, pkg->shlibs_provided.d[i])
		    != SQLITE_DONE) {
			ERROR_STMT_SQLITE(s, STMT(SHLIBS_PROV));
			return (EPKG_FATAL);
@@ -2051,11 +2049,11 @@ pkgdb_update_shlibs_provided(struct pkg *pkg, int64_t package_id, sqlite3 *s)
int
pkgdb_update_requires(struct pkg *pkg, int64_t package_id, sqlite3 *s)
{
-
	tll_foreach(pkg->requires, r) {
-
		if (run_prstmt(REQUIRE, r->item)
+
	vec_foreach(pkg->requires, i) {
+
		if (run_prstmt(REQUIRE, pkg->requires.d[i])
		    != SQLITE_DONE
		    ||
-
		    run_prstmt(PKG_REQUIRE, package_id, r->item)
+
		    run_prstmt(PKG_REQUIRE, package_id, pkg->requires.d[i])
		    != SQLITE_DONE) {
			ERROR_STMT_SQLITE(s, STMT(PKG_REQUIRE));
			return (EPKG_FATAL);
@@ -2068,11 +2066,11 @@ pkgdb_update_requires(struct pkg *pkg, int64_t package_id, sqlite3 *s)
int
pkgdb_update_provides(struct pkg *pkg, int64_t package_id, sqlite3 *s)
{
-
	tll_foreach(pkg->provides, p) {
-
		if (run_prstmt(PROVIDE, p->item)
+
	vec_foreach(pkg->provides, i) {
+
		if (run_prstmt(PROVIDE, pkg->provides.d[i])
		    != SQLITE_DONE
		    ||
-
		    run_prstmt(PKG_PROVIDE, package_id, p->item)
+
		    run_prstmt(PKG_PROVIDE, package_id, pkg->provides.d[i])
		    != SQLITE_DONE) {
			ERROR_STMT_SQLITE(s, STMT(PKG_PROVIDE));
			return (EPKG_FATAL);
@@ -2087,8 +2085,8 @@ pkgdb_insert_annotations(struct pkg *pkg, int64_t package_id, sqlite3 *s)
{
	struct pkg_kv	*kv;

-
	tll_foreach(pkg->annotations, k) {
-
		kv = k->item;
+
	vec_foreach(pkg->annotations, i) {
+
		kv = pkg->annotations.d[i];
		if (run_prstmt(ANNOTATE1, kv->key)
		    != SQLITE_DONE
		    ||
@@ -2885,14 +2883,14 @@ pkgdb_stats(struct pkgdb *db, pkg_stats_t type)
	case PKG_STATS_REMOTE_UNIQUE:
	case PKG_STATS_REMOTE_COUNT:
	case PKG_STATS_REMOTE_SIZE:
-
		tll_foreach(db->repos, rit) {
-
			if (rit->item->ops->stat != NULL)
-
				stats += rit->item->ops->stat(rit->item, type);
+
		vec_foreach(db->repos, i) {
+
			if (db->repos.d[i]->ops->stat != NULL)
+
				stats += db->repos.d[i]->ops->stat(db->repos.d[i], type);
		}
		return (stats);
		break;
	case PKG_STATS_REMOTE_REPOS:
-
		return (tll_length(db->repos));
+
		return (vec_len(&db->repos));
		break;
	}

@@ -2924,7 +2922,7 @@ pkgdb_begin_solver(struct pkgdb *db)
		"CREATE INDEX pkg_digest_id ON packages(name, manifestdigest);";
	struct pkgdb_it *it;
	struct pkg *p = NULL;
-
	tll(struct pkg *) pkglist = tll_init();
+
	pkgs_t pkglist = vec_init();
	int rc = EPKG_OK;
	int64_t cnt = 0, cur = 0;

@@ -2933,21 +2931,21 @@ pkgdb_begin_solver(struct pkgdb *db)
	if (it != NULL) {
		while (pkgdb_it_next(it, &p, PKG_LOAD_BASIC|PKG_LOAD_OPTIONS) == EPKG_OK) {
			pkg_checksum_calculate(p, NULL, false, true, false);
-
			tll_push_front(pkglist, p);
+
			vec_push(&pkglist, p);
			p = NULL;
			cnt ++;
		}
		pkgdb_it_free(it);

-
		if (tll_length(pkglist) > 0) {
+
		if (vec_len(&pkglist) > 0) {
			rc = sql_exec(db->sqlite, update_digests_sql);
			if (rc != EPKG_OK) {
				ERROR_SQLITE(db->sqlite, update_digests_sql);
			}
			else {
				pkg_emit_progress_start("Updating database digests format");
-
				tll_foreach(pkglist, pit) {
-
					p = pit->item;
+
				vec_foreach(pkglist, i) {
+
					p = pkglist.d[i];
					pkg_emit_progress_tick(cur++, cnt);
					rc = run_prstmt(UPDATE_DIGEST, p->digest, p->id);
					if (rc != SQLITE_DONE) {
@@ -2968,7 +2966,7 @@ pkgdb_begin_solver(struct pkgdb *db)
		if (rc == EPKG_OK)
			rc = sql_exec(db->sqlite, solver_sql);

-
		tll_free_and_free(pkglist, pkg_free);
+
		vec_free_and_free(&pkglist, pkg_free);
	} else {
		rc = sql_exec(db->sqlite, solver_sql);
	}
modified libpkg/pkgdb_iterator.c
@@ -1,5 +1,5 @@
/*-
-
 * Copyright (c) 2011-2023 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2011 Will Andrews <will@FreeBSD.org>
 * Copyright (c) 2011 Philippe Pepiot <phil@philpep.org>
@@ -10,28 +10,8 @@
 * Copyright (c) 2013-2017 Vsevolod Stakhov <vsevolod@FreeBSD.org>
 * Copyright (c) 2023 Serenity Cyber Security, LLC
 *                    Author: Gleb Popov <arrowd@FreeBSD.org>
-
 * All rights reserved.
 *
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 *
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 * SPDX-License-Identifier: BSD-2-Clause
 */

#ifdef HAVE_CONFIG_H
@@ -588,7 +568,7 @@ pkgdb_load_group(sqlite3 *sqlite, struct pkg *pkg)
static int
addshlib_required_raw(struct pkg *pkg, const char *name)
{
-
	tll_push_back(pkg->shlibs_required, xstrdup(name));
+
	vec_push(&pkg->shlibs_required, xstrdup(name));
	return (EPKG_OK);
}

@@ -611,7 +591,7 @@ pkgdb_load_shlib_required(sqlite3 *sqlite, struct pkg *pkg)
static int
addshlib_provided_raw(struct pkg *pkg, const char *name)
{
-
	tll_push_back(pkg->shlibs_provided, xstrdup(name));
+
	vec_push(&pkg->shlibs_provided, xstrdup(name));
	return (EPKG_OK);
}

@@ -902,7 +882,7 @@ populate_pkg(sqlite3_stmt *stmt, struct pkg *pkg) {
						struct pkg_message *message;
						message = xcalloc(1, sizeof(*message));
						message->str = xstrdup(msg);
-
						tll_push_back(pkg->message, message);
+
						vec_push(&pkg->message, message);
					}
				}
				break;
@@ -1138,16 +1118,15 @@ pkgdb_it_next(struct pkgdb_it *it, struct pkg **pkg_p, unsigned flags)
			return (r);
	}

-
	if (tll_length(it->remote) != 0) {
-
		if (it->opq_it == NULL)
-
			it->opq_it = it->remote.head;
-
		__typeof__(*(it->remote).head) *lit = it->opq_it;
-
		rit = lit->item;
+
	if (vec_len(&it->remote) != 0) {
+
		if (it->remote_pos >= it->remote.len)
+
			it->remote_pos = 0;
+
		struct pkg_repo_it *rit = it->remote.d[it->remote_pos];
		ret = rit->ops->next(rit, pkg_p, flags);
		if (ret != EPKG_OK) {
-
			if (it->opq_it == it->remote.tail)
+
			if (it->remote_pos == it->remote.len -1 )
				return (EPKG_END);
-
			it->opq_it = lit->next;
+
			it->remote_pos++;
			return (pkgdb_it_next(it, pkg_p, flags));
		}

@@ -1202,8 +1181,8 @@ pkgdb_it_reset(struct pkgdb_it *it)
	if (it->local != NULL) {
		pkgdb_sqlite_it_reset(it->local);
	}
-
	tll_foreach(it->remote, cur) {
-
		cur->item->ops->reset(cur->item);
+
	vec_foreach(it->remote, i) {
+
		it->remote.d[i]->ops->reset(it->remote.d[i]);
	}
}

@@ -1217,7 +1196,7 @@ pkgdb_it_free(struct pkgdb_it *it)
		pkgdb_sqlite_it_free(it->local);
		free(it->local);
	}
-
	tll_free_and_free(it->remote, remote_free);
+
	vec_free_and_free(&it->remote, remote_free);

	free(it);
}
@@ -1241,7 +1220,7 @@ pkgdb_it_new_sqlite(struct pkgdb *db, sqlite3_stmt *s, int type, short flags)

	it->local->flags = flags;
	it->local->finished = 0;
-
	it->opq_it = it->remote.head;
+
	it->remote_pos = 0;

	return (it);
}
@@ -1261,7 +1240,7 @@ pkgdb_it_new_repo(struct pkgdb *db)
void
pkgdb_it_repo_attach(struct pkgdb_it *it, struct pkg_repo_it *rit)
{
-
	tll_push_front(it->remote, rit);
+
	vec_push(&it->remote, rit);
}

int
@@ -1287,10 +1266,10 @@ pkgdb_ensure_loaded(struct pkgdb *db, struct pkg *pkg, unsigned flags)
	if (pkg->type == PKG_INSTALLED)
		return (pkgdb_ensure_loaded_sqlite(db->sqlite, pkg, flags));

-
	tll_foreach(db->repos, cur) {
-
		if (cur->item == pkg->repo) {
-
			if (cur->item->ops->ensure_loaded) {
-
				return (cur->item->ops->ensure_loaded(cur->item,
+
	vec_foreach(db->repos, i) {
+
		if (db->repos.d[i] == pkg->repo) {
+
			if (db->repos.d[i]->ops->ensure_loaded) {
+
				return (db->repos.d[i]->ops->ensure_loaded(db->repos.d[i],
				    pkg, flags));
			}
		}
modified libpkg/pkgdb_query.c
@@ -1,5 +1,5 @@
/*-
-
 * Copyright (c) 2011-2022 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2011 Will Andrews <will@FreeBSD.org>
 * Copyright (c) 2011 Philippe Pepiot <phil@philpep.org>
@@ -10,28 +10,8 @@
 * Copyright (c) 2013-2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
 * Copyright (c) 2023 Serenity Cyber Security, LLC
 *                    Author: Gleb Popov <arrowd@FreeBSD.org>
-
 * All rights reserved.
 *
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 *
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include "pkg/vec.h"
@@ -398,11 +378,9 @@ struct pkgdb_it *
pkgdb_repo_query_cond(struct pkgdb *db, const char *cond, const char *pattern, match_t match,
    const char *repo)
{
-
	c_charv_t r;
+
	c_charv_t r = vec_init();
	struct pkgdb_it *ret;

-
	vec_init(&r);
-

	if (repo != NULL)
		vec_push(&r, repo);

@@ -423,12 +401,12 @@ pkgdb_repo_query_cond2(struct pkgdb *db, const char *cond, const char *pattern,
	if (it == NULL)
		return (NULL);

-
	tll_foreach(db->repos, cur) {
-
		if (consider_this_repo(repos, cur->item->name)) {
+
	vec_foreach(db->repos, i) {
+
		if (consider_this_repo(repos, db->repos.d[i]->name)) {
			if (pattern != NULL && *pattern == '@')
-
				rit = cur->item->ops->groupquery(cur->item, pattern + 1, match);
+
				rit = db->repos.d[i]->ops->groupquery(db->repos.d[i], pattern + 1, match);
			else
-
				rit = cur->item->ops->query(cur->item, cond, pattern, match);
+
				rit = db->repos.d[i]->ops->query(db->repos.d[i], cond, pattern, match);
			if (rit != NULL)
				pkgdb_it_repo_attach(it, rit);
		}
@@ -459,10 +437,10 @@ pkgdb_repo_shlib_require(struct pkgdb *db, const char *require, c_charv_t *repos
	if (it == NULL)
		return (NULL);

-
	tll_foreach(db->repos, cur) {
-
		if (consider_this_repo(repos, cur->item->name)) {
-
			if (cur->item->ops->shlib_required != NULL) {
-
				rit = cur->item->ops->shlib_required(cur->item, require);
+
	vec_foreach(db->repos, i) {
+
		if (consider_this_repo(repos, db->repos.d[i]->name)) {
+
			if (db->repos.d[i]->ops->shlib_required != NULL) {
+
				rit = db->repos.d[i]->ops->shlib_required(db->repos.d[i], require);
				if (rit != NULL)
					pkgdb_it_repo_attach(it, rit);
			}
@@ -482,10 +460,10 @@ pkgdb_repo_shlib_provide(struct pkgdb *db, const char *require, c_charv_t *repos
	if (it == NULL)
		return (NULL);

-
	tll_foreach(db->repos, cur) {
-
		if (consider_this_repo(repos, cur->item->name)) {
-
			if (cur->item->ops->shlib_required != NULL) {
-
				rit = cur->item->ops->shlib_provided(cur->item, require);
+
	vec_foreach(db->repos, i) {
+
		if (consider_this_repo(repos, db->repos.d[i]->name)) {
+
			if (db->repos.d[i]->ops->shlib_required != NULL) {
+
				rit = db->repos.d[i]->ops->shlib_provided(db->repos.d[i], require);
				if (rit != NULL)
					pkgdb_it_repo_attach(it, rit);
			}
@@ -505,10 +483,10 @@ pkgdb_repo_require(struct pkgdb *db, const char *require, c_charv_t *repo)
	if (it == NULL)
		return (NULL);

-
	tll_foreach(db->repos, cur) {
-
		if (consider_this_repo(repo, cur->item->name)) {
-
			if (cur->item->ops->required != NULL) {
-
				rit = cur->item->ops->required(cur->item, require);
+
	vec_foreach(db->repos, i) {
+
		if (consider_this_repo(repo, db->repos.d[i]->name)) {
+
			if (db->repos.d[i]->ops->required != NULL) {
+
				rit = db->repos.d[i]->ops->required(db->repos.d[i], require);
				if (rit != NULL)
					pkgdb_it_repo_attach(it, rit);
			}
@@ -528,10 +506,10 @@ pkgdb_repo_provide(struct pkgdb *db, const char *require, c_charv_t *repo)
	if (it == NULL)
		return (NULL);

-
	tll_foreach(db->repos, cur) {
-
		if (consider_this_repo(repo, cur->item->name)) {
-
			if (cur->item->ops->required != NULL) {
-
				rit = cur->item->ops->provided(cur->item, require);
+
	vec_foreach(db->repos, i) {
+
		if (consider_this_repo(repo, db->repos.d[i]->name)) {
+
			if (db->repos.d[i]->ops->required != NULL) {
+
				rit = db->repos.d[i]->ops->provided(db->repos.d[i], require);
				if (rit != NULL)
					pkgdb_it_repo_attach(it, rit);
			}
@@ -545,10 +523,9 @@ struct pkgdb_it *
pkgdb_repo_search(struct pkgdb *db, const char *pattern, match_t match,
    pkgdb_field field, pkgdb_field sort, const char *repo)
{
-
	c_charv_t r;
+
	c_charv_t r = vec_init();
	struct pkgdb_it *ret;

-
	vec_init(&r);
	if (repo != NULL)
		vec_push(&r, repo);

@@ -569,16 +546,16 @@ pkgdb_repo_search2(struct pkgdb *db, const char *pattern, match_t match,
	if (it == NULL)
		return (NULL);

-
	tll_foreach(db->repos, cur) {
-
		if (consider_this_repo(repos, cur->item->name)) {
-
			if (cur->item->ops->search != NULL) {
-
				rit = cur->item->ops->search(cur->item, pattern, match,
+
	vec_foreach(db->repos, i) {
+
		if (consider_this_repo(repos, db->repos.d[i]->name)) {
+
			if (db->repos.d[i]->ops->search != NULL) {
+
				rit = db->repos.d[i]->ops->search(db->repos.d[i], pattern, match,
					field, sort);
				if (rit != NULL)
					pkgdb_it_repo_attach(it, rit);
			}
-
			if (cur->item->ops->groupsearch != NULL) {
-
				rit = cur->item->ops->groupsearch(cur->item, pattern, match, field);
+
			if (db->repos.d[i]->ops->groupsearch != NULL) {
+
				rit = db->repos.d[i]->ops->groupsearch(db->repos.d[i], pattern, match, field);
				if (rit != NULL)
					pkgdb_it_repo_attach(it, rit);
			}
@@ -592,11 +569,9 @@ struct pkgdb_it *
pkgdb_all_search(struct pkgdb *db, const char *pattern, match_t match,
    pkgdb_field field, pkgdb_field sort, const char *repo)
{
-
	c_charv_t r;
+
	c_charv_t r = vec_init();
	struct pkgdb_it *ret;

-
	vec_init(&r);
-

	if (repo != NULL)
		vec_push(&r, repo);

@@ -617,10 +592,10 @@ pkgdb_all_search2(struct pkgdb *db, const char *pattern, match_t match,

	it = pkgdb_query(db, pattern, match);

-
	tll_foreach(db->repos, cur) {
-
		if (consider_this_repo(repos, cur->item->name)) {
-
			if (cur->item->ops->search != NULL) {
-
				rit = cur->item->ops->search(cur->item, pattern, match,
+
	vec_foreach(db->repos, i) {
+
		if (consider_this_repo(repos, db->repos.d[i]->name)) {
+
			if (db->repos.d[i]->ops->search != NULL) {
+
				rit = db->repos.d[i]->ops->search(db->repos.d[i], pattern, match,
					field, sort);
				if (rit != NULL)
					pkgdb_it_repo_attach(it, rit);
modified libpkg/private/pkg.h
@@ -28,8 +28,6 @@
#include "private/fetch.h"
#include "pkghash.h"

-
#define UCL_COUNT(obj) ((obj)?((obj)->len):0)
-

#define PKG_NUM_SCRIPTS 9
#define PKG_NUM_LUA_SCRIPTS 5

@@ -99,7 +97,7 @@
} while (0)
#define DL_FREE(head, free_func) DL_FREE2(head, free_func, prev, next)

-
typedef tll(struct pkg_kv *) kvlist_t;
+
typedef vec_t(struct pkg_kv *) kvlist_t;

typedef enum {
	IPALL = 0,
@@ -112,17 +110,17 @@ struct pkg_kvlist {
};

struct pkg_stringlist {
-
	stringlist_t *list;
+
	charv_t *list;
};

struct pkg_kvlist_iterator {
	kvlist_t *list;
-
	void *cur;
+
	size_t pos;
};

struct pkg_stringlist_iterator {
-
	stringlist_t *list;
-
	void *cur;
+
	charv_t *list;
+
	size_t pos;
};

struct pkg_ctx {
@@ -173,16 +171,17 @@ struct pkg_repo;
struct url;
struct fetcher;
struct pkg_message;
-
typedef tll(struct pkg_message *) messages_t;
+
typedef vec_t(struct pkg_message *) messages_t;

struct pkg {
	bool		 direct;
	bool		 locked;
	bool		 automatic;
	bool		 vital;
+
	bool		 list_sorted;
	int64_t		 id;
	xstring		*scripts[PKG_NUM_SCRIPTS];
-
	stringlist_t	 lua_scripts[PKG_NUM_LUA_SCRIPTS];
+
	charv_t	 lua_scripts[PKG_NUM_LUA_SCRIPTS];
	char			*name;
	char			*origin;
	char			*version;
@@ -214,33 +213,37 @@ struct pkg {
	struct pkg_dep		*depends;
	pkghash			*rdepshash;
	struct pkg_dep		*rdepends;
-
	stringlist_t		 categories;
-
	stringlist_t		 licenses;
+
	charv_t		 categories;
+
	charv_t		 licenses;
	pkghash			*filehash;
	struct pkg_file		*files;
	pkghash			*dirhash;
	struct pkg_dir		*dirs;
	pkghash			*optionshash;
	struct pkg_option	*options;
-
	stringlist_t		 users;
-
	stringlist_t		 groups;
-
	stringlist_t		 shlibs_required;
-
	stringlist_t		 shlibs_provided;
+
	charv_t		 users;
+
	charv_t		 groups;
+
	charv_t		 shlibs_required;
+
	charv_t		 shlibs_provided;
	pkghash			*conflictshash;
	struct pkg_conflict	*conflicts;
-
	stringlist_t		 provides;
-
	stringlist_t		 requires;
+
	charv_t		 provides;
+
	charv_t		 requires;
	pkghash			*config_files_hash;
	struct pkg_config_file	*config_files;
	kvlist_t		 annotations;
	unsigned			flags;
	int		rootfd;
	char		rootpath[MAXPATHLEN];
-
	stringlist_t	dir_to_del;
+
	charv_t	dir_to_del;
	pkg_t		 type;
	struct pkg_repo		*repo;
};
-
typedef tll(struct pkg *) pkg_chain_t;
+
typedef vec_t(struct pkg *) pkgs_t;
+

+
DEFINE_VEC_INSERT_SORTED_PROTO(pkgs_t, pkgs, struct pkg *);
+
struct pkg **pkgs_search(pkgs_t *, char *);
+
void pkgs_sort(pkgs_t *);

typedef enum {
	SCRIPT_UNKNOWN = 0,
@@ -265,7 +268,7 @@ struct trigger {
	} cleanup;
	pkghash *matched;
};
-
typedef tll(struct trigger *) trigger_t;
+
typedef vec_t(struct trigger *) trigger_t;

struct triggers {
	ucl_object_t *schema;
@@ -557,7 +560,7 @@ struct pkg_repo {
	struct pkg_repo *next, *prev;
};

-
typedef tll(struct action *) actions_t;
+
typedef vec_t(struct action *) actions_t;
struct keyword {
	char *keyword;
	actions_t actions;
@@ -663,7 +666,7 @@ int pkg_start_stop_rc_scripts(struct pkg *, pkg_rc_attr attr);

int pkg_script_run(struct pkg *, pkg_script type, bool upgrade, bool noexec);
int pkg_lua_script_run(struct pkg *, pkg_lua_script type, bool upgrade);
-
ucl_object_t *pkg_lua_script_to_ucl(stringlist_t *);
+
ucl_object_t *pkg_lua_script_to_ucl(charv_t *);
int pkg_script_run_child(int pid, int *pstat, int inputfd, const char* script_name);

int pkg_open2(struct pkg **p, struct archive **a, struct archive_entry **ae,
@@ -675,6 +678,9 @@ void pkg_list_free(struct pkg *, pkg_list);

struct pkg_kv *pkg_kv_new(const char *key, const char *val);
void pkg_kv_free(struct pkg_kv *);
+
struct pkg_kv *pkg_kv_search(kvlist_t *, char *);
+
void pkg_kv_sort(kvlist_t *);
+
DEFINE_VEC_INSERT_SORTED_PROTO(kvlist_t, pkg_kv, struct pkg_kv *);

void pkg_dep_free(struct pkg_dep *);
void pkg_file_free(struct pkg_file *);
@@ -790,7 +796,7 @@ int pkg_adddir(struct pkg *pkg, const char *path, bool check_duplicates);
int pkg_adddir_attr(struct pkg *pkg, const char *path, const char *uname,
    const char *gname, mode_t perm, u_long fflags, bool check_duplicates);

-
int pkg_addstring(stringlist_t *s, const char *value, const char *title);
+
int pkg_addstring(charv_t *s, const char *value, const char *title);
int pkg_kv_add(kvlist_t *kv, const char *key, const char *value, const char *title);
const char *pkg_kv_get(const kvlist_t *kv, const char *key);
int pkg_adduser(struct pkg *pkg, const char *name);
@@ -860,14 +866,13 @@ void trigger_is_it_a_cleanup(struct triggers *t, const char *path);
void trigger_free(struct trigger *);
void append_touched_dir(const char *path);
void append_touched_file(const char *path);
-
bool stringlist_contains(stringlist_t *l, const char *name);

int pkg_parse_manifest_ucl(struct pkg *pkg, ucl_object_t *o);
int pkg_get_reposdirfd(void);
char * expand_plist_variables(const char *in, kvlist_t *vars);

-
int scan_system_shlibs(pkghash **system_shlibs, const char *rootdir);
+
int scan_system_shlibs(charv_t *system_shlibs, const char *rootdir);
void pkg_lists_sort(struct pkg *p);
-
void pkg_cleanup_shlibs_required(struct pkg *pkg, stringlist_t *internal_provided);
+
void pkg_cleanup_shlibs_required(struct pkg *pkg, charv_t *internal_provided);

#endif
modified libpkg/private/pkg_jobs.h
@@ -29,7 +29,6 @@
#include <stdbool.h>
#include <utlist.h>
#include <ucl.h>
-
#include <tllist.h>

#include "private/utils.h"
#include "private/pkg.h"
@@ -97,7 +96,7 @@ struct pkg_solved {
	enum pkg_solved_cycle_mark mark;/* scheduling cycle detection */
	struct pkg_solved *path_next;	/* scheduling cycle detection */
};
-
typedef tll(struct pkg_solved *) pkg_solved_list;
+
typedef vec_t(struct pkg_solved *) pkg_solved_list;

struct pkg_job_provide {
	struct pkg_job_universe_item *un;
@@ -143,7 +142,7 @@ struct pkg_jobs {
	struct triggers triggers;
	struct pkghash *orphaned;
	struct pkghash *notorphaned;
-
	struct pkghash *system_shlibs;
+
	charv_t system_shlibs;
};

#define PKG_PATTERN_FLAG_FILE (1 << 0)
@@ -229,7 +228,7 @@ int pkg_conflicts_append_chain(struct pkg_job_universe_item *it,
/*
 * Check whether `rp` is an upgrade for `lp`
 */
-
bool pkg_jobs_need_upgrade(struct pkghash *system_shlibs, struct pkg *rp, struct pkg *lp);
+
bool pkg_jobs_need_upgrade(charv_t *system_shlibs, struct pkg *rp, struct pkg *lp);

/*
 * Pre-process universe to fix complex upgrade chains
modified libpkg/private/pkgdb.h
@@ -1,30 +1,9 @@
/*-
-
 * Copyright (c) 2011-2022 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2023 Serenity Cyber Security, LLC
 *                    Author: Gleb Popov <arrowd@FreeBSD.org>
-
 * All rights reserved.
 *
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 *
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _PKGDB_H
@@ -33,13 +12,13 @@
#include "pkg.h"

#include <sqlite3.h>
-
#include <tllist.h>
+
#include "pkg/vec.h"

struct pkgdb {
	sqlite3		*sqlite;
	bool		 prstmt_initialized;

-
	tll(struct pkg_repo *) repos;
+
	vec_t(struct pkg_repo *) repos;
};

struct pkgdb_sqlite_it {
@@ -54,8 +33,8 @@ struct pkg_repo_it;

struct pkgdb_it {
	struct pkgdb *db;
-
	tll(struct pkg_repo_it *) remote;
-
	void *opq_it;
+
	vec_t(struct pkg_repo_it *) remote;
+
	size_t remote_pos;
	struct pkgdb_sqlite_it *local;
};

modified libpkg/private/utils.h
@@ -1,30 +1,11 @@
/*-
-
 * Copyright (c) 2011-2022 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2023 Serenity Cyber Security, LLC
 *                    Author: Gleb Popov <arrowd@FreeBSD.org>
 * All rights reserved.
 *
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 *
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 * SPDX-License-Identifier: BSD-2-Clause
 */

#ifndef _PKG_UTIL_H
@@ -34,15 +15,12 @@
#include <sys/stat.h>
#include <sys/param.h>
#include <ucl.h>
-
#include <tllist.h>
#include <pkg.h>
#include <xstring.h>

#define STARTS_WITH(string, needle) (strncasecmp(string, needle, strlen(needle)) == 0)
#define RELATIVE_PATH(p) (p + (*p == '/' ? 1 : 0))

-
typedef tll(char *) stringlist_t;
-

#define ERROR_SQLITE(db, query) do { \
	pkg_emit_error("sqlite error while executing %s in file %s:%d: %s", query, \
	__FILE__, __LINE__, sqlite3_errmsg(db)); \
@@ -119,6 +97,10 @@ void append_random_suffix(char *buf, int buflen, int suffixlen);
char *json_escape(const char *str);
const char *get_http_auth(void);
bool c_charv_contains(c_charv_t *, const char *, bool);
+
bool charv_contains(charv_t *, const char *, bool);
bool str_ends_with(const char *str, const char *end);
+
int char_cmp(const void *a, const void *b);
+
const char *charv_search(charv_t *, const char *);
+
DEFINE_VEC_INSERT_SORTED_PROTO(charv_t, charv, char *);

#endif
modified libpkg/repo/binary/update.c
@@ -1,6 +1,6 @@
/*
 * Copyright (c) 2014, Vsevolod Stakhov
-
 * Copyright (c) 2012-2024 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2012-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2024 Serenity Cyber Security, LLC
 *                    Author: Gleb Popov <arrowd@FreeBSD.org>
@@ -149,7 +149,7 @@ try_again:
	    pkg->origin, pkg->name, pkg->version, pkg->comment, pkg->desc,
	    arch, pkg->maintainer, pkg->www, pkg->prefix, pkg->pkgsize,
	    pkg->flatsize, (int64_t)pkg->licenselogic, pkg->sum, pkg->repopath,
-
	    pkg->digest, pkg->old_digest, pkg->vital)) != SQLITE_DONE) {
+
	    pkg->digest, pkg->old_digest, (int64_t)pkg->vital)) != SQLITE_DONE) {
		if (ret == SQLITE_CONSTRAINT) {
			ERROR_SQLITE(sqlite, "grmbl");
			switch(pkg_repo_binary_delete_conflicting(pkg->origin,
@@ -181,22 +181,22 @@ try_again:
		}
	}

-
	tll_foreach(pkg->categories, c) {
-
		ret = pkg_repo_binary_run_prstatement(CAT1, c->item);
+
	vec_foreach(pkg->categories, i) {
+
		const char *s = pkg->categories.d[i];
+
		ret = pkg_repo_binary_run_prstatement(CAT1, s);
		if (ret == SQLITE_DONE)
-
			ret = pkg_repo_binary_run_prstatement(CAT2, package_id,
-
			    c->item);
+
			ret = pkg_repo_binary_run_prstatement(CAT2, package_id, s);
		if (ret != SQLITE_DONE) {
			ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(CAT2));
			return (EPKG_FATAL);
		}
	}

-
	tll_foreach(pkg->licenses, l) {
-
		ret = pkg_repo_binary_run_prstatement(LIC1, l->item);
+
	vec_foreach(pkg->licenses, i) {
+
		const char *s = pkg->licenses.d[i];
+
		ret = pkg_repo_binary_run_prstatement(LIC1, s);
		if (ret == SQLITE_DONE)
-
			ret = pkg_repo_binary_run_prstatement(LIC2, package_id,
-
			    l->item);
+
			ret = pkg_repo_binary_run_prstatement(LIC2, package_id, s);
		if (ret != SQLITE_DONE) {
			ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(LIC2));
			return (EPKG_FATAL);
@@ -215,52 +215,52 @@ try_again:
		}
	}

-
	tll_foreach(pkg->shlibs_required, s) {
-
		ret = pkg_repo_binary_run_prstatement(SHLIB1, s->item);
+
	vec_foreach(pkg->shlibs_required, i) {
+
		const char *s = pkg->shlibs_required.d[i];
+
		ret = pkg_repo_binary_run_prstatement(SHLIB1, s);
		if (ret == SQLITE_DONE)
-
			ret = pkg_repo_binary_run_prstatement(SHLIB_REQD, package_id,
-
			    s->item);
+
			ret = pkg_repo_binary_run_prstatement(SHLIB_REQD, package_id, s);
		if (ret != SQLITE_DONE) {
			ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(SHLIB_REQD));
			return (EPKG_FATAL);
		}
	}

-
	tll_foreach(pkg->shlibs_provided, s) {
-
		ret = pkg_repo_binary_run_prstatement(SHLIB1, s->item);
+
	vec_foreach(pkg->shlibs_provided, i) {
+
		const char *s = pkg->shlibs_provided.d[i];
+
		ret = pkg_repo_binary_run_prstatement(SHLIB1, s);
		if (ret == SQLITE_DONE)
-
			ret = pkg_repo_binary_run_prstatement(SHLIB_PROV, package_id,
-
			    s->item);
+
			ret = pkg_repo_binary_run_prstatement(SHLIB_PROV, package_id, s);
		if (ret != SQLITE_DONE) {
			ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(SHLIB_PROV));
			return (EPKG_FATAL);
		}
	}

-
	tll_foreach(pkg->provides, p) {
-
		ret = pkg_repo_binary_run_prstatement(PROVIDE, p->item);
+
	vec_foreach(pkg->provides, i) {
+
		const char *s = pkg->provides.d[i];
+
		ret = pkg_repo_binary_run_prstatement(PROVIDE, s);
		if (ret == SQLITE_DONE)
-
			ret = pkg_repo_binary_run_prstatement(PROVIDES, package_id,
-
			    p->item);
+
			ret = pkg_repo_binary_run_prstatement(PROVIDES, package_id, s);
		if (ret != SQLITE_DONE) {
			ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(PROVIDES));
			return (EPKG_FATAL);
		}
	}

-
	tll_foreach(pkg->requires, r) {
-
		ret = pkg_repo_binary_run_prstatement(REQUIRE, r->item);
+
	vec_foreach(pkg->requires, i) {
+
		const char *s = pkg->requires.d[i];
+
		ret = pkg_repo_binary_run_prstatement(REQUIRE, s);
		if (ret == SQLITE_DONE)
-
			ret = pkg_repo_binary_run_prstatement(REQUIRES, package_id,
-
			    r->item);
+
			ret = pkg_repo_binary_run_prstatement(REQUIRES, package_id, s);
		if (ret != SQLITE_DONE) {
			ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(REQUIRES));
			return (EPKG_FATAL);
		}
	}

-
	tll_foreach(pkg->annotations, k) {
-
		kv = k->item;
+
	vec_foreach(pkg->annotations, i) {
+
		kv = pkg->annotations.d[i];
		ret = pkg_repo_binary_run_prstatement(ANNOTATE1, kv->key);
		if (ret == SQLITE_DONE)
			ret = pkg_repo_binary_run_prstatement(ANNOTATE1, kv->value);
modified libpkg/triggers.c
@@ -1,26 +1,7 @@
/*-
-
 * Copyright (c) 2020-2022 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2020-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 *
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 *
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include "pkg_config.h"
@@ -290,7 +271,7 @@ trigger_is_it_a_cleanup(struct triggers *t, const char *path)
		if (t->cleanup == NULL)
			t->cleanup = xcalloc(1, sizeof(*t->cleanup));

-
		tll_push_back(*t->cleanup, trig);
+
		vec_push(t->cleanup, trig);
	}
}

@@ -340,7 +321,7 @@ triggers_load(bool cleanup_only)
			continue;
		t = trigger_load(dfd, e->d_name, cleanup_only, schema);
		if (t != NULL)
-
			tll_push_back(*triggers, t);
+
			vec_push(triggers, t);
	}

	closedir(d);
@@ -544,11 +525,11 @@ triggers_execute(trigger_t *cleanup_triggers)
	triggers = triggers_load(false);
	pkg_emit_triggers_begin();
	if (cleanup_triggers != NULL) {
-
		tll_foreach(*cleanup_triggers, it) {
-
			pkg_emit_trigger(it->item->name, true);
-
			if (it->item->cleanup.type == SCRIPT_LUA) {
-
				ret = trigger_execute_lua(it->item->cleanup.script,
-
				    it->item->cleanup.sandbox, NULL);
+
		vec_foreach(*cleanup_triggers, i) {
+
			pkg_emit_trigger(cleanup_triggers->d[i]->name, true);
+
			if (cleanup_triggers->d[i]->cleanup.type == SCRIPT_LUA) {
+
				ret = trigger_execute_lua(cleanup_triggers->d[i]->cleanup.script,
+
				    cleanup_triggers->d[i]->cleanup.sandbox, NULL);
			}
			if (ret != EPKG_OK)
				goto cleanup;
@@ -558,19 +539,19 @@ triggers_execute(trigger_t *cleanup_triggers)
	if (ctx.touched_dir_hash) {
		pkghash_it it = pkghash_iterator(ctx.touched_dir_hash);
		while (pkghash_next(&it)) {
-
			tll_foreach(*triggers, t)
-
				trigger_check_match(t->item, it.key);
+
			vec_foreach(*triggers, i)
+
				trigger_check_match(triggers->d[i], it.key);
			/* We need to check if that matches a trigger */
		}
	}

-
	tll_foreach(*triggers, it) {
-
		if (it->item->matched == NULL)
+
	vec_foreach(*triggers, i) {
+
		if (triggers->d[i]->matched == NULL)
			continue;
-
		pkg_emit_trigger(it->item->name, false);
-
		if (it->item->script.type == SCRIPT_LUA) {
-
			ret = trigger_execute_lua(it->item->script.script,
-
			    it->item->script.sandbox, it->item->matched);
+
		pkg_emit_trigger(triggers->d[i]->name, false);
+
		if (triggers->d[i]->script.type == SCRIPT_LUA) {
+
			ret = trigger_execute_lua(triggers->d[i]->script.script,
+
			    triggers->d[i]->script.sandbox, triggers->d[i]->matched);
		}
		if (ret != EPKG_OK)
			goto cleanup;
@@ -578,7 +559,7 @@ triggers_execute(trigger_t *cleanup_triggers)
	pkg_emit_triggers_finished();

cleanup:
-
	tll_free_and_free(*triggers, trigger_free);
+
	vec_free_and_free(triggers, trigger_free);
	free(triggers);

	return (EPKG_OK);
modified libpkg/utils.c
@@ -59,7 +59,6 @@
#include "private/utils.h"
#include "private/pkg.h"
#include "xmalloc.h"
-
#include "tllist.h"

extern struct pkg_ctx ctx;

@@ -392,7 +391,7 @@ check_for_hardlink(hardlinks_t *hl, struct stat *st)
{
	struct hardlink *h;

-
	for (size_t i = 0; i < hl->len; i++) {
+
	vec_foreach(*hl, i) {
		h = hl->d[i];
		if (h->ino == st->st_ino &&
		    h->dev == st->st_dev)
@@ -1074,9 +1073,25 @@ get_http_auth(void)
}

bool
+
charv_contains(charv_t *v, const char *el, bool casesensitive)
+
{
+
	vec_foreach(*v, i) {
+
		if (casesensitive) {
+
			if (STREQ(v->d[i], el))
+
				return (true);
+
		} else {
+
			if (STRIEQ(v->d[i], el)) {
+
				return (true);
+
			}
+
		}
+
	}
+
	return (false);
+
}
+

+
bool
c_charv_contains(c_charv_t *v, const char *el, bool casesensitive)
{
-
	for (size_t i = 0; i < v->len; i ++) {
+
	vec_foreach(*v, i) {
		if (casesensitive) {
			if (STREQ(v->d[i], el))
				return (true);
@@ -1105,3 +1120,21 @@ str_ends_with(const char *str, const char *end)
		return (false);
	return (strncmp(str + (sl - el), end, (sl - el)) == 0);
}
+

+
int
+
char_cmp(const void *a, const void *b) {
+
	return strcmp(*(char **)a, *(char **)b);
+
}
+

+
DEFINE_VEC_INSERT_SORTED_FUNC(charv_t, charv, char *, char_cmp);
+

+
const char *
+
charv_search(charv_t *v, const char *el)
+
{
+
	if (v->len == 0)
+
		return (NULL);
+
	const char **res = bsearch(&el, v->d, v->len, sizeof(char *), char_cmp);
+
	if (res == NULL)
+
		return (NULL);
+
	return *res;
+
}
modified src/Makefile.autosetup
@@ -69,10 +69,6 @@ OTHER_LIBS+= -lfts
OTHER_LIBS+=	-ldl
@endif

-
@if HAVE_LIBMD
-
OTHER_LIBS+=	-lmd
-
@endif
-

@if PKG_OPENSSL_LIBS
LOCAL_CFLAGS+=	@PKG_OPENSSL_CFLAGS@
OTHER_LIBS+=	@PKG_OPENSSL_LDFLAGS@ @PKG_OPENSSL_LIBS@
@@ -80,14 +76,23 @@ OTHER_LIBS+= @PKG_OPENSSL_LDFLAGS@ @PKG_OPENSSL_LIBS@
OTHER_LIBS+=	-lssl -lcrypto
@endif

+
# libmd must be linked after libssl/libcrypto.
+
@if HAVE_LIBMD
+
OTHER_LIBS+=	-lmd
+
@endif
+

@if PKG_LIBCURL_LIBS
LOCAL_CFLAGS+=	@PKG_LIBCURL_CFLAGS@
OTHER_LIBS+=	@PKG_LIBCURL_LDFLAGS@ @PKG_LIBCURL_LIBS@
@endif

@if pkgos_darwin
-
LOCAL_LDFLAGS=	$(LIBPKGFLAT) $(LIBS) $(OTHER_LIBS) -lresolv
-
STATIC_LDFLAGS=	$(LIBPKGFLAT) $(LIBS) $(OTHER_LIBS) -lresolv
+
LOCAL_LDFLAGS=	$(LIBPKGFLAT) $(LIBS) $(OTHER_LIBS) -lresolv -lz \
+
	-framework CoreFoundation -framework CoreServices \
+
	-framework SystemConfiguration
+
STATIC_LDFLAGS=	$(LIBPKGFLAT) $(LIBS) $(OTHER_LIBS) -lresolv -lz \
+
	-framework CoreFoundation -framework CoreServices \
+
	-framework SystemConfiguration
# OSX doesn't support static binaries, sigh
STATIC_ARG=
@else
modified src/check.c
@@ -1,5 +1,5 @@
/*-
-
 * Copyright (c) 2011-2024 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
 * Copyright (c) 2014 Matthew Seaman <matthew@FreeBSD.org>
 * Copyright (c) 2016 Vsevolod Stakhov <vsevolod@FreeBSD.org>
@@ -19,21 +19,18 @@
#include <unistd.h>

#include <pkg.h>
-
#include <tllist.h>
#include <xmalloc.h>

#include "pkgcli.h"

-
typedef tll(char *) deps_entries;
-

-
static int check_deps(struct pkgdb *db, struct pkg *pkg, deps_entries *dh,
+
static int check_deps(struct pkgdb *db, struct pkg *pkg, charv_t *dh,
    bool noinstall, xstring *out);
-
static void add_missing_dep(struct pkg_dep *d, deps_entries *dh, int *nbpkgs);
-
static int fix_deps(struct pkgdb *db, deps_entries *dh, int nbpkgs);
-
static void check_summary(struct pkgdb *db, deps_entries *dh);
+
static void add_missing_dep(struct pkg_dep *d, charv_t *dh, int *nbpkgs);
+
static int fix_deps(struct pkgdb *db, charv_t *dh, int nbpkgs);
+
static void check_summary(struct pkgdb *db, charv_t *dh);

static int
-
check_deps(struct pkgdb *db, struct pkg *p, deps_entries *dh, bool noinstall, xstring *out)
+
check_deps(struct pkgdb *db, struct pkg *p, charv_t *dh, bool noinstall, xstring *out)
{
	struct pkg_dep *dep = NULL;
	struct pkgdb_it *it;
@@ -108,7 +105,7 @@ check_deps(struct pkgdb *db, struct pkg *p, deps_entries *dh, bool noinstall, xs
}

static void
-
add_missing_dep(struct pkg_dep *d, deps_entries *dh, int *nbpkgs)
+
add_missing_dep(struct pkg_dep *d, charv_t *dh, int *nbpkgs)
{
	const char *name = NULL;

@@ -117,35 +114,26 @@ add_missing_dep(struct pkg_dep *d, deps_entries *dh, int *nbpkgs)
	/* do not add duplicate entries in the queue */
	name = pkg_dep_name(d);

-
	tll_foreach(*dh, it) {
-
		if (STREQ(it->item, name))
+
	vec_foreach(*dh, i) {
+
		if (STREQ(dh->d[i], name))
			return;
	}
	(*nbpkgs)++;

-
	tll_push_back(*dh, xstrdup(name));
+
	vec_push(dh, xstrdup(name));
}

static int
-
fix_deps(struct pkgdb *db, deps_entries *dh, int nbpkgs)
+
fix_deps(struct pkgdb *db, charv_t *dh, int nbpkgs)
{
	struct pkg_jobs *jobs = NULL;
-
	char **pkgs = NULL;
-
	int i = 0;
	bool rc;
	pkg_flags f = PKG_FLAG_AUTOMATIC;

	assert(db != NULL);
	assert(nbpkgs > 0);

-
	if ((pkgs = calloc(nbpkgs, sizeof (char *))) == NULL)
-
		err(1, "calloc()");
-

-
	tll_foreach(*dh, it)
-
		pkgs[i++] = it->item;
-

	if (pkgdb_open(&db, PKGDB_REMOTE) != EPKG_OK) {
-
		free(pkgs);
		return (EPKG_ENODB);
	}

@@ -155,7 +143,7 @@ fix_deps(struct pkgdb *db, deps_entries *dh, int nbpkgs)

	pkg_jobs_set_flags(jobs, f);

-
	if (pkg_jobs_add(jobs, MATCH_EXACT, pkgs, nbpkgs) == EPKG_FATAL) {
+
	if (pkg_jobs_add(jobs, MATCH_EXACT, dh->d, dh->len) == EPKG_FATAL) {
		goto cleanup;
	}

@@ -187,7 +175,6 @@ fix_deps(struct pkgdb *db, deps_entries *dh, int nbpkgs)
	}

cleanup:
-
	free(pkgs);
	if (jobs != NULL)
		pkg_jobs_free(jobs);

@@ -195,7 +182,7 @@ cleanup:
}

static void
-
check_summary(struct pkgdb *db, deps_entries *dh)
+
check_summary(struct pkgdb *db, charv_t *dh)
{
	struct pkg *pkg = NULL;
	struct pkgdb_it *it = NULL;
@@ -205,15 +192,15 @@ check_summary(struct pkgdb *db, deps_entries *dh)

	printf(">>> Summary of actions performed:\n\n");

-
	tll_foreach(*dh, e) {
-
		if ((it = pkgdb_query(db, e->item, MATCH_EXACT)) == NULL)
+
	vec_foreach(*dh, i) {
+
		if ((it = pkgdb_query(db, dh->d[i], MATCH_EXACT)) == NULL)
			return;

		if (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) != EPKG_OK) {
			fixed = false;
-
			printf("%s dependency failed to be fixed\n", e->item);
+
			printf("%s dependency failed to be fixed\n", dh->d[i]);
		} else
-
			printf("%s dependency has been fixed\n", e->item);
+
			printf("%s dependency has been fixed\n", dh->d[i]);

		pkgdb_it_free(it);
	}
@@ -257,6 +244,7 @@ exec_check(int argc, char **argv)
	int i, processed, total = 0;
	int verbose = 0;
	int nbactions;
+
	charv_t dh = vec_init();

	struct option longopts[] = {
		{ "all",		no_argument,	NULL,	'a' },
@@ -275,8 +263,6 @@ exec_check(int argc, char **argv)
		{ NULL,			0,		NULL,	0   },
	};

-
	deps_entries dh = tll_init();
-

	processed = 0;

	while ((ch = getopt_long(argc, argv, "+aBCdginqrsvxy", longopts, NULL)) != -1) {
@@ -470,7 +456,7 @@ cleanup:
	if (!verbose)
		progressbar_stop();
	xstring_free(msg);
-
	tll_free_and_free(dh, free);
+
	vec_free_and_free(&dh, free);
	pkg_free(pkg);
	pkgdb_close(db);

modified src/clean.c
@@ -2,29 +2,9 @@
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2013-2014 Matthew Seaman <matthew@FreeBSD.org>
 * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
-
 * Copyright (c) 2016 Baptiste Daroussin <bapt@FreeBSD.org>
-
 * All rights reserved.
+
 * Copyright (c) 2016-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 *
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 *
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 * SPDX-License-Identifier: BSD-2-Clause
 */

#ifdef HAVE_CONFIG_H
@@ -49,7 +29,6 @@
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
-
#include <tllist.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
@@ -59,8 +38,7 @@
#include "pkgcli.h"
#include "pkghash.h"
#include "xmalloc.h"
-

-
typedef tll(char *) dl_list;
+
#include "pkg/vec.h"

#define OUT_OF_DATE	(1U<<0)
#define REMOVED		(1U<<1)
@@ -69,7 +47,7 @@ typedef tll(char *) dl_list;
#define ALL		(1U<<4)

static size_t
-
add_to_dellist(int fd, dl_list *dl, const char *cachedir, const char *path)
+
add_to_dellist(int fd, charv_t *dl, const char *cachedir, const char *path)
{
	static bool first_entry = true;
	struct stat st;
@@ -93,13 +71,13 @@ add_to_dellist(int fd, dl_list *dl, const char *cachedir, const char *path)
	relpath = path + strlen(cachedir) + 1;
	if (fstatat(fd, relpath, &st, AT_SYMLINK_NOFOLLOW) != -1 && S_ISREG(st.st_mode))
		sz = st.st_size;
-
	tll_push_back(*dl, store_path);
+
	vec_push(dl, store_path);

	return (sz);
}

static int
-
delete_dellist(int fd, const char *cachedir,  dl_list *dl, int total)
+
delete_dellist(int fd, const char *cachedir,  charv_t *dl)
{
	struct stat st;
	int retcode = EXIT_SUCCESS;
@@ -107,15 +85,15 @@ delete_dellist(int fd, const char *cachedir, dl_list *dl, int total)
	unsigned int count = 0, processed = 0;
	char *file, *relpath;

-
	count = tll_length(*dl);
+
	count = dl->len;
	progressbar_start("Deleting files");
-
	tll_foreach(*dl, it) {
+
	vec_foreach(*dl, i) {
		flag = 0;
-
		relpath = file = it->item;
+
		relpath = file = dl->d[i];
		relpath += strlen(cachedir) + 1;
		if (fstatat(fd, relpath, &st, AT_SYMLINK_NOFOLLOW) == -1) {
			++processed;
-
			progressbar_tick(processed, total);
+
			progressbar_tick(processed, dl->len);
			warn("can't stat %s", file);
			continue;
		}
@@ -126,11 +104,11 @@ delete_dellist(int fd, const char *cachedir, dl_list *dl, int total)
			retcode = EXIT_FAILURE;
		}
		free(file);
-
		it->item = NULL;
+
		dl->d[i] = NULL;
		++processed;
-
		progressbar_tick(processed, total);
+
		progressbar_tick(processed, dl->len);
	}
-
	progressbar_tick(processed, total);
+
	progressbar_tick(processed, dl->len);

	if (!quiet) {
		if (retcode != EXIT_SUCCESS)
@@ -160,7 +138,7 @@ populate_sums(struct pkgdb *db)
		free(cksum);
	}
	pkgdb_it_free(it);
-
	
+

	return (suml);
}

@@ -194,7 +172,7 @@ extract_filename_sum(const char *fname, char sum[])

static int
recursive_analysis(int fd, struct pkgdb *db, const char *dir,
-
    const char *cachedir, dl_list *dl, pkghash **sumlist, bool all,
+
    const char *cachedir, charv_t *dl, pkghash **sumlist, bool all,
    size_t *total)
{
	DIR *d;
@@ -283,7 +261,7 @@ exec_clean(int argc, char **argv)
{
	struct pkgdb	*db = NULL;
	pkghash		*sumlist = NULL;
-
	dl_list		 dl = tll_init();
+
	charv_t		 dl = vec_init();
	const char	*cachedir;
	bool		 all = false;
	int		 retcode;
@@ -385,7 +363,7 @@ exec_clean(int argc, char **argv)
	    &total);
	pkghash_destroy(sumlist);

-
	if (tll_length(dl) == 0) {
+
	if (dl.len == 0) {
		if (!quiet)
			printf("Nothing to do.\n");
		retcode = EXIT_SUCCESS;
@@ -400,7 +378,7 @@ exec_clean(int argc, char **argv)
	if (!dry_run) {
			if (query_yesno(false,
			  "\nProceed with cleaning the cache? ")) {
-
				retcode = delete_dellist(cachefd, cachedir, &dl, tll_length(dl));
+
				retcode = delete_dellist(cachefd, cachedir, &dl);
			}
	} else {
		retcode = EXIT_SUCCESS;
@@ -409,7 +387,7 @@ exec_clean(int argc, char **argv)
cleanup:
	pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
	pkgdb_close(db);
-
	tll_free_and_free(dl, free);
+
	vec_free_and_free(&dl, free);

	if (cachefd != -1)
		close(cachefd);
modified src/create.c
@@ -1,30 +1,10 @@
/*-
-
 * Copyright (c) 2011-2020 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2011 Will Andrews <will@FreeBSD.org>
 * Copyright (c) 2015 Matthew Seaman <matthew@FreeBSD.org>
-
 * All rights reserved.
 *
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 *
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 * SPDX-License-Identifier: BSD-2-Clause
 */

#ifdef HAVE_CONFIG_H
@@ -47,12 +27,9 @@
#include <string.h>
#include <strings.h>
#include <unistd.h>
-
#include <tllist.h>

#include "pkgcli.h"

-
tll(struct pkg *) pkg_head = tll_init();
-

void
usage_create(void)
{
@@ -81,6 +58,7 @@ pkg_create_matches(int argc, char **argv, match_t match, struct pkg_create *pc)
	    PKG_LOAD_PROVIDES | PKG_LOAD_REQUIRES |
	    PKG_LOAD_SHLIBS_PROVIDED | PKG_LOAD_ANNOTATIONS | PKG_LOAD_LUA_SCRIPTS;
	bool foundone;
+
	vec_t(struct pkg *) pkglist = vec_init();

	if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) {
		pkgdb_close(db);
@@ -110,7 +88,7 @@ pkg_create_matches(int argc, char **argv, match_t match, struct pkg_create *pc)

		foundone = false;
		while ((ret = pkgdb_it_next(it, &pkg, query_flags)) == EPKG_OK) {
-
			tll_push_back(pkg_head, pkg);
+
			vec_push(&pkglist, pkg);
			pkg = NULL;
			foundone = true;
		}
@@ -125,19 +103,19 @@ pkg_create_matches(int argc, char **argv, match_t match, struct pkg_create *pc)
			retcode = EXIT_FAILURE;
	}

-
	tll_foreach(pkg_head, el) {
-
		pkg_printf("Creating package for %n-%v\n", el->item, el->item);
-
		ret = pkg_create_i(pc, el->item, false);
+
	vec_foreach(pkglist, i) {
+
		pkg_printf("Creating package for %n-%v\n", pkglist.d[i], pkglist.d[i]);
+
		ret = pkg_create_i(pc, pkglist.d[i], false);
		if (ret == EPKG_EXIST) {
			pkg_printf("%n-%v already packaged, skipping...\n",
-
			  el->item, el->item);
+
			  pkglist.d[i], pkglist.d[i]);
		}
		if (ret != EPKG_OK && ret != EPKG_EXIST)
			retcode = EXIT_FAILURE;
-
		tll_remove_and_free(pkg_head, el, pkg_free);
	}

cleanup:
+
	vec_free_and_free(&pkglist, pkg_free);
	pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
	pkgdb_close(db);

modified src/event.c
@@ -54,7 +54,6 @@
#ifdef HAVE_LIBUTIL_H
#include <libutil.h>
#endif
-
#include <tllist.h>

#include <bsd_compat.h>

@@ -84,7 +83,7 @@ static int64_t bytes_per_second;
static time_t last_update;
static time_t begin = 0;
static int add_deps_depth;
-
static tll(struct cleanup *) cleanup_list = tll_init();
+
static vec_t(struct cleanup *) cleanup_list = vec_init();
static bool signal_handler_installed = false;
static size_t nbactions = 0;
static size_t nbdone = 0;
@@ -99,11 +98,11 @@ cleanup_handler(int dummy __unused)
{
	struct cleanup *ev;

-
	if (tll_length(cleanup_list) == 0)
+
	if (cleanup_list.len == 0)
		return;
	warnx("\nsignal received, cleaning up");
-
	tll_foreach(cleanup_list, it) {
-
		ev = it->item;
+
	vec_foreach(cleanup_list, i) {
+
		ev = cleanup_list.d[i];
		ev->cb(ev->data);
	}
	exit(1);
@@ -692,16 +691,16 @@ event_callback(void *data, struct pkg_event *ev)
		evtmp = xmalloc(sizeof(struct cleanup));
		evtmp->cb = ev->e_cleanup_callback.cleanup_cb;
		evtmp->data = ev->e_cleanup_callback.data;
-
		tll_push_back(cleanup_list, evtmp);
+
		vec_push(&cleanup_list, evtmp);
		break;
	case PKG_EVENT_CLEANUP_CALLBACK_UNREGISTER:
		if (!signal_handler_installed)
			break;
-
		tll_foreach(cleanup_list, it) {
-
			evtmp = it->item;
+
		vec_foreach(cleanup_list, i) {
+
			evtmp = cleanup_list.d[i];
			if (evtmp->cb == ev->e_cleanup_callback.cleanup_cb &&
			    evtmp->data == ev->e_cleanup_callback.data) {
-
				tll_remove_and_free(cleanup_list, it, free);
+
				vec_remove_and_free(&cleanup_list, i, free);
				break;
			}
		}
modified src/fetch.c
@@ -64,7 +64,7 @@ exec_fetch(int argc, char **argv)
	unsigned	 mode;
	match_t		 match = MATCH_EXACT;
	pkg_flags	 f = PKG_FLAG_NONE;
-
	c_charv_t	reponames;
+
	c_charv_t	reponames = vec_init();

	struct option longopts[] = {
		{ "all",		no_argument,		NULL,	'a' },
@@ -82,7 +82,6 @@ exec_fetch(int argc, char **argv)
		{ NULL,			0,			NULL,	0   },
	};

-
	vec_init(&reponames);
	while ((ch = getopt_long(argc, argv, "+aCdgiqr:Uuxyo:", longopts, NULL)) != -1) {
		switch (ch) {
		case 'a':
modified src/install.c
@@ -69,7 +69,7 @@ exec_install(int argc, char **argv)
	bool		 local_only = false;
	match_t		 match = MATCH_EXACT;
	pkg_flags	 f = PKG_FLAG_NONE | PKG_FLAG_PKG_VERSION_TEST;
-
	c_charv_t	reponames;
+
	c_charv_t	reponames = vec_init();

	struct option longopts[] = {
		{ "automatic",		no_argument,		NULL,	'A' },
@@ -99,7 +99,6 @@ exec_install(int argc, char **argv)
		quiet = true;
	}

-
	vec_init(&reponames);
	while ((ch = getopt_long(argc, argv, "+ACfFgiIlMnqr:RUxy", longopts, NULL)) != -1) {
		switch (ch) {
		case 'A':
modified src/lock.c
@@ -1,27 +1,8 @@
/*-
 * Copyright (c) 2012-2014 Matthew Seaman <matthew@FreeBSD.org>
-
 * Copyright (c) 2015-2024 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2015-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 *
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 *
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <err.h>
@@ -31,7 +12,6 @@
#include <unistd.h>

#include <pkg.h>
-
#include <tllist.h>

#include "pkgcli.h"

@@ -101,7 +81,7 @@ do_lock_unlock(struct pkgdb *db, int match, const char *pkgname,
	int		 retcode;
	int		 exitcode = EXIT_SUCCESS;
	bool		 gotone = false;
-
	tll(struct pkg *)pkgs = tll_init();
+
	vec_t(struct pkg *)pkgs = vec_init();

	if (pkgdb_obtain_lock(db, PKGDB_LOCK_EXCLUSIVE) != EPKG_OK) {
		pkgdb_close(db);
@@ -117,11 +97,11 @@ do_lock_unlock(struct pkgdb *db, int match, const char *pkgname,

	while (pkgdb_it_next(it, &pkg, 0) == EPKG_OK) {
		gotone = true;
-
		tll_push_back(pkgs, pkg);
+
		vec_push(&pkgs, pkg);
		pkg = NULL;
	}
-
	tll_foreach(pkgs, p) {
-
		retcode = lockfct(db, p->item, match != MATCH_EXACT);
+
	vec_foreach(pkgs, i) {
+
		retcode = lockfct(db, pkgs.d[i], match != MATCH_EXACT);
		if (retcode != EPKG_OK) {
			exitcode = EXIT_FAILURE;
			goto cleanup;
@@ -133,7 +113,7 @@ do_lock_unlock(struct pkgdb *db, int match, const char *pkgname,
	        exitcode = EXIT_FAILURE;

cleanup:
-
	tll_free_and_free(pkgs, pkg_free);
+
	vec_free_and_free(&pkgs, pkg_free);
	pkgdb_it_free(it);

	pkgdb_release_lock(db, PKGDB_LOCK_EXCLUSIVE);
modified src/main.c
@@ -36,7 +36,6 @@
#include <signal.h>

#include <pkg.h>
-
#include <tllist.h>
#include <xmalloc.h>

#include "pkgcli.h"
@@ -104,7 +103,7 @@ struct plugcmd {
	const char *desc;
	int (*exec)(int argc, char **argv);
};
-
static tll(struct plugcmd *)plugins = tll_init();
+
static vec_t(struct plugcmd *)plugins = vec_init();

typedef int (register_cmd)(int idx, const char **name, const char **desc, int (**exec)(int argc, char **argv));
typedef int (nb_cmd)(void);
@@ -178,9 +177,9 @@ usage(const char *conffile, const char *reposdir, FILE *out, enum pkg_usage_reas

			fprintf(out, "\nCommands provided by plugins:\n");

-
			tll_foreach(plugins, it) {
-
				fprintf(out, "\t%-15s%s\n", it->item->name,
-
				    it->item->desc);
+
			vec_foreach(plugins, i) {
+
				fprintf(out, "\t%-15s%s\n", plugins.d[i]->name,
+
				    plugins.d[i]->desc);
			}
		}
		fprintf(out, "\nFor more information on the different commands"
@@ -227,9 +226,9 @@ exec_help(int argc, char **argv)
	plugins_enabled = pkg_object_bool(pkg_config_get("PKG_ENABLE_PLUGINS"));

	if (plugins_enabled) {
-
		tll_foreach(plugins, it) {
-
			if (STREQ(it->item->name, argv[1])) {
-
				xasprintf(&manpage, "/usr/bin/man pkg-%s", it->item->name);
+
		vec_foreach(plugins, i) {
+
			if (STREQ(plugins.d[i]->name, argv[1])) {
+
				xasprintf(&manpage, "/usr/bin/man pkg-%s", plugins.d[i]->name);
				system(manpage);
				free(manpage);

@@ -304,7 +303,7 @@ show_version_info(int version)
	printf("%-24s: %s\n", "libpkg", pkg_libversion());

	pkg_kvl_t *lib = pkg_external_libs_version();
-
	for (size_t i = 0; i < lib->len; i++) {
+
	vec_foreach(*lib, i) {
		printf("%-24s: %s\n", lib->d[i]->key, lib->d[i]->value);
	}
	free(lib);
@@ -709,7 +708,7 @@ main(int argc, char **argv)
				for (j = 0; j < n ; j++) {
					c = xmalloc(sizeof(struct plugcmd));
					reg(j, &c->name, &c->desc, &c->exec);
-
					tll_push_back(plugins, c);
+
					vec_push(&plugins, c);
				}
			}
		}
@@ -790,10 +789,10 @@ main(int argc, char **argv)
		/* Check if a plugin provides the requested command */
		ret = EPKG_FATAL;
		if (plugins_enabled) {
-
			tll_foreach(plugins, it) {
-
				if (STREQ(it->item->name, argv[0])) {
+
			vec_foreach(plugins, i) {
+
				if (STREQ(plugins.d[i]->name, argv[0])) {
					plugin_found = true;
-
					ret = it->item->exec(argc, argv);
+
					ret = plugins.d[i]->exec(argc, argv);
					break;
				}
			}
modified src/rquery.c
@@ -121,7 +121,7 @@ exec_rquery(int argc, char **argv)
	bool			 onematched = false;
	bool			 old_quiet;
	bool			 index_output = false;
-
	c_charv_t		reponames;
+
	c_charv_t		reponames = vec_init();

	struct option longopts[] = {
		{ "all",		no_argument,		NULL,	'a' },
@@ -138,7 +138,6 @@ exec_rquery(int argc, char **argv)

	portsdir = pkg_object_string(pkg_config_get("PORTSDIR"));

-
	vec_init(&reponames);
	while ((ch = getopt_long(argc, argv, "+aCgiIxe:r:U", longopts, NULL)) != -1) {
		switch (ch) {
		case 'a':
modified src/search.c
@@ -254,7 +254,7 @@ exec_search(int argc, char **argv)
	struct pkg	*pkg = NULL;
	bool		 atleastone = false;
	bool		 old_quiet;
-
	c_charv_t	reponames;
+
	c_charv_t	reponames = vec_init();

	struct option longopts[] = {
		{ "case-sensitive",	no_argument,		NULL,	'C' },
@@ -280,7 +280,6 @@ exec_search(int argc, char **argv)
		{ NULL,			0,			NULL,	0   },
	};

-
	vec_init(&reponames);
	while ((ch = getopt_long(argc, argv, "+CcDdefgiL:opqQ:r:RS:sUx", longopts, NULL)) != -1) {
		switch (ch) {
		case 'C':
modified src/update.c
@@ -44,7 +44,7 @@
static bool
_find_repo(c_charv_t *reponames, const char *name)
{
-
	for (size_t i = 0; i < reponames->len; i++) {
+
	vec_foreach(*reponames, i) {
		if (STREQ(name, reponames->d[i]))
			return (true);
	}
@@ -113,7 +113,7 @@ pkgcli_update(bool force, bool strict, c_charv_t *reponames)
			if (reponames == NULL || reponames->len == 0)
				printf("All repositories are up to date.\n");
			else {
-
				for (size_t i = 0; i < reponames->len; i++)
+
				vec_foreach(*reponames, i)
					printf("%s%s", i == 0 ? "" : ", ", reponames->d[i]);
				printf(" %s up to date.\n", reponames->len == 1 ? "is" : "are");
			}
@@ -149,7 +149,7 @@ exec_update(int argc, char **argv)
{
	int		 ret;
	int		 ch;
-
	c_charv_t 	reponames;
+
	c_charv_t 	reponames = vec_init();

	struct option longopts[] = {
		{ "force",	no_argument,		NULL,	'f' },
@@ -158,7 +158,6 @@ exec_update(int argc, char **argv)
		{ NULL,		0,			NULL,	0   },
	};

-
	vec_init(&reponames);
	while ((ch = getopt_long(argc, argv, "+fqr:", longopts, NULL)) != -1) {
		switch (ch) {
		case 'f':
modified src/updating.c
@@ -1,28 +1,8 @@
/*-
-
 * Copyright (c) 2011-2022 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2014 Matthew Seaman <matthew@FreeBSD.org>
-
 * All rights reserved.
 *
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 *
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 * SPDX-License-Identifier: BSD-2-Clause
 */

#ifdef HAVE_CONFIG_H
@@ -43,31 +23,16 @@
#include <unistd.h>
#include <ctype.h>
#include <regex.h>
-
#include <tllist.h>

#include "pkgcli.h"

-
struct installed_ports {
-
	char *origin;
-
};
-

struct regex_cache {
	char *pattern;
	regex_t reg;
};

-

-
static void
-
installed_ports_free(struct installed_ports *p) 
-
{
-
	if (!p)
-
		return;
-
	free(p->origin);
-
	free(p);
-
}
-

static void
-
regex_cache_free(struct regex_cache *p) 
+
regex_cache_free(struct regex_cache *p)
{
	if (!p)
		return;
@@ -138,7 +103,7 @@ matcher(const char *affects, const char *origin, bool ignorecase)
	size_t len;
	char *re, *buf, *p, **words;
	struct regex_cache *ent;
-
	tll(struct regex_cache *) cache = tll_init();
+
	vec_t(struct regex_cache *) cache = vec_init();

	len = strlen(affects);
	buf = strdup(affects);
@@ -200,14 +165,14 @@ matcher(const char *affects, const char *origin, bool ignorecase)
		}

		found = 0;
-
		tll_foreach(cache, it) {
+
		vec_foreach(cache, j) {
			if (ignorecase)
-
				rc = strcasecmp(words[i], it->item->pattern);
+
				rc = strcasecmp(words[i], cache.d[j]->pattern);
			else
-
				rc = strcmp(words[i], it->item->pattern);
+
				rc = strcmp(words[i], cache.d[j]->pattern);
			if (rc == 0) {
				found++;
-
				if (regexec(&it->item->reg, origin, 0, NULL, 0) == 0) {
+
				if (regexec(&cache.d[j]->reg, origin, 0, NULL, 0) == 0) {
					ret = 1;
					break;
				}
@@ -231,7 +196,7 @@ matcher(const char *affects, const char *origin, bool ignorecase)
			}
			regcomp(&ent->reg, re, (ignorecase) ? REG_ICASE|REG_EXTENDED : REG_EXTENDED);
			free(re);
-
			tll_push_front(cache, ent);
+
			vec_push(&cache, ent);
			if (regexec(&ent->reg, origin, 0, NULL, 0) == 0) {
				ret = 1;
				break;
@@ -240,8 +205,7 @@ matcher(const char *affects, const char *origin, bool ignorecase)
	}

out:
-
	tll_foreach(cache, it)
-
		tll_remove_and_free(cache, it, regex_cache_free);
+
	vec_free_and_free(&cache, regex_cache_free);
	free(words);
	free(buf);
	return (ret);
@@ -254,8 +218,7 @@ exec_updating(int argc, char **argv)
	char			*dateline = NULL;
	char			*updatingfile = NULL;
	bool			caseinsensitive = false;
-
	struct installed_ports	*port;
-
	tll(struct installed_ports *) origins = tll_init();
+
	charv_t 		 origins = vec_init();
	int			 ch;
	char			*line = NULL;
	size_t			 linecap = 0;
@@ -351,15 +314,14 @@ exec_updating(int argc, char **argv)
		}

		while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) == EPKG_OK) {
-
			port = malloc(sizeof(struct installed_ports));
-
			pkg_asprintf(&port->origin, "%o", pkg);
-
			tll_push_front(origins, port);
+
			char *orig;
+
			pkg_asprintf(&orig, "%o", pkg);
+
			vec_push(&origins, orig);
		}
	} else {
		while (*argv) {
-
			port = malloc(sizeof(struct installed_ports));
-
			port->origin = strdup(*argv);
-
			tll_push_front(origins, port);
+
			char *orig = strdup(*argv);
+
			vec_push(&origins, orig);
			argv++;
		}
	}
@@ -377,8 +339,8 @@ exec_updating(int argc, char **argv)
		tmp = NULL;
		if (found == 0) {
			if (strstr(line, "AFFECTS") != NULL) {
-
				tll_foreach(origins, it) {
-
					if (matcher(line, it->item->origin, caseinsensitive) != 0) {
+
				vec_foreach(origins, i) {
+
					if (matcher(line, origins.d[i], caseinsensitive) != 0) {
						tmp = "";
						break;
					}
@@ -402,8 +364,7 @@ exec_updating(int argc, char **argv)
	fclose(fd);

cleanup:
-
	tll_foreach(origins, it)
-
		tll_remove_and_free(origins, it, installed_ports_free);
+
	vec_free_and_free(&origins, free);
	pkgdb_it_free(it);
	pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
	pkgdb_close(db);
modified src/upgrade.c
@@ -250,7 +250,7 @@ exec_upgrade(int argc, char **argv)
	int		 scriptnoexec = 0;
	bool	rc = true;
	pkg_flags	 f = PKG_FLAG_NONE | PKG_FLAG_PKG_VERSION_TEST;
-
	c_charv_t	reponames;
+
	c_charv_t	reponames = vec_init();

	struct option longopts[] = {
		{ "case-sensitive",	no_argument,		NULL,	'C' },
@@ -270,8 +270,6 @@ exec_upgrade(int argc, char **argv)
		{ NULL,			0,			NULL,	0   },
	};

-
	vec_init(&reponames);
-

	while ((ch = getopt_long(argc, argv, "+CfFgiInqr:Uxyv", longopts, NULL)) != -1) {
		switch (ch) {
		case 'C':
modified src/utils.c
@@ -31,7 +31,6 @@
#include <errno.h>
#include <pwd.h>
#include <pkg.h>
-
#include <tllist.h>
#include <xmalloc.h>

#include <bsd_compat.h>
@@ -804,7 +803,7 @@ struct pkg_solved_display {
	pkg_solved_t solved_type;
};

-
typedef tll(struct pkg_solved_display *) pkg_solved_display_t;
+
typedef vec_t(struct pkg_solved_display *) pkg_solved_display_t;

static void
set_jobs_summary_pkg(struct pkg_jobs *jobs, struct pkg *new_pkg,
@@ -840,7 +839,7 @@ set_jobs_summary_pkg(struct pkg_jobs *jobs, struct pkg *new_pkg,

	if (old_pkg != NULL && pkg_is_locked(old_pkg)) {
		it->display_type = PKG_DISPLAY_LOCKED;
-
		tll_push_back(disp[it->display_type], it);
+
		vec_push(&disp[it->display_type], it);
		return;
	}

@@ -935,7 +934,7 @@ set_jobs_summary_pkg(struct pkg_jobs *jobs, struct pkg *new_pkg,

		break;
	}
-
	tll_push_back(disp[it->display_type], it);
+
	vec_push(&disp[it->display_type], it);
}

static void
@@ -1078,7 +1077,6 @@ print_jobs_summary(struct pkg_jobs *jobs, const char *msg, ...)
	int type, displayed = 0;
	int64_t dlsize, oldsize, newsize;
	pkg_solved_display_t disp[PKG_DISPLAY_MAX];
-
	struct pkg_solved_display **displays;
	bool first = true;
	size_t bytes_change, limbytes;
	struct jobs_sum_number sum;
@@ -1095,7 +1093,7 @@ print_jobs_summary(struct pkg_jobs *jobs, const char *msg, ...)
	}

	for (type = 0; type < PKG_DISPLAY_MAX; type ++) {
-
		if (tll_length(disp[type]) != 0) {
+
		if (disp[type].len != 0) {
			/* Space between each section. */
			if (!first)
				putchar('\n');
@@ -1109,18 +1107,12 @@ print_jobs_summary(struct pkg_jobs *jobs, const char *msg, ...)
				msg = NULL;
			}
			printf("%s:\n", pkg_display_messages[type]);
-
			displays = xcalloc(tll_length(disp[type]), sizeof(*displays));
-
			size_t i = 0;
-
			tll_foreach(disp[type], d) {
-
				displays[i++] = d->item;
-
			}
-
			qsort(displays, i, sizeof(displays[0]), namecmp);
-
			for (i = 0; i < tll_length(disp[type]); i++) {
-
				display_summary_item(displays[i], dlsize);
+
			qsort(disp[type].d, disp[type].len, sizeof(disp[type].d[0]), namecmp);
+
			vec_foreach(disp[type], i) {
+
				display_summary_item(disp[type].d[i], dlsize);
				displayed ++;
			}
-
			tll_free_and_free(disp[type], free);
-
			free(displays);
+
			vec_free_and_free(&disp[type], free);
		}
	}

modified src/version.c
@@ -807,7 +807,7 @@ exec_version(int argc, char **argv)
	match_t		 match = MATCH_ALL;
	char		*pattern = NULL;
	int		 ch;
-
	c_charv_t	reponames;
+
	c_charv_t	reponames = vec_init();

	struct option longopts[] = {
		{ "case-sensitive",	no_argument,		NULL,	'C' },
@@ -833,7 +833,6 @@ exec_version(int argc, char **argv)
		{ NULL,			0,			NULL,	0   },
	};

-
	vec_init(&reponames);
	while ((ch = getopt_long(argc, argv, "+Ce:g:hIiL:l:n:O:oPqRr:TtUvx:",
				 longopts, NULL)) != -1) {
		switch (ch) {
modified src/which.c
@@ -1,30 +1,10 @@
/*-
-
 * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2025 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
 * Copyright (c) 2014 Matthew Seaman <matthew@FreeBSD.org>
-
 * All rights reserved.
-
 * 
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 * 
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 *
+
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <sys/param.h>
@@ -41,9 +21,6 @@
#include "pkgcli.h"
#include <string.h>
#include <xmalloc.h>
-
#include <tllist.h>
-

-
typedef tll(char *) charlist;

void
usage_which(void)
@@ -56,10 +33,10 @@ static bool is_there(char *);
int get_match(char **, char **, char *);

static bool
-
already_in_list(charlist *list, const char *pattern)
+
already_in_list(charv_t *list, const char *pattern)
{
-
	tll_foreach(*list, it) {
-
		if (STREQ(it->item, pattern))
+
	vec_foreach(*list, i) {
+
		if (STREQ(list->d[i], pattern))
			return (true);
	}

@@ -82,7 +59,7 @@ exec_which(int argc, char **argv)
	bool		 search = false;
	bool		 search_s = false;
	bool		 show_match = false;
-
	charlist	 patterns = tll_init();
+
	charv_t		 patterns = vec_init();

	struct option longopts[] = {
		{ "glob",		no_argument,	NULL,	'g' },
@@ -184,7 +161,7 @@ exec_which(int argc, char **argv)
						/* ensure not not append twice an entry if PATH is messy */
						if (already_in_list(&patterns, pathabs))
							continue;
-
						tll_push_back(patterns, xstrdup(pathabs));
+
						vec_push(&patterns, xstrdup(pathabs));
						free(match);
					}
				}
@@ -194,18 +171,18 @@ exec_which(int argc, char **argv)

		if (!glob && !search) {
			pkg_absolutepath(argv[0], pathabs, sizeof(pathabs), false);
-
			tll_push_back(patterns, xstrdup(pathabs));
+
			vec_push(&patterns, xstrdup(pathabs));
		} else if (!search) {
			if (strlcpy(pathabs, argv[0], sizeof(pathabs)) >= sizeof(pathabs)) {
				retcode = EXIT_FAILURE;
				goto cleanup;
                        }
-
			tll_push_back(patterns, xstrdup(pathabs));
+
			vec_push(&patterns, xstrdup(pathabs));
		}


-
		tll_foreach(patterns, item) {
-
			if ((it = pkgdb_query_which(db, item->item, glob)) == NULL) {
+
		vec_foreach(patterns, i) {
+
			if ((it = pkgdb_query_which(db, patterns.d[i], glob)) == NULL) {
				retcode = EXIT_FAILURE;
				goto cleanup;
			}
@@ -218,30 +195,30 @@ exec_which(int argc, char **argv)
				else if (quiet && !orig && !show_match)
					pkg_printf("%n-%v\n", pkg, pkg);
				else if (!quiet && orig && !show_match)
-
					pkg_printf("%S was installed by package %o\n", item->item, pkg);
+
					pkg_printf("%S was installed by package %o\n", patterns.d[i], pkg);
				else if (!quiet && !orig && !show_match)
-
					pkg_printf("%S was installed by package %n-%v\n", item->item, pkg, pkg);
+
					pkg_printf("%S was installed by package %n-%v\n", patterns.d[i], pkg, pkg);
				else if (glob && show_match) {
					if (!quiet)
-
						pkg_printf("%S was glob searched and found in package %n-%v\n", item->item, pkg, pkg, pkg);
+
						pkg_printf("%S was glob searched and found in package %n-%v\n", patterns.d[i], pkg, pkg, pkg);
					while(pkg_files(pkg, &file) == EPKG_OK) {
						pkg_asprintf(&match, "%Fn", file);
						if (match == NULL)
							err(EXIT_FAILURE, "pkg_asprintf");
-
						if(!fnmatch(item->item, match, 0))
+
						if(!fnmatch(patterns.d[i], match, 0))
							printf("%s\n", match);
						free(match);
					}
				}
			}
			if (retcode != EXIT_SUCCESS && !quiet)
-
				printf("%s was not found in the database\n", item->item);
+
				printf("%s was not found in the database\n", patterns.d[i]);

			pkg_free(pkg);
			pkgdb_it_free(it);

		}
-
		tll_free_and_free(patterns, free);
+
		vec_free_and_free(&patterns, free);

		argc--;
		argv++;
modified tests/Makefile.autosetup
@@ -8,6 +8,7 @@ TESTS= \
	pkg_add_dir_to_del \
	pkg_printf \
	pkg_validation \
+
	pkg \
	plist \
	lua \
	ssh \
@@ -16,7 +17,8 @@ TESTS= \
	vec \
	pkg_elf \
	hash \
-
	shlibs
+
	shlibs \
+
	kv

TESTS_SH= \
	frontend/pkg.sh \
@@ -116,6 +118,8 @@ vec_OBJS= lib/vec.o
pkg_elf_OBJS=	lib/pkg_elf.o
hash_OBJS=	lib/hash.o
shlibs_OBJS=	lib/shlibs.o
+
kv_OBJS=	lib/kv.o
+
pkg_OBJS=	lib/pkg.o

SRCS=	\
	$(packing_OBJS:.o=.c) \
@@ -134,6 +138,8 @@ SRCS= \
	$(pkg_elf_OBJS:.o=.c) \
	$(hash_OBJS:.o=.c) \
	$(shlibs_OBJS:.o=.c) \
+
	$(kv_OBJS:.o=.c) \
+
	$(pkg_OBJS:.o=.c)

include $(MK)/common.mk

modified tests/frontend/conflicts.sh
@@ -353,14 +353,14 @@ Installed packages to be REMOVED:
Number of packages to be removed: 2
Number of packages to be installed: 2
Number of packages to be upgraded: 1
-
[1/6] Deinstalling other-1.0...
-
[2/6] Deinstalling foo-1.0...
+
[1/6] Deinstalling foo-1.0...
+
[2/6] Deinstalling other-1.0...
[3/6] Deinstalling bar-1.0...
[3/6] Deleting files for bar-1.0:  done
[4/6] Installing bar1-1.1...
[4/6] Extracting bar1-1.1:  done
-
[5/6] Installing foo-1.0_1...
-
[6/6] Installing arp-1.0_1...
+
[5/6] Installing arp-1.0_1...
+
[6/6] Installing foo-1.0_1...
"

	atf_check \
modified tests/frontend/pkg.sh
@@ -71,7 +71,7 @@ files:
EOF
	atf_check \
	    -o empty \
-
	    -e inline:"${PROGNAME}: Bad format in manifest for key: files\n" \
+
	    -e inline:"${PROGNAME}: Bad format in manifest for key: files\n${PROGNAME}: Error parsing testpkg/.metadir/+MANIFEST\n" \
	    -s exit:1 \
	    pkg create -q -m testpkg/.metadir -r testpkg
}
modified tests/frontend/test_environment.sh.in
@@ -75,13 +75,13 @@ bin_meta() {
			XABI=FreeBSD:13:armv6
			XALTABI=freebsd:13:armv6:32:el:eabi:hardfp
			XFreeBSD_version=1304000
-
			Xshlibs_required="libgcc_s.so.1 libc.so.7"
+
			Xshlibs_required="libc.so.7 libgcc_s.so.1"
			;;
		*freebsd-armv7.bin)
			XABI=FreeBSD:14:armv7
			XALTABI=freebsd:14:armv7:32:el:eabi:hardfp
			XFreeBSD_version=1401000
-
			Xshlibs_required="libgcc_s.so.1 libc.so.7"
+
			Xshlibs_required="libc.so.7 libgcc_s.so.1"
			;;
		*freebsd-i386.bin)
			XABI=FreeBSD:14:i386
added tests/lib/kv.c
@@ -0,0 +1,121 @@
+
/*-
+
 * Copyright(c) 2025 Baptiste Daroussin <bapt@FreeBSD.org>
+
 *
+
 * SPDX-License-Identifier: BSD-2-Clause
+
 */
+

+
#include <atf-c.h>
+
#include <private/pkg.h>
+

+
ATF_TC_WITHOUT_HEAD(kv_sort);
+
ATF_TC_WITHOUT_HEAD(kv_insert_sorted);
+
ATF_TC_WITHOUT_HEAD(kv_search);
+

+
ATF_TC_BODY(kv_insert_sorted, tc)
+
{
+
	kvlist_t kvl = vec_init();
+

+
	ATF_REQUIRE_EQ_MSG(kvl.d, NULL, "vec_init failed");
+
	ATF_REQUIRE_EQ_MSG(kvl.cap, 0, "vec_init failed");
+
	ATF_REQUIRE_EQ_MSG(kvl.len, 0, "vec_init failed");
+

+
	struct pkg_kv *kv = pkg_kv_new("key", "value");
+
	ATF_REQUIRE_EQ(pkg_kv_insert_sorted(&kvl, kv), NULL);
+
	ATF_REQUIRE_EQ(kvl.len, 1);
+
	ATF_REQUIRE(pkg_kv_insert_sorted(&kvl, kv) != NULL);
+
	ATF_REQUIRE_EQ(kvl.len, 1);
+

+
	kv = pkg_kv_new("akey", "value");
+
	ATF_REQUIRE_EQ(pkg_kv_insert_sorted(&kvl, kv), NULL);
+
	ATF_REQUIRE_EQ(kvl.len, 2);
+
	ATF_REQUIRE_STREQ(kvl.d[0]->key, "akey");
+
	ATF_REQUIRE_STREQ(kvl.d[1]->key, "key");
+
}
+

+
ATF_TC_BODY(kv_sort, tc)
+
{
+
	kvlist_t kvl = vec_init();
+

+
	ATF_REQUIRE_EQ_MSG(kvl.d, NULL, "vec_init failed");
+
	ATF_REQUIRE_EQ_MSG(kvl.cap, 0, "vec_init failed");
+
	ATF_REQUIRE_EQ_MSG(kvl.len, 0, "vec_init failed");
+

+
	struct pkg_kv *kv = pkg_kv_new("key", "value");
+
	vec_push(&kvl, kv);
+
	ATF_REQUIRE_MSG(kvl.d != NULL, "vec_push failed");
+
	ATF_REQUIRE_EQ_MSG(kvl.cap, 1, "vec_push failed");
+
	ATF_REQUIRE_EQ_MSG(kvl.len, 1, "vec_push failed");
+

+
	pkg_kv_sort(&kvl);
+

+
	kv = pkg_kv_new("akey", "value");
+
	vec_push(&kvl, kv);
+
	ATF_REQUIRE_EQ_MSG(kvl.cap, 2, "vec_push failed");
+
	ATF_REQUIRE_EQ_MSG(kvl.len, 2, "vec_push failed");
+
	ATF_REQUIRE_STREQ_MSG(kvl.d[0]->key, "key", "Invalid first key");
+
	ATF_REQUIRE_STREQ_MSG(kvl.d[1]->key, "akey", "Invalid first key");
+

+
	pkg_kv_sort(&kvl);
+
	ATF_REQUIRE_STREQ_MSG(kvl.d[0]->key, "akey", "Invalid first key");
+
	ATF_REQUIRE_STREQ_MSG(kvl.d[1]->key, "key", "Invalid first key");
+

+
	vec_free_and_free(&kvl, pkg_kv_free);
+
}
+

+
ATF_TC_BODY(kv_search, tc)
+
{
+
	kvlist_t kvl = vec_init();
+

+
	ATF_REQUIRE_EQ_MSG(kvl.d, NULL, "vec_init failed");
+
	ATF_REQUIRE_EQ_MSG(kvl.cap, 0, "vec_init failed");
+
	ATF_REQUIRE_EQ_MSG(kvl.len, 0, "vec_init failed");
+

+
	struct pkg_kv *kv = pkg_kv_new("key", "value");
+
	vec_push(&kvl, kv);
+
	ATF_REQUIRE_MSG(kvl.d != NULL, "vec_push failed");
+
	ATF_REQUIRE_EQ_MSG(kvl.cap, 1, "vec_push failed");
+
	ATF_REQUIRE_EQ_MSG(kvl.len, 1, "vec_push failed");
+

+
	kv = pkg_kv_search(&kvl, "bla");
+
	ATF_REQUIRE(kv == NULL);
+

+
	kv = pkg_kv_search(&kvl, "key");
+
	ATF_REQUIRE(kv != NULL);
+
	ATF_REQUIRE_STREQ_MSG(kv->key, "key", "Invalid search result");
+
	ATF_REQUIRE_STREQ_MSG(kv->value, "value", "Invalid search result");
+

+
	kv = pkg_kv_new("akey", "value");
+
	vec_push(&kvl, kv);
+
	ATF_REQUIRE_EQ_MSG(kvl.cap, 2, "vec_push failed");
+
	ATF_REQUIRE_EQ_MSG(kvl.len, 2, "vec_push failed");
+
	ATF_REQUIRE_STREQ_MSG(kvl.d[0]->key, "key", "Invalid first key");
+
	ATF_REQUIRE_STREQ_MSG(kvl.d[1]->key, "akey", "Invalid first key");
+

+
	pkg_kv_sort(&kvl);
+
	ATF_REQUIRE_STREQ_MSG(kvl.d[0]->key, "akey", "Invalid first key");
+
	ATF_REQUIRE_STREQ_MSG(kvl.d[1]->key, "key", "Invalid first key");
+

+
	kv = pkg_kv_search(&kvl, "key");
+
	ATF_REQUIRE(kv != NULL);
+
	ATF_REQUIRE_STREQ_MSG(kv->key, "key", "Invalid search result");
+
	ATF_REQUIRE_STREQ_MSG(kv->value, "value", "Invalid search result");
+

+
	kv = pkg_kv_search(&kvl, "akey");
+
	ATF_REQUIRE(kv != NULL);
+
	ATF_REQUIRE_STREQ_MSG(kv->key, "akey", "Invalid search result");
+
	ATF_REQUIRE_STREQ_MSG(kv->value, "value", "Invalid search result");
+

+
	kv = pkg_kv_search(&kvl, "bla");
+
	ATF_REQUIRE(kv == NULL);
+

+
	vec_free_and_free(&kvl, pkg_kv_free);
+
}
+

+
ATF_TP_ADD_TCS(tp)
+
{
+
	ATF_TP_ADD_TC(tp, kv_insert_sorted);
+
	ATF_TP_ADD_TC(tp, kv_sort);
+
	ATF_TP_ADD_TC(tp, kv_search);
+

+
	return (atf_no_error());
+
}
modified tests/lib/pkg.c
@@ -1,7 +1,41 @@
#include <atf-c.h>
-
#include <pkg.h>
+
#include <private/pkg.h>

-
void
-
test_pkg(void)
+
ATF_TC_WITHOUT_HEAD(pkgs_insert_sorted);
+
ATF_TC_BODY(pkgs_insert_sorted, tc)
{
+
	pkgs_t pkgs = vec_init();
+

+
	ATF_REQUIRE_EQ_MSG(pkgs.d, NULL, "vec_init failed");
+
	ATF_REQUIRE_EQ_MSG(pkgs.cap, 0, "vec_init failed");
+
	ATF_REQUIRE_EQ_MSG(pkgs.len, 0, "vec_init failed");
+

+
	struct pkg *p;
+

+
	ATF_REQUIRE_EQ(EPKG_OK, pkg_new(&p, PKG_FILE));
+
	ATF_REQUIRE(p != NULL);
+
	p->name = xstrdup("name1");
+
	ATF_REQUIRE_EQ(pkgs_insert_sorted(&pkgs, p), NULL);
+
	ATF_REQUIRE_EQ_MSG(pkgs.len, 1, "Fail to insert");
+

+
	p = NULL;
+
	ATF_REQUIRE_EQ(EPKG_OK, pkg_new(&p, PKG_FILE));
+
	p->name = xstrdup("name1");
+
	ATF_REQUIRE_MSG(pkgs_insert_sorted(&pkgs, p) !=  NULL, "Collision not detected");
+

+
	free(p->name);
+
	p->name = xstrdup("aname1");
+

+
	ATF_REQUIRE_EQ(pkgs_insert_sorted(&pkgs, p), NULL);
+
	ATF_REQUIRE_EQ_MSG(pkgs.len, 2, "Fail to insert");
+

+
	ATF_REQUIRE_STREQ(pkgs.d[0]->name, "aname1");
+
	ATF_REQUIRE_STREQ(pkgs.d[1]->name, "name1");
+
}
+

+
ATF_TP_ADD_TCS(tp)
+
{
+
	ATF_TP_ADD_TC(tp, pkgs_insert_sorted);
+

+
	return (atf_no_error());
}
modified tests/lib/pkg_add_dir_to_del.c
@@ -27,7 +27,6 @@
#include <atf-c.h>
#include <pkg.h>
#include <private/pkg.h>
-
#include <tllist.h>

ATF_TC_WITHOUT_HEAD(pkg_add_dir_to_del);

@@ -38,26 +37,26 @@ ATF_TC_BODY(pkg_add_dir_to_del, tc)
	ATF_REQUIRE_EQ(EPKG_OK, pkg_new(&p, PKG_FILE));
	pkg_set(p, PKG_ATTR_PREFIX, "/usr/local");

-
	ATF_REQUIRE_EQ(tll_length(p->dir_to_del), 0);
+
	ATF_REQUIRE_EQ(vec_len(&p->dir_to_del), 0);

	pkg_add_dir_to_del(p, "/usr/local/plop/bla", NULL);

-
	ATF_REQUIRE_STREQ(tll_back(p->dir_to_del), "/usr/local/plop/");
+
	ATF_REQUIRE_STREQ(vec_last(&p->dir_to_del), "/usr/local/plop/");

	pkg_add_dir_to_del(p, NULL, "/usr/local/plop");

-
	ATF_REQUIRE_EQ(tll_length(p->dir_to_del), 1);
+
	ATF_REQUIRE_EQ(vec_len(&p->dir_to_del), 1);

	pkg_add_dir_to_del(p, NULL, "/var/run/yeah");

-
	ATF_REQUIRE_STREQ(tll_back(p->dir_to_del), "/var/run/yeah/");
+
	ATF_REQUIRE_STREQ(vec_last(&p->dir_to_del), "/var/run/yeah/");

	pkg_free(p);
}

ATF_TP_ADD_TCS(tp)
{
-
	ATF_TP_ADD_TC(tp, pkg_add_dir_to_del); 
+
	ATF_TP_ADD_TC(tp, pkg_add_dir_to_del);

	return (atf_no_error());
}
modified tests/lib/pkg_elf.c
@@ -13,7 +13,6 @@
#include <private/pkg_abi.h>
#include <private/binfmt.h>
#include <xstring.h>
-
#include <tllist.h>
#include <pkg.h>

#ifndef __unused
@@ -59,13 +58,13 @@ ATF_TC_BODY(analyse_elf, tc)
	ATF_REQUIRE_EQ(EPKG_OK, pkg_new(&p, PKG_INSTALLED));
	ATF_REQUIRE(p != NULL);

-
	ATF_REQUIRE_EQ(tll_length(p->shlibs_required), 0);
+
	ATF_REQUIRE_EQ(vec_len(&p->shlibs_required), 0);
	ATF_REQUIRE_EQ(pkg_analyse_elf(false, p, binpath, &provided, &provided_flags), EPKG_OK);
-
	ATF_REQUIRE_EQ(tll_length(p->shlibs_provided), 0);
+
	ATF_REQUIRE_EQ(vec_len(&p->shlibs_provided), 0);
	ATF_REQUIRE_STREQ(provided, "libtestfbsd.so.1");
	ATF_REQUIRE_EQ(provided_flags, PKG_SHLIB_FLAGS_NONE);
-
	ATF_REQUIRE_EQ(tll_length(p->shlibs_required), 1);
-
	ATF_REQUIRE_STREQ(tll_front(p->shlibs_required), "libc.so.7");
+
	ATF_REQUIRE_EQ(vec_len(&p->shlibs_required), 1);
+
	ATF_REQUIRE_STREQ(vec_first(&p->shlibs_required), "libc.so.7");
	free(provided);
	free(binpath);

@@ -73,10 +72,10 @@ ATF_TC_BODY(analyse_elf, tc)
	provided_flags = PKG_SHLIB_FLAGS_NONE;
	xasprintf(&binpath, "%s/Makefile", atf_tc_get_config_var(tc, "srcdir"));
	ATF_REQUIRE_EQ(pkg_analyse_elf(false, p, binpath, &provided, &provided_flags), EPKG_END);
-
	ATF_REQUIRE_EQ(tll_length(p->shlibs_provided), 0);
+
	ATF_REQUIRE_EQ(vec_len(&p->shlibs_provided), 0);
	ATF_REQUIRE_EQ(provided, NULL);
	ATF_REQUIRE_EQ(provided_flags, PKG_SHLIB_FLAGS_NONE);
-
	ATF_REQUIRE_EQ(tll_length(p->shlibs_required), 1);
+
	ATF_REQUIRE_EQ(vec_len(&p->shlibs_required), 1);
	free(provided);
	free(binpath);

@@ -84,12 +83,12 @@ ATF_TC_BODY(analyse_elf, tc)
	provided_flags = PKG_SHLIB_FLAGS_NONE;
	xasprintf(&binpath, "%s/frontend/libtest2fbsd.so.1", atf_tc_get_config_var(tc, "srcdir"));
	ATF_REQUIRE_EQ(pkg_analyse_elf(false, p, binpath, &provided, &provided_flags), EPKG_OK);
-
	ATF_REQUIRE_EQ(tll_length(p->shlibs_provided), 0);
+
	ATF_REQUIRE_EQ(vec_len(&p->shlibs_provided), 0);
	ATF_REQUIRE_STREQ(provided, "libtest2fbsd.so.1");
	ATF_REQUIRE_EQ(provided_flags, PKG_SHLIB_FLAGS_NONE);
-
	ATF_REQUIRE_EQ(tll_length(p->shlibs_required), 2);
-
	ATF_REQUIRE_STREQ(tll_front(p->shlibs_required), "libc.so.7");
-
	ATF_REQUIRE_STREQ(tll_back(p->shlibs_required), "libfoo.so.1");
+
	ATF_REQUIRE_EQ(vec_len(&p->shlibs_required), 2);
+
	ATF_REQUIRE_STREQ(vec_first(&p->shlibs_required), "libc.so.7");
+
	ATF_REQUIRE_STREQ(vec_last(&p->shlibs_required), "libfoo.so.1");
	free(provided);
	free(binpath);

modified tests/lib/plist.c
@@ -275,14 +275,14 @@ ATF_TC_BODY(parse_plist, tc)
ATF_TC_BODY(expand_plist_variables, tc)
{
	char *plop;
-
	kvlist_t kv = tll_init();
+
	kvlist_t kv = vec_init();

	plop = expand_plist_variables("%%this%% is a line", &kv);
	ATF_REQUIRE_STREQ(plop, "%%this%% is a line");
	free(plop);

	struct pkg_kv *keyval = pkg_kv_new("this", "@comment ");
-
	tll_push_back(kv, keyval);
+
	vec_push(&kv, keyval);

	plop = expand_plist_variables("%%this%% is a line", &kv);
	ATF_REQUIRE_STREQ(plop, "@comment  is a line");
@@ -297,7 +297,7 @@ ATF_TC_BODY(expand_plist_variables, tc)
	free(plop);

	struct pkg_kv *kv2 = pkg_kv_new("new", "var");
-
	tll_push_back(kv, kv2);
+
	vec_push(&kv, kv2);

	plop = expand_plist_variables("%%this%% %F is a %%new%% line", &kv);
	ATF_REQUIRE_STREQ(plop, "@comment  %F is a var line");
@@ -319,7 +319,7 @@ ATF_TC_BODY(expand_plist_variables, tc)
	ATF_REQUIRE_STREQ(plop, "@comment  %F is %%kof a var line %");
	free(plop);

-
	tll_free_and_free(kv, pkg_kv_free);
+
	vec_free_and_free(&kv, pkg_kv_free);
}

ATF_TP_ADD_TCS(tp)
modified tests/lib/shlibs.c
@@ -6,34 +6,80 @@

#include <atf-c.h>
#include <private/pkg.h>
-
#include <tllist.h>

ATF_TC_WITHOUT_HEAD(cleanup_shlibs_required);
+
ATF_TC_WITHOUT_HEAD(cleanup_shlibs_required_multiple_provided);
+
ATF_TC_WITHOUT_HEAD(cleanup_shlibs_required_consecutive_provided);

ATF_TC_BODY(cleanup_shlibs_required, tc)
{
	struct pkg *p;
-
	stringlist_t internal_provided = tll_init();
+
	charv_t internal_provided = vec_init();

	ATF_REQUIRE_EQ(pkg_new(&p, PKG_FILE), EPKG_OK);
	ATF_REQUIRE(p != NULL);
-
	tll_push_back(p->shlibs_required, xstrdup("lib1.so:32"));
-
	tll_push_back(p->shlibs_required, xstrdup("lib1.so"));
-
	tll_push_back(p->shlibs_required, xstrdup("libA.so"));
-
	tll_push_back(p->shlibs_required, xstrdup("libA.so:32"));
+
	vec_push(&p->shlibs_required, xstrdup("lib1.so:32"));
+
	vec_push(&p->shlibs_required, xstrdup("lib1.so"));
+
	vec_push(&p->shlibs_required, xstrdup("libA.so"));
+
	vec_push(&p->shlibs_required, xstrdup("libA.so:32"));
	pkg_cleanup_shlibs_required(p, &internal_provided);
-
	ATF_REQUIRE_EQ(tll_length(p->shlibs_required), 4);
-
	tll_push_back(p->shlibs_provided, "lib1.so");
+
	ATF_REQUIRE_EQ(vec_len(&p->shlibs_required), 4);
+
	vec_push(&p->shlibs_provided, "lib1.so");
	pkg_cleanup_shlibs_required(p, &internal_provided);
-
	ATF_REQUIRE_EQ(tll_length(p->shlibs_required), 3);
-
	tll_push_back(internal_provided, "lib1.so:32");
+
	ATF_REQUIRE_EQ(vec_len(&p->shlibs_required), 3);
+
	vec_push(&internal_provided, "lib1.so:32");
	pkg_cleanup_shlibs_required(p, &internal_provided);
-
	ATF_REQUIRE_EQ(tll_length(p->shlibs_required), 2);
+
	ATF_REQUIRE_EQ_MSG(vec_len(&p->shlibs_required), 2, "expecint 2 got %zu", vec_len(&p->shlibs_required));
+
}
+

+
ATF_TC_BODY(cleanup_shlibs_required_multiple_provided, tc)
+
{
+
	struct pkg *p;
+
	charv_t internal_provided = vec_init();
+

+
	ATF_REQUIRE_EQ(pkg_new(&p, PKG_FILE), EPKG_OK);
+
	ATF_REQUIRE(p != NULL);
+
	vec_push(&p->shlibs_required, xstrdup("lib1.so.1"));
+
	vec_push(&p->shlibs_required, xstrdup("libA.so.2"));
+
	vec_push(&p->shlibs_required, xstrdup("libB.so.2"));
+
	vec_push(&p->shlibs_required, xstrdup("libC.so.2"));
+
	vec_push(&p->shlibs_provided, xstrdup("libA.so.2"));
+
	vec_push(&p->shlibs_provided, xstrdup("libC.so.3"));
+
	vec_push(&p->shlibs_provided, xstrdup("libZ.so.3"));
+
	ATF_REQUIRE_EQ(vec_len(&p->shlibs_required), 4);
+
	pkg_cleanup_shlibs_required(p, &internal_provided);
+
	ATF_REQUIRE_EQ(vec_len(&p->shlibs_required), 3);
+
	ATF_REQUIRE_STREQ(p->shlibs_required.d[0], "lib1.so.1");
+
	ATF_REQUIRE_STREQ(p->shlibs_required.d[1], "libB.so.2");
+
	ATF_REQUIRE_STREQ(p->shlibs_required.d[2], "libC.so.2");
+
}
+

+
ATF_TC_BODY(cleanup_shlibs_required_consecutive_provided, tc)
+
{
+
	struct pkg *p;
+
	charv_t internal_provided = vec_init();
+

+
	ATF_REQUIRE_EQ(pkg_new(&p, PKG_FILE), EPKG_OK);
+
	ATF_REQUIRE(p != NULL);
+
	vec_push(&p->shlibs_required, xstrdup("lib1.so.1"));
+
	vec_push(&p->shlibs_required, xstrdup("libA.so.2"));
+
	vec_push(&p->shlibs_required, xstrdup("libB.so.2"));
+
	vec_push(&p->shlibs_required, xstrdup("libC.so.2"));
+
	vec_push(&p->shlibs_provided, xstrdup("libA.so.2"));
+
	vec_push(&p->shlibs_provided, xstrdup("libB.so.2"));
+
	vec_push(&p->shlibs_provided, xstrdup("libZ.so.3"));
+
	ATF_REQUIRE_EQ(vec_len(&p->shlibs_required), 4);
+
	pkg_cleanup_shlibs_required(p, &internal_provided);
+
	ATF_REQUIRE_EQ(vec_len(&p->shlibs_required), 2);
+
	ATF_REQUIRE_STREQ(p->shlibs_required.d[0], "lib1.so.1");
+
	ATF_REQUIRE_STREQ(p->shlibs_required.d[2], "libC.so.2");
}

ATF_TP_ADD_TCS(tp)
{
	ATF_TP_ADD_TC(tp, cleanup_shlibs_required);
+
	ATF_TP_ADD_TC(tp, cleanup_shlibs_required_multiple_provided);
+
	ATF_TP_ADD_TC(tp, cleanup_shlibs_required_consecutive_provided);

	return (atf_no_error());
}
modified tests/lib/vec.c
@@ -12,12 +12,14 @@
ATF_TC_WITHOUT_HEAD(c_charv_t);
ATF_TC_WITHOUT_HEAD(c_charv_contains);
ATF_TC_WITHOUT_HEAD(charv_t);
+
ATF_TC_WITHOUT_HEAD(vec_remove_and_free);
+
ATF_TC_WITHOUT_HEAD(charv_search);
+
ATF_TC_WITHOUT_HEAD(charv_insert_sorted);

ATF_TC_BODY(c_charv_t, tc)
{
-
	c_charv_t list;
+
	c_charv_t list = vec_init();

-
	vec_init(&list);
	ATF_REQUIRE_EQ_MSG(list.d, NULL, "vec_init failed");
	ATF_REQUIRE_EQ_MSG(list.cap, 0, "vec_init failed");
	ATF_REQUIRE_EQ_MSG(list.len, 0, "vec_init failed");
@@ -53,9 +55,8 @@ ATF_TC_BODY(c_charv_t, tc)

ATF_TC_BODY(charv_t, tc)
{
-
	charv_t list;
+
	charv_t list = vec_init();

-
	vec_init(&list);
	ATF_REQUIRE_EQ_MSG(list.d, NULL, "vec_init failed");
	ATF_REQUIRE_EQ_MSG(list.cap, 0, "vec_init failed");
	ATF_REQUIRE_EQ_MSG(list.len, 0, "vec_init failed");
@@ -91,9 +92,8 @@ ATF_TC_BODY(charv_t, tc)

ATF_TC_BODY(c_charv_contains, tc)
{
-
	c_charv_t list;
+
	c_charv_t list = vec_init();

-
	vec_init(&list);
	ATF_REQUIRE_EQ_MSG(list.d, NULL, "vec_init failed");
	ATF_REQUIRE_EQ_MSG(list.cap, 0, "vec_init failed");
	ATF_REQUIRE_EQ_MSG(list.len, 0, "vec_init failed");
@@ -120,11 +120,67 @@ ATF_TC_BODY(c_charv_contains, tc)
	vec_free(&list);
}

+
ATF_TC_BODY(vec_remove_and_free, tc)
+
{
+
	charv_t list = vec_init();
+

+
	vec_push(&list, xstrdup("test1"));
+
	ATF_REQUIRE_EQ(list.len, 1);
+
	vec_remove_and_free(&list, 0, free);
+
	ATF_REQUIRE_EQ(list.len, 0);
+
	vec_push(&list, xstrdup("test2"));
+
	vec_push(&list, xstrdup("test3"));
+
	vec_push(&list, xstrdup("test4"));
+
	ATF_REQUIRE_EQ(list.len, 3);
+
	vec_foreach(list, i) {
+
		if (strcmp(list.d[i], "test3") == 0) {
+
			vec_remove_and_free(&list, i, free);
+
		}
+
	}
+
	ATF_REQUIRE_EQ(list.len, 2);
+
	ATF_REQUIRE_STREQ(list.d[0], "test2");
+
	ATF_REQUIRE_STREQ(list.d[1], "test4");
+
}
+

+
ATF_TC_BODY(charv_search, tc)
+
{
+
	charv_t list = vec_init();
+

+
	ATF_REQUIRE(charv_search(&list, "key") == NULL);
+
	vec_push(&list, xstrdup("bla"));
+
	ATF_REQUIRE(charv_search(&list, "key") == NULL);
+
	ATF_REQUIRE_STREQ(charv_search(&list, "bla"), "bla");
+
	vec_free_and_free(&list, free);
+
}
+

+
ATF_TC_BODY(charv_insert_sorted, tc)
+
{
+
	charv_t list = vec_init();
+

+
	char *p = xstrdup("bla");
+
	ATF_REQUIRE_EQ(charv_insert_sorted(&list, p), NULL);
+
	ATF_REQUIRE_EQ(list.len, 1);
+
	ATF_REQUIRE_STREQ(list.d[0], "bla");
+

+
	ATF_REQUIRE(charv_insert_sorted(&list, p) != NULL);
+
	ATF_REQUIRE_EQ(list.len, 1);
+
	ATF_REQUIRE_STREQ(list.d[0], "bla");
+

+
	p = xstrdup("a");
+
	ATF_REQUIRE_EQ(charv_insert_sorted(&list, p), NULL);
+
	ATF_REQUIRE_EQ(list.len, 2);
+
	ATF_REQUIRE_STREQ(list.d[0], "a");
+
	ATF_REQUIRE_STREQ(list.d[1], "bla");
+
}
+

ATF_TP_ADD_TCS(tp)
{
	ATF_TP_ADD_TC(tp, c_charv_t);
	ATF_TP_ADD_TC(tp, charv_t);
	ATF_TP_ADD_TC(tp, c_charv_contains);
+
	ATF_TP_ADD_TC(tp, vec_remove_and_free);
+
	ATF_TP_ADD_TC(tp, charv_search);
+
	ATF_TP_ADD_TC(tp, charv_insert_sorted);

	return (atf_no_error());
}