From owner-svn-src-head@FreeBSD.ORG Mon Apr 27 17:23:22 2015 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id EDA6A21C; Mon, 27 Apr 2015 17:23:21 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id D8E3611C5; Mon, 27 Apr 2015 17:23:21 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t3RHNLhO081268; Mon, 27 Apr 2015 17:23:21 GMT (envelope-from marcel@FreeBSD.org) Received: (from marcel@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t3RHNKbP081255; Mon, 27 Apr 2015 17:23:20 GMT (envelope-from marcel@FreeBSD.org) Message-Id: <201504271723.t3RHNKbP081255@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: marcel set sender to marcel@FreeBSD.org using -f From: Marcel Moolenaar Date: Mon, 27 Apr 2015 17:23:20 +0000 (UTC) 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... X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 27 Apr 2015 17:23:22 -0000 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 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 my-box example.com 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,
36
-
./src
+
./src
40
-
./bin
+
./bin
90
-
./
+
./
** 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 path for finding css/javascript files | +| -c | Command to execute | +| -f | 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[] = ""; - 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
. + */ + 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
. + */ + 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[] = "
"; + static char div_open[] = "
"; static char div_close[] = "
"; 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 ***