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

Reply via email to