From f84b587d9cf0879e614368482ff1919424aef6d1 Mon Sep 17 00:00:00 2001 From: Duncan Overbruck Date: Mon, 20 Feb 2023 23:54:08 +0100 Subject: [PATCH] bin/xbps-query: add -F/--format flag --- bin/xbps-query/defs.h | 8 +- bin/xbps-query/list.c | 273 ++++++++++++++++++++++-------------------- bin/xbps-query/main.c | 53 ++++++-- 3 files changed, 182 insertions(+), 152 deletions(-) diff --git a/bin/xbps-query/defs.h b/bin/xbps-query/defs.h index 2a1747253..0f4623114 100644 --- a/bin/xbps-query/defs.h +++ b/bin/xbps-query/defs.h @@ -52,14 +52,10 @@ int repo_show_pkg_namedesc(struct xbps_handle *, xbps_object_t, void *, int ownedby(struct xbps_handle *, const char *, bool, bool); /* From list.c */ -unsigned int find_longest_pkgver(struct xbps_handle *, xbps_object_t); - -int list_pkgs_in_dict(struct xbps_handle *, xbps_object_t, const char *, void *, bool *); int list_manual_pkgs(struct xbps_handle *, xbps_object_t, const char *, void *, bool *); -int list_hold_pkgs(struct xbps_handle *, xbps_object_t, const char *, void *, bool *); -int list_repolock_pkgs(struct xbps_handle *, xbps_object_t, const char *, void *, bool *); -int list_orphans(struct xbps_handle *); +int list_orphans(struct xbps_handle *, const char *); int list_pkgs_pkgdb(struct xbps_handle *); +int list_pkgdb(struct xbps_handle *, int (*filter)(xbps_object_t), const char *format); int repo_list(struct xbps_handle *); diff --git a/bin/xbps-query/list.c b/bin/xbps-query/list.c index c22ae00de..ff46dda28 100644 --- a/bin/xbps-query/list.c +++ b/bin/xbps-query/list.c @@ -24,29 +24,59 @@ */ #include -#include + +#include +#include +#include +#include #include +#include #include -#include #include -#include #include "defs.h" +#include "xbps.h" + +struct length_max_cb { + const char *key; + int max; +}; + +static int +length_max_cb(struct xbps_handle *xhp UNUSED, xbps_object_t obj, + const char *key UNUSED, void *arg, bool *loop_done UNUSED) +{ + struct length_max_cb *ctx = arg; + const char *s = NULL; + size_t len; + + if (!xbps_dictionary_get_cstring_nocopy(obj, ctx->key, &s)) + return -errno; + + len = strlen(s); + if (len > INT_MAX) + return -ERANGE; + if ((int)len > ctx->max) + ctx->max = len; + + return 0; +} struct list_pkgver_cb { - unsigned int pkgver_len; + unsigned int pkgver_align; unsigned int maxcols; - char *linebuf; + char *buf; + struct xbps_fmt *fmt; }; -int -list_pkgs_in_dict(struct xbps_handle *xhp UNUSED, +static int +list_pkgs_pkgdb_cb(struct xbps_handle *xhp UNUSED, xbps_object_t obj, const char *key UNUSED, void *arg, bool *loop_done UNUSED) { - struct list_pkgver_cb *lpc = arg; + struct list_pkgver_cb *ctx = arg; const char *pkgver = NULL, *short_desc = NULL, *state_str = NULL; unsigned int len; pkg_state_t state; @@ -58,104 +88,107 @@ list_pkgs_in_dict(struct xbps_handle *xhp UNUSED, xbps_pkg_state_dictionary(obj, &state); - if (state == XBPS_PKG_STATE_INSTALLED) - state_str = "ii"; - else if (state == XBPS_PKG_STATE_UNPACKED) - state_str = "uu"; - else if (state == XBPS_PKG_STATE_HALF_REMOVED) - state_str = "hr"; - else - state_str = "??"; - - if (lpc->linebuf == NULL) { - printf("%s %-*s %s\n", - state_str, - lpc->pkgver_len, pkgver, - short_desc); + switch (state) { + case XBPS_PKG_STATE_INSTALLED: state_str = "ii"; break; + case XBPS_PKG_STATE_UNPACKED: state_str = "uu"; break; + case XBPS_PKG_STATE_HALF_REMOVED: state_str = "hr"; break; + case XBPS_PKG_STATE_BROKEN: state_str = "br"; break; + case XBPS_PKG_STATE_NOT_INSTALLED: state_str = "??"; break; + } + + if (!ctx->buf) { + printf("%s %-*s %s\n", state_str, ctx->pkgver_align, pkgver, + short_desc); return 0; } - len = snprintf(lpc->linebuf, lpc->maxcols, "%s %-*s %s", - state_str, - lpc->pkgver_len, pkgver, - short_desc); /* add ellipsis if the line was truncated */ - if (len >= lpc->maxcols && lpc->maxcols > 4) { - for (unsigned int j = 0; j < 3; j++) - lpc->linebuf[lpc->maxcols-j-1] = '.'; - lpc->linebuf[lpc->maxcols] = '\0'; - } - puts(lpc->linebuf); + len = snprintf(ctx->buf, ctx->maxcols, "%s %-*s %s\n", state_str, + ctx->pkgver_align, pkgver, short_desc); + if (len >= ctx->maxcols && ctx->maxcols > sizeof("...")) + memcpy(ctx->buf + ctx->maxcols - sizeof("..."), "...", sizeof("...")); + fputs(ctx->buf, stdout); return 0; } int -list_manual_pkgs(struct xbps_handle *xhp UNUSED, - xbps_object_t obj, - const char *key UNUSED, - void *arg UNUSED, - bool *loop_done UNUSED) +list_pkgs_pkgdb(struct xbps_handle *xhp) { - const char *pkgver = NULL; - bool automatic = false; + struct length_max_cb longest = {.key = "pkgver"}; + struct list_pkgver_cb lpc = {0}; - xbps_dictionary_get_bool(obj, "automatic-install", &automatic); - if (automatic == false) { - xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); - puts(pkgver); + int r = xbps_pkgdb_foreach_cb_multi(xhp, length_max_cb, &longest); + if (r < 0) + return r; + + lpc.pkgver_align = longest.max; + lpc.maxcols = get_maxcols(); + if (lpc.maxcols > 0) { + lpc.buf = malloc(lpc.maxcols); + if (!lpc.buf) + return -errno; } - return 0; + return xbps_pkgdb_foreach_cb(xhp, list_pkgs_pkgdb_cb, &lpc); } -int -list_hold_pkgs(struct xbps_handle *xhp UNUSED, - xbps_object_t obj, - const char *key UNUSED, - void *arg UNUSED, - bool *loop_done UNUSED) -{ - const char *pkgver = NULL; +struct list_pkgdb_cb { + struct xbps_fmt *fmt; + int (*filter)(xbps_object_t obj); +}; - if (xbps_dictionary_get(obj, "hold")) { - xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); - puts(pkgver); +static int +list_pkgdb_cb(struct xbps_handle *xhp UNUSED, xbps_object_t obj, + const char *key UNUSED, void *arg, bool *loop_done UNUSED) +{ + struct list_pkgdb_cb *ctx = arg; + int r; + + if (ctx->filter) { + r = ctx->filter(obj); + if (r < 0) + return r; + if (r == 0) + return 0; } + r = xbps_fmt_dictionary(ctx->fmt, obj, stdout); + if (r < 0) + return r; return 0; } int -list_repolock_pkgs(struct xbps_handle *xhp UNUSED, - xbps_object_t obj, - const char *key UNUSED, - void *arg UNUSED, - bool *loop_done UNUSED) +list_pkgdb(struct xbps_handle *xhp, int (*filter)(xbps_object_t), const char *format) { - const char *pkgver = NULL; - - if (xbps_dictionary_get(obj, "repolock")) { - xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); - puts(pkgver); + struct list_pkgdb_cb ctx = {.filter = filter}; + int r; + + ctx.fmt = xbps_fmt_parse(format); + if (!ctx.fmt) { + r = -errno; + xbps_error_printf("failed to parse format: %s\n", strerror(-r)); + return r; } - - return 0; + r = xbps_pkgdb_foreach_cb(xhp, list_pkgdb_cb, &ctx); + xbps_fmt_free(ctx.fmt); + return r; } int -list_orphans(struct xbps_handle *xhp) +list_manual_pkgs(struct xbps_handle *xhp UNUSED, + xbps_object_t obj, + const char *key UNUSED, + void *arg UNUSED, + bool *loop_done UNUSED) { - xbps_array_t orphans; const char *pkgver = NULL; + bool automatic = false; - orphans = xbps_find_pkg_orphans(xhp, NULL); - if (orphans == NULL) - return EINVAL; - - for (unsigned int i = 0; i < xbps_array_count(orphans); i++) { - xbps_dictionary_get_cstring_nocopy(xbps_array_get(orphans, i), - "pkgver", &pkgver); + xbps_dictionary_get_bool(obj, "automatic-install", &automatic); + if (automatic == false) { + xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); puts(pkgver); } @@ -163,22 +196,43 @@ list_orphans(struct xbps_handle *xhp) } int -list_pkgs_pkgdb(struct xbps_handle *xhp) +list_orphans(struct xbps_handle *xhp, const char *format) { - struct list_pkgver_cb lpc; + xbps_array_t orphans; + struct xbps_fmt *fmt; + int r = 0; + + fmt = xbps_fmt_parse(format); + if (!fmt) { + r = -errno; + xbps_error_printf("failed to parse format: %s\n", strerror(-r)); + return r; + } - lpc.pkgver_len = find_longest_pkgver(xhp, NULL); - lpc.maxcols = get_maxcols(); - lpc.linebuf = NULL; - if (lpc.maxcols > 0) { - lpc.linebuf = malloc(lpc.maxcols); - if (lpc.linebuf == NULL) - exit(1); + orphans = xbps_find_pkg_orphans(xhp, NULL); + if (!orphans) { + r = -errno; + xbps_error_printf("failed to find orphans: %s\n", strerror(-r)); + goto err; } - return xbps_pkgdb_foreach_cb(xhp, list_pkgs_in_dict, &lpc); + for (unsigned int i = 0; i < xbps_array_count(orphans); i++) { + xbps_object_t obj = xbps_array_get(orphans, i); + if (!obj) + return -errno; + r = xbps_fmt_dictionary(fmt, obj, stdout); + if (r < 0) + goto err; + } +err: + xbps_fmt_free(fmt); + return r; } +#ifndef __UNCONST +#define __UNCONST(a) ((void *)(uintptr_t)(const void *)(a)) +#endif + static void repo_list_uri(struct xbps_repo *repo) { @@ -230,50 +284,3 @@ repo_list(struct xbps_handle *xhp) } return 0; } - -struct fflongest { - xbps_dictionary_t d; - unsigned int len; -}; - -static int -_find_longest_pkgver_cb(struct xbps_handle *xhp UNUSED, - xbps_object_t obj, - const char *key UNUSED, - void *arg, - bool *loop_done UNUSED) -{ - struct fflongest *ffl = arg; - const char *pkgver = NULL; - unsigned int len; - - xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); - len = strlen(pkgver); - if (ffl->len == 0 || len > ffl->len) - ffl->len = len; - - return 0; -} - -unsigned int -find_longest_pkgver(struct xbps_handle *xhp, xbps_object_t o) -{ - struct fflongest ffl; - - ffl.d = o; - ffl.len = 0; - - if (xbps_object_type(o) == XBPS_TYPE_DICTIONARY) { - xbps_array_t array; - - array = xbps_dictionary_all_keys(o); - (void)xbps_array_foreach_cb_multi(xhp, array, o, - _find_longest_pkgver_cb, &ffl); - xbps_object_release(array); - } else { - (void)xbps_pkgdb_foreach_cb_multi(xhp, - _find_longest_pkgver_cb, &ffl); - } - - return ffl.len; -} diff --git a/bin/xbps-query/main.c b/bin/xbps-query/main.c index 44316c1ad..42afddb99 100644 --- a/bin/xbps-query/main.c +++ b/bin/xbps-query/main.c @@ -23,13 +23,15 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include +#include +#include #include #include #include -#include -#include #include + #include "defs.h" static void __attribute__((noreturn)) @@ -41,6 +43,7 @@ usage(bool fail) " -C, --config Path to confdir (xbps.d)\n" " -c, --cachedir Path to cachedir\n" " -d, --debug Debug mode shown to stderr\n" + " -F, --format Format for list output\n" " -h, --help Show usage\n" " -i, --ignore-conf-repos Ignore repositories defined in xbps.d\n" " -M, --memory-sync Remote repository data is fetched and stored\n" @@ -74,10 +77,30 @@ usage(bool fail) exit(fail ? EXIT_FAILURE : EXIT_SUCCESS); } +static int +filter_hold(xbps_object_t obj) +{ + return xbps_dictionary_get(obj, "hold") != NULL; +} + +static int +filter_manual(xbps_object_t obj) +{ + bool automatic = false; + xbps_dictionary_get_bool(obj, "automatic-install", &automatic); + return !automatic; +} + +static int +filter_repolock(xbps_object_t obj) +{ + return xbps_dictionary_get(obj, "repolock") != NULL; +} + int main(int argc, char **argv) { - const char *shortopts = "C:c:df:hHiLlMmOo:p:Rr:s:S:VvX:x:"; + const char *shortopts = "C:c:dF:f:hHiLlMmOo:p:Rr:s:S:VvX:x:"; const struct option longopts[] = { { "config", required_argument, NULL, 'C' }, { "cachedir", required_argument, NULL, 'c' }, @@ -100,6 +123,7 @@ main(int argc, char **argv) { "version", no_argument, NULL, 'V' }, { "verbose", no_argument, NULL, 'v' }, { "files", required_argument, NULL, 'f' }, + { "format", required_argument, NULL, 'F' }, { "deps", required_argument, NULL, 'x' }, { "revdeps", required_argument, NULL, 'X' }, { "regex", no_argument, NULL, 0 }, @@ -108,13 +132,13 @@ main(int argc, char **argv) { NULL, 0, NULL, 0 }, }; struct xbps_handle xh; - const char *pkg, *rootdir, *cachedir, *confdir, *props, *catfile; + const char *pkg, *rootdir, *cachedir, *confdir, *props, *catfile, *format; int c, flags, rv; bool list_pkgs, list_repos, orphans, own, list_repolock; bool list_manual, list_hold, show_prop, show_files, show_deps, show_rdeps; bool show, pkg_search, regex, repo_mode, opmode, fulldeptree; - rootdir = cachedir = confdir = props = pkg = catfile = NULL; + rootdir = cachedir = confdir = props = pkg = catfile = format = NULL; flags = rv = c = 0; list_pkgs = list_repos = list_hold = orphans = pkg_search = own = false; list_manual = list_repolock = show_prop = show_files = false; @@ -138,6 +162,9 @@ main(int argc, char **argv) pkg = optarg; show_files = opmode = true; break; + case 'F': + format = optarg; + break; case 'H': list_hold = opmode = true; break; @@ -259,24 +286,24 @@ main(int argc, char **argv) rv = repo_list(&xh); } else if (list_hold) { - /* list on hold pkgs */ - rv = xbps_pkgdb_foreach_cb(&xh, list_hold_pkgs, NULL); + rv = list_pkgdb(&xh, filter_hold, format ? format : "{pkgver}\n") < 0; } else if (list_repolock) { - /* list repolocked packages */ - rv = xbps_pkgdb_foreach_cb(&xh, list_repolock_pkgs, NULL); + rv = list_pkgdb(&xh, filter_repolock, format ? format : "{pkgver}\n") < 0; } else if (list_manual) { - /* list manual pkgs */ - rv = xbps_pkgdb_foreach_cb(&xh, list_manual_pkgs, NULL); + rv = list_pkgdb(&xh, filter_manual, format ? format : "{pkgver}\n") < 0; } else if (list_pkgs) { /* list available pkgs */ - rv = list_pkgs_pkgdb(&xh); + if (format) + rv = list_pkgdb(&xh, NULL, format); + else + rv = list_pkgs_pkgdb(&xh); } else if (orphans) { /* list pkg orphans */ - rv = list_orphans(&xh); + rv = list_orphans(&xh, format ? format : "{pkgver}\n") < 0; } else if (own) { /* ownedby mode */