Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Finish converting struct pkg into a proper structure
Baptiste Daroussin committed 11 years ago
commit eab4f94a9ccfc426dd9eaafdbca0625adff1cbaf
parent 6692e02
16 files changed +239 -249
modified libpkg/libpkg.ver
@@ -17,10 +17,10 @@ global:
	pkg_audit_load;
	pkg_audit_new;
	pkg_audit_process;
-
	pkg_category_name;
	pkg_compiled_for_same_os_major;
	pkg_conf;
	pkg_config_dump;
+
	pkg_config_files;
	pkg_config_get;
	pkg_conflict_uniqueid;
	pkg_conflicts;
@@ -29,7 +29,6 @@ global:
	pkg_create_installed;
	pkg_create_repo;
	pkg_create_staged;
-
	pkg_delannotation;
	pkg_dep_get;
	pkg_dep_is_locked;
	pkg_deps;
modified libpkg/pkg.c
@@ -84,7 +84,6 @@ pkg_new(struct pkg **pkg, pkg_t type)
		return EPKG_FATAL;
	}

-
	(*pkg)->fields = ucl_object_typed_new(UCL_OBJECT);
	(*pkg)->type = type;
	(*pkg)->rootfd = -1;

@@ -99,8 +98,6 @@ pkg_reset(struct pkg *pkg, pkg_t type)
	if (pkg == NULL)
		return;

-
	ucl_object_unref(pkg->fields);
-
	pkg->fields = ucl_object_typed_new(UCL_OBJECT);
	pkg->flags &= ~PKG_LOAD_CATEGORIES;
	pkg->flags &= ~PKG_LOAD_LICENSES;
	pkg->flags &= ~PKG_LOAD_ANNOTATIONS;
@@ -131,8 +128,6 @@ pkg_free(struct pkg *pkg)
	if (pkg == NULL)
		return;

-
	ucl_object_unref(pkg->fields);
-

	free(pkg->name);
	free(pkg->origin);
	free(pkg->old_version);
@@ -164,6 +159,11 @@ pkg_free(struct pkg *pkg)
	pkg_list_free(pkg, PKG_GROUPS);
	pkg_list_free(pkg, PKG_SHLIBS_REQUIRED);
	pkg_list_free(pkg, PKG_SHLIBS_PROVIDED);
+

+
	LL_FREE(pkg->categories, pkg_strel_free);
+
	LL_FREE(pkg->licenses, pkg_strel_free);
+
	LL_FREE(pkg->annotations, pkg_kv_free);
+

	if (pkg->rootfd != -1)
		close(pkg->rootfd);

@@ -398,13 +398,13 @@ pkg_vget(const struct pkg * restrict pkg, va_list ap)
			*va_arg(ap, int64_t *) = pkg->timestamp;
			break;
		case PKG_ANNOTATIONS:
-
			*va_arg(ap, const pkg_object **) = ucl_object_find_key(pkg->fields, "annotations");
+
			*va_arg(ap, const struct pkg_kv **) = pkg->annotations;
			break;
		case PKG_CATEGORIES:
-
			*va_arg(ap, const pkg_object **) = ucl_object_find_key(pkg->fields, "categories");
+
			*va_arg(ap, const struct pkg_strel **) = pkg->categories;
			break;
		case PKG_LICENSES:
-
			*va_arg(ap, const pkg_object **) = ucl_object_find_key(pkg->fields, "licenses");
+
			*va_arg(ap, const struct pkg_strel **) = pkg->licenses;
			break;
		case PKG_UNIQUEID:
			*va_arg(ap, const char **) = pkg->uid;
@@ -439,8 +439,9 @@ pkg_vset(struct pkg *pkg, va_list ap)
	int attr;

	while ((attr = va_arg(ap, int)) > 0) {
+
		printf("%d\n", attr);
		if (attr >= PKG_NUM_FIELDS || attr <= 0) {
-
			pkg_emit_error("Bad argument on pkg_get");
+
			pkg_emit_error("Bad argument on pkg_set %s", attr);
			return (EPKG_FATAL);
		}

@@ -710,41 +711,6 @@ pkg_provides(const struct pkg *pkg, struct pkg_provide **c)
}

int
-
pkg_addlicense(struct pkg *pkg, const char *name)
-
{
-
	const pkg_object *o, *licenses;
-
	pkg_object *l, *lic;
-
	pkg_iter iter = NULL;
-

-
	assert(pkg != NULL);
-
	assert(name != NULL && name[0] != '\0');
-

-
	pkg_get(pkg, PKG_LICENSES, &licenses);
-

-
	while ((o = pkg_object_iterate(licenses, &iter))) {
-
		if (strcmp(pkg_object_string(o), name) == 0) {
-
			if (pkg_object_bool(pkg_config_get("DEVELOPER_MODE"))) {
-
				pkg_emit_error("duplicate license listing: %s, fatal (developer mode)", name);
-
				return (EPKG_FATAL);
-
			} else {
-
				pkg_emit_error("duplicate license listing: %s, ignoring", name);
-
				return (EPKG_OK);
-
			}
-
		}
-
	}
-

-
	pkg_get(pkg, PKG_LICENSES, &lic);
-
	l = ucl_object_fromstring_common(name, strlen(name), 0);
-
	if (lic == NULL) {
-
		lic = ucl_object_typed_new(UCL_ARRAY);
-
		pkg_set(pkg, PKG_LICENSES, lic);
-
	}
-
	ucl_array_append(lic, l);
-

-
	return (EPKG_OK);
-
}
-

-
int
pkg_adduid(struct pkg *pkg, const char *name, const char *uidstr)
{
	struct pkg_user *u = NULL;
@@ -965,35 +931,29 @@ pkg_addconfig_file(struct pkg *pkg, const char *path, const char *content)
}

int
-
pkg_addcategory(struct pkg *pkg, const char *name)
+
pkg_strel_add(struct pkg_strel **list, const char *val, const char *title)
{
-
	const pkg_object *o, *categories;
-
	pkg_object *c, *cat;
-
	pkg_iter iter = NULL;
+
	struct pkg_strel *c;

-
	assert(pkg != NULL);
-
	assert(name != NULL && name[0] != '\0');
+
	assert(val != NULL);
+
	assert(title != NULL);

-
	pkg_get(pkg, PKG_CATEGORIES, &categories);
-
	while ((o = (pkg_object_iterate(categories, &iter)))) {
-
		if (strcmp(pkg_object_string(o), name) == 0) {
+
	LL_FOREACH(*list, c) {
+
		if (strcmp(c->value, val) == 0) {
			if (pkg_object_bool(pkg_config_get("DEVELOPER_MODE"))) {
-
				pkg_emit_error("duplicate category listing: %s, fatal (developer mode)", name);
+
				pkg_emit_error("duplicate %s listing: %s, fatal"
+
				    " (developer mode)", title, val);
				return (EPKG_FATAL);
			} else {
-
				pkg_emit_error("duplicate category listing: %s, ignoring", name);
+
				pkg_emit_error("duplicate %s listing: %s, "
+
				    "ignoring", title, val);
				return (EPKG_OK);
			}
		}
	}

-
	pkg_get(pkg, PKG_CATEGORIES, &cat);
-
	c = ucl_object_fromstring_common(name, strlen(name), 0);
-
	if (cat == NULL) {
-
		cat = ucl_object_typed_new(UCL_ARRAY);
-
		pkg_set(pkg, PKG_CATEGORIES, cat);
-
	}
-
	ucl_array_append(cat, c);
+
	pkg_strel_new(&c, val);
+
	LL_APPEND(*list, c);

	return (EPKG_OK);
}
@@ -1406,72 +1366,46 @@ pkg_addprovide(struct pkg *pkg, const char *name)
}

const char *
-
pkg_getannotation(const struct pkg *pkg, const char *tag)
+
pkg_kv_get(struct pkg_kv *const *kv, const char *tag)
{
-
	const ucl_object_t *an, *notes;
+
	struct pkg_kv *k;

-
	assert(pkg != NULL);
	assert(tag != NULL);

-
	pkg_get(pkg, PKG_ANNOTATIONS, &notes);
-
	an = pkg_object_find(notes, tag);
+
	LL_FOREACH(*kv, k) {
+
		if (strcmp(k->key, tag) == 0)
+
			return (k->value);
+
	}

-
	if (an == NULL)
-
		return (NULL);
-
	return (pkg_object_string(an));
+
	return (NULL);
}

int
-
pkg_addannotation(struct pkg *pkg, const char *tag, const char *value)
+
pkg_kv_add(struct pkg_kv **list, const char *key, const char *val, const char *title)
{
-
	ucl_object_t *o, *annotations;
+
	struct pkg_kv *kv;

-
	assert(pkg != NULL);
-
	assert(tag != NULL);
-
	assert(value != NULL);
+
	assert(val != NULL);
+
	assert(title != NULL);

-
	/* Tags are unique per-package */
-

-
	if (pkg_getannotation(pkg, tag) != NULL) {
-
		if (pkg_object_bool(pkg_config_get("DEVELOPER_MODE"))) {
-
			pkg_emit_error("duplicate annotation tag: %s value: %s,"
-
			    " fatal (developer mode)", tag, value);
-
			return (EPKG_OK);
-
		} else {
-
			pkg_emit_error("duplicate annotation tag: %s value: %s,"
-
			    " ignoring", tag, value);
-
			return (EPKG_OK);
+
	LL_FOREACH(*list, kv) {
+
		if (strcmp(kv->key, key) == 0) {
+
			if (pkg_object_bool(pkg_config_get("DEVELOPER_MODE"))) {
+
				pkg_emit_error("duplicate %s: %s, fatal"
+
				    " (developer mode)", title, key);
+
				return (EPKG_FATAL);
+
			} else {
+
				pkg_emit_error("duplicate %s: %s, "
+
				    "ignoring", title, val);
+
				return (EPKG_OK);
+
			}
		}
	}
-
	o = ucl_object_fromstring_common(value, strlen(value), 0);
-
	pkg_get(pkg, PKG_ANNOTATIONS, &annotations);
-
	if (annotations == NULL) {
-
		annotations = ucl_object_typed_new(UCL_OBJECT);
-
		pkg_set(pkg, PKG_ANNOTATIONS, annotations);
-
	}
-
	ucl_object_insert_key(annotations, o, tag, strlen(tag), true);

-
	return (EPKG_OK);
-
}
+
	pkg_kv_new(&kv, key, val);
+
	LL_APPEND(*list, kv);

-
int
-
pkg_delannotation(struct pkg *pkg, const char *tag)
-
{
-
	ucl_object_t *an, *notes;
-

-
	assert(pkg != NULL);
-
	assert(tag != NULL);
-

-
	pkg_get(pkg, PKG_ANNOTATIONS, &notes);
-
	an = ucl_object_pop_keyl(notes, tag, strlen(tag));
-
	if (an != NULL) {
-
		ucl_object_unref(an);
-
		return (EPKG_OK);
-
	} else {
-
		pkg_emit_error("deleting annotation tagged \'%s\' -- "
-
	           "not found", tag);
-
		return (EPKG_WARN);
-
	}
+
	return (EPKG_OK);
}

int
@@ -1986,7 +1920,7 @@ pkg_open_root_fd(struct pkg *pkg)
	if (pkg->rootfd != -1)
		return (EPKG_OK);

-
	path = pkg_getannotation(pkg, "relocated");
+
	path = pkg_kv_get(&pkg->annotations, "relocated");
	if (path == NULL)
		path = "/";

modified libpkg/pkg.h.in
@@ -83,7 +83,7 @@ struct pkg_dep;
struct pkg_conflict;
struct pkg_file;
struct pkg_dir;
-
struct pkg_category;
+
struct pkg_strel;
struct pkg_option;
struct pkg_license;
struct pkg_user;
@@ -108,6 +108,12 @@ struct pkg_manifest_parser;
typedef struct ucl_object_s pkg_object;
typedef void * pkg_iter;

+
struct pkg_kv {
+
	char *key;
+
	char *value;
+
	struct pkg_kv *next;
+
};
+

/**
 * The system-wide pkg(8) status: ie. is it a) installed or otherwise
 * available on the sysem, b) database (local.sqlite) initialised and
@@ -700,18 +706,6 @@ int pkg_addscript_file(struct pkg *pkg, const char *path);
int pkg_addscript_fileat(int fd, struct pkg *pkg, const char *path);

/**
-
 * Add annotation key+value pair
-
 * @return An error code
-
 */
-
int pkg_addannotation(struct pkg *pkg, const char *tag, const char *value);
-

-
/**
-
 * Delete annotation identified by the key
-
 * @return An error code
-
 */
-
int pkg_delannotation(struct pkg *pkg, const char *tag);
-

-
/**
 * Parse a manifest and set the attributes of pkg accordingly.
 * @param buf An NULL-terminated buffer containing the manifest data.
 * @return An error code.
@@ -752,9 +746,6 @@ bool pkg_dep_is_locked(struct pkg_dep const * const);
bool pkg_has_dir(struct pkg *, const char *);
bool pkg_has_file(struct pkg *, const char *);

-
/* pkg_category */
-
const char *pkg_category_name(struct pkg_category const * const);
-

/* pkg_license */
const char *pkg_license_name(struct pkg_license const * const);

modified libpkg/pkg_add.c
@@ -486,8 +486,8 @@ pkg_add_common(struct pkgdb *db, const char *path, unsigned flags,
	else {
		if (remote->repo != NULL) {
			/* Save reponame */
-
			pkg_addannotation(pkg, "repository", remote->repo->name);
-
			pkg_addannotation(pkg, "repo_type", remote->repo->ops->type);
+
			pkg_kv_add(&pkg->annotations, "repository", remote->repo->name, "annotation");
+
			pkg_kv_add(&pkg->annotations, "repo_type", remote->repo->ops->type, "annotation");
		}

		free(pkg->digest);
@@ -498,7 +498,7 @@ pkg_add_common(struct pkgdb *db, const char *path, unsigned flags,
	}

	if (location != NULL)
-
		pkg_addannotation(pkg, "relocated", location);
+
		pkg_kv_add(&pkg->annotations, "relocated", location, "annotation");

	/* register the package before installing it in case there are
	 * problems that could be caught here. */
modified libpkg/pkg_attributes.c
@@ -354,3 +354,55 @@ pkg_config_file_free(struct pkg_config_file *c)
	free(c->content);
	free(c);
}
+

+
/*
+
 * strel
+
 */
+

+
int
+
pkg_strel_new(struct pkg_strel **c, const char *val)
+
{
+
	if ((*c = calloc(1, sizeof(struct pkg_strel))) == NULL)
+
		return (EPKG_FATAL);
+

+
	(*c)->value = strdup(val);
+

+
	return (EPKG_OK);
+
}
+

+
void
+
pkg_strel_free(struct pkg_strel *c)
+
{
+
	if (c == NULL)
+
		return;
+

+
	free(c->value);
+
	free(c);
+
}
+

+
/*
+
 * kv
+
 */
+

+
int
+
pkg_kv_new(struct pkg_kv **c, const char *key, const char *val)
+
{
+
	if ((*c = calloc(1, sizeof(struct pkg_kv))) == NULL)
+
		return (EPKG_FATAL);
+

+
	(*c)->key = strdup(key);
+
	(*c)->value = strdup(val);
+

+
	return (EPKG_OK);
+
}
+

+
void
+
pkg_kv_free(struct pkg_kv *c)
+
{
+
	if (c == NULL)
+
		return;
+

+
	free(c->key);
+
	free(c->value);
+
	free(c);
+
}
modified libpkg/pkg_create.c
@@ -60,7 +60,7 @@ pkg_create_from_dir(struct pkg *pkg, const char *root,
		return (EPKG_FATAL);
	}

-
	relocation = pkg_getannotation(pkg, "relocated");
+
	relocation = pkg_kv_get(&pkg->annotations, "relocated");
	if (relocation == NULL)
		relocation = "";

modified libpkg/pkg_elf.c
@@ -501,7 +501,7 @@ pkg_analyse_files(struct pkgdb *db, struct pkg *pkg, const char *stage)
	 * if the package is not supposed to provide share libraries then
	 * drop the provided one
	 */
-
	if (pkg_getannotation(pkg, "no_provide_shlib") != NULL)
+
	if (pkg_kv_get(&pkg->annotations, "no_provide_shlib") != NULL)
		HASH_FREE(pkg->shlibs_provided, pkg_shlib_free);

	if (failures)
modified libpkg/pkg_jobs.c
@@ -489,7 +489,7 @@ pkg_jobs_process_add_request(struct pkg_jobs *j, bool top)
			lp = pkg_jobs_universe_get_local(j->universe, req->item->pkg->uid, 0);
			/* Check reponame */
			if (lp != NULL)
-
				lrepo = pkg_getannotation(lp, "repository");
+
				lrepo = pkg_kv_get(&lp->annotations, "repository");

			DL_FOREACH(req->item, it) {
				rrepo = it->pkg->reponame;
modified libpkg/pkg_manifest.c
@@ -361,13 +361,15 @@ pkg_array(struct pkg *pkg, const ucl_object_t *obj, int attr)
			if (cur->type != UCL_STRING)
				pkg_emit_error("Skipping malformed category");
			else
-
				pkg_addcategory(pkg, ucl_object_tostring(cur));
+
				pkg_strel_add(&pkg->categories,
+
				    ucl_object_tostring(cur), "category");
			break;
		case PKG_LICENSES:
			if (cur->type != UCL_STRING)
				pkg_emit_error("Skipping malformed license");
			else
-
				pkg_addlicense(pkg, ucl_object_tostring(cur));
+
				pkg_strel_add(&pkg->licenses,
+
				    ucl_object_tostring(cur), "license");
			break;
		case PKG_USERS:
			if (cur->type == UCL_STRING)
@@ -548,7 +550,7 @@ pkg_obj(struct pkg *pkg, const ucl_object_t *obj, int attr)
				pkg_emit_error("Skipping malformed annotation %s",
				    key);
			else
-
				pkg_addannotation(pkg, key, ucl_object_tostring(cur));
+
				pkg_kv_add(&pkg->annotations, key, ucl_object_tostring(cur), "annotation");
			break;
		}
	}
@@ -908,6 +910,8 @@ pkg_emit_filelist(struct pkg *pkg, FILE *f)
pkg_object*
pkg_emit_object(struct pkg *pkg, short flags)
{
+
	struct pkg_strel	*el;
+
	struct pkg_kv		*kv;
	struct pkg_dep		*dep      = NULL;
	struct pkg_option	*option   = NULL;
	struct pkg_file		*file     = NULL;
@@ -922,17 +926,8 @@ pkg_emit_object(struct pkg *pkg, short flags)
	int i;
	const char *script_types = NULL;
	char legacyarch[BUFSIZ];
-
	ucl_object_iter_t it = NULL;
-
	ucl_object_t *annotations, *categories, *licenses;
	ucl_object_t *map, *seq, *submap;
	ucl_object_t *top = ucl_object_typed_new(UCL_OBJECT);
-
	const ucl_object_t *o;
-
	const char *key;
-
	size_t key_len;
-

-
	pkg_get(pkg, 
-
	    PKG_ANNOTATIONS, &annotations, PKG_LICENSES, &licenses,
-
	    PKG_CATEGORIES, &categories);

	pkg_arch_to_legacy(pkg->abi, legacyarch, BUFSIZ);
	pkg->arch = strdup(pkg->arch);
@@ -942,7 +937,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
	ucl_object_insert_key(top, ucl_object_fromstring_common(pkg->origin, 0,
	    UCL_STRING_TRIM), "origin", 6, false);
	ucl_object_insert_key(top, ucl_object_fromstring_common(pkg->version, 0,
-
	    UCL_STRING_TRIM), "version", 6, false);
+
	    UCL_STRING_TRIM), "version", 7, false);
	ucl_object_insert_key(top, ucl_object_fromstring_common(pkg->comment, 0,
	    UCL_STRING_TRIM), "comment", 7, false);
	ucl_object_insert_key(top, ucl_object_fromstring_common(pkg->maintainer, 0,
@@ -952,7 +947,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
	ucl_object_insert_key(top, ucl_object_fromstring_common(pkg->abi, 0,
	    UCL_STRING_TRIM), "abi", 3, false);
	ucl_object_insert_key(top, ucl_object_fromstring_common(pkg->arch, 0,
-
	    UCL_STRING_TRIM), "arch", 3, false);
+
	    UCL_STRING_TRIM), "arch", 4, false);
	ucl_object_insert_key(top, ucl_object_fromstring_common(pkg->prefix, 0,
	    UCL_STRING_TRIM), "prefix", 6, false);
	ucl_object_insert_key(top, ucl_object_fromstring_common(pkg->sum, 0,
@@ -981,9 +976,15 @@ pkg_emit_object(struct pkg *pkg, short flags)
	}

	pkg_debug(4, "Emitting licenses");
-
	if (licenses != NULL)
-
		ucl_object_insert_key(top,
-
		    ucl_object_ref(licenses), "licenses", 8, false);
+
	seq = NULL;
+
	el = NULL;
+
	LL_FOREACH(pkg->licenses, el) {
+
		if (seq == NULL)
+
			seq = ucl_object_typed_new(UCL_ARRAY);
+
		ucl_array_append(seq, ucl_object_fromstring(el->value));
+
	}
+
	if (seq)
+
		ucl_object_insert_key(top, seq, "licenses", 8, false);

	if (pkg->pkgsize > 0)
		ucl_object_insert_key(top, ucl_object_fromint(pkg->pkgsize), "pkgsize", 7, false);
@@ -1009,9 +1010,15 @@ pkg_emit_object(struct pkg *pkg, short flags)
		ucl_object_insert_key(top, map, "deps", 4, false);

	pkg_debug(4, "Emitting categories");
-
	if (categories != NULL)
-
		ucl_object_insert_key(top,
-
		    ucl_object_ref(categories), "categories", 10, false);
+
	seq = NULL;
+
	el = NULL;
+
	LL_FOREACH(pkg->categories, el) {
+
		if (seq == NULL)
+
			seq = ucl_object_typed_new(UCL_ARRAY);
+
		ucl_array_append(seq, ucl_object_fromstring(el->value));
+
	}
+
	if (seq)
+
		ucl_object_insert_key(top, seq, "categories", 10, false);

	pkg_debug(4, "Emitting users");
	seq = NULL;
@@ -1090,22 +1097,20 @@ pkg_emit_object(struct pkg *pkg, short flags)
	if (map)
		ucl_object_insert_key(top, map, "options", 7, false);

-
	if (annotations != NULL) {
-
		it = NULL;
-
		map = ucl_object_typed_new(UCL_OBJECT);
+
	map = NULL;
+
	kv = NULL;
+
	LL_FOREACH(pkg->annotations, kv) {
+
		if (map == NULL)
+
			map = ucl_object_typed_new(UCL_OBJECT);
		/* Add annotations except for internal ones. */
-
		while ((o = ucl_iterate_object(annotations, &it, true))) {
-
			if ((key = ucl_object_keyl(o, &key_len)) == NULL)
-
				continue;
-
			/* Internal annotations. */
-
			if (strcmp(key, "repository") == 0 ||
-
			    strcmp(key, "relocated") == 0)
-
				continue;
-
			ucl_object_insert_key(map, ucl_object_ref(o), key,
-
			    key_len, true);
-
		}
-
		ucl_object_insert_key(top, map, "annotations", 11, false);
+
		if (strcmp(kv->key, "repository") == 0 ||
+
		    strcmp(kv->key, "relocated") == 0)
+
			continue;
+
		ucl_object_insert_key(map, ucl_object_fromstring(kv->value),
+
		    kv->key, strlen(kv->key), true);
	}
+
	if (map)
+
		ucl_object_insert_key(top, map, "annotations", 11, false);

	if ((flags & PKG_MANIFEST_EMIT_COMPACT) == 0) {
		if ((flags & PKG_MANIFEST_EMIT_NOFILES) == 0) {
modified libpkg/pkg_ports.c
@@ -1230,7 +1230,7 @@ pkg_add_port(struct pkgdb *db, struct pkg *pkg, const char *input_path,
	int rc = EPKG_OK;

	if (location != NULL)
-
		pkg_addannotation(pkg, "relocated", location);
+
		pkg_kv_add(&pkg->annotations, "relocated", location, "annotation");

	pkg_emit_install_begin(pkg);

modified libpkg/pkg_printf.c
@@ -36,6 +36,7 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
+
#include <utlist.h>

#include "pkg.h"
#include <private/pkg_printf.h>
@@ -910,27 +911,22 @@ struct sbuf *
format_categories(struct sbuf *sbuf, const void *data, struct percent_esc *p)
{
	const struct pkg	*pkg = data;
-
	const pkg_object	*obj;
-

-
	pkg_get(pkg, PKG_CATEGORIES, &obj);
-

-
	if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
-
		return (list_count(sbuf, pkg_object_count(obj), p));
-
	else {
-
		const pkg_object	*cat;
-
		pkg_iter		 it = NULL;
-
		int			 count;
+
	struct pkg_strel	*el;
+
	int			 count = 0;

+
	if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) {
+
		LL_COUNT(pkg->categories, el, count);
+
		return (list_count(sbuf, count, p));
+
	} else {
		set_list_defaults(p, "%Cn", ", ");

		count = 1;
-
		while ((cat = pkg_object_iterate(obj, &it))) {
+
		LL_FOREACH(pkg->categories, el) {
			if (count > 1)
-
				iterate_item(sbuf, pkg, sbuf_data(p->sep_fmt),
-
					     cat, count, PP_C);
+
				iterate_item(sbuf, pkg, el->value, el, count,
+
				    PP_C);

-
			iterate_item(sbuf, pkg, sbuf_data(p->item_fmt), 
-
				     cat, count, PP_C);
+
			iterate_item(sbuf, pkg, el->value, el, count, PP_C);
			count++;
		}
	}
@@ -1191,27 +1187,22 @@ struct sbuf *
format_licenses(struct sbuf *sbuf, const void *data, struct percent_esc *p)
{
	const struct pkg	*pkg = data;
-
	const pkg_object	*obj;
-

-
	pkg_get(pkg, PKG_LICENSES, &obj);
-

-
	if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
-
		return (list_count(sbuf, pkg_object_count(obj), p));
-
	else {
-
		const pkg_object	*lic;
-
		pkg_iter		 iter = NULL;
-
		int			 count;
+
	struct pkg_strel	*el;
+
	int			 count = 0;

+
	if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) {
+
		LL_COUNT(pkg->licenses, el, count);
+
		return (list_count(sbuf, count, p));
+
	} else {
		set_list_defaults(p, "%Ln", " %l ");

		count = 1;
-
		while ((lic = pkg_object_iterate(obj, &iter))) {
+
		LL_FOREACH(pkg->licenses, el) {
			if (count > 1)
-
				iterate_item(sbuf, pkg, sbuf_data(p->sep_fmt),
-
					     lic, count, PP_L);
+
				iterate_item(sbuf, pkg, el->value, el, count,
+
				    PP_L);

-
			iterate_item(sbuf, pkg, sbuf_data(p->item_fmt),
-
				     lic, count, PP_L);
+
			iterate_item(sbuf, pkg, el->value, el, count, PP_L);
			count++;
		}
	}
@@ -1251,7 +1242,7 @@ format_repo_ident(struct sbuf *sbuf, const void *data, struct percent_esc *p)

	reponame = pkg->reponame;
	if (reponame == NULL) {
-
		reponame = pkg_getannotation(pkg, "repository");
+
		reponame = pkg_kv_get(&pkg->annotations, "repository");
		if (reponame == NULL)
			reponame = "unknown-repository";
	}
modified libpkg/pkgdb_iterator.c
@@ -95,6 +95,24 @@ static struct column_mapping {
};

static int
+
pkg_addcategory(struct pkg *pkg, const char *data)
+
{
+
	return (pkg_strel_add(&pkg->categories, data, "category"));
+
}
+

+
static int
+
pkg_addlicense(struct pkg *pkg, const char *data)
+
{
+
	return (pkg_strel_add(&pkg->licenses, data, "license"));
+
}
+

+
static int
+
pkg_addannotation(struct pkg *pkg, const char *k, const char *v)
+
{
+
	return (pkg_kv_add(&pkg->annotations, k, v, "annotation"));
+
}
+

+
static int
load_val(sqlite3 *db, struct pkg *pkg, const char *sql, unsigned flags,
    int (*pkg_adddata)(struct pkg *pkg, const char *data), int list)
{
modified libpkg/private/pkg.h
@@ -121,7 +121,6 @@ struct pkg_repo_it;
struct pkg_repo;

struct pkg {
-
	ucl_object_t	*fields;
	bool		 direct;
	bool		 locked;
	bool		 automatic;
@@ -154,6 +153,8 @@ struct pkg {
	int64_t			 timestamp;
	struct pkg_dep		*deps;
	struct pkg_dep		*rdeps;
+
	struct pkg_strel	*categories;
+
	struct pkg_strel	*licenses;
	struct pkg_file		*files;
	struct pkg_dir		*dirs;
	struct pkg_option	*options;
@@ -164,6 +165,7 @@ struct pkg {
	struct pkg_conflict *conflicts;
	struct pkg_provide	*provides;
	struct pkg_config_file	*config_files;
+
	struct pkg_kv		*annotations;
	unsigned			flags;
	int		rootfd;
	char		rootpath[MAXPATHLEN];
@@ -185,6 +187,11 @@ struct pkg_dep {
	UT_hash_handle	 hh;
};

+
struct pkg_strel {
+
	char *value;
+
	struct pkg_strel *next;
+
};
+

enum pkg_conflict_type {
	PKG_CONFLICT_ALL = 0,
	PKG_CONFLICT_REMOTE_LOCAL,
@@ -512,6 +519,12 @@ int pkg_validate(struct pkg *pkg);

void pkg_list_free(struct pkg *, pkg_list);

+
int pkg_strel_new(struct pkg_strel **, const char *val);
+
void pkg_strel_free(struct pkg_strel *);
+

+
int pkg_kv_new(struct pkg_kv **, const char *key, const char *val);
+
void pkg_kv_free(struct pkg_kv *);
+

int pkg_dep_new(struct pkg_dep **);
void pkg_dep_free(struct pkg_dep *);

@@ -612,7 +625,6 @@ void pkg_add_dir_to_del(struct pkg *pkg, const char *file, const char *dir);
struct plist *plist_new(struct pkg *p, const char *stage);
int plist_parse_line(struct pkg *pkg, struct plist *p, char *line);
void plist_free(struct plist *);
-
const char *pkg_getannotation(const struct pkg *, const char *);
int pkg_appendscript(struct pkg *pkg, const char *cmd, pkg_script type);

int pkg_addscript(struct pkg *pkg, const char *data, pkg_script type);
@@ -628,8 +640,9 @@ int pkg_adddir_attr(struct pkg *pkg, const char *path, const char *uname,
		    const char *gname, mode_t perm, bool try,
		    bool check_duplicates);

-
int pkg_addcategory(struct pkg *pkg, const char *name);
-
int pkg_addlicense(struct pkg *pkg, const char *name);
+
int pkg_strel_add(struct pkg_strel **l, const char *name, const char *title);
+
int pkg_kv_add(struct pkg_kv **kv, const char *key, const char *value, const char *title);
+
const char *pkg_kv_get(struct pkg_kv *const*kv, const char *key);
int pkg_adduser(struct pkg *pkg, const char *name);
int pkg_addgroup(struct pkg *pkg, const char *group);
int pkg_adduid(struct pkg *pkg, const char *name, const char *uidstr);
@@ -647,5 +660,4 @@ int pkg_addoption_description(struct pkg *pkg, const char *key, const char *desc
int pkg_arch_to_legacy(const char *arch, char *dest, size_t sz);
bool pkg_is_config_file(struct pkg *p, const char *path, const struct pkg_file **file, struct pkg_config_file **cfile);

-

#endif
modified libpkg/repo/binary/update.c
@@ -138,15 +138,11 @@ pkg_repo_binary_add_pkg(struct pkg *pkg, const char *pkg_path,
	struct pkg_dep		*dep      = NULL;
	struct pkg_option	*option   = NULL;
	struct pkg_shlib	*shlib    = NULL;
-
	const pkg_object	*obj, *licenses, *categories, *annotations;
+
	struct pkg_strel	*el;
+
	struct pkg_kv		*kv;
	const char		*arch;
-
	pkg_iter		 it;
	int64_t			 package_id;

-
	pkg_get(pkg,
-
	    PKG_LICENSES, &licenses, PKG_CATEGORIES, &categories,
-
	    PKG_ANNOTATIONS, &annotations);
-

	arch = pkg->abi != NULL ? pkg->abi : pkg->arch;

try_again:
@@ -195,30 +191,28 @@ try_again:
		}
	}

-
	it = NULL;
-
	while ((obj = pkg_object_iterate(categories, &it))) {
-
		ret = pkg_repo_binary_run_prstatement(CAT1, pkg_object_string(obj));
+
	LL_FOREACH(pkg->categories, el) {
+
		ret = pkg_repo_binary_run_prstatement(CAT1, el->value);
		if (ret == SQLITE_DONE)
			ret = pkg_repo_binary_run_prstatement(CAT2, package_id,
-
			    pkg_object_string(obj));
-
		if (ret != SQLITE_DONE)
-
		{
+
			    el->value);
+
		if (ret != SQLITE_DONE) {
			ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(CAT2));
			return (EPKG_FATAL);
		}
	}

-
	it = NULL;
-
	while ((obj = pkg_object_iterate(licenses, &it))) {
-
		ret = pkg_repo_binary_run_prstatement(LIC1, pkg_object_string(obj));
+
	LL_FOREACH(pkg->licenses, el) {
+
		ret = pkg_repo_binary_run_prstatement(LIC1, el->value);
		if (ret == SQLITE_DONE)
			ret = pkg_repo_binary_run_prstatement(LIC2, package_id,
-
			    pkg_object_string(obj));
+
			    el->value);
		if (ret != SQLITE_DONE) {
			ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(LIC2));
			return (EPKG_FATAL);
		}
	}
+

	option = NULL;
	while (pkg_options(pkg, &option) == EPKG_OK) {
		ret = pkg_repo_binary_run_prstatement(OPT1, pkg_option_opt(option));
@@ -259,17 +253,13 @@ try_again:
		}
	}

-
	it = NULL;
-
	while ((obj = pkg_object_iterate(annotations, &it))) {
-
		const char *note_tag = pkg_object_key(obj);
-
		const char *note_val = pkg_object_string(obj);
-

-
		ret = pkg_repo_binary_run_prstatement(ANNOTATE1, note_tag);
+
	LL_FOREACH(pkg->annotations, kv) {
+
		ret = pkg_repo_binary_run_prstatement(ANNOTATE1, kv->key);
		if (ret == SQLITE_DONE)
-
			ret = pkg_repo_binary_run_prstatement(ANNOTATE1, note_val);
+
			ret = pkg_repo_binary_run_prstatement(ANNOTATE1, kv->value);
		if (ret == SQLITE_DONE)
			ret = pkg_repo_binary_run_prstatement(ANNOTATE2, package_id,
-
				  note_tag, note_val);
+
				  kv->key, kv->value);
		if (ret != SQLITE_DONE) {
			ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(ANNOTATE2));
			return (EPKG_FATAL);
modified src/annotate.c
@@ -142,23 +142,22 @@ do_delete(struct pkgdb *db, struct pkg *pkg, const char *tag)
static int
do_show(struct pkg *pkg, const char *tag)
{
-
	const pkg_object	*annotations, *note;
-
	pkg_iter		 it = NULL;
-
	int			 ret = EPKG_OK;
+
	struct pkg_kv *note;

-
	pkg_get(pkg, PKG_ANNOTATIONS, &annotations);
-
	while ((note = pkg_object_iterate(annotations, &it)) != NULL) {
-
		if (strcmp(tag, pkg_object_key(note)) == 0) {
+
	pkg_get(pkg, PKG_ANNOTATIONS, &note);
+
	while (note != NULL) {
+
		if (strcmp(tag, note->key) == 0) {
			if (quiet)
-
				printf("%s\n", pkg_object_string(note));
+
				printf("%s\n", note->value);
			else
				pkg_printf("%n-%v: Tag: %S Value: %S\n",
-
				    pkg, pkg, pkg_object_key(note),
-
				    pkg_object_string(note));
+
				    pkg, pkg, note->key, note->value);
+
			return (EPKG_OK);
		}
+
		note = note->next;
	}

-
	return (ret);
+
	return (EPKG_FATAL);
}


modified src/query.c
@@ -333,8 +333,7 @@ print_query(struct pkg *pkg, char *qstr, char multiline)
	struct pkg_dep		*dep    = NULL;
	struct pkg_option	*option = NULL;
	struct pkg_file		*file   = NULL;
-
	const pkg_object	*o, *list;
-
	pkg_iter		 it;
+
	struct pkg_kv		*kv;

	switch (multiline) {
	case 'd':
@@ -383,11 +382,11 @@ print_query(struct pkg *pkg, char *qstr, char multiline)
		pkg_printf("%b", pkg);
		break;
	case 'A':
-
		it = NULL;
-
		pkg_get(pkg, PKG_ANNOTATIONS, &list);
-
		while ((o = pkg_object_iterate(list, &it))) {
-
			format_str(pkg, output, qstr, o);
+
		pkg_get(pkg, PKG_ANNOTATIONS, &kv);
+
		while (kv != NULL) {
+
			format_str(pkg, output, qstr, kv);
			printf("%s\n", sbuf_data(output));
+
			kv = kv->next;
		}
		break;
	default: