Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 27 Apr 2015 17:23:20 +0000 (UTC)
From:      Marcel Moolenaar <marcel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r282100 - in head: contrib/libxo contrib/libxo/doc contrib/libxo/libxo contrib/libxo/m4 contrib/libxo/tests/core contrib/libxo/tests/core/saved contrib/libxo/xo contrib/libxo/xohtml con...
Message-ID:  <201504271723.t3RHNKbP081255@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: marcel
Date: Mon Apr 27 17:23:19 2015
New Revision: 282100
URL: https://svnweb.freebsd.org/changeset/base/282100

Log:
  Upgrade libxo to 0.3.2.
  
  Obtained from:  https://github.com/Juniper/libxo/tree/0.3.2
  Requested by: Phil Shafer <phil@juniper.net>
  
  This import incorporates local change 279966.
  Local change 276260 has been merged-in.

Added:
  head/contrib/libxo/libxo/xo_open_marker.3   (contents, props changed)
  head/contrib/libxo/libxo/xo_set_version.3   (contents, props changed)
  head/contrib/libxo/tests/core/saved/test_10.H.err
  head/contrib/libxo/tests/core/saved/test_10.H.out
  head/contrib/libxo/tests/core/saved/test_10.HIPx.err
  head/contrib/libxo/tests/core/saved/test_10.HIPx.out
  head/contrib/libxo/tests/core/saved/test_10.HP.err
  head/contrib/libxo/tests/core/saved/test_10.HP.out
  head/contrib/libxo/tests/core/saved/test_10.J.err
  head/contrib/libxo/tests/core/saved/test_10.J.out
  head/contrib/libxo/tests/core/saved/test_10.JP.err
  head/contrib/libxo/tests/core/saved/test_10.JP.out
  head/contrib/libxo/tests/core/saved/test_10.T.err
  head/contrib/libxo/tests/core/saved/test_10.T.out
  head/contrib/libxo/tests/core/saved/test_10.X.err
  head/contrib/libxo/tests/core/saved/test_10.X.out
  head/contrib/libxo/tests/core/saved/test_10.XP.err
  head/contrib/libxo/tests/core/saved/test_10.XP.out
  head/contrib/libxo/tests/core/saved/test_10.err
  head/contrib/libxo/tests/core/saved/test_10.out
  head/contrib/libxo/tests/core/test_10.c   (contents, props changed)
  head/contrib/libxo/xohtml/Makefile.am   (contents, props changed)
  head/contrib/libxo/xohtml/xohtml.1   (contents, props changed)
Modified:
  head/contrib/libxo/Makefile.am
  head/contrib/libxo/configure.ac
  head/contrib/libxo/doc/libxo.txt
  head/contrib/libxo/libxo/Makefile.am
  head/contrib/libxo/libxo/libxo.c
  head/contrib/libxo/libxo/xo.h
  head/contrib/libxo/libxo/xo_error.3
  head/contrib/libxo/libxo/xo_format.5
  head/contrib/libxo/libxo/xo_open_container.3
  head/contrib/libxo/libxo/xoconfig.h
  head/contrib/libxo/libxo/xoconfig.h.in
  head/contrib/libxo/libxo/xoversion.h
  head/contrib/libxo/m4/libtool.m4
  head/contrib/libxo/m4/ltoptions.m4
  head/contrib/libxo/m4/ltversion.m4
  head/contrib/libxo/tests/core/Makefile.am
  head/contrib/libxo/tests/core/saved/test_01.JP.out
  head/contrib/libxo/tests/core/saved/test_02.JP.out
  head/contrib/libxo/tests/core/saved/test_05.H.out
  head/contrib/libxo/tests/core/saved/test_05.HIPx.out
  head/contrib/libxo/tests/core/saved/test_05.HP.out
  head/contrib/libxo/tests/core/saved/test_05.J.out
  head/contrib/libxo/tests/core/saved/test_05.JP.out
  head/contrib/libxo/tests/core/saved/test_05.T.out
  head/contrib/libxo/tests/core/saved/test_05.X.out
  head/contrib/libxo/tests/core/saved/test_05.XP.out
  head/contrib/libxo/tests/core/saved/test_09.JP.out
  head/contrib/libxo/tests/core/test_05.c
  head/contrib/libxo/xo/xo.1
  head/contrib/libxo/xohtml/xohtml.css
  head/contrib/libxo/xohtml/xohtml.sh.in
  head/contrib/libxo/xolint/Makefile.am
  head/contrib/libxo/xolint/xolint.1
  head/contrib/libxo/xolint/xolint.pl
  head/lib/libxo/Makefile

Modified: head/contrib/libxo/Makefile.am
==============================================================================
--- head/contrib/libxo/Makefile.am	Mon Apr 27 17:04:27 2015	(r282099)
+++ head/contrib/libxo/Makefile.am	Mon Apr 27 17:23:19 2015	(r282100)
@@ -10,7 +10,7 @@
 
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = libxo xo xolint tests doc
+SUBDIRS = libxo xo xolint xohtml tests doc
 bin_SCRIPTS=libxo-config
 dist_doc_DATA = Copyright
 

Modified: head/contrib/libxo/configure.ac
==============================================================================
--- head/contrib/libxo/configure.ac	Mon Apr 27 17:04:27 2015	(r282099)
+++ head/contrib/libxo/configure.ac	Mon Apr 27 17:23:19 2015	(r282100)
@@ -12,7 +12,7 @@
 #
 
 AC_PREREQ(2.2)
-AC_INIT([libxo], [0.2.0], [phil@juniper.net])
+AC_INIT([libxo], [0.3.2], [phil@juniper.net])
 AM_INIT_AUTOMAKE([-Wall -Werror foreign -Wno-portability])
 
 # Support silent build rules.  Requires at least automake-1.11.
@@ -133,6 +133,14 @@ AC_ARG_ENABLE([debug],
 AC_MSG_RESULT([$LIBXO_DEBUG])
 AM_CONDITIONAL([LIBXO_DEBUG], [test "$LIBXO_DEBUG" != "no"])
 
+AC_MSG_CHECKING([whether to build with text-only rendering])
+AC_ARG_ENABLE([text-only],
+    [  --enable-text-only    Turn on text-only rendering],
+    [LIBXO_TEXT_ONLY=yes; AC_DEFINE([LIBXO_TEXT_ONLY], [1], [Enable text-only rendering])],
+    [LIBXO_TEXT_ONLY=no])
+AC_MSG_RESULT([$LIBXO_TEXT_ONLY])
+AM_CONDITIONAL([LIBXO_TEXT_ONLY], [test "$LIBXO_TEXT_ONLY" != "no"])
+
 AC_CHECK_LIB([m], [lrint])
 AM_CONDITIONAL([HAVE_LIBM], [test "$HAVE_LIBM" != "no"])
 
@@ -233,6 +241,7 @@ AC_CONFIG_FILES([
   libxo/xoversion.h
   xo/Makefile
   xolint/Makefile
+  xohtml/Makefile
   packaging/libxo.pc
   doc/Makefile
   tests/Makefile
@@ -253,6 +262,7 @@ AC_MSG_NOTICE([summary of build options:
   bindir:           ${XO_BINDIR}
   includedir:       ${XO_INCLUDEDIR}
   share dir:        ${XO_SHAREDIR}
+  oxtradoc dir:     ${SLAX_OXTRADOCDIR}
 
   compiler:         ${CC} (${HAVE_GCC:-no})
   compiler flags:   ${CFLAGS}
@@ -262,4 +272,5 @@ AC_MSG_NOTICE([summary of build options:
   debug:            ${LIBXO_DEBUG:-no}
   printf-like:      ${HAVE_PRINTFLIKE:-no}
   libxo-options:    ${LIBXO_OPTS:-no}
+  text-only:        ${LIBXO_TEXT_ONLY:-no}
 ])

Modified: head/contrib/libxo/doc/libxo.txt
==============================================================================
--- head/contrib/libxo/doc/libxo.txt	Mon Apr 27 17:04:27 2015	(r282099)
+++ head/contrib/libxo/doc/libxo.txt	Mon Apr 27 17:23:19 2015	(r282100)
@@ -134,7 +134,7 @@ A single libxo function call in source c
       <host>my-box</host>
       <domain>example.com</domain>
     JSON:
-      "host": my-box",
+      "host": "my-box",
       "domain": "example.com"
       
 For brevity, the HTML output is emitted.
@@ -228,17 +228,17 @@ data, including data type, description, 
     <div class="line">
       <div class="data" data-tag="blocks">36</div>
       <div class="padding">      </div>
-      <div class="data data-tag="path">./src</div>
+      <div class="data" data-tag="path">./src</div>
     </div>
     <div class="line">
       <div class="data" data-tag="blocks">40</div>
       <div class="padding">      </div>
-      <div class="data data-tag="path">./bin</div>
+      <div class="data" data-tag="path">./bin</div>
     </div>
     <div class="line">
       <div class="data" data-tag="blocks">90</div>
       <div class="padding">      </div>
-      <div class="data data-tag="path">./</div>
+      <div class="data" data-tag="path">./</div>
     </div>
 
 ** Format Strings @format-strings@
@@ -285,6 +285,7 @@ content.  The roles are listed below; on
 |---+--------------+-------------------------------------------------|
 | M | Name         | Description                                     |
 |---+--------------+-------------------------------------------------|
+| C | color/effect | Field has color and effect controls             |
 | D | decoration   | Field is non-text (e.g., colon, comma)          |
 | E | error        | Field is an error message                       |
 | L | label        | Field is text that prefixes a value             |
@@ -298,6 +299,56 @@ content.  The roles are listed below; on
 | ] | stop anchor  | End a section of anchored variable-width text   |
 |---+--------------+-------------------------------------------------|
 
+**** The Color Role ({C:})
+
+Colors and effects control how text values are displayed; they are
+used for display styles (TEXT and HTML).  The color content can be
+either static, when placed directly within the field descriptor, or a
+printf-style format descriptor can be used, if preceded by a slash ("/"):
+
+    xo_emit("{C:bold}{Lwc:Cost}{:cost/%u}{C:reset}\n", cost);
+    xo_emit("{C:/fg-%s,bg-%s}{Lwc:Cost}{:cost/%u}{C:reset}\n",
+            fg_color, bg_color, cost);
+
+The content should be a comma-separated list of zero or more colors or
+display effects.  Colors and effects remain in effect until
+modified by other "C" roles.  If the content is empty, the "reset"
+action is performed.
+
+|---------------+-------------------------------------------------|
+|  Name         | Description                                     |
+|---------------+-------------------------------------------------|
+|  bg-XXXXX     | Change background color                         |
+|  bold         | Start bold text effect                          |
+|  fg-XXXXX     | Change foreground color                         |
+|  inverse      | Start inverse (aka reverse) text effect         |
+|  no-bold      | Stop bold text effect                           |
+|  no-inverse   | Stop inverse (aka reverse) text effect          |
+|  no-underline | Stop underline text effect                      |
+|  normal       | Reset effects (only)                            |
+|  reset        | Reset colors and effects (restore defaults)     |
+|  underline    | Start underline text effect                     |
+|---------------+-------------------------------------------------|
+
+The following color names are supported:
+
+|---------------|
+|  Name         |
+|---------------|
+| black         |
+| blue          |
+| cyan          |
+| default       |
+| green         |
+| magenta       |
+| red           |
+| white         |
+| yellow        |
+|---------------|
+
+Color names are prefixed with either "fg-" or "bg-" to change the
+foreground and background colors, respectively.
+
 **** The Decoration Role ({D:})
 
 Decorations are typically punctuation marks such as colons,
@@ -1404,9 +1455,21 @@ functions like xo_failure, xo_warn, xo_e
 initialized by xo_parse_args, but subsequent calls to xo_set_program
 can override this value.
 
+    xo_set_program(argv[0]);
+
 Note that the value is not copied, so the memory passed to
 xo_set_program (and xo_parse_args) must be maintained by the caller.
 
+*** xo_set_version
+
+The xo_set_version function records a version number to be emitted as
+part of the data for encoding styles (XML and JSON).  This version
+number is suitable for tracking changes in the content, allowing a
+user of the data to discern which version of the data model is in use.
+
+     void xo_set_version (const char *version);
+     void xo_set_version_h (xo_handle_t *xop, const char *version);
+
 *** Field Information (xo_info_t) @info@
 
 HTML data can include additional information in attributes that
@@ -1705,6 +1768,32 @@ The "-V" option does not report errors, 
 all field names, sorted alphabetically.  The output can help spot
 inconsistencies and spelling errors.
 
+* xohtml
+
+xohtml is a tool for turning the output of libxo-enabled commands into
+html files suitable for display in modern HTML web browsers.  It can
+be used to test and debug HTML output, as well as to make the user
+ache to escape the world of 70s terminal devices.
+
+xohtml is given a command, either on the command line or via the "-c"
+option.  If not command is given, standard input is used.  The
+command's output is wrapped in HTML tags, with references to
+supporting CSS and Javascript files, and written to standard output or
+the file given in the "-f" option.  The "-b" option can be used to
+provide an alternative base path for the support files.
+
+|--------------+---------------------------------------------------|
+| Option       | Meaning                                           |
+|--------------+---------------------------------------------------|
+| -b <base>    | Base path for finding css/javascript files        |
+| -c <command> | Command to execute                                |
+| -f <file>    | Output file name                                  |
+|--------------+---------------------------------------------------|
+
+The "-c" option takes a full command with arguments, including
+any libxo options needed to generate html ("--libxo=html").  This
+value must be quoted if it consists of multiple tokens.
+
 * FAQs
 
 This section contains the set of questions that users typically ask,

Modified: head/contrib/libxo/libxo/Makefile.am
==============================================================================
--- head/contrib/libxo/libxo/Makefile.am	Mon Apr 27 17:04:27 2015	(r282099)
+++ head/contrib/libxo/libxo/Makefile.am	Mon Apr 27 17:23:19 2015	(r282100)
@@ -38,12 +38,15 @@ man_MANS = \
     xo_no_setlocale.3 \
     xo_open_container.3 \
     xo_open_list.3 \
+    xo_open_marker.3 \
     xo_parse_args.3 \
     xo_set_allocator.3 \
     xo_set_flags.3 \
     xo_set_info.3 \
     xo_set_options.3 \
     xo_set_style.3 \
+    xo_set_version.3 \
     xo_set_writer.3
 
-EXTRA_DIST =
+EXTRA_DIST = ${man_MANS}
+

Modified: head/contrib/libxo/libxo/libxo.c
==============================================================================
--- head/contrib/libxo/libxo/libxo.c	Mon Apr 27 17:04:27 2015	(r282099)
+++ head/contrib/libxo/libxo/libxo.c	Mon Apr 27 17:23:19 2015	(r282100)
@@ -121,6 +121,50 @@ typedef struct xo_stack_s {
     char *xs_keys;		/* XPath predicate for any key fields */
 } xo_stack_t;
 
+/* "colors" refers to fancy ansi codes */
+#define XO_COL_DEFAULT		0
+#define XO_COL_BLACK		1
+#define XO_COL_RED		2
+#define XO_COL_GREEN		3
+#define XO_COL_YELLOW		4
+#define XO_COL_BLUE		5
+#define XO_COL_MAGENTA		6
+#define XO_COL_CYAN		7
+#define XO_COL_WHITE		8
+
+#define XO_NUM_COLORS		9
+
+/* "effects" refers to fancy ansi codes */
+/*
+ * Yes, there's no blink.  We're civilized.  We like users.  Blink
+ * isn't something one does to someone you like.  Friends don't let
+ * friends use blink.  On friends.  You know what I mean.  Blink is
+ * like, well, it's like bursting into show tunes at a funeral.  It's
+ * just not done.  Not something anyone wants.  And on those rare
+ * instances where it might actually be appropriate, it's still wrong.
+ * It's likely done my the wrong person for the wrong reason.  Just
+ * like blink.  And if I implemented blink, I'd be like a funeral
+ * director who adds "Would you like us to burst into show tunes?" on
+ * the list of questions asking while making funeral arrangements.
+ * It's formalizing wrongness in the wrong way.  And we're just too
+ * civilized to do that.   Hhhmph!
+ */
+#define XO_EFF_RESET		(1<<0)
+#define XO_EFF_NORMAL		(1<<1)
+#define XO_EFF_BOLD		(1<<2)
+#define XO_EFF_UNDERLINE	(1<<3)
+#define XO_EFF_INVERSE		(1<<4)
+
+#define XO_EFF_CLEAR_BITS 	XO_EFF_RESET
+
+typedef uint8_t xo_effect_t;
+typedef uint8_t xo_color_t;
+typedef struct xo_colors_s {
+    xo_effect_t xoc_effects;	/* Current effect set */
+    xo_color_t xoc_col_fg;	/* Foreground color */
+    xo_color_t xoc_col_bg;	/* Background color */
+} xo_colors_t;
+
 /*
  * xo_handle_t: this is the principle data structure for libxo.
  * It's used as a store for state, options, and content.
@@ -136,7 +180,6 @@ struct xo_handle_s {
     xo_formatter_t xo_formatter; /* Custom formating function */
     xo_checkpointer_t xo_checkpointer; /* Custom formating support function */
     void *xo_opaque;		/* Opaque data for write function */
-    FILE *xo_fp;		/* XXX File pointer */
     xo_buffer_t xo_data;	/* Output data */
     xo_buffer_t xo_fmt;	   	/* Work area for building format strings */
     xo_buffer_t xo_attrs;	/* Work area for building XML attributes */
@@ -154,6 +197,11 @@ struct xo_handle_s {
     int xo_anchor_min_width;	/* Desired width of anchored text */
     unsigned xo_units_offset;	/* Start of units insertion point */
     unsigned xo_columns;	/* Columns emitted during this xo_emit call */
+    uint8_t xo_color_map_fg[XO_NUM_COLORS]; /* Foreground color mappings */
+    uint8_t xo_color_map_bg[XO_NUM_COLORS]; /* Background color mappings */
+    xo_colors_t xo_colors;	/* Current color and effect values */
+    xo_buffer_t xo_color_buf;	/* HTML: buffer of colors and effects */
+    char *xo_version;		/* Version string */
 };
 
 /* Flags for formatting functions */
@@ -161,7 +209,7 @@ typedef unsigned long xo_xff_flags_t;
 #define XFF_COLON	(1<<0)	/* Append a ":" */
 #define XFF_COMMA	(1<<1)	/* Append a "," iff there's more output */
 #define XFF_WS		(1<<2)	/* Append a blank */
-#define XFF_ENCODE_ONLY	(1<<3)	/* Only emit for encoding formats (xml and json) */
+#define XFF_ENCODE_ONLY	(1<<3)	/* Only emit for encoding formats (xml, json) */
 
 #define XFF_QUOTE	(1<<4)	/* Force quotes */
 #define XFF_NOQUOTE	(1<<5)	/* Force no quotes */
@@ -277,6 +325,24 @@ static void
 xo_anchor_clear (xo_handle_t *xop);
 
 /*
+ * xo_style is used to retrieve the current style.  When we're built
+ * for "text only" mode, we use this function to drive the removal
+ * of most of the code in libxo.  We return a constant and the compiler
+ * happily removes the non-text code that is not longer executed.  This
+ * trims our code nicely without needing to trampel perfectly readable
+ * code with ifdefs.
+ */
+static inline unsigned short
+xo_style (xo_handle_t *xop UNUSED)
+{
+#ifdef LIBXO_TEXT_ONLY
+    return XO_STYLE_TEXT;
+#else /* LIBXO_TEXT_ONLY */
+    return xop->xo_style;
+#endif /* LIBXO_TEXT_ONLY */
+}
+
+/*
  * Callback to write data to a FILE pointer
  */
 static int
@@ -321,6 +387,24 @@ xo_buf_init (xo_buffer_t *xbp)
 }
 
 /*
+ * Reset the buffer to empty
+ */
+static void
+xo_buf_reset (xo_buffer_t *xbp)
+{
+    xbp->xb_curp = xbp->xb_bufp;
+}
+
+/*
+ * Reset the buffer to empty
+ */
+static int
+xo_buf_is_empty (xo_buffer_t *xbp)
+{
+    return (xbp->xb_curp == xbp->xb_bufp);
+}
+
+/*
  * Initialize the contents of an xo_buffer_t.
  */
 static void
@@ -363,8 +447,8 @@ xo_no_setlocale (void)
 /*
  * We need to decide if stdout is line buffered (_IOLBF).  Lacking a
  * standard way to decide this (e.g. getlinebuf()), we have configure
- * look to find __flbf, which glibc supported.  If not, we'll rely
- * on isatty, with the assumption that terminals are the only thing
+ * look to find __flbf, which glibc supported.  If not, we'll rely on
+ * isatty, with the assumption that terminals are the only thing
  * that's line buffered.  We _could_ test for "steam._flags & _IOLBF",
  * which is all __flbf does, but that's even tackier.  Like a
  * bedazzled Elvis outfit on an ugly lap dog sort of tacky.  Not
@@ -399,6 +483,13 @@ xo_init_handle (xo_handle_t *xop)
 	xop->xo_flags |= XOF_FLUSH_LINE;
 
     /*
+     * We only want to do color output on terminals, but we only want
+     * to do this if the user has asked for color.
+     */
+    if ((xop->xo_flags & XOF_COLOR_ALLOWED) && isatty(1))
+	xop->xo_flags |= XOF_COLOR;
+
+    /*
      * We need to initialize the locale, which isn't really pretty.
      * Libraries should depend on their caller to set up the
      * environment.  But we really can't count on the caller to do
@@ -497,7 +588,7 @@ xo_default (xo_handle_t *xop)
 
 /*
  * Return the number of spaces we should be indenting.  If
- * we are pretty-printing, theis is indent * indent_by.
+ * we are pretty-printing, this is indent * indent_by.
  */
 static int
 xo_indent (xo_handle_t *xop)
@@ -647,6 +738,21 @@ xo_buf_append (xo_buffer_t *xbp, const c
     xbp->xb_curp += len;
 }
 
+/*
+ * Append the given NUL-terminated string to the given buffer
+ */
+static void
+xo_buf_append_str (xo_buffer_t *xbp, const char *str)
+{
+    int len = strlen(str);
+
+    if (!xo_buf_has_room(xbp, len))
+	return;
+
+    memcpy(xbp->xb_curp, str, len);
+    xbp->xb_curp += len;
+}
+
 static void
 xo_buf_escape (xo_handle_t *xop, xo_buffer_t *xbp,
 	       const char *str, int len, xo_xff_flags_t flags)
@@ -656,7 +762,7 @@ xo_buf_escape (xo_handle_t *xop, xo_buff
 
     memcpy(xbp->xb_curp, str, len);
 
-    switch (xop->xo_style) {
+    switch (xo_style(xop)) {
     case XO_STYLE_XML:
     case XO_STYLE_HTML:
 	len = xo_escape_xml(xbp, len, (flags & XFF_ATTR));
@@ -711,7 +817,7 @@ xo_vsnprintf (xo_handle_t *xop, xo_buffe
     else
 	rc = vsnprintf(xbp->xb_curp, left, fmt, va_local);
 
-    if (rc > xbp->xb_size) {
+    if (rc >= left) {
 	if (!xo_buf_has_room(xbp, rc)) {
 	    va_end(va_local);
 	    return -1;
@@ -721,7 +827,7 @@ xo_vsnprintf (xo_handle_t *xop, xo_buffe
 	 * After we call vsnprintf(), the stage of vap is not defined.
 	 * We need to copy it before we pass.  Then we have to do our
 	 * own logic below to move it along.  This is because the
-	 * implementation can have va_list be a point (bsd) or a
+	 * implementation can have va_list be a pointer (bsd) or a
 	 * structure (macosx) or anything in between.
 	 */
 
@@ -730,7 +836,7 @@ xo_vsnprintf (xo_handle_t *xop, xo_buffe
 
 	left = xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp);
 	if (xop->xo_formatter)
-	    xop->xo_formatter(xop, xbp->xb_curp, left, fmt, va_local);
+	    rc = xop->xo_formatter(xop, xbp->xb_curp, left, fmt, va_local);
 	else
 	    rc = vsnprintf(xbp->xb_curp, left, fmt, va_local);
     }
@@ -1219,7 +1325,7 @@ xo_message_hcv (xo_handle_t *xop, int co
 
     int need_nl = (fmt[strlen(fmt) - 1] != '\n');
 
-    switch (xop->xo_style) {
+    switch (xo_style(xop)) {
     case XO_STYLE_XML:
 	xbp = &xop->xo_data;
 	if (xop->xo_flags & XOF_PRETTY)
@@ -1431,6 +1537,10 @@ xo_destroy (xo_handle_t *xop_arg)
     xo_buf_cleanup(&xop->xo_fmt);
     xo_buf_cleanup(&xop->xo_predicate);
     xo_buf_cleanup(&xop->xo_attrs);
+    xo_buf_cleanup(&xop->xo_color_buf);
+
+    if (xop->xo_version)
+	xo_free(xop->xo_version);
 
     if (xop_arg == NULL) {
 	bzero(&xo_default_handle, sizeof(xo_default_handle));
@@ -1457,7 +1567,7 @@ xo_style_t
 xo_get_style (xo_handle_t *xop)
 {
     xop = xo_default(xop);
-    return xop->xo_style;
+    return xo_style(xop);
 }
 
 static int
@@ -1492,6 +1602,8 @@ xo_name_to_flag (const char *name)
 	return XOF_INFO;
     if (strcmp(name, "warn-xml") == 0)
 	return XOF_WARN_XML;
+    if (strcmp(name, "color") == 0)
+	return XOF_COLOR_ALLOWED;
     if (strcmp(name, "columns") == 0)
 	return XOF_COLUMNS;
     if (strcmp(name, "dtrt") == 0)
@@ -1547,6 +1659,11 @@ xo_set_options (xo_handle_t *xop, const 
 
     xop = xo_default(xop);
 
+#ifdef LIBXO_COLOR_ON_BY_DEFAULT
+    /* If the installer used --enable-color-on-by-default, then we allow it */
+    xop->xo_flags |= XOF_COLOR_ALLOWED;
+#endif /* LIBXO_COLOR_ON_BY_DEFAULT */
+
     /*
      * We support a simpler, old-school style of giving option
      * also, using a single character for each option.  It's
@@ -1557,6 +1674,10 @@ xo_set_options (xo_handle_t *xop, const 
 
 	for (input++ ; *input; input++) {
 	    switch (*input) {
+	    case 'c':
+		xop->xo_flags |= XOF_COLOR_ALLOWED;
+		break;
+
 	    case 'f':
 		xop->xo_flags |= XOF_FLUSH;
 		break;
@@ -1634,6 +1755,11 @@ xo_set_options (xo_handle_t *xop, const 
 	if (vp)
 	    *vp++ = '\0';
 
+	if (strcmp("colors", cp) == 0) {
+	    /* XXX Look for colors=red-blue+green-yellow */
+	    continue;
+	}
+
 	new_style = xo_name_to_style(cp);
 	if (new_style >= 0) {
 	    if (style >= 0)
@@ -1645,7 +1771,9 @@ xo_set_options (xo_handle_t *xop, const 
 	    if (new_flag != 0)
 		xop->xo_flags |= new_flag;
 	    else {
-		if (strcmp(cp, "indent") == 0) {
+		if (strcmp(cp, "no-color") == 0) {
+		    xop->xo_flags &= ~XOF_COLOR_ALLOWED;
+		} else if (strcmp(cp, "indent") == 0) {
 		    xop->xo_indent_by = atoi(vp);
 		} else {
 		    xo_warnx("unknown option: '%s'", cp);
@@ -1801,7 +1929,7 @@ xo_line_ensure_open (xo_handle_t *xop, x
     if (xop->xo_flags & XOF_DIV_OPEN)
 	return;
 
-    if (xop->xo_style != XO_STYLE_HTML)
+    if (xo_style(xop) != XO_STYLE_HTML)
 	return;
 
     xop->xo_flags |= XOF_DIV_OPEN;
@@ -1819,7 +1947,7 @@ xo_line_close (xo_handle_t *xop)
 {
     static char div_close[] = "</div>";
 
-    switch (xop->xo_style) {
+    switch (xo_style(xop)) {
     case XO_STYLE_HTML:
 	if (!(xop->xo_flags & XOF_DIV_OPEN))
 	    xo_line_ensure_open(xop, 0);
@@ -1976,7 +2104,7 @@ xo_format_string_direct (xo_handle_t *xo
 	if (width < 0)
 	    width = iswcntrl(wc) ? 0 : 1;
 
-	if (xop->xo_style == XO_STYLE_TEXT || xop->xo_style == XO_STYLE_HTML) {
+	if (xo_style(xop) == XO_STYLE_TEXT || xo_style(xop) == XO_STYLE_HTML) {
 	    if (max > 0 && cols + width > max)
 		break;
 	}
@@ -1985,7 +2113,7 @@ xo_format_string_direct (xo_handle_t *xo
 	case XF_ENC_UTF8:
 
 	    /* Output in UTF-8 needs to be escaped, based on the style */
-	    switch (xop->xo_style) {
+	    switch (xo_style(xop)) {
 	    case XO_STYLE_XML:
 	    case XO_STYLE_HTML:
 		if (wc == '<')
@@ -2071,7 +2199,7 @@ xo_format_string (xo_handle_t *xop, xo_b
     wchar_t *wcp = NULL;
     int len, cols = 0, rc = 0;
     int off = xbp->xb_curp - xbp->xb_bufp, off2;
-    int need_enc = (xop->xo_style == XO_STYLE_TEXT)
+    int need_enc = (xo_style(xop) == XO_STYLE_TEXT)
 	? XF_ENC_LOCALE : XF_ENC_UTF8;
 
     if (xo_check_conversion(xop, xfp->xf_enc, need_enc))
@@ -2185,7 +2313,7 @@ static void
 xo_data_append_content (xo_handle_t *xop, const char *str, int len)
 {
     int cols;
-    int need_enc = (xop->xo_style == XO_STYLE_TEXT)
+    int need_enc = (xo_style(xop) == XO_STYLE_TEXT)
 	? XF_ENC_LOCALE : XF_ENC_UTF8;
 
     cols = xo_format_string_direct(xop, &xop->xo_data, XFF_UNESCAPE,
@@ -2246,9 +2374,9 @@ xo_format_data (xo_handle_t *xop, xo_buf
     xo_format_t xf;
     const char *cp, *ep, *sp, *xp = NULL;
     int rc, cols;
-    int style = (flags & XFF_XML) ? XO_STYLE_XML : xop->xo_style;
+    int style = (flags & XFF_XML) ? XO_STYLE_XML : xo_style(xop);
     unsigned make_output = !(flags & XFF_NO_OUTPUT);
-    int need_enc = (xop->xo_style == XO_STYLE_TEXT)
+    int need_enc = (xo_style(xop) == XO_STYLE_TEXT)
 	? XF_ENC_LOCALE : XF_ENC_UTF8;
     
     if (xbp == NULL)
@@ -2310,11 +2438,11 @@ xo_format_data (xo_handle_t *xop, xo_buf
 	/* Hidden fields are only visible to JSON and XML */
 	if (xop->xo_flags & XFF_ENCODE_ONLY) {
 	    if (style != XO_STYLE_XML
-		    && xop->xo_style != XO_STYLE_JSON)
+		    && xo_style(xop) != XO_STYLE_JSON)
 		xf.xf_skip = 1;
 	} else if (xop->xo_flags & XFF_DISPLAY_ONLY) {
 	    if (style != XO_STYLE_TEXT
-		    && xop->xo_style != XO_STYLE_HTML)
+		    && xo_style(xop) != XO_STYLE_HTML)
 		xf.xf_skip = 1;
 	}
 
@@ -2420,8 +2548,8 @@ xo_format_data (xo_handle_t *xop, xo_buf
 		rc = xo_format_string(xop, xbp, flags, &xf);
 
 		if ((flags & XFF_TRIM_WS)
-			&& (xop->xo_style == XO_STYLE_XML
-				|| xop->xo_style == XO_STYLE_JSON))
+			&& (xo_style(xop) == XO_STYLE_XML
+				|| xo_style(xop) == XO_STYLE_JSON))
 		    rc = xo_trim_ws(xbp, rc);
 
 	    } else {
@@ -2567,6 +2695,20 @@ xo_fix_encoding (xo_handle_t *xop UNUSED
 }
 
 static void
+xo_color_append_html (xo_handle_t *xop)
+{
+    /*
+     * If the color buffer has content, we add it now.  It's already
+     * prebuilt and ready, since we want to add it to every <div>.
+     */
+    if (!xo_buf_is_empty(&xop->xo_color_buf)) {
+	xo_buffer_t *xbp = &xop->xo_color_buf;
+
+	xo_data_append(xop, xbp->xb_bufp, xbp->xb_curp - xbp->xb_bufp);
+    }
+}
+
+static void
 xo_buf_append_div (xo_handle_t *xop, const char *class, xo_xff_flags_t flags,
 		   const char *name, int nlen,
 		   const char *value, int vlen,
@@ -2663,6 +2805,16 @@ xo_buf_append_div (xo_handle_t *xop, con
     xo_data_append(xop, div_start, sizeof(div_start) - 1);
     xo_data_append(xop, class, strlen(class));
 
+    /*
+     * If the color buffer has content, we add it now.  It's already
+     * prebuilt and ready, since we want to add it to every <div>.
+     */
+    if (!xo_buf_is_empty(&xop->xo_color_buf)) {
+	xo_buffer_t *xbp = &xop->xo_color_buf;
+
+	xo_data_append(xop, xbp->xb_bufp, xbp->xb_curp - xbp->xb_bufp);
+    }
+
     if (name) {
 	xo_data_append(xop, div_tag, sizeof(div_tag) - 1);
 	xo_data_escape(xop, name, nlen);
@@ -2753,7 +2905,7 @@ xo_buf_append_div (xo_handle_t *xop, con
 static void
 xo_format_text (xo_handle_t *xop, const char *str, int len)
 {
-    switch (xop->xo_style) {
+    switch (xo_style(xop)) {
     case XO_STYLE_TEXT:
 	xo_buf_append_locale(xop, &xop->xo_data, str, len);
 	break;
@@ -2768,7 +2920,8 @@ static void
 xo_format_title (xo_handle_t *xop, const char *str, int len,
 		 const char *fmt, int flen)
 {
-    static char div_open[] = "<div class=\"title\">";
+    static char div_open[] = "<div class=\"title";
+    static char div_middle[] = "\">";
     static char div_close[] = "</div>";
 
     if (flen == 0) {
@@ -2776,7 +2929,7 @@ xo_format_title (xo_handle_t *xop, const
 	flen = 2;
     }
 
-    switch (xop->xo_style) {
+    switch (xo_style(xop)) {
     case XO_STYLE_XML:
     case XO_STYLE_JSON:
 	/*
@@ -2794,12 +2947,14 @@ xo_format_title (xo_handle_t *xop, const
     int rc;
     int need_enc = XF_ENC_LOCALE;
 
-    if (xop->xo_style == XO_STYLE_HTML) {
+    if (xo_style(xop) == XO_STYLE_HTML) {
 	need_enc = XF_ENC_UTF8;
 	xo_line_ensure_open(xop, 0);
 	if (xop->xo_flags & XOF_PRETTY)
 	    xo_buf_indent(xop, xop->xo_indent_by);
 	xo_buf_append(&xop->xo_data, div_open, sizeof(div_open) - 1);
+	xo_color_append_html(xop);
+	xo_buf_append(&xop->xo_data, div_middle, sizeof(div_middle) - 1);
     }
 
     start = xbp->xb_curp - xbp->xb_bufp; /* Reset start */
@@ -2862,7 +3017,7 @@ xo_format_title (xo_handle_t *xop, const
     }
 
     /* If we're styling HTML, then we need to escape it */
-    if (xop->xo_style == XO_STYLE_HTML) {
+    if (xo_style(xop) == XO_STYLE_HTML) {
 	rc = xo_escape_xml(xbp, rc, 0);
     }
 
@@ -2870,7 +3025,7 @@ xo_format_title (xo_handle_t *xop, const
 	xbp->xb_curp += rc;
 
  move_along:
-    if (xop->xo_style == XO_STYLE_HTML) {
+    if (xo_style(xop) == XO_STYLE_HTML) {
 	xo_data_append(xop, div_close, sizeof(div_close) - 1);
 	if (xop->xo_flags & XOF_PRETTY)
 	    xo_data_append(xop, "\n", 1);
@@ -2978,7 +3133,7 @@ xo_format_value (xo_handle_t *xop, const
 	}
     }
 
-    switch (xop->xo_style) {
+    switch (xo_style(xop)) {
     case XO_STYLE_TEXT:
 	if (flags & XFF_ENCODE_ONLY)
 	    flags |= XFF_NO_OUTPUT;
@@ -3103,7 +3258,9 @@ xo_format_value (xo_handle_t *xop, const
 	}
 
 	if (flags & XFF_LEAF_LIST) {
-	    if (first && pretty)
+	    if (!first && pretty)
+		xo_data_append(xop, "\n", 1);
+	    if (pretty)
 		xo_buf_indent(xop, -1);
 	} else {
 	    if (pretty)
@@ -3122,10 +3279,10 @@ xo_format_value (xo_handle_t *xop, const
 			xbp->xb_bufp[off] = '_';
 	    }
 	    xo_data_append(xop, "\":", 2);
+	    if (pretty)
+	        xo_data_append(xop, " ", 1);
 	}
 
-	if (pretty)
-	    xo_data_append(xop, " ", 1);
 	if (quote)
 	    xo_data_append(xop, "\"", 1);
 
@@ -3142,7 +3299,7 @@ xo_format_content (xo_handle_t *xop, con
 		   const char *xml_tag, int display_only,
 		   const char *str, int len, const char *fmt, int flen)
 {
-    switch (xop->xo_style) {
+    switch (xo_style(xop)) {
     case XO_STYLE_TEXT:
 	if (len) {
 	    xo_data_append_content(xop, str, len);
@@ -3195,6 +3352,362 @@ xo_format_content (xo_handle_t *xop, con
     }
 }
 
+static const char *xo_color_names[] = {
+    "default",	/* XO_COL_DEFAULT */
+    "black",	/* XO_COL_BLACK */
+    "red",	/* XO_CLOR_RED */
+    "green",	/* XO_COL_GREEN */
+    "yellow",	/* XO_COL_YELLOW */
+    "blue",	/* XO_COL_BLUE */
+    "magenta",	/* XO_COL_MAGENTA */
+    "cyan",	/* XO_COL_CYAN */
+    "white",	/* XO_COL_WHITE */
+    NULL
+};
+
+static int
+xo_color_find (const char *str)
+{
+    int i;
+
+    for (i = 0; xo_color_names[i]; i++) {
+	if (strcmp(xo_color_names[i], str) == 0)
+	    return i;
+    }
+
+    return -1;
+}
+
+static const char *xo_effect_names[] = {
+    "reset",			/* XO_EFF_RESET */
+    "normal",			/* XO_EFF_NORMAL */
+    "bold",			/* XO_EFF_BOLD */
+    "underline",		/* XO_EFF_UNDERLINE */
+    "inverse",			/* XO_EFF_INVERSE */
+    NULL
+};
+
+static const char *xo_effect_on_codes[] = {
+    "0",			/* XO_EFF_RESET */
+    "0",			/* XO_EFF_NORMAL */
+    "1",			/* XO_EFF_BOLD */
+    "4",			/* XO_EFF_UNDERLINE */
+    "7",			/* XO_EFF_INVERSE */
+    NULL
+};
+
+#if 0
+/*
+ * See comment below re: joy of terminal standards.  These can
+ * be use by just adding:
+ *	if (newp->xoc_effects & bit)
+ *	    code = xo_effect_on_codes[i];
+ * +	else
+ * +	    code = xo_effect_off_codes[i];
+ * in xo_color_handle_text.
+ */
+static const char *xo_effect_off_codes[] = {
+    "0",			/* XO_EFF_RESET */
+    "0",			/* XO_EFF_NORMAL */
+    "21",			/* XO_EFF_BOLD */
+    "24",			/* XO_EFF_UNDERLINE */
+    "27",			/* XO_EFF_INVERSE */
+    NULL
+};
+#endif /* 0 */
+
+static int
+xo_effect_find (const char *str)
+{
+    int i;
+
+    for (i = 0; xo_effect_names[i]; i++) {
+	if (strcmp(xo_effect_names[i], str) == 0)
+	    return i;
+    }
+
+    return -1;
+}
+
+static void
+xo_colors_parse (xo_handle_t *xop, xo_colors_t *xocp, char *str)
+{
+#ifdef LIBXO_TEXT_ONLY
+    return;
+#endif /* LIBXO_TEXT_ONLY */
+
+    char *cp, *ep, *np, *xp;
+    int len = strlen(str);
+    int rc;
+
+    /*
+     * Possible tokens: colors, bg-colors, effects, no-effects, "reset".
+     */
+    for (cp = str, ep = cp + len - 1; cp && cp < ep; cp = np) {
+	/* Trim leading whitespace */
+	while (isspace((int) *cp))
+	    cp += 1;
+
+	np = strchr(cp, ',');
+	if (np)
+	    *np++ = '\0';
+
+	/* Trim trailing whitespace */
+	xp = cp + strlen(cp) - 1;
+	while (isspace(*xp) && xp > cp)
+	    *xp-- = '\0';
+
+	if (cp[0] == 'f' && cp[1] == 'g' && cp[2] == '-') {
+	    rc = xo_color_find(cp + 3);
+	    if (rc < 0)
+		goto unknown;
+
+	    xocp->xoc_col_fg = rc;
+
+	} else if (cp[0] == 'b' && cp[1] == 'g' && cp[2] == '-') {
+	    rc = xo_color_find(cp + 3);
+	    if (rc < 0)
+		goto unknown;
+	    xocp->xoc_col_bg = rc;
+
+	} else if (cp[0] == 'n' && cp[1] == 'o' && cp[2] == '-') {
+	    rc = xo_effect_find(cp + 3);
+	    if (rc < 0)
+		goto unknown;
+	    xocp->xoc_effects &= ~(1 << rc);
+
+	} else {
+	    rc = xo_effect_find(cp);
+	    if (rc < 0)
+		goto unknown;
+	    xocp->xoc_effects |= 1 << rc;
+
+	    switch (1 << rc) {
+	    case XO_EFF_RESET:
+		xocp->xoc_col_fg = xocp->xoc_col_bg = 0;
+		/* Note: not "|=" since we want to wipe out the old value */
+		xocp->xoc_effects = XO_EFF_RESET;
+		break;
+
+	    case XO_EFF_NORMAL:
+		xocp->xoc_effects &= ~(XO_EFF_BOLD | XO_EFF_UNDERLINE
+				      | XO_EFF_INVERSE | XO_EFF_NORMAL);
+		break;
+	    }
+	}
+	continue;
+
+    unknown:
+	if (xop->xo_flags & XOF_WARN)
+	    xo_failure(xop, "unknown color/effect string detected: '%s'", cp);
+    }
+}
+
+static inline int
+xo_colors_enabled (xo_handle_t *xop UNUSED)
+{
+#ifdef LIBXO_TEXT_ONLY
+    return 0;
+#else /* LIBXO_TEXT_ONLY */
+    return ((xop->xo_flags & XOF_COLOR) ? 1 : 0);
+#endif /* LIBXO_TEXT_ONLY */
+}
+
+static void
+xo_colors_handle_text (xo_handle_t *xop UNUSED, xo_colors_t *newp)
+{
+    char buf[BUFSIZ];
+    char *cp = buf, *ep = buf + sizeof(buf);
+    unsigned i, bit;
+    xo_colors_t *oldp = &xop->xo_colors;
+    const char *code;
+
+    /*
+     * Start the buffer with an escape.  We don't want to add the '['
+     * now, since we let xo_effect_text_add unconditionally add the ';'.
+     * We'll replace the first ';' with a '[' when we're done.
+     */
+    *cp++ = 0x1b;		/* Escape */
+
+    /*
+     * Terminals were designed back in the age before "certainty" was
+     * invented, when standards were more what you'd call "guidelines"
+     * than actual rules.  Anyway we can't depend on them to operate
+     * correctly.  So when display attributes are changed, we punt,
+     * reseting them all and turning back on the ones we want to keep.
+     * Longer, but should be completely reliable.  Savvy?
+     */
+    if (oldp->xoc_effects != (newp->xoc_effects & oldp->xoc_effects)) {
+	newp->xoc_effects |= XO_EFF_RESET;
+	oldp->xoc_effects = 0;
+    }
+
+    for (i = 0, bit = 1; xo_effect_names[i]; i++, bit <<= 1) {
+	if ((newp->xoc_effects & bit) == (oldp->xoc_effects & bit))
+	    continue;
+
+	if (newp->xoc_effects & bit)
+	    code = xo_effect_on_codes[i];
+
+	cp += snprintf(cp, ep - cp, ";%s", code);
+	if (cp >= ep)
+	    return;		/* Should not occur */
+
+	if (bit == XO_EFF_RESET) {
+	    /* Mark up the old value so we can detect current values as new */
+	    oldp->xoc_effects = 0;
+	    oldp->xoc_col_fg = oldp->xoc_col_bg = XO_COL_DEFAULT;
+	}
+    }
+
+    if (newp->xoc_col_fg != oldp->xoc_col_fg) {
+	cp += snprintf(cp, ep - cp, ";3%u",
+		       (newp->xoc_col_fg != XO_COL_DEFAULT)
+		       ? newp->xoc_col_fg - 1 : 9);
+    }
+
+    if (newp->xoc_col_bg != oldp->xoc_col_bg) {
+	cp += snprintf(cp, ep - cp, ";4%u",
+		       (newp->xoc_col_bg != XO_COL_DEFAULT)
+		       ? newp->xoc_col_bg - 1 : 9);
+    }
+
+    if (cp - buf != 1 && cp < ep - 3) {
+	buf[1] = '[';		/* Overwrite leading ';' */
+	*cp++ = 'm';
+	*cp = '\0';
+	xo_buf_append(&xop->xo_data, buf, cp - buf);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201504271723.t3RHNKbP081255>