XML Output: libxo - provide single API to output TXT, XML, JSON and HTML

Phil Shafer phil at juniper.net
Thu Jul 31 09:08:06 UTC 2014


"Simon J. Gerraty" writes:
>We now have an API and library that can avoid the need to double the
>cost of adding new output to apps, ie you only write to libxo's api
>and it does plain TXT for you if needed.

I'm appending another example, using "wc".

I've added the "xo" equivalent of warn/warnx/err/errx/etc.  Normally,
they'll make the expected noise on stderr, but with the XO_WARN_XML
flag, they generate XML content on the stdout (or whatever xo_handle_t
is in use).  I don't have a JSON equivalent because, well, I don't
know what the json equivalent would look like.

There's also a xo_attr function that will add an attribute to
the next element emitted, so one can:

    xo_attr("seconds", stop - start);
    xo_emit("{:time}", fancy_time(stop - start));

to make:

    <time seconds="600">10 minutes</time>

There's also the "printf(1)" equivalent command "xo" for use in
shell scripts:

% xo --wrap response/data 'The {:animal} is {:color} and {:mood}\n' bear brown angry
The bear is brown and angry
% xo -X -p --wrap response/data 'The {:animal} is {:color} and {:mood}\n' bear brown angry
<response>
  <data>
    <animal>bear</animal>
    <color>brown</color>
    <mood>angry</mood>
  </data>
</response>

The code is in github:
    https://github.com/Juniper/libxo
HTML docs are here:
    http://juniper.github.io/libxo/libxo-manual.html
Text/source docs are here:
    https://raw.githubusercontent.com/Juniper/libxo/master/doc/libxo.txt

I'm using the common master/develop branching scheme, so "master"
should be stable, while "develop" is where I'm working.

Simon said there's a github mirror for freebsd, so I make fork that
and add the patches for the various utilities I'm working thru.

Thanks,
 Phil

-----------

diff -rbu /usr/src/usr.bin/wc/wc.c ./wc.c
--- /usr/src/usr.bin/wc/wc.c	2010-12-21 12:09:25.000000000 -0500
+++ ./wc.c	2014-07-31 04:20:15.000000000 -0400
@@ -61,6 +61,7 @@
 #include <unistd.h>
 #include <wchar.h>
 #include <wctype.h>
+#include <libxo/libxo.h>
 
 uintmax_t tlinect, twordct, tcharct, tlongline;
 int doline, doword, dochar, domulti, dolongline;
@@ -105,33 +106,45 @@
 	if (doline + doword + dochar + domulti + dolongline == 0)
 		doline = doword = dochar = 1;
 
+	xo_open_container("wc");
+	xo_open_list("file");
 	errors = 0;
 	total = 0;
 	if (!*argv) {
+	 	xo_open_instance("file");
 		if (cnt((char *)NULL) != 0)
 			++errors;
 		else
-			(void)printf("\n");
+			xo_emit("\n");
+	 	xo_close_instance("file");
 	}
 	else do {
+	 	xo_open_instance("file");
+		xo_emit(" {ek:filename/%s}\n", *argv);
 		if (cnt(*argv) != 0)
 			++errors;
 		else
-			(void)printf(" %s\n", *argv);
+			xo_emit(" {d:filename/%s}\n", *argv);
+	 	xo_close_instance("file");
 		++total;
 	} while(*++argv);
+	xo_close_list("file");
 
 	if (total > 1) {
+		xo_open_container("total");
 		if (doline)
-			(void)printf(" %7ju", tlinect);
+			xo_emit(" {:lines/%7ju/%ju}", tlinect);
 		if (doword)
-			(void)printf(" %7ju", twordct);
+			xo_emit(" {:words/%7ju/%ju", twordct);
 		if (dochar || domulti)
-			(void)printf(" %7ju", tcharct);
+			xo_emit(" {:characters/%7ju/%ju}", tcharct);
 		if (dolongline)
-			(void)printf(" %7ju", tlongline);
-		(void)printf(" total\n");
+			xo_emit(" {:long-lines/%7ju/%ju}", tlongline);
+		xo_emit(" total\n");
+		xo_close_container("total");
 	}
+	xo_close_container("wc");
+	xo_flush();
 	exit(errors == 0 ? 0 : 1);
 }
 
@@ -154,7 +167,7 @@
 		fd = STDIN_FILENO;
 	} else {
 		if ((fd = open(file, O_RDONLY, 0)) < 0) {
-			warn("%s: open", file);
+			xo_warn("%s: open", file);
 			return (1);
 		}
 		if (doword || (domulti && MB_CUR_MAX != 1))
@@ -167,7 +180,7 @@
 		if (doline) {
 			while ((len = read(fd, buf, MAXBSIZE))) {
 				if (len == -1) {
-					warn("%s: read", file);
+					xo_warn("%s: read", file);
 					(void)close(fd);
 					return (1);
 				}
@@ -182,15 +195,15 @@
 						tmpll++;
 			}
 			tlinect += linect;
-			(void)printf(" %7ju", linect);
+			xo_emit(" {:lines/%7ju/%ju}", linect);
 			if (dochar) {
 				tcharct += charct;
-				(void)printf(" %7ju", charct);
+				xo_emit(" {:characters/%7ju/%ju}", charct);
 			}
 			if (dolongline) {
 				if (llct > tlongline)
 					tlongline = llct;
-				(void)printf(" %7ju", tlongline);
+				xo_emit(" {:long-lines/%7ju/%ju}", tlongline);
 			}
 			(void)close(fd);
 			return (0);
@@ -201,12 +214,13 @@
 		 */
 		if (dochar || domulti) {
 			if (fstat(fd, &sb)) {
-				warn("%s: fstat", file);
+				xo_warn("%s: fstat", file);
 				(void)close(fd);
 				return (1);
 			}
 			if (S_ISREG(sb.st_mode)) {
-				(void)printf(" %7lld", (long long)sb.st_size);
+				xo_emit(" {:characters/%7lld/%lld}",
+					(long long)sb.st_size);
 				tcharct += sb.st_size;
 				(void)close(fd);
 				return (0);
@@ -220,7 +234,7 @@
 	memset(&mbs, 0, sizeof(mbs));
 	while ((len = read(fd, buf, MAXBSIZE)) != 0) {
 		if (len == -1) {
-			warn("%s: read", file);
+			xo_warn("%s: read", file);
 			(void)close(fd);
 			return (1);
 		}
@@ -233,7 +247,7 @@
 			    (size_t)-1) {
 				if (!warned) {
 					errno = EILSEQ;
-					warn("%s", file);
+					xo_warn("%s", file);
 					warned = 1;
 				}
 				memset(&mbs, 0, sizeof(mbs));
@@ -264,23 +278,23 @@
 	}
 	if (domulti && MB_CUR_MAX > 1)
 		if (mbrtowc(NULL, NULL, 0, &mbs) == (size_t)-1 && !warned)
-			warn("%s", file);
+			xo_warn("%s", file);
 	if (doline) {
 		tlinect += linect;
-		(void)printf(" %7ju", linect);
+		xo_emit(" {:lines/%7ju/%ju}", linect);
 	}
 	if (doword) {
 		twordct += wordct;
-		(void)printf(" %7ju", wordct);
+		xo_emit(" {:words/%7ju/%ju}", wordct);
 	}
 	if (dochar || domulti) {
 		tcharct += charct;
-		(void)printf(" %7ju", charct);
+		xo_emit(" {:characters/%7ju/%ju}", charct);
 	}
 	if (dolongline) {
 		if (llct > tlongline)
 			tlongline = llct;
-		(void)printf(" %7ju", llct);
+		xo_emit(" {:long-lines/%7ju/%ju}", llct);
 	}
 	(void)close(fd);
 	return (0);
@@ -289,6 +303,6 @@
 static void
 usage()
 {
-	(void)fprintf(stderr, "usage: wc [-Lclmw] [file ...]\n");
+	xo_error("usage: wc [-Lclmw] [file ...]\n");
 	exit(1);
 }


More information about the freebsd-arch mailing list