commit: b07aa71dfb7d6377fe0ca519e7d835f59ae3573d Author: Mike Frysinger <vapier <AT> gentoo <DOT> org> AuthorDate: Thu Oct 15 20:17:02 2015 +0000 Commit: Mike Frysinger <vapier <AT> gentoo <DOT> org> CommitDate: Thu Oct 15 21:02:35 2015 +0000 URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=b07aa71d
qatom: add a --format flag for controlling output Rather than forcing people to deal with the ad-hoc output and run it through another program to reassemble things, add a --format flag so they can explicitly get the output hey care about. This drops support for the letter field, but no one was really using that in the first place. If anyone does care, we can re-add it as a new field. This does change the output slightly from existing behavior: there will be extra spaces between the latter fields, but this shouldn't break existing programs as they generally split on whitespace. qatom.c | 104 +++++++++++++++++++++++++++++++++++++++++++-------- tests/Makefile | 2 +- tests/qatom/Makefile | 11 ++++++ tests/qatom/dotest | 44 ++++++++++++++++++++++ 4 files changed, 144 insertions(+), 17 deletions(-) diff --git a/qatom.c b/qatom.c index f2c7ae4..16445dd 100644 --- a/qatom.c +++ b/qatom.c @@ -8,20 +8,104 @@ #ifdef APPLET_qatom -#define QATOM_FLAGS "c" COMMON_FLAGS +#define QATOM_FORMAT "%{CATEGORY} %{PN} %{PV} %[PR] %[SLOT] %[pfx] %[sfx]" + +#define QATOM_FLAGS "F:c" COMMON_FLAGS static struct option const qatom_long_opts[] = { + {"format", a_argument, NULL, 'F'}, {"compare", no_argument, NULL, 'c'}, COMMON_LONG_OPTS }; static const char * const qatom_opts_help[] = { + "Custom output format (default: " QATOM_FORMAT ")", "Compare two atoms", COMMON_OPTS_HELP }; #define qatom_usage(ret) usage(ret, QATOM_FLAGS, qatom_long_opts, qatom_opts_help, lookup_applet_idx("qatom")) +/* Run printf on an atom! The format field takes the form: + * %{keyword}: Always display the field that matches "keyword" + * %[keyword]: Only display the field when it's valid (or pverbose) + * The possible "keywords" are: + * CATEGORY P PN PV PVR PF PR SLOT + * - these are all the standard portage variables (so see ebuild(5)) + * pfx - the version qualifier if set (e.g. > < = !) + * sfx - the version qualifier if set (e.g. *) + */ +_q_static +void qatom_printf(const char *format, const depend_atom *atom, int pverbose) +{ + char bracket; + const char *fmt, *p; + + if (!atom) { + printf("(NULL:atom)"); + return; + } + + p = format; + while (*p != '\0') { + fmt = strchr(p, '%'); + if (fmt == NULL) { + printf("%s", p); + return; + } else if (fmt != p) + printf("%.*s", (int)(fmt - p), p); + + bracket = fmt[1]; + if (bracket == '{' || bracket == '[') { + fmt += 2; + p = strchr(fmt, bracket == '{' ? '}' : ']'); + if (p) { + size_t len = p - fmt; + bool showit = (bracket == '{') || pverbose; + if (!strncmp("CATEGORY", fmt, len)) { + if (showit || atom->CATEGORY) + printf("%s", atom->CATEGORY); + } else if (!strncmp("P", fmt, len)) { + if (showit || atom->P) + printf("%s", atom->P); + } else if (!strncmp("PN", fmt, len)) { + if (showit || atom->PN) + printf("%s", atom->PN); + } else if (!strncmp("PV", fmt, len)) { + if (showit || atom->PV) + printf("%s", atom->PV); + } else if (!strncmp("PVR", fmt, len)) { + if (showit || atom->PVR) + printf("%s", atom->PVR); + } else if (!strncmp("PF", fmt, len)) { + printf("%s", atom->PN); + if (atom->PV) + printf("-%s", atom->PV); + if (atom->PR_int) + printf("-r%i", atom->PR_int); + } else if (!strncmp("PR", fmt, len)) { + if (showit || atom->PR_int) + printf("r%i", atom->PR_int); + } else if (!strncmp("SLOT", fmt, len)) { + if (showit || atom->SLOT) + printf(":%s", atom->SLOT ? : "-"); + } else if (!strncmp("pfx", fmt, len)) { + if (showit || atom->pfx_op != ATOM_OP_NONE) + fputs(atom->pfx_op == ATOM_OP_NONE ? "-" : atom_op_str[atom->pfx_op], stdout); + } else if (!strncmp("sfx", fmt, len)) { + if (showit || atom->sfx_op != ATOM_OP_NONE) + fputs(atom->sfx_op == ATOM_OP_NONE ? "-" : atom_op_str[atom->sfx_op], stdout); + } else + printf("<BAD:%.*s>", (int)len, fmt); + ++p; + } else + p = fmt + 1; + } else + ++p; + } +} + int qatom_main(int argc, char **argv) { enum qatom_atom { _EXPLODE=0, _COMPARE } action = _EXPLODE; + const char *format = QATOM_FORMAT; depend_atom *atom; int i; @@ -30,6 +114,7 @@ int qatom_main(int argc, char **argv) while ((i = GETOPT_LONG(QATOM, qatom, "")) != -1) { switch (i) { + case 'F': format = optarg; break; case 'c': action = _COMPARE; break; COMMON_GETOPTS_CASES(qatom) } @@ -49,23 +134,10 @@ int qatom_main(int argc, char **argv) break; case _EXPLODE: atom = atom_explode(argv[i]); - if (!atom) { - warnf("failed exploding atom %s", argv[i]); - continue; - } - printf("%s %s %s", atom->CATEGORY, atom->PN, atom->PV); - if (verbose || atom->PR_int) - printf(" r%i", atom->PR_int); - if (verbose || atom->SLOT) - printf(" :%s", atom->SLOT ? atom->SLOT : "-"); - if (verbose || atom->pfx_op != ATOM_OP_NONE) - printf(" %s", atom->pfx_op == ATOM_OP_NONE ? "-" : atom_op_str[atom->pfx_op]); - if (verbose || atom->sfx_op != ATOM_OP_NONE) - printf(" %s", atom->sfx_op == ATOM_OP_NONE ? "-" : atom_op_str[atom->sfx_op]); - if (verbose > 1) - printf(" %c", (atom->letter ? : '-')); + qatom_printf(format, atom, verbose); putchar('\n'); atom_implode(atom); + break; } } diff --git a/tests/Makefile b/tests/Makefile index b4d6005..2fdea84 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,6 +1,6 @@ TESTS = \ reinitialize atom_compare atom_explode mkdir \ - qcheck qdepends qfile qlist qlop qmerge qtbz2 quse qxpak \ + qatom qcheck qdepends qfile qlist qlop qmerge qtbz2 quse qxpak \ install profile source all: check diff --git a/tests/qatom/Makefile b/tests/qatom/Makefile new file mode 100644 index 0000000..6f3bb54 --- /dev/null +++ b/tests/qatom/Makefile @@ -0,0 +1,11 @@ +thisdir = qatom +include ../subdir.mk + +all: check + +test check: + $(Q)$(s)/dotest + +clean: + +.PHONY: all check clean test diff --git a/tests/qatom/dotest b/tests/qatom/dotest new file mode 100755 index 0000000..5580b98 --- /dev/null +++ b/tests/qatom/dotest @@ -0,0 +1,44 @@ +#!/bin/bash + +. ../init.sh + +test() { + local num=$1 exp=$2 ret=0 out + shift 2 + set -- q atom "$@" + out=$("$@") || ret=$? + if [[ ${num} == l* ]] ; then + out=$(echo "${out}" | sed -r -e 's: +: :g' -e 's: *$::') + fi + if [[ ${out} != "${exp}" ]] ; then + tfail "output does not match: wanted '${exp}' but got '${out}'" + elif [[ ${ret} -ne 0 ]] ; then + tfail "exit code (${ret}) does not match expected (0)" + fi + tend $? "$*" +} + +# Legacy format. +test l01 "(null) pkg (null)" "pkg" +test l02 "cat pkg (null)" "cat/pkg" +test l03 "cat pkg 123" "cat/pkg-123" +test l04 "cat pkg 123 r4" "cat/pkg-123-r4" +test l05 "cat pkg 123 r4 :5" "cat/pkg-123-r4:5" +test l06 "cat pkg 123 :5" "cat/pkg-123:5" +test l07 "cat pkg 123 >=" ">=cat/pkg-123" +test l07 "cat pkg 123 = *" "=cat/pkg-123*" + +# Explicit format. +test f01 "cat" -F '%{CATEGORY}' "cat/pkg" +test f02 "(null)" -F '%{CATEGORY}' "pkg" +test f03 "" -F '%[CATEGORY]' "pkg" +test f04 "cat" -F '%{CATEGORY}' "cat/pkg-123-r4:5" +test f05 "pkg-123" -F '%{P}' "cat/pkg-123-r4:5" +test f06 "pkg" -F '%{PN}' "cat/pkg-123-r4:5" +test f07 "123" -F '%{PV}' "cat/pkg-123-r4:5" +test f08 "123-r4" -F '%{PVR}' "cat/pkg-123-r4:5" +test f09 "pkg-123-r4" -F '%{PF}' "cat/pkg-123-r4:5" +test f10 "r4" -F '%{PR}' "cat/pkg-123-r4:5" +test f11 ":5" -F '%{SLOT}' "cat/pkg-123-r4:5" + +end