Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
philshafer committed Jan 23, 2020
2 parents 0ea9259 + 10a1e14 commit a462347
Show file tree
Hide file tree
Showing 19 changed files with 293 additions and 44 deletions.
59 changes: 59 additions & 0 deletions doc/api.rst
Expand Up @@ -1204,6 +1204,11 @@ message associated with either *errno* or the *code* parameter::
xo_err(1, "cannot open file '%s'", filename);
.. index:: xo_error
.. index:: xo_error_h
.. index:: xo_error_hv
.. index:: xo_errorn
.. index:: xo_errorn_h
.. index:: xo_errorn_hv
xo_error
~~~~~~~~
Expand All @@ -1214,6 +1219,50 @@ xo_error
:type fmt: const char *
:returns: void
.. c:function:: void xo_error_h (xo_handle_t *xop, const char *fmt, ...)
:param xop: libxo handle pointer
:type xop: xo_handle_t *
:param fmt: Format string
:type fmt: const char *
:returns: void
.. c:function:: void xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap)
:param xop: libxo handle pointer
:type xop: xo_handle_t *
:param fmt: Format string
:type fmt: const char *
:param vap: variadic arguments
:type xop: va_list
:returns: void
.. c:function:: void xo_errorn (const char *fmt, ...)
:param fmt: Format string
:type fmt: const char *
:returns: void
.. c:function:: void xo_errorn_h (xo_handle_t *xop, const char *fmt, ...)
:param xop: libxo handle pointer
:type xop: xo_handle_t *
:param fmt: Format string
:type fmt: const char *
:returns: void
.. c:function:: void xo_errorn_hv (xo_handle_t *xop, int need_newline, const char *fmt, va_list vap)
:param xop: libxo handle pointer
:type xop: xo_handle_t *
:param need_newline: boolean indicating need for trailing newline
:type need_newline: int
:param fmt: Format string
:type fmt: const char *
:param vap: variadic arguments
:type xop: va_list
:returns: void
The `xo_error` function can be used for generic errors that should
be reported over the handle, rather than to stderr. The `xo_error`
function behaves like `xo_err` for TEXT and HTML output styles, but
Expand All @@ -1226,6 +1275,16 @@ xo_error
JSON::
"error": { "message": "Does not compute" }
The `xo_error_h` and `xo_error_hv` add a handle object and a
variadic-ized parameter to the signature, respectively.
The `xo_errorn` function supplies a newline at the end the error
message if the format string does not include one. The
`xo_errorn_h` and `xo_errorn_hv` functions add a handle object and
a variadic-ized parameter to the signature, respectively. The
`xo_errorn_hv` function also adds a boolean to indicate the need for
a trailing newline.
.. index:: xo_no_setlocale
.. index:: Locale
Expand Down
13 changes: 9 additions & 4 deletions doc/encoders.rst
Expand Up @@ -26,12 +26,13 @@ example uses the "cbor" encoder, saving the output into a file::
df --libxo encoder=cbor > df-output.cbor

Encoders can support specific options that can be accessed by
following the encoder name with a colon (':') and one of more options,
separated by a plus sign "+"::
following the encoder name with a colon (':') or a plus sign ('+') and
one of more options, separated by the same character::

df --libxo encoder=csv:path=filesystem+leaf=name+no-header
df --libxo encoder=csv+path=filesystem+leaf=name+no-header
df --libxo encoder=csv:path=filesystem:leaf=name:no-header

This example instructs libxo to load the "csv" encoder and pass the
These examples instructs libxo to load the "csv" encoder and pass the
following options::

path=filesystem
Expand All @@ -42,6 +43,10 @@ Each of these option is interpreted by the encoder, and all such
options names and semantics are specific to the particular encoder.
Refer to the intended encoder for documentation on its options.

The string "@" can be used in place of the string "encoder=".

df --libxo @csv:no-header

.. _csv_encoder:

CSV - Comma Separated Values
Expand Down
20 changes: 20 additions & 0 deletions doc/options.rst
Expand Up @@ -162,3 +162,23 @@ foreground and background output to "yellow", give only the fifth
mapping, skipping the first four mappings with bare plus signs ("+")::

--libxo colors=++++yellow/yellow

Encoders
--------

In addition to the four "built-in" formats, libxo supports an
extensible mechanism for adding encoders. These are activated
using the "encoder" keyword::

--libxo encoder=cbor

The encoder can include encoder-specific options, separated by either
colons (":") or plus signs ("+"):

--libxo encoder=csv+path=filesystem+leaf=name+no-header
--libxo encoder=csv:path=filesystem:leaf=name:no-header

For brevity, the string "@" can be used in place of the string
"encoder=".

df --libxo @csv:no-header
24 changes: 16 additions & 8 deletions encoder/csv/enc_csv.c
Expand Up @@ -41,10 +41,12 @@
* (double) quote characters.
* - Leading and trialing whitespace require fields be quoted.
*
* Cheesy, but simple. The RFC also requires MS-DOS end-of-line, which
* we only do with the "dos" option. Strange that we still live in a
* DOS-friendly world, but then again, we make spaceships based on the
* horse butts (http://www.astrodigital.org/space/stshorse.html).
* Cheesy, but simple. The RFC also requires MS-DOS end-of-line,
* which we only do with the "dos" option. Strange that we still live
* in a DOS-friendly world, but then again, we make spaceships based
* on the horse butts (http://www.astrodigital.org/space/stshorse.html
* though the "built by English expatriates” bit is rubbish; better to
* say the first engines used in America were built by Englishmen.)
*/

#include <string.h>
Expand Down Expand Up @@ -655,10 +657,12 @@ csv_record_path (xo_handle_t *xop, csv_private_t *csv, const char *path_raw)

/*
* Extract the option values. The format is:
* -libxo encoder=csv:kw=val+kw=val+kw=val,pretty,etc
* -libxo encoder=csv:kw=val:kw=val:kw=val,pretty
* -libxo encoder=csv+kw=val+kw=val+kw=val,pretty
*/
static int
csv_options (xo_handle_t *xop, csv_private_t *csv, const char *raw_opts)
csv_options (xo_handle_t *xop, csv_private_t *csv,
const char *raw_opts, char opts_char)
{
ssize_t len = strlen(raw_opts);
char *options = alloca(len + 1);
Expand All @@ -667,7 +671,7 @@ csv_options (xo_handle_t *xop, csv_private_t *csv, const char *raw_opts)

char *cp, *ep, *np, *vp;
for (cp = options, ep = options + len + 1; cp && cp < ep; cp = np) {
np = strchr(cp, '+');
np = strchr(cp, opts_char);
if (np)
*np++ = '\0';

Expand Down Expand Up @@ -761,7 +765,11 @@ csv_handler (XO_ENCODER_HANDLER_ARGS)
break;

case XO_OP_OPTIONS:
rc = csv_options(xop, csv, value);
rc = csv_options(xop, csv, value, ':');
break;

case XO_OP_OPTIONS_PLUS:
rc = csv_options(xop, csv, value, '+');
break;

case XO_OP_OPEN_LIST:
Expand Down
103 changes: 78 additions & 25 deletions libxo/libxo.c
Expand Up @@ -2371,6 +2371,25 @@ xo_set_options (xo_handle_t *xop, const char *input)
if (np)
*np++ = '\0';

/*
* "@foo" is a shorthand for "encoder=foo". This is driven
* chiefly by a desire to make pluggable encoders not appear
* so distinct from built-in encoders.
*/
if (*cp == '@') {
vp = cp + 1;

if (*vp == '\0')
xo_failure(xop, "missing value for encoder option");
else {
rc = xo_encoder_init(xop, vp);
if (rc)
xo_warnx("error initializing encoder: %s", vp);
}

continue;
}

vp = strchr(cp, '=');
if (vp)
*vp++ = '\0';
Expand Down Expand Up @@ -8007,21 +8026,23 @@ xo_finish_atexit (void)
* Generate an error message, such as would be displayed on stderr
*/
void
xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap)
xo_errorn_hv (xo_handle_t *xop, int need_newline, const char *fmt, va_list vap)
{
xop = xo_default(xop);

/*
* If the format string doesn't end with a newline, we pop
* one on ourselves.
*/
ssize_t len = strlen(fmt);
if (len > 0 && fmt[len - 1] != '\n') {
char *newfmt = alloca(len + 2);
memcpy(newfmt, fmt, len);
newfmt[len] = '\n';
newfmt[len + 1] = '\0';
fmt = newfmt;
if (need_newline) {
ssize_t len = strlen(fmt);
if (len > 0 && fmt[len - 1] != '\n') {
char *newfmt = alloca(len + 2);
memcpy(newfmt, fmt, len);
newfmt[len] = '\n';
newfmt[len + 1] = '\0';
fmt = newfmt;
}
}

switch (xo_style(xop)) {
Expand Down Expand Up @@ -8069,7 +8090,7 @@ xo_error_h (xo_handle_t *xop, const char *fmt, ...)
va_list vap;

va_start(vap, fmt);
xo_error_hv(xop, fmt, vap);
xo_errorn_hv(xop, 0, fmt, vap);
va_end(vap);
}

Expand All @@ -8082,7 +8103,30 @@ xo_error (const char *fmt, ...)
va_list vap;

va_start(vap, fmt);
xo_error_hv(NULL, fmt, vap);
xo_errorn_hv(NULL, 0, fmt, vap);
va_end(vap);
}

void
xo_errorn_h (xo_handle_t *xop, const char *fmt, ...)
{
va_list vap;

va_start(vap, fmt);
xo_errorn_hv(xop, 1, fmt, vap);
va_end(vap);
}

/*
* Generate an error message, such as would be displayed on stderr
*/
void
xo_errorn (const char *fmt, ...)
{
va_list vap;

va_start(vap, fmt);
xo_errorn_hv(NULL, 1, fmt, vap);
va_end(vap);
}

Expand All @@ -8099,21 +8143,30 @@ xo_parse_args (int argc, char **argv)
char *cp;
int i, save;

/* Save our program name for xo_err and friends */
xo_program = argv[0];
cp = strrchr(xo_program, '/');
if (cp)
xo_program = ++cp;
else
cp = argv[0]; /* Reset to front of string */

/* GNU tools add an annoying ".test" as the program extension; remove it */
size_t len = strlen(xo_program);
static const char gnu_ext[] = ".test";
if (len >= sizeof(gnu_ext)) {
cp += len + 1 - sizeof(gnu_ext);
if (xo_streq(cp, gnu_ext))
*cp = '\0';
/*
* If xo_set_program has always been called, we honor that value
*/
if (xo_program == NULL) {
/* Save our program name for xo_err and friends */
xo_program = argv[0];
cp = strrchr(xo_program, '/');
if (cp)
xo_program = ++cp;
else
cp = argv[0]; /* Reset to front of string */

/*
* GNU libtool add an annoying ".test" as the program
* extension; we remove it. libtool also adds a "lt-" prefix
* that we cannot remove.
*/
size_t len = strlen(xo_program);
static const char gnu_ext[] = ".test";
if (len >= sizeof(gnu_ext)) {
cp += len + 1 - sizeof(gnu_ext);
if (xo_streq(cp, gnu_ext))
*cp = '\0';
}
}

xo_handle_t *xop = xo_default(NULL);
Expand Down
9 changes: 9 additions & 0 deletions libxo/xo.h
Expand Up @@ -389,6 +389,15 @@ xo_error_h (xo_handle_t *xop, const char *fmt, ...);
void
xo_error (const char *fmt, ...);

void
xo_errorn_hv (xo_handle_t *xop, int need_newline, const char *fmt, va_list vap);

void
xo_errorn_h (xo_handle_t *xop, const char *fmt, ...);

void
xo_errorn (const char *fmt, ...);

xo_ssize_t
xo_flush_h (xo_handle_t *xop);

Expand Down
21 changes: 19 additions & 2 deletions libxo/xo_encoder.c
Expand Up @@ -290,8 +290,21 @@ xo_encoder_init (xo_handle_t *xop, const char *name)
{
xo_encoder_setup();

const char *opts = strchr(name, ':');
char opts_char = '\0';
const char *col_opts = strchr(name, ':');
const char *plus_opts = strchr(name, '+');

/*
* Find the option-separating character (plus or colon) which
* appears first in the options string.
*/
const char *opts = (col_opts == NULL) ? plus_opts
: (plus_opts == NULL) ? col_opts
: (plus_opts < col_opts) ? plus_opts : col_opts;

if (opts) {
opts_char = *opts;

/* Make a writable copy of the name */
size_t len = strlen(name);
char *copy = alloca(len + 1);
Expand Down Expand Up @@ -329,7 +342,11 @@ xo_encoder_init (xo_handle_t *xop, const char *name)

int rc = xo_encoder_handle(xop, XO_OP_CREATE, name, NULL, 0);
if (rc == 0 && opts != NULL) {
rc = xo_encoder_handle(xop, XO_OP_OPTIONS, name, opts, 0);
xo_encoder_op_t op;

/* Encoder API is limited, so we're stuck with two different options */
op = (opts_char == '+') ? XO_OP_OPTIONS_PLUS : XO_OP_OPTIONS;
rc = xo_encoder_handle(xop, op, name, opts, 0);
}

return rc;
Expand Down
1 change: 1 addition & 0 deletions libxo/xo_encoder.h
Expand Up @@ -90,6 +90,7 @@ typedef unsigned xo_encoder_op_t;
#define XO_OP_ATTRIBUTE 15 /* Attribute name/value */
#define XO_OP_VERSION 16 /* Version string */
#define XO_OP_OPTIONS 17 /* Additional command line options */
#define XO_OP_OPTIONS_PLUS 18 /* Additional command line options */

#define XO_ENCODER_HANDLER_ARGS \
xo_handle_t *xop __attribute__ ((__unused__)), \
Expand Down

0 comments on commit a462347

Please sign in to comment.