.
+ */
+ 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);
+ }
+}
+
+/*
+ * A wrapper for humanize_number that autoscales, since the
+ * HN_AUTOSCALE flag scales as needed based on the size of
+ * the output buffer, not the size of the value. I also
+ * wish HN_DECIMAL was more imperative, without the <10
+ * test. But the boat only goes where we want when we hold
+ * the rudder, so xo_humanize fixes part of the problem.
+ */
+static int
+xo_humanize (char *buf, int len, uint64_t value, int flags)
+{
+ int scale = 0;
+
+ if (value) {
+ uint64_t left = value;
+
+ if (flags & HN_DIVISOR_1000) {
+ for ( ; left; scale++)
+ left /= 1000;
+ } else {
+ for ( ; left; scale++)
+ left /= 1024;
+ }
+ scale -= 1;
+ }
+
+ return xo_humanize_number(buf, len, value, "", scale, flags);
+}
+
+/*
+ * This is an area where we can save information from the handle for
+ * later restoration. We need to know what data was rendered to know
+ * what needs cleaned up.
+ */
+typedef struct xo_humanize_save_s {
+ unsigned xhs_offset; /* Saved xo_offset */
+ unsigned xhs_columns; /* Saved xo_columns */
+ unsigned xhs_anchor_columns; /* Saved xo_anchor_columns */
+} xo_humanize_save_t;
+
+/*
+ * Format a "humanized" value for a numeric, meaning something nice
+ * like "44M" instead of "44470272". We autoscale, choosing the
+ * most appropriate value for K/M/G/T/P/E based on the value given.
+ */
+static void
+xo_format_humanize (xo_handle_t *xop, xo_buffer_t *xbp,
+ xo_humanize_save_t *savep, xo_xff_flags_t flags)
+{
+ if (XOF_ISSET(xop, XOF_NO_HUMANIZE))
+ return;
+
+ unsigned end_offset = xbp->xb_curp - xbp->xb_bufp;
+ if (end_offset == savep->xhs_offset) /* Huh? Nothing to render */
+ return;
+
+ /*
+ * We have a string that's allegedly a number. We want to
+ * humanize it, which means turning it back into a number
+ * and calling xo_humanize_number on it.
+ */
+ uint64_t value;
+ char *ep;
+
+ xo_buf_append(xbp, "", 1); /* NUL-terminate it */
+
+ value = strtoull(xbp->xb_bufp + savep->xhs_offset, &ep, 0);
+ if (!(value == ULLONG_MAX && errno == ERANGE)
+ && (ep != xbp->xb_bufp + savep->xhs_offset)) {
+ /*
+ * There are few values where humanize_number needs
+ * more bytes than the original value. I've used
+ * 10 as a rectal number to cover those scenarios.
+ */
+ if (xo_buf_has_room(xbp, 10)) {
+ xbp->xb_curp = xbp->xb_bufp + savep->xhs_offset;
+
+ int rc;
+ int left = (xbp->xb_bufp + xbp->xb_size) - xbp->xb_curp;
+ int hn_flags = HN_NOSPACE; /* On by default */
+
+ if (flags & XFF_HN_SPACE)
+ hn_flags &= ~HN_NOSPACE;
+
+ if (flags & XFF_HN_DECIMAL)
+ hn_flags |= HN_DECIMAL;
+
+ if (flags & XFF_HN_1000)
+ hn_flags |= HN_DIVISOR_1000;
+
+ rc = xo_humanize(xbp->xb_curp,
+ left, value, hn_flags);
+ if (rc > 0) {
+ xbp->xb_curp += rc;
+ xop->xo_columns = savep->xhs_columns + rc;
+ xop->xo_anchor_columns = savep->xhs_anchor_columns + rc;
+ }
+ }
+ }
+}
+
+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,
+ const char *encoding, int elen)
+{
+ static char div_start[] = "
";
+
+ /*
+ * To build our XPath predicate, we need to save the va_list before
+ * we format our data, and then restore it before we format the
+ * xpath expression.
+ * Display-only keys implies that we've got an encode-only key
+ * elsewhere, so we don't use them from making predicates.
+ */
+ int need_predidate =
+ (name && (flags & XFF_KEY) && !(flags & XFF_DISPLAY_ONLY)
+ && XOF_ISSET(xop, XOF_XPATH));
+
+ if (need_predidate) {
+ va_list va_local;
+
+ va_copy(va_local, xop->xo_vap);
+ if (xop->xo_checkpointer)
+ xop->xo_checkpointer(xop, xop->xo_vap, 0);
+
+ /*
+ * Build an XPath predicate expression to match this key.
+ * We use the format buffer.
+ */
+ xo_buffer_t *pbp = &xop->xo_predicate;
+ pbp->xb_curp = pbp->xb_bufp; /* Restart buffer */
+
+ xo_buf_append(pbp, "[", 1);
+ xo_buf_escape(xop, pbp, name, nlen, 0);
+ if (XOF_ISSET(xop, XOF_PRETTY))
+ xo_buf_append(pbp, " = '", 4);
+ else
+ xo_buf_append(pbp, "='", 2);
+
+ /* The encoding format defaults to the normal format */
+ if (encoding == NULL) {
+ char *enc = alloca(vlen + 1);
+ memcpy(enc, value, vlen);
+ enc[vlen] = '\0';
+ encoding = xo_fix_encoding(xop, enc);
+ elen = strlen(encoding);
+ }
+
+ xo_xff_flags_t pflags = flags | XFF_XML | XFF_ATTR;
+ pflags &= ~(XFF_NO_OUTPUT | XFF_ENCODE_ONLY);
+ xo_do_format_field(xop, pbp, encoding, elen, pflags);
+
+ xo_buf_append(pbp, "']", 2);
+
+ /* Now we record this predicate expression in the stack */
+ xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth];
+ int olen = xsp->xs_keys ? strlen(xsp->xs_keys) : 0;
+ int dlen = pbp->xb_curp - pbp->xb_bufp;
+
+ char *cp = xo_realloc(xsp->xs_keys, olen + dlen + 1);
+ if (cp) {
+ memcpy(cp + olen, pbp->xb_bufp, dlen);
+ cp[olen + dlen] = '\0';
+ xsp->xs_keys = cp;
+ }
+
+ /* Now we reset the xo_vap as if we were never here */
+ va_end(xop->xo_vap);
+ va_copy(xop->xo_vap, va_local);
+ va_end(va_local);
+ if (xop->xo_checkpointer)
+ xop->xo_checkpointer(xop, xop->xo_vap, 1);
+ }
+
+ if (flags & XFF_ENCODE_ONLY) {
+ /*
+ * Even if this is encode-only, we need to go thru the
+ * work of formatting it to make sure the args are cleared
+ * from xo_vap.
+ */
+ xo_do_format_field(xop, NULL, encoding, elen,
+ flags | XFF_NO_OUTPUT);
+ return;
+ }
+
+ xo_line_ensure_open(xop, 0);
+
+ if (XOF_ISSET(xop, XOF_PRETTY))
+ xo_buf_indent(xop, xop->xo_indent_by);
+
+ 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);
+
+ /*
+ * Save the offset at which we'd place units. See xo_format_units.
+ */
+ if (XOF_ISSET(xop, XOF_UNITS)) {
+ XOIF_SET(xop, XOIF_UNITS_PENDING);
+ /*
+ * Note: We need the '+1' here because we know we've not
+ * added the closing quote. We add one, knowing the quote
+ * will be added shortly.
+ */
+ xop->xo_units_offset =
+ xop->xo_data.xb_curp -xop->xo_data.xb_bufp + 1;
+ }
+
+ if (XOF_ISSET(xop, XOF_XPATH)) {
+ int i;
+ xo_stack_t *xsp;
+
+ xo_data_append(xop, div_xpath, sizeof(div_xpath) - 1);
+ if (xop->xo_leading_xpath)
+ xo_data_append(xop, xop->xo_leading_xpath,
+ strlen(xop->xo_leading_xpath));
+
+ for (i = 0; i <= xop->xo_depth; i++) {
+ xsp = &xop->xo_stack[i];
+ if (xsp->xs_name == NULL)
+ continue;
+
+ /*
+ * XSS_OPEN_LIST and XSS_OPEN_LEAF_LIST stack frames
+ * are directly under XSS_OPEN_INSTANCE frames so we
+ * don't need to put these in our XPath expressions.
+ */
+ if (xsp->xs_state == XSS_OPEN_LIST
+ || xsp->xs_state == XSS_OPEN_LEAF_LIST)
+ continue;
+
+ xo_data_append(xop, "/", 1);
+ xo_data_escape(xop, xsp->xs_name, strlen(xsp->xs_name));
+ if (xsp->xs_keys) {
+ /* Don't show keys for the key field */
+ if (i != xop->xo_depth || !(flags & XFF_KEY))
+ xo_data_append(xop, xsp->xs_keys, strlen(xsp->xs_keys));
+ }
+ }
+
+ xo_data_append(xop, "/", 1);
+ xo_data_escape(xop, name, nlen);
+ }
+
+ if (XOF_ISSET(xop, XOF_INFO) && xop->xo_info) {
+ static char in_type[] = "\" data-type=\"";
+ static char in_help[] = "\" data-help=\"";
+
+ xo_info_t *xip = xo_info_find(xop, name, nlen);
+ if (xip) {
+ if (xip->xi_type) {
+ xo_data_append(xop, in_type, sizeof(in_type) - 1);
+ xo_data_escape(xop, xip->xi_type, strlen(xip->xi_type));
+ }
+ if (xip->xi_help) {
+ xo_data_append(xop, in_help, sizeof(in_help) - 1);
+ xo_data_escape(xop, xip->xi_help, strlen(xip->xi_help));
+ }
+ }
+ }
+
+ if ((flags & XFF_KEY) && XOF_ISSET(xop, XOF_KEYS))
+ xo_data_append(xop, div_key, sizeof(div_key) - 1);
+ }
+
+ xo_buffer_t *xbp = &xop->xo_data;
+ unsigned base_offset = xbp->xb_curp - xbp->xb_bufp;
+
+ xo_data_append(xop, div_end, sizeof(div_end) - 1);
+
+ xo_humanize_save_t save; /* Save values for humanizing logic */
+
+ save.xhs_offset = xbp->xb_curp - xbp->xb_bufp;
+ save.xhs_columns = xop->xo_columns;
+ save.xhs_anchor_columns = xop->xo_anchor_columns;
+
+ xo_do_format_field(xop, NULL, value, vlen, flags);
+
+ if (flags & XFF_HUMANIZE) {
+ /*
+ * Unlike text style, we want to retain the original value and
+ * stuff it into the "data-number" attribute.
+ */
+ static const char div_number[] = "\" data-number=\"";
+ int div_len = sizeof(div_number) - 1;
+
+ unsigned end_offset = xbp->xb_curp - xbp->xb_bufp;
+ int olen = end_offset - save.xhs_offset;
+
+ char *cp = alloca(olen + 1);
+ memcpy(cp, xbp->xb_bufp + save.xhs_offset, olen);
+ cp[olen] = '\0';
+
+ xo_format_humanize(xop, xbp, &save, flags);
+
+ if (xo_buf_has_room(xbp, div_len + olen)) {
+ unsigned new_offset = xbp->xb_curp - xbp->xb_bufp;
+
+
+ /* Move the humanized string off to the left */
+ memmove(xbp->xb_bufp + base_offset + div_len + olen,
+ xbp->xb_bufp + base_offset, new_offset - base_offset);
+
+ /* Copy the data_number attribute name */
+ memcpy(xbp->xb_bufp + base_offset, div_number, div_len);
+
+ /* Copy the original long value */
+ memcpy(xbp->xb_bufp + base_offset + div_len, cp, olen);
+ xbp->xb_curp += div_len + olen;
+ }
+ }
+
+ xo_data_append(xop, div_close, sizeof(div_close) - 1);
+
+ if (XOF_ISSET(xop, XOF_PRETTY))
+ xo_data_append(xop, "\n", 1);
+}
+
+static void
+xo_format_text (xo_handle_t *xop, const char *str, int len)
+{
+ switch (xo_style(xop)) {
+ case XO_STYLE_TEXT:
+ xo_buf_append_locale(xop, &xop->xo_data, str, len);
+ break;
+
+ case XO_STYLE_HTML:
+ xo_buf_append_div(xop, "text", 0, NULL, 0, str, len, NULL, 0);
+ break;
+ }
+}
+
+static void
+xo_format_title (xo_handle_t *xop, xo_field_info_t *xfip)
+{
+ const char *str = xfip->xfi_content;
+ unsigned len = xfip->xfi_clen;
+ const char *fmt = xfip->xfi_format;
+ unsigned flen = xfip->xfi_flen;
+ xo_xff_flags_t flags = xfip->xfi_flags;
+
+ static char div_open[] = "
";
+ static char div_close[] = "
";
+
+ if (flen == 0) {
+ fmt = "%s";
+ flen = 2;
+ }
+
+ switch (xo_style(xop)) {
+ case XO_STYLE_XML:
+ case XO_STYLE_JSON:
+ case XO_STYLE_SDPARAMS:
+ case XO_STYLE_ENCODER:
+ /*
+ * Even though we don't care about text, we need to do
+ * enough parsing work to skip over the right bits of xo_vap.
+ */
+ if (len == 0)
+ xo_do_format_field(xop, NULL, fmt, flen, flags | XFF_NO_OUTPUT);
+ return;
+ }
+
+ xo_buffer_t *xbp = &xop->xo_data;
+ int start = xbp->xb_curp - xbp->xb_bufp;
+ int left = xbp->xb_size - start;
+ int rc;
+
+ if (xo_style(xop) == XO_STYLE_HTML) {
+ xo_line_ensure_open(xop, 0);
+ if (XOF_ISSET(xop, 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 */
+ if (len) {
+ char *newfmt = alloca(flen + 1);
+ memcpy(newfmt, fmt, flen);
+ newfmt[flen] = '\0';
+
+ /* If len is non-zero, the format string apply to the name */
+ char *newstr = alloca(len + 1);
+ memcpy(newstr, str, len);
+ newstr[len] = '\0';
+
+ if (newstr[len - 1] == 's') {
+ char *bp;
+
+ rc = snprintf(NULL, 0, newfmt, newstr);
+ if (rc > 0) {
+ /*
+ * We have to do this the hard way, since we might need
+ * the columns.
+ */
+ bp = alloca(rc + 1);
+ rc = snprintf(bp, rc + 1, newfmt, newstr);
+
+ xo_data_append_content(xop, bp, rc, flags);
+ }
+ goto move_along;
+
+ } else {
+ rc = snprintf(xbp->xb_curp, left, newfmt, newstr);
+ if (rc >= left) {
+ if (!xo_buf_has_room(xbp, rc))
+ return;
+ left = xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp);
+ rc = snprintf(xbp->xb_curp, left, newfmt, newstr);
+ }
+
+ if (rc > 0) {
+ if (XOF_ISSET(xop, XOF_COLUMNS))
+ xop->xo_columns += rc;
+ if (XOIF_ISSET(xop, XOIF_ANCHOR))
+ xop->xo_anchor_columns += rc;
+ }
+ }
+
+ } else {
+ xo_do_format_field(xop, NULL, fmt, flen, flags);
+
+ /* xo_do_format_field moved curp, so we need to reset it */
+ rc = xbp->xb_curp - (xbp->xb_bufp + start);
+ xbp->xb_curp = xbp->xb_bufp + start;
+ }
+
+ /* If we're styling HTML, then we need to escape it */
+ if (xo_style(xop) == XO_STYLE_HTML) {
+ rc = xo_escape_xml(xbp, rc, 0);
+ }
+
+ if (rc > 0)
+ xbp->xb_curp += rc;
+
+ move_along:
+ if (xo_style(xop) == XO_STYLE_HTML) {
+ xo_data_append(xop, div_close, sizeof(div_close) - 1);
+ if (XOF_ISSET(xop, XOF_PRETTY))
+ xo_data_append(xop, "\n", 1);
+ }
+}
+
+static void
+xo_format_prep (xo_handle_t *xop, xo_xff_flags_t flags)
+{
+ if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST) {
+ xo_data_append(xop, ",", 1);
+ if (!(flags & XFF_LEAF_LIST) && XOF_ISSET(xop, XOF_PRETTY))
+ xo_data_append(xop, "\n", 1);
+ } else
+ xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST;
+}
+
+#if 0
+/* Useful debugging function */
+void
+xo_arg (xo_handle_t *xop);
+void
+xo_arg (xo_handle_t *xop)
+{
+ xop = xo_default(xop);
+ fprintf(stderr, "0x%x", va_arg(xop->xo_vap, unsigned));
+}
+#endif /* 0 */
+
+static void
+xo_format_value (xo_handle_t *xop, const char *name, int nlen,
+ const char *format, int flen,
+ const char *encoding, int elen, xo_xff_flags_t flags)
+{
+ int pretty = XOF_ISSET(xop, XOF_PRETTY);
+ int quote;
+
+ /*
+ * Before we emit a value, we need to know that the frame is ready.
+ */
+ xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth];
+
+ if (flags & XFF_LEAF_LIST) {
+ /*
+ * Check if we've already started to emit normal leafs
+ * or if we're not in a leaf list.
+ */
+ if ((xsp->xs_flags & (XSF_EMIT | XSF_EMIT_KEY))
+ || !(xsp->xs_flags & XSF_EMIT_LEAF_LIST)) {
+ char nbuf[nlen + 1];
+ memcpy(nbuf, name, nlen);
+ nbuf[nlen] = '\0';
+
+ int rc = xo_transition(xop, 0, nbuf, XSS_EMIT_LEAF_LIST);
+ if (rc < 0)
+ flags |= XFF_DISPLAY_ONLY | XFF_ENCODE_ONLY;
+ else
+ xop->xo_stack[xop->xo_depth].xs_flags |= XSF_EMIT_LEAF_LIST;
+ }
+
+ xsp = &xop->xo_stack[xop->xo_depth];
+ if (xsp->xs_name) {
+ name = xsp->xs_name;
+ nlen = strlen(name);
+ }
+
+ } else if (flags & XFF_KEY) {
+ /* Emitting a 'k' (key) field */
+ if ((xsp->xs_flags & XSF_EMIT) && !(flags & XFF_DISPLAY_ONLY)) {
+ xo_failure(xop, "key field emitted after normal value field: '%.*s'",
+ nlen, name);
+
+ } else if (!(xsp->xs_flags & XSF_EMIT_KEY)) {
+ char nbuf[nlen + 1];
+ memcpy(nbuf, name, nlen);
+ nbuf[nlen] = '\0';
+
+ int rc = xo_transition(xop, 0, nbuf, XSS_EMIT);
+ if (rc < 0)
+ flags |= XFF_DISPLAY_ONLY | XFF_ENCODE_ONLY;
+ else
+ xop->xo_stack[xop->xo_depth].xs_flags |= XSF_EMIT_KEY;
+
+ xsp = &xop->xo_stack[xop->xo_depth];
+ xsp->xs_flags |= XSF_EMIT_KEY;
+ }
+
+ } else {
+ /* Emitting a normal value field */
+ if ((xsp->xs_flags & XSF_EMIT_LEAF_LIST)
+ || !(xsp->xs_flags & XSF_EMIT)) {
+ char nbuf[nlen + 1];
+ memcpy(nbuf, name, nlen);
+ nbuf[nlen] = '\0';
+
+ int rc = xo_transition(xop, 0, nbuf, XSS_EMIT);
+ if (rc < 0)
+ flags |= XFF_DISPLAY_ONLY | XFF_ENCODE_ONLY;
+ else
+ xop->xo_stack[xop->xo_depth].xs_flags |= XSF_EMIT;
+
+ xsp = &xop->xo_stack[xop->xo_depth];
+ xsp->xs_flags |= XSF_EMIT;
+ }
+ }
+
+ xo_buffer_t *xbp = &xop->xo_data;
+ xo_humanize_save_t save; /* Save values for humanizing logic */
+
+ switch (xo_style(xop)) {
+ case XO_STYLE_TEXT:
+ if (flags & XFF_ENCODE_ONLY)
+ flags |= XFF_NO_OUTPUT;
+
+ save.xhs_offset = xbp->xb_curp - xbp->xb_bufp;
+ save.xhs_columns = xop->xo_columns;
+ save.xhs_anchor_columns = xop->xo_anchor_columns;
+
+ xo_do_format_field(xop, NULL, format, flen, flags);
+
+ if (flags & XFF_HUMANIZE)
+ xo_format_humanize(xop, xbp, &save, flags);
+ break;
+
+ case XO_STYLE_HTML:
+ if (flags & XFF_ENCODE_ONLY)
+ flags |= XFF_NO_OUTPUT;
+
+ xo_buf_append_div(xop, "data", flags, name, nlen,
+ format, flen, encoding, elen);
+ break;
+
+ case XO_STYLE_XML:
+ /*
+ * Even though we're not making output, we still need to
+ * let the formatting code handle the va_arg popping.
+ */
+ if (flags & XFF_DISPLAY_ONLY) {
+ flags |= XFF_NO_OUTPUT;
+ xo_do_format_field(xop, NULL, format, flen, flags);
+ break;
+ }
+
+ if (encoding) {
+ format = encoding;
+ flen = elen;
+ } else {
+ char *enc = alloca(flen + 1);
+ memcpy(enc, format, flen);
+ enc[flen] = '\0';
+ format = xo_fix_encoding(xop, enc);
+ flen = strlen(format);
+ }
+
+ if (nlen == 0) {
+ static char missing[] = "missing-field-name";
+ xo_failure(xop, "missing field name: %s", format);
+ name = missing;
+ nlen = sizeof(missing) - 1;
+ }
+
+ if (pretty)
+ xo_buf_indent(xop, -1);
+ xo_data_append(xop, "<", 1);
+ xo_data_escape(xop, name, nlen);
+
+ if (xop->xo_attrs.xb_curp != xop->xo_attrs.xb_bufp) {
+ xo_data_append(xop, xop->xo_attrs.xb_bufp,
+ xop->xo_attrs.xb_curp - xop->xo_attrs.xb_bufp);
+ xop->xo_attrs.xb_curp = xop->xo_attrs.xb_bufp;
+ }
+
+ /*
+ * We indicate 'key' fields using the 'key' attribute. While
+ * this is really committing the crime of mixing meta-data with
+ * data, it's often useful. Especially when format meta-data is
+ * difficult to come by.
+ */
+ if ((flags & XFF_KEY) && XOF_ISSET(xop, XOF_KEYS)) {
+ static char attr[] = " key=\"key\"";
+ xo_data_append(xop, attr, sizeof(attr) - 1);
+ }
+
+ /*
+ * Save the offset at which we'd place units. See xo_format_units.
+ */
+ if (XOF_ISSET(xop, XOF_UNITS)) {
+ XOIF_SET(xop, XOIF_UNITS_PENDING);
+ xop->xo_units_offset = xop->xo_data.xb_curp -xop->xo_data.xb_bufp;
+ }
+
+ xo_data_append(xop, ">", 1);
+ xo_do_format_field(xop, NULL, format, flen, flags);
+ xo_data_append(xop, "", 2);
+ xo_data_escape(xop, name, nlen);
+ xo_data_append(xop, ">", 1);
+ if (pretty)
+ xo_data_append(xop, "\n", 1);
+ break;
+
+ case XO_STYLE_JSON:
+ if (flags & XFF_DISPLAY_ONLY) {
+ flags |= XFF_NO_OUTPUT;
+ xo_do_format_field(xop, NULL, format, flen, flags);
+ break;
+ }
+
+ if (encoding) {
+ format = encoding;
+ flen = elen;
+ } else {
+ char *enc = alloca(flen + 1);
+ memcpy(enc, format, flen);
+ enc[flen] = '\0';
+ format = xo_fix_encoding(xop, enc);
+ flen = strlen(format);
+ }
+
+ int first = !(xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST);
+
+ xo_format_prep(xop, flags);
+
+ if (flags & XFF_QUOTE)
+ quote = 1;
+ else if (flags & XFF_NOQUOTE)
+ quote = 0;
+ else if (flen == 0) {
+ quote = 0;
+ format = "true"; /* JSON encodes empty tags as a boolean true */
+ flen = 4;
+ } else if (strchr("diouxXDOUeEfFgGaAcCp", format[flen - 1]) == NULL)
+ quote = 1;
+ else
+ quote = 0;
+
+ if (nlen == 0) {
+ static char missing[] = "missing-field-name";
+ xo_failure(xop, "missing field name: %s", format);
+ name = missing;
+ nlen = sizeof(missing) - 1;
+ }
+
+ if (flags & XFF_LEAF_LIST) {
+ if (!first && pretty)
+ xo_data_append(xop, "\n", 1);
+ if (pretty)
+ xo_buf_indent(xop, -1);
+ } else {
+ if (pretty)
+ xo_buf_indent(xop, -1);
+ xo_data_append(xop, "\"", 1);
+
+ xbp = &xop->xo_data;
+ int off = xbp->xb_curp - xbp->xb_bufp;
+
+ xo_data_escape(xop, name, nlen);
+
+ if (XOF_ISSET(xop, XOF_UNDERSCORES)) {
+ int now = xbp->xb_curp - xbp->xb_bufp;
+ for ( ; off < now; off++)
+ if (xbp->xb_bufp[off] == '-')
+ xbp->xb_bufp[off] = '_';
+ }
+ xo_data_append(xop, "\":", 2);
+ if (pretty)
+ xo_data_append(xop, " ", 1);
+ }
+
+ if (quote)
+ xo_data_append(xop, "\"", 1);
+
+ xo_do_format_field(xop, NULL, format, flen, flags);
+
+ if (quote)
+ xo_data_append(xop, "\"", 1);
+ break;
+
+ case XO_STYLE_SDPARAMS:
+ if (flags & XFF_DISPLAY_ONLY) {
+ flags |= XFF_NO_OUTPUT;
+ xo_do_format_field(xop, NULL, format, flen, flags);
+ break;
+ }
+
+ if (encoding) {
+ format = encoding;
+ flen = elen;
+ } else {
+ char *enc = alloca(flen + 1);
+ memcpy(enc, format, flen);
+ enc[flen] = '\0';
+ format = xo_fix_encoding(xop, enc);
+ flen = strlen(format);
+ }
+
+ if (nlen == 0) {
+ static char missing[] = "missing-field-name";
+ xo_failure(xop, "missing field name: %s", format);
+ name = missing;
+ nlen = sizeof(missing) - 1;
+ }
+
+ xo_data_escape(xop, name, nlen);
+ xo_data_append(xop, "=\"", 2);
+ xo_do_format_field(xop, NULL, format, flen, flags);
+ xo_data_append(xop, "\" ", 2);
+ break;
+
+ case XO_STYLE_ENCODER:
+ if (flags & XFF_DISPLAY_ONLY) {
+ flags |= XFF_NO_OUTPUT;
+ xo_do_format_field(xop, NULL, format, flen, flags);
+ break;
+ }
+
+ if (flags & XFF_QUOTE)
+ quote = 1;
+ else if (flags & XFF_NOQUOTE)
+ quote = 0;
+ else if (flen == 0) {
+ quote = 0;
+ format = "true"; /* JSON encodes empty tags as a boolean true */
+ flen = 4;
+ } else if (strchr("diouxXDOUeEfFgGaAcCp", format[flen - 1]) == NULL)
+ quote = 1;
+ else
+ quote = 0;
+
+ if (encoding) {
+ format = encoding;
+ flen = elen;
+ } else {
+ char *enc = alloca(flen + 1);
+ memcpy(enc, format, flen);
+ enc[flen] = '\0';
+ format = xo_fix_encoding(xop, enc);
+ flen = strlen(format);
+ }
+
+ if (nlen == 0) {
+ static char missing[] = "missing-field-name";
+ xo_failure(xop, "missing field name: %s", format);
+ name = missing;
+ nlen = sizeof(missing) - 1;
+ }
+
+ unsigned name_offset = xo_buf_offset(&xop->xo_data);
+ xo_data_append(xop, name, nlen);
+ xo_data_append(xop, "", 1);
+
+ unsigned value_offset = xo_buf_offset(&xop->xo_data);
+ xo_do_format_field(xop, NULL, format, flen, flags);
+ xo_data_append(xop, "", 1);
+
+ xo_encoder_handle(xop, quote ? XO_OP_STRING : XO_OP_CONTENT,
+ xo_buf_data(&xop->xo_data, name_offset),
+ xo_buf_data(&xop->xo_data, value_offset));
+ xo_buf_reset(&xop->xo_data);
+ break;
+ }
+}
+
+static void
+xo_set_gettext_domain (xo_handle_t *xop, xo_field_info_t *xfip)
+{
+ const char *str = xfip->xfi_content;
+ unsigned len = xfip->xfi_clen;
+ const char *fmt = xfip->xfi_format;
+ unsigned flen = xfip->xfi_flen;
+
+ /* Start by discarding previous domain */
+ if (xop->xo_gt_domain) {
+ xo_free(xop->xo_gt_domain);
+ xop->xo_gt_domain = NULL;
+ }
+
+ /* An empty {G:} means no domainname */
+ if (len == 0 && flen == 0)
+ return;
+
+ int start_offset = -1;
+ if (len == 0 && flen != 0) {
+ /* Need to do format the data to get the domainname from args */
+ start_offset = xop->xo_data.xb_curp - xop->xo_data.xb_bufp;
+ xo_do_format_field(xop, NULL, fmt, flen, 0);
+
+ int end_offset = xop->xo_data.xb_curp - xop->xo_data.xb_bufp;
+ len = end_offset - start_offset;
+ str = xop->xo_data.xb_bufp + start_offset;
+ }
+
+ xop->xo_gt_domain = xo_strndup(str, len);
+
+ /* Reset the current buffer point to avoid emitting the name as output */
+ if (start_offset >= 0)
+ xop->xo_data.xb_curp = xop->xo_data.xb_bufp + start_offset;
+}
+
+static void
+xo_format_content (xo_handle_t *xop, const char *class_name,
+ const char *tag_name,
+ const char *str, int len, const char *fmt, int flen,
+ xo_xff_flags_t flags)
+{
+ switch (xo_style(xop)) {
+ case XO_STYLE_TEXT:
+ if (len)
+ xo_data_append_content(xop, str, len, flags);
+ else
+ xo_do_format_field(xop, NULL, fmt, flen, flags);
+ break;
+
+ case XO_STYLE_HTML:
+ if (len == 0) {
+ str = fmt;
+ len = flen;
+ }
+
+ xo_buf_append_div(xop, class_name, flags, NULL, 0, str, len, NULL, 0);
+ break;
+
+ case XO_STYLE_XML:
+ case XO_STYLE_JSON:
+ case XO_STYLE_SDPARAMS:
+ if (tag_name) {
+ if (len == 0) {
+ str = fmt;
+ len = flen;
+ }
+
+ xo_open_container_h(xop, tag_name);
+ xo_format_value(xop, "message", 7, str, len, NULL, 0, flags);
+ xo_close_container_h(xop, tag_name);
+
+ } else {
+ /*
+ * Even though we don't care about labels, we need to do
+ * enough parsing work to skip over the right bits of xo_vap.
+ */
+ if (len == 0)
+ xo_do_format_field(xop, NULL, fmt, flen,
+ flags | XFF_NO_OUTPUT);
+ }
+ break;
+
+ case XO_STYLE_ENCODER:
+ if (len == 0)
+ xo_do_format_field(xop, NULL, fmt, flen,
+ flags | XFF_NO_OUTPUT);
+ break;
+ }
+}
+
+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 (XOF_ISSET(xop, 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 XOF_ISSET(xop, XOF_COLOR);
+#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 = NULL;
+
+ /*
+ * 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;
+
+ 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);
+ }
+}
+
+static void
+xo_colors_handle_html (xo_handle_t *xop, xo_colors_t *newp)
+{
+ xo_colors_t *oldp = &xop->xo_colors;
+
+ /*
+ * HTML colors are mostly trivial: fill in xo_color_buf with
+ * a set of class tags representing the colors and effects.
+ */
+
+ /* If nothing changed, then do nothing */
+ if (oldp->xoc_effects == newp->xoc_effects
+ && oldp->xoc_col_fg == newp->xoc_col_fg
+ && oldp->xoc_col_bg == newp->xoc_col_bg)
+ return;
+
+ unsigned i, bit;
+ xo_buffer_t *xbp = &xop->xo_color_buf;
+
+ xo_buf_reset(xbp); /* We rebuild content after each change */
+
+ for (i = 0, bit = 1; xo_effect_names[i]; i++, bit <<= 1) {
+ if (!(newp->xoc_effects & bit))
+ continue;
+
+ xo_buf_append_str(xbp, " effect-");
+ xo_buf_append_str(xbp, xo_effect_names[i]);
+ }
+
+ const char *fg = NULL;
+ const char *bg = NULL;
+
+ if (newp->xoc_col_fg != XO_COL_DEFAULT)
+ fg = xo_color_names[newp->xoc_col_fg];
+ if (newp->xoc_col_bg != XO_COL_DEFAULT)
+ bg = xo_color_names[newp->xoc_col_bg];
+
+ if (newp->xoc_effects & XO_EFF_INVERSE) {
+ const char *tmp = fg;
+ fg = bg;
+ bg = tmp;
+ if (fg == NULL)
+ fg = "inverse";
+ if (bg == NULL)
+ bg = "inverse";
+
+ }
+
+ if (fg) {
+ xo_buf_append_str(xbp, " color-fg-");
+ xo_buf_append_str(xbp, fg);
+ }
+
+ if (bg) {
+ xo_buf_append_str(xbp, " color-bg-");
+ xo_buf_append_str(xbp, bg);
+ }
+}
+
+static void
+xo_format_colors (xo_handle_t *xop, xo_field_info_t *xfip)
+{
+ const char *str = xfip->xfi_content;
+ unsigned len = xfip->xfi_clen;
+ const char *fmt = xfip->xfi_format;
+ unsigned flen = xfip->xfi_flen;
+
+ xo_buffer_t xb;
+
+ /* If the string is static and we've in an encoding style, bail */
+ if (len != 0 && xo_style_is_encoding(xop))
+ return;
+
+ xo_buf_init(&xb);
+
+ if (len)
+ xo_buf_append(&xb, str, len);
+ else if (flen)
+ xo_do_format_field(xop, &xb, fmt, flen, 0);
+ else
+ xo_buf_append(&xb, "reset", 6); /* Default if empty */
+
+ if (xo_colors_enabled(xop)) {
+ switch (xo_style(xop)) {
+ case XO_STYLE_TEXT:
+ case XO_STYLE_HTML:
+ xo_buf_append(&xb, "", 1);
+
+ xo_colors_t xoc = xop->xo_colors;
+ xo_colors_parse(xop, &xoc, xb.xb_bufp);
+
+ if (xo_style(xop) == XO_STYLE_TEXT) {
+ /*
+ * Text mode means emitting the colors as ANSI character
+ * codes. This will allow people who like colors to have
+ * colors. The issue is, of course conflicting with the
+ * user's perfectly reasonable color scheme. Which leads
+ * to the hell of LSCOLORS, where even app need to have
+ * customization hooks for adjusting colors. Instead we
+ * provide a simpler-but-still-annoying answer where one
+ * can map colors to other colors.
+ */
+ xo_colors_handle_text(xop, &xoc);
+ xoc.xoc_effects &= ~XO_EFF_RESET; /* After handling it */
+
+ } else {
+ /*
+ * HTML output is wrapped in divs, so the color information
+ * must appear in every div until cleared. Most pathetic.
+ * Most unavoidable.
+ */
+ xoc.xoc_effects &= ~XO_EFF_RESET; /* Before handling effects */
+ xo_colors_handle_html(xop, &xoc);
+ }
+
+ xop->xo_colors = xoc;
+ break;
+
+ case XO_STYLE_XML:
+ case XO_STYLE_JSON:
+ case XO_STYLE_SDPARAMS:
+ case XO_STYLE_ENCODER:
+ /*
+ * Nothing to do; we did all that work just to clear the stack of
+ * formatting arguments.
+ */
+ break;
+ }
+ }
+
+ xo_buf_cleanup(&xb);
+}
+
+static void
+xo_format_units (xo_handle_t *xop, xo_field_info_t *xfip)
+{
+ const char *str = xfip->xfi_content;
+ unsigned len = xfip->xfi_clen;
+ const char *fmt = xfip->xfi_format;
+ unsigned flen = xfip->xfi_flen;
+ xo_xff_flags_t flags = xfip->xfi_flags;
+
+ static char units_start_xml[] = " units=\"";
+ static char units_start_html[] = " data-units=\"";
+
+ if (!XOIF_ISSET(xop, XOIF_UNITS_PENDING)) {
+ xo_format_content(xop, "units", NULL, str, len, fmt, flen, flags);
+ return;
+ }
+
+ xo_buffer_t *xbp = &xop->xo_data;
+ int start = xop->xo_units_offset;
+ int stop = xbp->xb_curp - xbp->xb_bufp;
+
+ if (xo_style(xop) == XO_STYLE_XML)
+ xo_buf_append(xbp, units_start_xml, sizeof(units_start_xml) - 1);
+ else if (xo_style(xop) == XO_STYLE_HTML)
+ xo_buf_append(xbp, units_start_html, sizeof(units_start_html) - 1);
+ else
+ return;
+
+ if (len)
+ xo_data_escape(xop, str, len);
+ else
+ xo_do_format_field(xop, NULL, fmt, flen, flags);
+
+ xo_buf_append(xbp, "\"", 1);
+
+ int now = xbp->xb_curp - xbp->xb_bufp;
+ int delta = now - stop;
+ if (delta <= 0) { /* Strange; no output to move */
+ xbp->xb_curp = xbp->xb_bufp + stop; /* Reset buffer to prior state */
+ return;
+ }
+
+ /*
+ * Now we're in it alright. We've need to insert the unit value
+ * we just created into the right spot. We make a local copy,
+ * move it and then insert our copy. We know there's room in the
+ * buffer, since we're just moving this around.
+ */
+ char *buf = alloca(delta);
+
+ memcpy(buf, xbp->xb_bufp + stop, delta);
+ memmove(xbp->xb_bufp + start + delta, xbp->xb_bufp + start, stop - start);
+ memmove(xbp->xb_bufp + start, buf, delta);
+}
+
+static int
+xo_find_width (xo_handle_t *xop, xo_field_info_t *xfip)
+{
+ const char *str = xfip->xfi_content;
+ unsigned len = xfip->xfi_clen;
+ const char *fmt = xfip->xfi_format;
+ unsigned flen = xfip->xfi_flen;
+
+ long width = 0;
+ char *bp;
+ char *cp;
+
+ if (len) {
+ bp = alloca(len + 1); /* Make local NUL-terminated copy of str */
+ memcpy(bp, str, len);
+ bp[len] = '\0';
+
+ width = strtol(bp, &cp, 0);
+ if (width == LONG_MIN || width == LONG_MAX
+ || bp == cp || *cp != '\0' ) {
+ width = 0;
+ xo_failure(xop, "invalid width for anchor: '%s'", bp);
+ }
+ } else if (flen) {
+ if (flen != 2 || strncmp("%d", fmt, flen) != 0)
+ xo_failure(xop, "invalid width format: '%*.*s'", flen, flen, fmt);
+ if (!XOF_ISSET(xop, XOF_NO_VA_ARG))
+ width = va_arg(xop->xo_vap, int);
+ }
+
+ return width;
+}
+
+static void
+xo_anchor_clear (xo_handle_t *xop)
+{
+ XOIF_CLEAR(xop, XOIF_ANCHOR);
+ xop->xo_anchor_offset = 0;
+ xop->xo_anchor_columns = 0;
+ xop->xo_anchor_min_width = 0;
+}
+
+/*
+ * An anchor is a marker used to delay field width implications.
+ * Imagine the format string "{[:10}{min:%d}/{cur:%d}/{max:%d}{:]}".
+ * We are looking for output like " 1/4/5"
+ *
+ * To make this work, we record the anchor and then return to
+ * format it when the end anchor tag is seen.
+ */
+static void
+xo_anchor_start (xo_handle_t *xop, xo_field_info_t *xfip)
+{
+ if (xo_style(xop) != XO_STYLE_TEXT && xo_style(xop) != XO_STYLE_HTML)
+ return;
+
+ if (XOIF_ISSET(xop, XOIF_ANCHOR))
+ xo_failure(xop, "the anchor already recording is discarded");
+
+ XOIF_SET(xop, XOIF_ANCHOR);
+ xo_buffer_t *xbp = &xop->xo_data;
+ xop->xo_anchor_offset = xbp->xb_curp - xbp->xb_bufp;
+ xop->xo_anchor_columns = 0;
+
+ /*
+ * Now we find the width, if possible. If it's not there,
+ * we'll get it on the end anchor.
+ */
+ xop->xo_anchor_min_width = xo_find_width(xop, xfip);
+}
+
+static void
+xo_anchor_stop (xo_handle_t *xop, xo_field_info_t *xfip)
+{
+ if (xo_style(xop) != XO_STYLE_TEXT && xo_style(xop) != XO_STYLE_HTML)
+ return;
+
+ if (!XOIF_ISSET(xop, XOIF_ANCHOR)) {
+ xo_failure(xop, "no start anchor");
+ return;
+ }
+
+ XOIF_CLEAR(xop, XOIF_UNITS_PENDING);
+
+ int width = xo_find_width(xop, xfip);
+ if (width == 0)
+ width = xop->xo_anchor_min_width;
+
+ if (width == 0) /* No width given; nothing to do */
+ goto done;
+
+ xo_buffer_t *xbp = &xop->xo_data;
+ int start = xop->xo_anchor_offset;
+ int stop = xbp->xb_curp - xbp->xb_bufp;
+ int abswidth = (width > 0) ? width : -width;
+ int blen = abswidth - xop->xo_anchor_columns;
+
+ if (blen <= 0) /* Already over width */
+ goto done;
+
+ if (abswidth > XO_MAX_ANCHOR_WIDTH) {
+ xo_failure(xop, "width over %u are not supported",
+ XO_MAX_ANCHOR_WIDTH);
+ goto done;
+ }
+
+ /* Make a suitable padding field and emit it */
+ char *buf = alloca(blen);
+ memset(buf, ' ', blen);
+ xo_format_content(xop, "padding", NULL, buf, blen, NULL, 0, 0);
+
+ if (width < 0) /* Already left justified */
+ goto done;
+
+ int now = xbp->xb_curp - xbp->xb_bufp;
+ int delta = now - stop;
+ if (delta <= 0) /* Strange; no output to move */
+ goto done;
+
+ /*
+ * Now we're in it alright. We've need to insert the padding data
+ * we just created (which might be an HTML
or text) before
+ * the formatted data. We make a local copy, move it and then
+ * insert our copy. We know there's room in the buffer, since
+ * we're just moving this around.
+ */
+ if (delta > blen)
+ buf = alloca(delta); /* Expand buffer if needed */
+
+ memcpy(buf, xbp->xb_bufp + stop, delta);
+ memmove(xbp->xb_bufp + start + delta, xbp->xb_bufp + start, stop - start);
+ memmove(xbp->xb_bufp + start, buf, delta);
+
+ done:
+ xo_anchor_clear(xop);
+}
+
+static const char *
+xo_class_name (int ftype)
+{
+ switch (ftype) {
+ case 'D': return "decoration";
+ case 'E': return "error";
+ case 'L': return "label";
+ case 'N': return "note";
+ case 'P': return "padding";
+ case 'W': return "warning";
+ }
+
+ return NULL;
+}
+
+static const char *
+xo_tag_name (int ftype)
+{
+ switch (ftype) {
+ case 'E': return "__error";
+ case 'W': return "__warning";
+ }
+
+ return NULL;
+}
+
+static int
+xo_role_wants_default_format (int ftype)
+{
+ switch (ftype) {
+ /* These roles can be completely empty and/or without formatting */
+ case 'C':
+ case 'G':
+ case '[':
+ case ']':
+ return 0;
+ }
+
+ return 1;
+}
+
+static xo_mapping_t xo_role_names[] = {
+ { 'C', "color" },
+ { 'D', "decoration" },
+ { 'E', "error" },
+ { 'L', "label" },
+ { 'N', "note" },
+ { 'P', "padding" },
+ { 'T', "title" },
+ { 'U', "units" },
+ { 'V', "value" },
+ { 'W', "warning" },
+ { '[', "start-anchor" },
+ { ']', "stop-anchor" },
+ { 0, NULL }
+};
+
+#define XO_ROLE_EBRACE '{' /* Escaped braces */
+#define XO_ROLE_TEXT '+'
+#define XO_ROLE_NEWLINE '\n'
+
+static xo_mapping_t xo_modifier_names[] = {
+ { XFF_COLON, "colon" },
+ { XFF_COMMA, "comma" },
+ { XFF_DISPLAY_ONLY, "display" },
+ { XFF_ENCODE_ONLY, "encoding" },
+ { XFF_GT_FIELD, "gettext" },
+ { XFF_HUMANIZE, "humanize" },
+ { XFF_HUMANIZE, "hn" },
+ { XFF_HN_SPACE, "hn-space" },
+ { XFF_HN_DECIMAL, "hn-decimal" },
+ { XFF_HN_1000, "hn-1000" },
+ { XFF_KEY, "key" },
+ { XFF_LEAF_LIST, "leaf-list" },
+ { XFF_LEAF_LIST, "list" },
+ { XFF_NOQUOTE, "no-quotes" },
+ { XFF_NOQUOTE, "no-quote" },
+ { XFF_GT_PLURAL, "plural" },
+ { XFF_QUOTE, "quotes" },
+ { XFF_QUOTE, "quote" },
+ { XFF_TRIM_WS, "trim" },
+ { XFF_WS, "white" },
+ { 0, NULL }
+};
+
+#ifdef NOT_NEEDED_YET
+static xo_mapping_t xo_modifier_short_names[] = {
+ { XFF_COLON, "c" },
+ { XFF_DISPLAY_ONLY, "d" },
+ { XFF_ENCODE_ONLY, "e" },
+ { XFF_GT_FIELD, "g" },
+ { XFF_HUMANIZE, "h" },
+ { XFF_KEY, "k" },
+ { XFF_LEAF_LIST, "l" },
+ { XFF_NOQUOTE, "n" },
+ { XFF_GT_PLURAL, "p" },
+ { XFF_QUOTE, "q" },
+ { XFF_TRIM_WS, "t" },
+ { XFF_WS, "w" },
+ { 0, NULL }
+};
+#endif /* NOT_NEEDED_YET */
+
+static int
+xo_count_fields (xo_handle_t *xop UNUSED, const char *fmt)
+{
+ int rc = 1;
+ const char *cp;
+
+ for (cp = fmt; *cp; cp++)
+ if (*cp == '{' || *cp == '\n')
+ rc += 1;
+
+ return rc * 2 + 1;
+}
+
+/*
+ * The field format is:
+ * '{' modifiers ':' content [ '/' print-fmt [ '/' encode-fmt ]] '}'
+ * Roles are optional and include the following field types:
+ * 'D': decoration; something non-text and non-data (colons, commmas)
+ * 'E': error message
+ * 'G': gettext() the entire string; optional domainname as content
+ * 'L': label; text preceding data
+ * 'N': note; text following data
+ * 'P': padding; whitespace
+ * 'T': Title, where 'content' is a column title
+ * 'U': Units, where 'content' is the unit label
+ * 'V': value, where 'content' is the name of the field (the default)
+ * 'W': warning message
+ * '[': start a section of anchored text
+ * ']': end a section of anchored text
+ * The following modifiers are also supported:
+ * 'c': flag: emit a colon after the label
+ * 'd': field is only emitted for display styles (text and html)
+ * 'e': field is only emitted for encoding styles (xml and json)
+ * 'g': gettext() the field
+ * 'h': humanize a numeric value (only for display styles)
+ * 'k': this field is a key, suitable for XPath predicates
+ * 'l': a leaf-list, a simple list of values
+ * 'n': no quotes around this field
+ * 'p': the field has plural gettext semantics (ngettext)
+ * 'q': add quotes around this field
+ * 't': trim whitespace around the value
+ * 'w': emit a blank after the label
+ * The print-fmt and encode-fmt strings is the printf-style formating
+ * for this data. JSON and XML will use the encoding-fmt, if present.
+ * If the encode-fmt is not provided, it defaults to the print-fmt.
+ * If the print-fmt is not provided, it defaults to 's'.
+ */
+static const char *
+xo_parse_roles (xo_handle_t *xop, const char *fmt,
+ const char *basep, xo_field_info_t *xfip)
+{
+ const char *sp;
+ unsigned ftype = 0;
+ xo_xff_flags_t flags = 0;
+ uint8_t fnum = 0;
+
+ for (sp = basep; sp; sp++) {
+ if (*sp == ':' || *sp == '/' || *sp == '}')
+ break;
+
+ if (*sp == '\\') {
+ if (sp[1] == '\0') {
+ xo_failure(xop, "backslash at the end of string");
+ return NULL;
+ }
+
+ /* Anything backslashed is ignored */
+ sp += 1;
+ continue;
+ }
+
+ if (*sp == ',') {
+ const char *np;
+ for (np = ++sp; *np; np++)
+ if (*np == ':' || *np == '/' || *np == '}' || *np == ',')
+ break;
+
+ int slen = np - sp;
+ if (slen > 0) {
+ xo_xff_flags_t value;
+
+ value = xo_name_lookup(xo_role_names, sp, slen);
+ if (value)
+ ftype = value;
+ else {
+ value = xo_name_lookup(xo_modifier_names, sp, slen);
+ if (value)
+ flags |= value;
+ else
+ xo_failure(xop, "unknown keyword ignored: '%.*s'",
+ slen, sp);
+ }
+ }
+
+ sp = np - 1;
+ continue;
+ }
+
+ switch (*sp) {
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'G':
+ case 'L':
+ case 'N':
+ case 'P':
+ case 'T':
+ case 'U':
+ case 'V':
+ case 'W':
+ case '[':
+ case ']':
+ if (ftype != 0) {
+ xo_failure(xop, "field descriptor uses multiple types: '%s'",
+ xo_printable(fmt));
+ return NULL;
+ }
+ ftype = *sp;
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ fnum = (fnum * 10) + (*sp - '0');
+ break;
+
+ case 'c':
+ flags |= XFF_COLON;
+ break;
+
+ case 'd':
+ flags |= XFF_DISPLAY_ONLY;
+ break;
+
+ case 'e':
+ flags |= XFF_ENCODE_ONLY;
+ break;
+
+ case 'g':
+ flags |= XFF_GT_FIELD;
+ break;
+
+ case 'h':
+ flags |= XFF_HUMANIZE;
+ break;
+
+ case 'k':
+ flags |= XFF_KEY;
+ break;
+
+ case 'l':
+ flags |= XFF_LEAF_LIST;
+ break;
+
+ case 'n':
+ flags |= XFF_NOQUOTE;
+ break;
+
+ case 'p':
+ flags |= XFF_GT_PLURAL;
+ break;
+
+ case 'q':
+ flags |= XFF_QUOTE;
+ break;
+
+ case 't':
+ flags |= XFF_TRIM_WS;
+ break;
+
+ case 'w':
+ flags |= XFF_WS;
+ break;
+
+ default:
+ xo_failure(xop, "field descriptor uses unknown modifier: '%s'",
+ xo_printable(fmt));
+ /*
+ * No good answer here; a bad format will likely
+ * mean a core file. We just return and hope
+ * the caller notices there's no output, and while
+ * that seems, well, bad, there's nothing better.
+ */
+ return NULL;
+ }
+
+ if (ftype == 'N' || ftype == 'U') {
+ if (flags & XFF_COLON) {
+ xo_failure(xop, "colon modifier on 'N' or 'U' field ignored: "
+ "'%s'", xo_printable(fmt));
+ flags &= ~XFF_COLON;
+ }
+ }
+ }
+
+ xfip->xfi_flags = flags;
+ xfip->xfi_ftype = ftype ?: 'V';
+ xfip->xfi_fnum = fnum;
+
+ return sp;
+}
+
+/*
+ * Number any remaining fields that need numbers. Note that some
+ * field types (text, newline, escaped braces) never get numbers.
+ */
+static void
+xo_gettext_finish_numbering_fields (xo_handle_t *xop UNUSED,
+ const char *fmt UNUSED,
+ xo_field_info_t *fields)
+{
+ xo_field_info_t *xfip;
+ unsigned fnum, max_fields;
+ uint64_t bits = 0;
+
+ /* First make a list of add the explicitly used bits */
+ for (xfip = fields, fnum = 0; xfip->xfi_ftype; xfip++) {
+ switch (xfip->xfi_ftype) {
+ case XO_ROLE_NEWLINE: /* Don't get numbered */
+ case XO_ROLE_TEXT:
+ case XO_ROLE_EBRACE:
+ case 'G':
+ continue;
+ }
+
+ fnum += 1;
+ if (fnum >= 63)
+ break;
+
+ if (xfip->xfi_fnum)
+ bits |= 1 << xfip->xfi_fnum;
+ }
+
+ max_fields = fnum;
+
+ for (xfip = fields, fnum = 0; xfip->xfi_ftype; xfip++) {
+ switch (xfip->xfi_ftype) {
+ case XO_ROLE_NEWLINE: /* Don't get numbered */
+ case XO_ROLE_TEXT:
+ case XO_ROLE_EBRACE:
+ case 'G':
+ continue;
+ }
+
+ if (xfip->xfi_fnum != 0)
+ continue;
+
+ /* Find the next unassigned field */
+ for (fnum++; bits & (1 << fnum); fnum++)
+ continue;
+
+ if (fnum > max_fields)
+ break;
+
+ xfip->xfi_fnum = fnum; /* Mark the field number */
+ bits |= 1 << fnum; /* Mark it used */
+ }
+}
+
+/*
+ * The format string uses field numbers, so we need to whiffle thru it
+ * and make sure everything's sane and lovely.
+ */
+static int
+xo_parse_field_numbers (xo_handle_t *xop, const char *fmt,
+ xo_field_info_t *fields, unsigned num_fields)
+{
+ xo_field_info_t *xfip;
+ unsigned field, fnum;
+ uint64_t bits = 0;
+
+ for (xfip = fields, field = 0; field < num_fields; xfip++, field++) {
+ /* Fields default to 1:1 with natural position */
+ if (xfip->xfi_fnum == 0)
+ xfip->xfi_fnum = field + 1;
+ else if (xfip->xfi_fnum > num_fields) {
+ xo_failure(xop, "field number exceeds number of fields: '%s'", fmt);
+ return -1;
+ }
+
+ fnum = xfip->xfi_fnum - 1; /* Move to zero origin */
+ if (fnum < 64) { /* Only test what fits */
+ if (bits & (1 << fnum)) {
+ xo_failure(xop, "field number %u reused: '%s'",
+ xfip->xfi_fnum, fmt);
+ return -1;
+ }
+ bits |= 1 << fnum;
+ }
+ }
+
+ return 0;
+}
+
+static int
+xo_parse_fields (xo_handle_t *xop, xo_field_info_t *fields,
+ unsigned num_fields, const char *fmt)
+{
+ static const char default_format[] = "%s";
+ const char *cp, *sp, *ep, *basep;
+ unsigned field = 0;
+ xo_field_info_t *xfip = fields;
+ unsigned seen_fnum = 0;
+
+ for (cp = fmt; *cp && field < num_fields; field++, xfip++) {
+ xfip->xfi_start = cp;
+
+ if (*cp == '\n') {
+ xfip->xfi_ftype = XO_ROLE_NEWLINE;
+ xfip->xfi_len = 1;
+ cp += 1;
+ continue;
+ }
+
+ if (*cp != '{') {
+ /* Normal text */
+ for (sp = cp; *sp; sp++) {
+ if (*sp == '{' || *sp == '\n')
+ break;
+ }
+
+ xfip->xfi_ftype = XO_ROLE_TEXT;
+ xfip->xfi_content = cp;
+ xfip->xfi_clen = sp - cp;
+ xfip->xfi_next = sp;
+
+ cp = sp;
+ continue;
+ }
+
+ if (cp[1] == '{') { /* Start of {{escaped braces}} */
+ xfip->xfi_start = cp + 1; /* Start at second brace */
+ xfip->xfi_ftype = XO_ROLE_EBRACE;
+
+ cp += 2; /* Skip over _both_ characters */
+ for (sp = cp; *sp; sp++) {
+ if (*sp == '}' && sp[1] == '}')
+ break;
+ }
+ if (*sp == '\0') {
+ xo_failure(xop, "missing closing '}}': '%s'",
+ xo_printable(fmt));
+ return -1;
+ }
+
+ xfip->xfi_len = sp - xfip->xfi_start + 1;
+
+ /* Move along the string, but don't run off the end */
+ if (*sp == '}' && sp[1] == '}')
+ sp += 2;
+ cp = *sp ? sp : sp;
+ xfip->xfi_next = cp;
+ continue;
+ }
+
+ /* We are looking at the start of a field definition */
+ xfip->xfi_start = basep = cp + 1;
+
+ const char *format = NULL;
+ int flen = 0;
+
+ /* Looking at roles and modifiers */
+ sp = xo_parse_roles(xop, fmt, basep, xfip);
+ if (sp == NULL) {
+ /* xo_failure has already been called */
+ return -1;
+ }
+
+ if (xfip->xfi_fnum)
+ seen_fnum = 1;
+
+ /* Looking at content */
+ if (*sp == ':') {
+ for (ep = ++sp; *sp; sp++) {
+ if (*sp == '}' || *sp == '/')
+ break;
+ if (*sp == '\\') {
+ if (sp[1] == '\0') {
+ xo_failure(xop, "backslash at the end of string");
+ return -1;
+ }
+ sp += 1;
+ continue;
+ }
+ }
+ if (ep != sp) {
+ xfip->xfi_clen = sp - ep;
+ xfip->xfi_content = ep;
+ }
+ } else {
+ xo_failure(xop, "missing content (':'): '%s'", xo_printable(fmt));
+ return -1;
+ }
+
+ /* Looking at main (display) format */
+ if (*sp == '/') {
+ for (ep = ++sp; *sp; sp++) {
+ if (*sp == '}' || *sp == '/')
+ break;
+ if (*sp == '\\') {
+ if (sp[1] == '\0') {
+ xo_failure(xop, "backslash at the end of string");
+ return -1;
+ }
+ sp += 1;
+ continue;
+ }
+ }
+ flen = sp - ep;
+ format = ep;
+ }
+
+ /* Looking at encoding format */
+ if (*sp == '/') {
+ for (ep = ++sp; *sp; sp++) {
+ if (*sp == '}')
+ break;
+ }
+
+ xfip->xfi_encoding = ep;
+ xfip->xfi_elen = sp - ep;
+ }
+
+ if (*sp != '}') {
+ xo_failure(xop, "missing closing '}': %s", xo_printable(fmt));
+ return -1;
+ }
+
+ xfip->xfi_len = sp - xfip->xfi_start;
+ xfip->xfi_next = ++sp;
+
+ /* If we have content, then we have a default format */
+ if (xfip->xfi_clen || format) {
+ if (format) {
+ xfip->xfi_format = format;
+ xfip->xfi_flen = flen;
+ } else if (xo_role_wants_default_format(xfip->xfi_ftype)) {
+ xfip->xfi_format = default_format;
+ xfip->xfi_flen = 2;
+ }
+ }
+
+ cp = sp;
+ }
+
+ int rc = 0;
+
+ /*
+ * If we saw a field number on at least one field, then we need
+ * to enforce some rules and/or guidelines.
+ */
+ if (seen_fnum)
+ rc = xo_parse_field_numbers(xop, fmt, fields, field);
+
+ return rc;
+}
+
+/*
+ * We are passed a pointer to a format string just past the "{G:}"
+ * field. We build a simplified version of the format string.
+ */
+static int
+xo_gettext_simplify_format (xo_handle_t *xop UNUSED,
+ xo_buffer_t *xbp,
+ xo_field_info_t *fields,
+ int this_field,
+ const char *fmt UNUSED,
+ xo_simplify_field_func_t field_cb)
+{
+ unsigned ftype;
+ xo_xff_flags_t flags;
+ int field = this_field + 1;
+ xo_field_info_t *xfip;
+ char ch;
+
+ for (xfip = &fields[field]; xfip->xfi_ftype; xfip++, field++) {
+ ftype = xfip->xfi_ftype;
+ flags = xfip->xfi_flags;
+
+ if ((flags & XFF_GT_FIELD) && xfip->xfi_content && ftype != 'V') {
+ if (field_cb)
+ field_cb(xfip->xfi_content, xfip->xfi_clen,
+ (flags & XFF_GT_PLURAL) ? 1 : 0);
+ }
+
+ switch (ftype) {
+ case 'G':
+ /* Ignore gettext roles */
+ break;
+
+ case XO_ROLE_NEWLINE:
+ xo_buf_append(xbp, "\n", 1);
+ break;
+
+ case XO_ROLE_EBRACE:
+ xo_buf_append(xbp, "{", 1);
+ xo_buf_append(xbp, xfip->xfi_content, xfip->xfi_clen);
+ xo_buf_append(xbp, "}", 1);
+ break;
+
+ case XO_ROLE_TEXT:
+ xo_buf_append(xbp, xfip->xfi_content, xfip->xfi_clen);
+ break;
+
+ default:
+ xo_buf_append(xbp, "{", 1);
+ if (ftype != 'V') {
+ ch = ftype;
+ xo_buf_append(xbp, &ch, 1);
+ }
+
+ unsigned fnum = xfip->xfi_fnum ?: 0;
+ if (fnum) {
+ char num[12];
+ /* Field numbers are origin 1, not 0, following printf(3) */
+ snprintf(num, sizeof(num), "%u", fnum);
+ xo_buf_append(xbp, num, strlen(num));
+ }
+
+ xo_buf_append(xbp, ":", 1);
+ xo_buf_append(xbp, xfip->xfi_content, xfip->xfi_clen);
+ xo_buf_append(xbp, "}", 1);
+ }
+ }
+
+ xo_buf_append(xbp, "", 1);
+ return 0;
+}
+
+void
+xo_dump_fields (xo_field_info_t *); /* Fake prototype for debug function */
+void
+xo_dump_fields (xo_field_info_t *fields)
+{
+ xo_field_info_t *xfip;
+
+ for (xfip = fields; xfip->xfi_ftype; xfip++) {
+ printf("%lu(%u): %lx [%c/%u] [%.*s] [%.*s] [%.*s]\n",
+ (unsigned long) (xfip - fields), xfip->xfi_fnum,
+ (unsigned long) xfip->xfi_flags,
+ isprint((int) xfip->xfi_ftype) ? xfip->xfi_ftype : ' ',
+ xfip->xfi_ftype,
+ xfip->xfi_clen, xfip->xfi_content ?: "",
+ xfip->xfi_flen, xfip->xfi_format ?: "",
+ xfip->xfi_elen, xfip->xfi_encoding ?: "");
+ }
+}
+
+#ifdef HAVE_GETTEXT
+/*
+ * Find the field that matches the given field number
+ */
+static xo_field_info_t *
+xo_gettext_find_field (xo_field_info_t *fields, unsigned fnum)
+{
+ xo_field_info_t *xfip;
+
+ for (xfip = fields; xfip->xfi_ftype; xfip++)
+ if (xfip->xfi_fnum == fnum)
+ return xfip;
+
+ return NULL;
+}
+
+/*
+ * At this point, we need to consider if the fields have been reordered,
+ * such as "The {:adjective} {:noun}" to "La {:noun} {:adjective}".
+ *
+ * We need to rewrite the new_fields using the old fields order,
+ * so that we can render the message using the arguments as they
+ * appear on the stack. It's a lot of work, but we don't really
+ * want to (eventually) fall into the standard printf code which
+ * means using the arguments straight (and in order) from the
+ * varargs we were originally passed.
+ */
+static void
+xo_gettext_rewrite_fields (xo_handle_t *xop UNUSED,
+ xo_field_info_t *fields, unsigned max_fields)
+{
+ xo_field_info_t tmp[max_fields];
+ bzero(tmp, max_fields * sizeof(tmp[0]));
+
+ unsigned fnum = 0;
+ xo_field_info_t *newp, *outp, *zp;
+ for (newp = fields, outp = tmp; newp->xfi_ftype; newp++, outp++) {
+ switch (newp->xfi_ftype) {
+ case XO_ROLE_NEWLINE: /* Don't get numbered */
+ case XO_ROLE_TEXT:
+ case XO_ROLE_EBRACE:
+ case 'G':
+ *outp = *newp;
+ outp->xfi_renum = 0;
+ continue;
+ }
+
+ zp = xo_gettext_find_field(fields, ++fnum);
+ if (zp == NULL) { /* Should not occur */
+ *outp = *newp;
+ outp->xfi_renum = 0;
+ continue;
+ }
+
+ *outp = *zp;
+ outp->xfi_renum = newp->xfi_fnum;
+ }
+
+ memcpy(fields, tmp, max_fields * sizeof(tmp[0]));
+}
+
+/*
+ * We've got two lists of fields, the old list from the original
+ * format string and the new one from the parsed gettext reply. The
+ * new list has the localized words, where the old list has the
+ * formatting information. We need to combine them into a single list
+ * (the new list).
+ *
+ * If the list needs to be reordered, then we've got more serious work
+ * to do.
+ */
+static int
+xo_gettext_combine_formats (xo_handle_t *xop, const char *fmt UNUSED,
+ const char *gtfmt, xo_field_info_t *old_fields,
+ xo_field_info_t *new_fields, unsigned new_max_fields,
+ int *reorderedp)
+{
+ int reordered = 0;
+ xo_field_info_t *newp, *oldp, *startp = old_fields;
+
+ xo_gettext_finish_numbering_fields(xop, fmt, old_fields);
+
+ for (newp = new_fields; newp->xfi_ftype; newp++) {
+ switch (newp->xfi_ftype) {
+ case XO_ROLE_NEWLINE:
+ case XO_ROLE_TEXT:
+ case XO_ROLE_EBRACE:
+ continue;
+
+ case 'V':
+ for (oldp = startp; oldp->xfi_ftype; oldp++) {
+ if (oldp->xfi_ftype != 'V')
+ continue;
+ if (newp->xfi_clen != oldp->xfi_clen
+ || strncmp(newp->xfi_content, oldp->xfi_content,
+ oldp->xfi_clen) != 0) {
+ reordered = 1;
+ continue;
+ }
+ startp = oldp + 1;
+ break;
+ }
+
+ /* Didn't find it on the first pass (starting from start) */
+ if (oldp->xfi_ftype == 0) {
+ for (oldp = old_fields; oldp < startp; oldp++) {
+ if (oldp->xfi_ftype != 'V')
+ continue;
+ if (newp->xfi_clen != oldp->xfi_clen)
+ continue;
+ if (strncmp(newp->xfi_content, oldp->xfi_content,
+ oldp->xfi_clen) != 0)
+ continue;
+ reordered = 1;
+ break;
+ }
+ if (oldp == startp) {
+ /* Field not found */
+ xo_failure(xop, "post-gettext format can't find field "
+ "'%.*s' in format '%s'",
+ newp->xfi_clen, newp->xfi_content,
+ xo_printable(gtfmt));
+ return -1;
+ }
+ }
+ break;
+
+ default:
+ /*
+ * Other fields don't have names for us to use, so if
+ * the types aren't the same, then we'll have to assume
+ * the original field is a match.
+ */
+ for (oldp = startp; oldp->xfi_ftype; oldp++) {
+ if (oldp->xfi_ftype == 'V') /* Can't go past these */
+ break;
+ if (oldp->xfi_ftype == newp->xfi_ftype)
+ goto copy_it; /* Assumably we have a match */
+ }
+ continue;
+ }
+
+ /*
+ * Found a match; copy over appropriate fields
+ */
+ copy_it:
+ newp->xfi_flags = oldp->xfi_flags;
+ newp->xfi_fnum = oldp->xfi_fnum;
+ newp->xfi_format = oldp->xfi_format;
+ newp->xfi_flen = oldp->xfi_flen;
+ newp->xfi_encoding = oldp->xfi_encoding;
+ newp->xfi_elen = oldp->xfi_elen;
+ }
+
+ *reorderedp = reordered;
+ if (reordered) {
+ xo_gettext_finish_numbering_fields(xop, fmt, new_fields);
+ xo_gettext_rewrite_fields(xop, new_fields, new_max_fields);
+ }
+
+ return 0;
+}
+
+/*
+ * We don't want to make gettext() calls here with a complete format
+ * string, since that means changing a flag would mean a
+ * labor-intensive re-translation expense. Instead we build a
+ * simplified form with a reduced level of detail, perform a lookup on
+ * that string and then re-insert the formating info.
+ *
+ * So something like:
+ * xo_emit("{G:}close {:fd/%ld} returned {g:error/%m} {:test/%6.6s}\n", ...)
+ * would have a lookup string of:
+ * "close {:fd} returned {:error} {:test}\n"
+ *
+ * We also need to handling reordering of fields, where the gettext()
+ * reply string uses fields in a different order than the original
+ * format string:
+ * "cluse-a {:fd} retoorned {:test}. Bork {:error} Bork. Bork.\n"
+ * If we have to reorder fields within the message, then things get
+ * complicated. See xo_gettext_rewrite_fields.
+ *
+ * Summary: i18n aighn't cheap.
+ */
+static const char *
+xo_gettext_build_format (xo_handle_t *xop UNUSED,
+ xo_field_info_t *fields UNUSED,
+ int this_field UNUSED,
+ const char *fmt, char **new_fmtp)
+{
+ if (xo_style_is_encoding(xop))
+ goto bail;
+
+ xo_buffer_t xb;
+ xo_buf_init(&xb);
+
+ if (xo_gettext_simplify_format(xop, &xb, fields,
+ this_field, fmt, NULL))
+ goto bail2;
+
+ const char *gtfmt = xo_dgettext(xop, xb.xb_bufp);
+ if (gtfmt == NULL || gtfmt == fmt || strcmp(gtfmt, fmt) == 0)
+ goto bail2;
+
+ xo_buf_cleanup(&xb);
+
+ char *new_fmt = xo_strndup(gtfmt, -1);
+ if (new_fmt == NULL)
+ goto bail2;
+
+ *new_fmtp = new_fmt;
+ return new_fmt;
+
+ bail2:
+ xo_buf_cleanup(&xb);
+ bail:
+ *new_fmtp = NULL;
+ return fmt;
+}
+
+static void
+xo_gettext_rebuild_content (xo_handle_t *xop, xo_field_info_t *fields,
+ unsigned *fstart, unsigned min_fstart,
+ unsigned *fend, unsigned max_fend)
+{
+ xo_field_info_t *xfip;
+ char *buf;
+ unsigned base = fstart[min_fstart];
+ unsigned blen = fend[max_fend] - base;
+ xo_buffer_t *xbp = &xop->xo_data;
+
+ if (blen == 0)
+ return;
+
+ buf = xo_realloc(NULL, blen);
+ if (buf == NULL)
+ return;
+
+ memcpy(buf, xbp->xb_bufp + fstart[min_fstart], blen); /* Copy our data */
+
+ unsigned field = min_fstart, soff, doff = base, len, fnum;
+ xo_field_info_t *zp;
+
+ /*
+ * Be aware there are two competing views of "field number": we
+ * want the user to thing in terms of "The {1:size}" where {G:},
+ * newlines, escaped braces, and text don't have numbers. But is
+ * also the internal view, where we have an array of
+ * xo_field_info_t and every field have an index. fnum, fstart[]
+ * and fend[] are the latter, but xfi_renum is the former.
+ */
+ for (xfip = fields + field; xfip->xfi_ftype; xfip++, field++) {
+ fnum = field;
+ if (xfip->xfi_renum) {
+ zp = xo_gettext_find_field(fields, xfip->xfi_renum);
+ fnum = zp ? zp - fields : field;
+ }
+
+ soff = fstart[fnum];
+ len = fend[fnum] - soff;
+
+ if (len > 0) {
+ soff -= base;
+ memcpy(xbp->xb_bufp + doff, buf + soff, len);
+ doff += len;
+ }
+ }
+
+ xo_free(buf);
+}
+#else /* HAVE_GETTEXT */
+static const char *
+xo_gettext_build_format (xo_handle_t *xop UNUSED,
+ xo_field_info_t *fields UNUSED,
+ int this_field UNUSED,
+ const char *fmt UNUSED, char **new_fmtp)
+{
+ *new_fmtp = NULL;
+ return fmt;
+}
+
+static int
+xo_gettext_combine_formats (xo_handle_t *xop UNUSED, const char *fmt UNUSED,
+ const char *gtfmt UNUSED,
+ xo_field_info_t *old_fields UNUSED,
+ xo_field_info_t *new_fields UNUSED,
+ unsigned new_max_fields UNUSED,
+ int *reorderedp UNUSED)
+{
+ return -1;
+}
+
+static void
+xo_gettext_rebuild_content (xo_handle_t *xop UNUSED,
+ xo_field_info_t *fields UNUSED,
+ unsigned *fstart UNUSED, unsigned min_fstart UNUSED,
+ unsigned *fend UNUSED, unsigned max_fend UNUSED)
+{
+ return;
+}
+#endif /* HAVE_GETTEXT */
+
+/*
+ * The central function for emitting libxo output.
+ */
+static int
+xo_do_emit (xo_handle_t *xop, const char *fmt)
+{
+ int gettext_inuse = 0;
+ int gettext_changed = 0;
+ int gettext_reordered = 0;
+ xo_field_info_t *new_fields = NULL;
+
+ int rc = 0;
+ int flush = XOF_ISSET(xop, XOF_FLUSH);
+ int flush_line = XOF_ISSET(xop, XOF_FLUSH_LINE);
+ char *new_fmt = NULL;
+
+ if (XOIF_ISSET(xop, XOIF_REORDER) || xo_style(xop) == XO_STYLE_ENCODER)
+ flush_line = 0;
+
+ xop->xo_columns = 0; /* Always reset it */
+ xop->xo_errno = errno; /* Save for "%m" */
+
+ unsigned max_fields = xo_count_fields(xop, fmt), field;
+ xo_field_info_t fields[max_fields], *xfip;
+
+ bzero(fields, max_fields * sizeof(fields[0]));
+
+ if (xo_parse_fields(xop, fields, max_fields, fmt))
+ return -1; /* Warning already displayed */
+
+ unsigned ftype;
+ xo_xff_flags_t flags;
+
+ /*
+ * Some overhead for gettext; if the fields in the msgstr returned
+ * by gettext are reordered, then we need to record start and end
+ * for each field. We'll go ahead and render the fields in the
+ * normal order, but later we can then reconstruct the reordered
+ * fields using these fstart/fend values.
+ */
+ unsigned flimit = max_fields * 2; /* Pessimistic limit */
+ unsigned min_fstart = flimit - 1;
+ unsigned max_fend = 0; /* Highest recorded fend[] entry */
+ unsigned fstart[flimit];
+ bzero(fstart, flimit * sizeof(fstart[0]));
+ unsigned fend[flimit];
+ bzero(fend, flimit * sizeof(fend[0]));
+
+ for (xfip = fields, field = 0; xfip->xfi_ftype && field < max_fields;
+ xfip++, field++) {
+ ftype = xfip->xfi_ftype;
+ flags = xfip->xfi_flags;
+
+ /* Record field start offset */
+ if (gettext_reordered) {
+ fstart[field] = xo_buf_offset(&xop->xo_data);
+ if (min_fstart > field)
+ min_fstart = field;
+ }
+
+ if (ftype == XO_ROLE_NEWLINE) {
+ xo_line_close(xop);
+ if (flush_line && xo_flush_h(xop) < 0)
+ return -1;
+ goto bottom;
+
+ } else if (ftype == XO_ROLE_EBRACE) {
+ xo_format_text(xop, xfip->xfi_start, xfip->xfi_len);
+ goto bottom;
+
+ } else if (ftype == XO_ROLE_TEXT) {
+ /* Normal text */
+ xo_format_text(xop, xfip->xfi_content, xfip->xfi_clen);
+ goto bottom;
+ }
+
+ /*
+ * Notes and units need the 'w' flag handled before the content.
+ */
+ if (ftype == 'N' || ftype == 'U') {
+ if (flags & XFF_WS) {
+ xo_format_content(xop, "padding", NULL, " ", 1,
+ NULL, 0, flags);
+ flags &= ~XFF_WS; /* Block later handling of this */
+ }
+ }
+
+ if (ftype == 'V')
+ xo_format_value(xop, xfip->xfi_content, xfip->xfi_clen,
+ xfip->xfi_format, xfip->xfi_flen,
+ xfip->xfi_encoding, xfip->xfi_elen, flags);
+ else if (ftype == '[')
+ xo_anchor_start(xop, xfip);
+ else if (ftype == ']')
+ xo_anchor_stop(xop, xfip);
+ else if (ftype == 'C')
+ xo_format_colors(xop, xfip);
+
+ else if (ftype == 'G') {
+ /*
+ * A {G:domain} field; disect the domain name and translate
+ * the remaining portion of the input string. If the user
+ * didn't put the {G:} at the start of the format string, then
+ * assumably they just want us to translate the rest of it.
+ * Since gettext returns strings in a static buffer, we make
+ * a copy in new_fmt.
+ */
+ xo_set_gettext_domain(xop, xfip);
+
+ if (!gettext_inuse) { /* Only translate once */
+ gettext_inuse = 1;
+ if (new_fmt) {
+ xo_free(new_fmt);
+ new_fmt = NULL;
+ }
+
+ xo_gettext_build_format(xop, fields, field,
+ xfip->xfi_next, &new_fmt);
+ if (new_fmt) {
+ gettext_changed = 1;
+
+ unsigned new_max_fields = xo_count_fields(xop, new_fmt);
+
+ if (++new_max_fields < max_fields)
+ new_max_fields = max_fields;
+
+ /* Leave a blank slot at the beginning */
+ int sz = (new_max_fields + 1) * sizeof(xo_field_info_t);
+ new_fields = alloca(sz);
+ bzero(new_fields, sz);
+
+ if (!xo_parse_fields(xop, new_fields + 1,
+ new_max_fields, new_fmt)) {
+ gettext_reordered = 0;
+
+ if (!xo_gettext_combine_formats(xop, fmt, new_fmt,
+ fields, new_fields + 1,
+ new_max_fields, &gettext_reordered)) {
+
+ if (gettext_reordered) {
+ if (XOF_ISSET(xop, XOF_LOG_GETTEXT))
+ xo_failure(xop, "gettext finds reordered "
+ "fields in '%s' and '%s'",
+ xo_printable(fmt),
+ xo_printable(new_fmt));
+ flush_line = 0; /* Must keep at content */
+ XOIF_SET(xop, XOIF_REORDER);
+ }
+
+ field = -1; /* Will be incremented at top of loop */
+ xfip = new_fields;
+ max_fields = new_max_fields;
+ }
+ }
+ }
+ }
+ continue;
+
+ } else if (xfip->xfi_clen || xfip->xfi_format) {
+
+ const char *class_name = xo_class_name(ftype);
+ if (class_name)
+ xo_format_content(xop, class_name, xo_tag_name(ftype),
+ xfip->xfi_content, xfip->xfi_clen,
+ xfip->xfi_format, xfip->xfi_flen, flags);
+ else if (ftype == 'T')
+ xo_format_title(xop, xfip);
+ else if (ftype == 'U')
+ xo_format_units(xop, xfip);
+ else
+ xo_failure(xop, "unknown field type: '%c'", ftype);
+ }
+
+ if (flags & XFF_COLON)
+ xo_format_content(xop, "decoration", NULL, ":", 1, NULL, 0, 0);
+
+ if (flags & XFF_WS)
+ xo_format_content(xop, "padding", NULL, " ", 1, NULL, 0, 0);
+
+ bottom:
+ /* Record the end-of-field offset */
+ if (gettext_reordered) {
+ fend[field] = xo_buf_offset(&xop->xo_data);
+ max_fend = field;
+ }
+ }
+
+ if (gettext_changed && gettext_reordered) {
+ /* Final step: rebuild the content using the rendered fields */
+ xo_gettext_rebuild_content(xop, new_fields + 1, fstart, min_fstart,
+ fend, max_fend);
+ }
+
+ XOIF_CLEAR(xop, XOIF_REORDER);
+
+ /* If we don't have an anchor, write the text out */
+ if (flush && !XOIF_ISSET(xop, XOIF_ANCHOR)) {
+ if (xo_write(xop) < 0)
+ rc = -1; /* Report failure */
+ else if (xop->xo_flush && xop->xo_flush(xop->xo_opaque) < 0)
+ rc = -1;
+ }
+
+ if (new_fmt)
+ xo_free(new_fmt);
+
+ /*
+ * We've carried the gettext domainname inside our handle just for
+ * convenience, but we need to ensure it doesn't survive across
+ * xo_emit calls.
+ */
+ if (xop->xo_gt_domain) {
+ xo_free(xop->xo_gt_domain);
+ xop->xo_gt_domain = NULL;
+ }
+
+ return (rc < 0) ? rc : (int) xop->xo_columns;
+}
+
+/*
+ * Rebuild a format string in a gettext-friendly format. This function
+ * is exposed to tools can perform this function. See xo(1).
+ */
+char *
+xo_simplify_format (xo_handle_t *xop, const char *fmt, int with_numbers,
+ xo_simplify_field_func_t field_cb)
+{
+ xop = xo_default(xop);
+
+ xop->xo_columns = 0; /* Always reset it */
+ xop->xo_errno = errno; /* Save for "%m" */
+
+ unsigned max_fields = xo_count_fields(xop, fmt);
+ xo_field_info_t fields[max_fields];
+
+ bzero(fields, max_fields * sizeof(fields[0]));
+
+ if (xo_parse_fields(xop, fields, max_fields, fmt))
+ return NULL; /* Warning already displayed */
+
+ xo_buffer_t xb;
+ xo_buf_init(&xb);
+
+ if (with_numbers)
+ xo_gettext_finish_numbering_fields(xop, fmt, fields);
+
+ if (xo_gettext_simplify_format(xop, &xb, fields, -1, fmt, field_cb))
+ return NULL;
+
+ return xb.xb_bufp;
+}
+
+int
+xo_emit_hv (xo_handle_t *xop, const char *fmt, va_list vap)
+{
+ int rc;
+
+ xop = xo_default(xop);
+ va_copy(xop->xo_vap, vap);
+ rc = xo_do_emit(xop, fmt);
+ va_end(xop->xo_vap);
+ bzero(&xop->xo_vap, sizeof(xop->xo_vap));
+
+ return rc;
+}
+
+int
+xo_emit_h (xo_handle_t *xop, const char *fmt, ...)
+{
+ int rc;
+
+ xop = xo_default(xop);
+ va_start(xop->xo_vap, fmt);
+ rc = xo_do_emit(xop, fmt);
+ va_end(xop->xo_vap);
+ bzero(&xop->xo_vap, sizeof(xop->xo_vap));
+
+ return rc;
+}
+
+int
+xo_emit (const char *fmt, ...)
+{
+ xo_handle_t *xop = xo_default(NULL);
+ int rc;
+
+ va_start(xop->xo_vap, fmt);
+ rc = xo_do_emit(xop, fmt);
+ va_end(xop->xo_vap);
+ bzero(&xop->xo_vap, sizeof(xop->xo_vap));
+
+ return rc;
+}
+
+int
+xo_attr_hv (xo_handle_t *xop, const char *name, const char *fmt, va_list vap)
+{
+ const int extra = 5; /* space, equals, quote, quote, and nul */
+ xop = xo_default(xop);
+
+ int rc = 0;
+ int nlen = strlen(name);
+ xo_buffer_t *xbp = &xop->xo_attrs;
+ unsigned name_offset, value_offset;
+
+ switch (xo_style(xop)) {
+ case XO_STYLE_XML:
+ if (!xo_buf_has_room(xbp, nlen + extra))
+ return -1;
+
+ *xbp->xb_curp++ = ' ';
+ memcpy(xbp->xb_curp, name, nlen);
+ xbp->xb_curp += nlen;
+ *xbp->xb_curp++ = '=';
+ *xbp->xb_curp++ = '"';
+
+ rc = xo_vsnprintf(xop, xbp, fmt, vap);
+
+ if (rc >= 0) {
+ rc = xo_escape_xml(xbp, rc, 1);
+ xbp->xb_curp += rc;
+ }
+
+ if (!xo_buf_has_room(xbp, 2))
+ return -1;
+
+ *xbp->xb_curp++ = '"';
+ *xbp->xb_curp = '\0';
+
+ rc += nlen + extra;
+ break;
+
+ case XO_STYLE_ENCODER:
+ name_offset = xo_buf_offset(xbp);
+ xo_buf_append(xbp, name, nlen);
+ xo_buf_append(xbp, "", 1);
+
+ value_offset = xo_buf_offset(xbp);
+ rc = xo_vsnprintf(xop, xbp, fmt, vap);
+ if (rc >= 0) {
+ xbp->xb_curp += rc;
+ *xbp->xb_curp = '\0';
+ rc = xo_encoder_handle(xop, XO_OP_ATTRIBUTE,
+ xo_buf_data(xbp, name_offset),
+ xo_buf_data(xbp, value_offset));
+ }
+ }
+
+ return rc;
+}
+
+int
+xo_attr_h (xo_handle_t *xop, const char *name, const char *fmt, ...)
+{
+ int rc;
+ va_list vap;
+
+ va_start(vap, fmt);
+ rc = xo_attr_hv(xop, name, fmt, vap);
+ va_end(vap);
+
+ return rc;
+}
+
+int
+xo_attr (const char *name, const char *fmt, ...)
+{
+ int rc;
+ va_list vap;
+
+ va_start(vap, fmt);
+ rc = xo_attr_hv(NULL, name, fmt, vap);
+ va_end(vap);
+
+ return rc;
+}
+
+static void
+xo_stack_set_flags (xo_handle_t *xop)
+{
+ if (XOF_ISSET(xop, XOF_NOT_FIRST)) {
+ xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth];
+
+ xsp->xs_flags |= XSF_NOT_FIRST;
+ XOF_CLEAR(xop, XOF_NOT_FIRST);
+ }
+}
+
+static void
+xo_depth_change (xo_handle_t *xop, const char *name,
+ int delta, int indent, xo_state_t state, xo_xsf_flags_t flags)
+{
+ if (xo_style(xop) == XO_STYLE_HTML || xo_style(xop) == XO_STYLE_TEXT)
+ indent = 0;
+
+ if (XOF_ISSET(xop, XOF_DTRT))
+ flags |= XSF_DTRT;
+
+ if (delta >= 0) { /* Push operation */
+ if (xo_depth_check(xop, xop->xo_depth + delta))
+ return;
+
+ xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth + delta];
+ xsp->xs_flags = flags;
+ xsp->xs_state = state;
+ xo_stack_set_flags(xop);
+
+ if (name == NULL)
+ name = XO_FAILURE_NAME;
+
+ xsp->xs_name = xo_strndup(name, -1);
+
+ } else { /* Pop operation */
+ if (xop->xo_depth == 0) {
+ if (!XOF_ISSET(xop, XOF_IGNORE_CLOSE))
+ xo_failure(xop, "close with empty stack: '%s'", name);
+ return;
+ }
+
+ xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth];
+ if (XOF_ISSET(xop, XOF_WARN)) {
+ const char *top = xsp->xs_name;
+ if (top && strcmp(name, top) != 0) {
+ xo_failure(xop, "incorrect close: '%s' .vs. '%s'",
+ name, top);
+ return;
+ }
+ if ((xsp->xs_flags & XSF_LIST) != (flags & XSF_LIST)) {
+ xo_failure(xop, "list close on list confict: '%s'",
+ name);
+ return;
+ }
+ if ((xsp->xs_flags & XSF_INSTANCE) != (flags & XSF_INSTANCE)) {
+ xo_failure(xop, "list close on instance confict: '%s'",
+ name);
+ return;
+ }
+ }
+
+ if (xsp->xs_name) {
+ xo_free(xsp->xs_name);
+ xsp->xs_name = NULL;
+ }
+ if (xsp->xs_keys) {
+ xo_free(xsp->xs_keys);
+ xsp->xs_keys = NULL;
+ }
+ }
+
+ xop->xo_depth += delta; /* Record new depth */
+ xop->xo_indent += indent;
+}
+
+void
+xo_set_depth (xo_handle_t *xop, int depth)
+{
+ xop = xo_default(xop);
+
+ if (xo_depth_check(xop, depth))
+ return;
+
+ xop->xo_depth += depth;
+ xop->xo_indent += depth;
+}
+
+static xo_xsf_flags_t
+xo_stack_flags (unsigned xflags)
+{
+ if (xflags & XOF_DTRT)
+ return XSF_DTRT;
+ return 0;
+}
+
+static void
+xo_emit_top (xo_handle_t *xop, const char *ppn)
+{
+ xo_printf(xop, "%*s{%s", xo_indent(xop), "", ppn);
+ XOIF_SET(xop, XOIF_TOP_EMITTED);
+
+ if (xop->xo_version) {
+ xo_printf(xop, "%*s\"__version\": \"%s\", %s",
+ xo_indent(xop), "", xop->xo_version, ppn);
+ xo_free(xop->xo_version);
+ xop->xo_version = NULL;
+ }
+}
+
+static int
+xo_do_open_container (xo_handle_t *xop, xo_xof_flags_t flags, const char *name)
+{
+ int rc = 0;
+ const char *ppn = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : "";
+ const char *pre_nl = "";
+
+ if (name == NULL) {
+ xo_failure(xop, "NULL passed for container name");
+ name = XO_FAILURE_NAME;
+ }
+
+ flags |= xop->xo_flags; /* Pick up handle flags */
+
+ switch (xo_style(xop)) {
+ case XO_STYLE_XML:
+ rc = xo_printf(xop, "%*s<%s", xo_indent(xop), "", name);
+
+ if (xop->xo_attrs.xb_curp != xop->xo_attrs.xb_bufp) {
+ rc += xop->xo_attrs.xb_curp - xop->xo_attrs.xb_bufp;
+ xo_data_append(xop, xop->xo_attrs.xb_bufp,
+ xop->xo_attrs.xb_curp - xop->xo_attrs.xb_bufp);
+ xop->xo_attrs.xb_curp = xop->xo_attrs.xb_bufp;
+ }
+
+ rc += xo_printf(xop, ">%s", ppn);
+ break;
+
+ case XO_STYLE_JSON:
+ xo_stack_set_flags(xop);
+
+ if (!XOF_ISSET(xop, XOF_NO_TOP)
+ && !XOIF_ISSET(xop, XOIF_TOP_EMITTED))
+ xo_emit_top(xop, ppn);
+
+ if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST)
+ pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? ",\n" : ", ";
+ xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST;
+
+ rc = xo_printf(xop, "%s%*s\"%s\": {%s",
+ pre_nl, xo_indent(xop), "", name, ppn);
+ break;
+
+ case XO_STYLE_SDPARAMS:
+ break;
+
+ case XO_STYLE_ENCODER:
+ rc = xo_encoder_handle(xop, XO_OP_OPEN_CONTAINER, name, NULL);
+ break;
+ }
+
+ xo_depth_change(xop, name, 1, 1, XSS_OPEN_CONTAINER,
+ xo_stack_flags(flags));
+
+ return rc;
+}
+
+static int
+xo_open_container_hf (xo_handle_t *xop, xo_xof_flags_t flags, const char *name)
+{
+ return xo_transition(xop, flags, name, XSS_OPEN_CONTAINER);
+}
+
+int
+xo_open_container_h (xo_handle_t *xop, const char *name)
+{
+ return xo_open_container_hf(xop, 0, name);
+}
+
+int
+xo_open_container (const char *name)
+{
+ return xo_open_container_hf(NULL, 0, name);
+}
+
+int
+xo_open_container_hd (xo_handle_t *xop, const char *name)
+{
+ return xo_open_container_hf(xop, XOF_DTRT, name);
+}
+
+int
+xo_open_container_d (const char *name)
+{
+ return xo_open_container_hf(NULL, XOF_DTRT, name);
+}
+
+static int
+xo_do_close_container (xo_handle_t *xop, const char *name)
+{
+ xop = xo_default(xop);
+
+ int rc = 0;
+ const char *ppn = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : "";
+ const char *pre_nl = "";
+
+ if (name == NULL) {
+ xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth];
+
+ name = xsp->xs_name;
+ if (name) {
+ int len = strlen(name) + 1;
+ /* We need to make a local copy; xo_depth_change will free it */
+ char *cp = alloca(len);
+ memcpy(cp, name, len);
+ name = cp;
+ } else if (!(xsp->xs_flags & XSF_DTRT)) {
+ xo_failure(xop, "missing name without 'dtrt' mode");
+ name = XO_FAILURE_NAME;
+ }
+ }
+
+ switch (xo_style(xop)) {
+ case XO_STYLE_XML:
+ xo_depth_change(xop, name, -1, -1, XSS_CLOSE_CONTAINER, 0);
+ rc = xo_printf(xop, "%*s%s>%s", xo_indent(xop), "", name, ppn);
+ break;
+
+ case XO_STYLE_JSON:
+ pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : "";
+ ppn = (xop->xo_depth <= 1) ? "\n" : "";
+
+ xo_depth_change(xop, name, -1, -1, XSS_CLOSE_CONTAINER, 0);
+ rc = xo_printf(xop, "%s%*s}%s", pre_nl, xo_indent(xop), "", ppn);
+ xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST;
+ break;
+
+ case XO_STYLE_HTML:
+ case XO_STYLE_TEXT:
+ xo_depth_change(xop, name, -1, 0, XSS_CLOSE_CONTAINER, 0);
+ break;
+
+ case XO_STYLE_SDPARAMS:
+ break;
+
+ case XO_STYLE_ENCODER:
+ xo_depth_change(xop, name, -1, 0, XSS_CLOSE_CONTAINER, 0);
+ rc = xo_encoder_handle(xop, XO_OP_CLOSE_CONTAINER, name, NULL);
+ break;
+ }
+
+ return rc;
+}
+
+int
+xo_close_container_h (xo_handle_t *xop, const char *name)
+{
+ return xo_transition(xop, 0, name, XSS_CLOSE_CONTAINER);
+}
+
+int
+xo_close_container (const char *name)
+{
+ return xo_close_container_h(NULL, name);
+}
+
+int
+xo_close_container_hd (xo_handle_t *xop)
+{
+ return xo_close_container_h(xop, NULL);
+}
+
+int
+xo_close_container_d (void)
+{
+ return xo_close_container_h(NULL, NULL);
+}
+
+static int
+xo_do_open_list (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name)
+{
+ int rc = 0;
+ int indent = 0;
+
+ xop = xo_default(xop);
+
+ const char *ppn = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : "";
+ const char *pre_nl = "";
+
+ switch (xo_style(xop)) {
+ case XO_STYLE_JSON:
+
+ indent = 1;
+ if (!XOF_ISSET(xop, XOF_NO_TOP)
+ && !XOIF_ISSET(xop, XOIF_TOP_EMITTED))
+ xo_emit_top(xop, ppn);
+
+ if (name == NULL) {
+ xo_failure(xop, "NULL passed for list name");
+ name = XO_FAILURE_NAME;
+ }
+
+ xo_stack_set_flags(xop);
+
+ if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST)
+ pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? ",\n" : ", ";
+ xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST;
+
+ rc = xo_printf(xop, "%s%*s\"%s\": [%s",
+ pre_nl, xo_indent(xop), "", name, ppn);
+ break;
+
+ case XO_STYLE_ENCODER:
+ rc = xo_encoder_handle(xop, XO_OP_OPEN_LIST, name, NULL);
+ break;
+ }
+
+ xo_depth_change(xop, name, 1, indent, XSS_OPEN_LIST,
+ XSF_LIST | xo_stack_flags(flags));
+
+ return rc;
+}
+
+static int
+xo_open_list_hf (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name)
+{
+ return xo_transition(xop, flags, name, XSS_OPEN_LIST);
+}
+
+int
+xo_open_list_h (xo_handle_t *xop, const char *name UNUSED)
+{
+ return xo_open_list_hf(xop, 0, name);
+}
+
+int
+xo_open_list (const char *name)
+{
+ return xo_open_list_hf(NULL, 0, name);
+}
+
+int
+xo_open_list_hd (xo_handle_t *xop, const char *name UNUSED)
+{
+ return xo_open_list_hf(xop, XOF_DTRT, name);
+}
+
+int
+xo_open_list_d (const char *name)
+{
+ return xo_open_list_hf(NULL, XOF_DTRT, name);
+}
+
+static int
+xo_do_close_list (xo_handle_t *xop, const char *name)
+{
+ int rc = 0;
+ const char *pre_nl = "";
+
+ if (name == NULL) {
+ xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth];
+
+ name = xsp->xs_name;
+ if (name) {
+ int len = strlen(name) + 1;
+ /* We need to make a local copy; xo_depth_change will free it */
+ char *cp = alloca(len);
+ memcpy(cp, name, len);
+ name = cp;
+ } else if (!(xsp->xs_flags & XSF_DTRT)) {
+ xo_failure(xop, "missing name without 'dtrt' mode");
+ name = XO_FAILURE_NAME;
+ }
+ }
+
+ switch (xo_style(xop)) {
+ case XO_STYLE_JSON:
+ if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST)
+ pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : "";
+ xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST;
+
+ xo_depth_change(xop, name, -1, -1, XSS_CLOSE_LIST, XSF_LIST);
+ rc = xo_printf(xop, "%s%*s]", pre_nl, xo_indent(xop), "");
+ xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST;
+ break;
+
+ case XO_STYLE_ENCODER:
+ xo_depth_change(xop, name, -1, 0, XSS_CLOSE_LIST, XSF_LIST);
+ rc = xo_encoder_handle(xop, XO_OP_CLOSE_LIST, name, NULL);
+ break;
+
+ default:
+ xo_depth_change(xop, name, -1, 0, XSS_CLOSE_LIST, XSF_LIST);
+ xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST;
+ break;
+ }
+
+ return rc;
+}
+
+int
+xo_close_list_h (xo_handle_t *xop, const char *name)
+{
+ return xo_transition(xop, 0, name, XSS_CLOSE_LIST);
+}
+
+int
+xo_close_list (const char *name)
+{
+ return xo_close_list_h(NULL, name);
+}
+
+int
+xo_close_list_hd (xo_handle_t *xop)
+{
+ return xo_close_list_h(xop, NULL);
+}
+
+int
+xo_close_list_d (void)
+{
+ return xo_close_list_h(NULL, NULL);
+}
+
+static int
+xo_do_open_leaf_list (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name)
+{
+ int rc = 0;
+ int indent = 0;
+
+ xop = xo_default(xop);
+
+ const char *ppn = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : "";
+ const char *pre_nl = "";
+
+ switch (xo_style(xop)) {
+ case XO_STYLE_JSON:
+ indent = 1;
+
+ if (!XOF_ISSET(xop, XOF_NO_TOP)) {
+ if (!XOIF_ISSET(xop, XOIF_TOP_EMITTED)) {
+ xo_printf(xop, "%*s{%s", xo_indent(xop), "", ppn);
+ XOIF_SET(xop, XOIF_TOP_EMITTED);
+ }
+ }
+
+ if (name == NULL) {
+ xo_failure(xop, "NULL passed for list name");
+ name = XO_FAILURE_NAME;
+ }
+
+ xo_stack_set_flags(xop);
+
+ if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST)
+ pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? ",\n" : ", ";
+ xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST;
+
+ rc = xo_printf(xop, "%s%*s\"%s\": [%s",
+ pre_nl, xo_indent(xop), "", name, ppn);
+ break;
+
+ case XO_STYLE_ENCODER:
+ rc = xo_encoder_handle(xop, XO_OP_OPEN_LEAF_LIST, name, NULL);
+ break;
+ }
+
+ xo_depth_change(xop, name, 1, indent, XSS_OPEN_LEAF_LIST,
+ XSF_LIST | xo_stack_flags(flags));
+
+ return rc;
+}
+
+static int
+xo_do_close_leaf_list (xo_handle_t *xop, const char *name)
+{
+ int rc = 0;
+ const char *pre_nl = "";
+
+ if (name == NULL) {
+ xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth];
+
+ name = xsp->xs_name;
+ if (name) {
+ int len = strlen(name) + 1;
+ /* We need to make a local copy; xo_depth_change will free it */
+ char *cp = alloca(len);
+ memcpy(cp, name, len);
+ name = cp;
+ } else if (!(xsp->xs_flags & XSF_DTRT)) {
+ xo_failure(xop, "missing name without 'dtrt' mode");
+ name = XO_FAILURE_NAME;
+ }
+ }
+
+ switch (xo_style(xop)) {
+ case XO_STYLE_JSON:
+ if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST)
+ pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : "";
+ xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST;
+
+ xo_depth_change(xop, name, -1, -1, XSS_CLOSE_LEAF_LIST, XSF_LIST);
+ rc = xo_printf(xop, "%s%*s]", pre_nl, xo_indent(xop), "");
+ xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST;
+ break;
+
+ case XO_STYLE_ENCODER:
+ rc = xo_encoder_handle(xop, XO_OP_CLOSE_LEAF_LIST, name, NULL);
+ /*fallthru*/
+
+ default:
+ xo_depth_change(xop, name, -1, 0, XSS_CLOSE_LEAF_LIST, XSF_LIST);
+ xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST;
+ break;
+ }
+
+ return rc;
+}
+
+static int
+xo_do_open_instance (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name)
+{
+ xop = xo_default(xop);
+
+ int rc = 0;
+ const char *ppn = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : "";
+ const char *pre_nl = "";
+
+ flags |= xop->xo_flags;
+
+ if (name == NULL) {
+ xo_failure(xop, "NULL passed for instance name");
+ name = XO_FAILURE_NAME;
+ }
+
+ switch (xo_style(xop)) {
+ case XO_STYLE_XML:
+ rc = xo_printf(xop, "%*s<%s", xo_indent(xop), "", name);
+
+ if (xop->xo_attrs.xb_curp != xop->xo_attrs.xb_bufp) {
+ rc += xop->xo_attrs.xb_curp - xop->xo_attrs.xb_bufp;
+ xo_data_append(xop, xop->xo_attrs.xb_bufp,
+ xop->xo_attrs.xb_curp - xop->xo_attrs.xb_bufp);
+ xop->xo_attrs.xb_curp = xop->xo_attrs.xb_bufp;
+ }
+
+ rc += xo_printf(xop, ">%s", ppn);
+ break;
+
+ case XO_STYLE_JSON:
+ xo_stack_set_flags(xop);
+
+ if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST)
+ pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? ",\n" : ", ";
+ xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST;
+
+ rc = xo_printf(xop, "%s%*s{%s",
+ pre_nl, xo_indent(xop), "", ppn);
+ break;
+
+ case XO_STYLE_SDPARAMS:
+ break;
+
+ case XO_STYLE_ENCODER:
+ rc = xo_encoder_handle(xop, XO_OP_OPEN_INSTANCE, name, NULL);
+ break;
+ }
+
+ xo_depth_change(xop, name, 1, 1, XSS_OPEN_INSTANCE, xo_stack_flags(flags));
+
+ return rc;
+}
+
+static int
+xo_open_instance_hf (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name)
+{
+ return xo_transition(xop, flags, name, XSS_OPEN_INSTANCE);
+}
+
+int
+xo_open_instance_h (xo_handle_t *xop, const char *name)
+{
+ return xo_open_instance_hf(xop, 0, name);
+}
+
+int
+xo_open_instance (const char *name)
+{
+ return xo_open_instance_hf(NULL, 0, name);
+}
+
+int
+xo_open_instance_hd (xo_handle_t *xop, const char *name)
+{
+ return xo_open_instance_hf(xop, XOF_DTRT, name);
+}
+
+int
+xo_open_instance_d (const char *name)
+{
+ return xo_open_instance_hf(NULL, XOF_DTRT, name);
+}
+
+static int
+xo_do_close_instance (xo_handle_t *xop, const char *name)
+{
+ xop = xo_default(xop);
+
+ int rc = 0;
+ const char *ppn = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : "";
+ const char *pre_nl = "";
+
+ if (name == NULL) {
+ xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth];
+
+ name = xsp->xs_name;
+ if (name) {
+ int len = strlen(name) + 1;
+ /* We need to make a local copy; xo_depth_change will free it */
+ char *cp = alloca(len);
+ memcpy(cp, name, len);
+ name = cp;
+ } else if (!(xsp->xs_flags & XSF_DTRT)) {
+ xo_failure(xop, "missing name without 'dtrt' mode");
+ name = XO_FAILURE_NAME;
+ }
+ }
+
+ switch (xo_style(xop)) {
+ case XO_STYLE_XML:
+ xo_depth_change(xop, name, -1, -1, XSS_CLOSE_INSTANCE, 0);
+ rc = xo_printf(xop, "%*s%s>%s", xo_indent(xop), "", name, ppn);
+ break;
+
+ case XO_STYLE_JSON:
+ pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : "";
+
+ xo_depth_change(xop, name, -1, -1, XSS_CLOSE_INSTANCE, 0);
+ rc = xo_printf(xop, "%s%*s}", pre_nl, xo_indent(xop), "");
+ xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST;
+ break;
+
+ case XO_STYLE_HTML:
+ case XO_STYLE_TEXT:
+ xo_depth_change(xop, name, -1, 0, XSS_CLOSE_INSTANCE, 0);
+ break;
+
+ case XO_STYLE_SDPARAMS:
+ break;
+
+ case XO_STYLE_ENCODER:
+ xo_depth_change(xop, name, -1, 0, XSS_CLOSE_INSTANCE, 0);
+ rc = xo_encoder_handle(xop, XO_OP_CLOSE_INSTANCE, name, NULL);
+ break;
+ }
+
+ return rc;
+}
+
+int
+xo_close_instance_h (xo_handle_t *xop, const char *name)
+{
+ return xo_transition(xop, 0, name, XSS_CLOSE_INSTANCE);
+}
+
+int
+xo_close_instance (const char *name)
+{
+ return xo_close_instance_h(NULL, name);
+}
+
+int
+xo_close_instance_hd (xo_handle_t *xop)
+{
+ return xo_close_instance_h(xop, NULL);
+}
+
+int
+xo_close_instance_d (void)
+{
+ return xo_close_instance_h(NULL, NULL);
+}
+
+static int
+xo_do_close_all (xo_handle_t *xop, xo_stack_t *limit)
+{
+ xo_stack_t *xsp;
+ int rc = 0;
+ xo_xsf_flags_t flags;
+
+ for (xsp = &xop->xo_stack[xop->xo_depth]; xsp >= limit; xsp--) {
+ switch (xsp->xs_state) {
+ case XSS_INIT:
+ /* Nothing */
+ rc = 0;
+ break;
+
+ case XSS_OPEN_CONTAINER:
+ rc = xo_do_close_container(xop, NULL);
+ break;
+
+ case XSS_OPEN_LIST:
+ rc = xo_do_close_list(xop, NULL);
+ break;
+
+ case XSS_OPEN_INSTANCE:
+ rc = xo_do_close_instance(xop, NULL);
+ break;
+
+ case XSS_OPEN_LEAF_LIST:
+ rc = xo_do_close_leaf_list(xop, NULL);
+ break;
+
+ case XSS_MARKER:
+ flags = xsp->xs_flags & XSF_MARKER_FLAGS;
+ xo_depth_change(xop, xsp->xs_name, -1, 0, XSS_MARKER, 0);
+ xop->xo_stack[xop->xo_depth].xs_flags |= flags;
+ rc = 0;
+ break;
+ }
+
+ if (rc < 0)
+ xo_failure(xop, "close %d failed: %d", xsp->xs_state, rc);
+ }
+
+ return 0;
+}
+
+/*
+ * This function is responsible for clearing out whatever is needed
+ * to get to the desired state, if possible.
+ */
+static int
+xo_do_close (xo_handle_t *xop, const char *name, xo_state_t new_state)
+{
+ xo_stack_t *xsp, *limit = NULL;
+ int rc;
+ xo_state_t need_state = new_state;
+
+ if (new_state == XSS_CLOSE_CONTAINER)
+ need_state = XSS_OPEN_CONTAINER;
+ else if (new_state == XSS_CLOSE_LIST)
+ need_state = XSS_OPEN_LIST;
+ else if (new_state == XSS_CLOSE_INSTANCE)
+ need_state = XSS_OPEN_INSTANCE;
+ else if (new_state == XSS_CLOSE_LEAF_LIST)
+ need_state = XSS_OPEN_LEAF_LIST;
+ else if (new_state == XSS_MARKER)
+ need_state = XSS_MARKER;
+ else
+ return 0; /* Unknown or useless new states are ignored */
+
+ for (xsp = &xop->xo_stack[xop->xo_depth]; xsp > xop->xo_stack; xsp--) {
+ /*
+ * Marker's normally stop us from going any further, unless
+ * we are popping a marker (new_state == XSS_MARKER).
+ */
+ if (xsp->xs_state == XSS_MARKER && need_state != XSS_MARKER) {
+ if (name) {
+ xo_failure(xop, "close (xo_%s) fails at marker '%s'; "
+ "not found '%s'",
+ xo_state_name(new_state),
+ xsp->xs_name, name);
+ return 0;
+
+ } else {
+ limit = xsp;
+ xo_failure(xop, "close stops at marker '%s'", xsp->xs_name);
+ }
+ break;
+ }
+
+ if (xsp->xs_state != need_state)
+ continue;
+
+ if (name && xsp->xs_name && strcmp(name, xsp->xs_name) != 0)
+ continue;
+
+ limit = xsp;
+ break;
+ }
+
+ if (limit == NULL) {
+ xo_failure(xop, "xo_%s can't find match for '%s'",
+ xo_state_name(new_state), name);
+ return 0;
+ }
+
+ rc = xo_do_close_all(xop, limit);
+
+ return rc;
+}
+
+/*
+ * We are in a given state and need to transition to the new state.
+ */
+static int
+xo_transition (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name,
+ xo_state_t new_state)
+{
+ xo_stack_t *xsp;
+ int rc;
+ int old_state, on_marker;
+
+ xop = xo_default(xop);
+
+ rc = 0;
+ xsp = &xop->xo_stack[xop->xo_depth];
+ old_state = xsp->xs_state;
+ on_marker = (old_state == XSS_MARKER);
+
+ /* If there's a marker on top of the stack, we need to find a real state */
+ while (old_state == XSS_MARKER) {
+ if (xsp == xop->xo_stack)
+ break;
+ xsp -= 1;
+ old_state = xsp->xs_state;
+ }
+
+ /*
+ * At this point, the list of possible states are:
+ * XSS_INIT, XSS_OPEN_CONTAINER, XSS_OPEN_LIST,
+ * XSS_OPEN_INSTANCE, XSS_OPEN_LEAF_LIST, XSS_DISCARDING
+ */
+ switch (XSS_TRANSITION(old_state, new_state)) {
+
+ open_container:
+ case XSS_TRANSITION(XSS_INIT, XSS_OPEN_CONTAINER):
+ case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_OPEN_CONTAINER):
+ case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_OPEN_CONTAINER):
+ rc = xo_do_open_container(xop, flags, name);
+ break;
+
+ case XSS_TRANSITION(XSS_OPEN_LIST, XSS_OPEN_CONTAINER):
+ if (on_marker)
+ goto marker_prevents_close;
+ rc = xo_do_close_list(xop, NULL);
+ if (rc >= 0)
+ goto open_container;
+ break;
+
+ case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_OPEN_CONTAINER):
+ if (on_marker)
+ goto marker_prevents_close;
+ rc = xo_do_close_leaf_list(xop, NULL);
+ if (rc >= 0)
+ goto open_container;
+ break;
+
+ /*close_container:*/
+ case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_CLOSE_CONTAINER):
+ if (on_marker)
+ goto marker_prevents_close;
+ rc = xo_do_close(xop, name, new_state);
+ break;
+
+ case XSS_TRANSITION(XSS_INIT, XSS_CLOSE_CONTAINER):
+ /* This is an exception for "xo --close" */
+ rc = xo_do_close_container(xop, name);
+ break;
+
+ case XSS_TRANSITION(XSS_OPEN_LIST, XSS_CLOSE_CONTAINER):
+ case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_CLOSE_CONTAINER):
+ if (on_marker)
+ goto marker_prevents_close;
+ rc = xo_do_close(xop, name, new_state);
+ break;
+
+ case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_CLOSE_CONTAINER):
+ if (on_marker)
+ goto marker_prevents_close;
+ rc = xo_do_close_leaf_list(xop, NULL);
+ if (rc >= 0)
+ rc = xo_do_close(xop, name, new_state);
+ break;
+
+ open_list:
+ case XSS_TRANSITION(XSS_INIT, XSS_OPEN_LIST):
+ case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_OPEN_LIST):
+ case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_OPEN_LIST):
+ rc = xo_do_open_list(xop, flags, name);
+ break;
+
+ case XSS_TRANSITION(XSS_OPEN_LIST, XSS_OPEN_LIST):
+ if (on_marker)
+ goto marker_prevents_close;
+ rc = xo_do_close_list(xop, NULL);
+ if (rc >= 0)
+ goto open_list;
+ break;
+
+ case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_OPEN_LIST):
+ if (on_marker)
+ goto marker_prevents_close;
+ rc = xo_do_close_leaf_list(xop, NULL);
+ if (rc >= 0)
+ goto open_list;
+ break;
+
+ /*close_list:*/
+ case XSS_TRANSITION(XSS_OPEN_LIST, XSS_CLOSE_LIST):
+ if (on_marker)
+ goto marker_prevents_close;
+ rc = xo_do_close(xop, name, new_state);
+ break;
+
+ case XSS_TRANSITION(XSS_INIT, XSS_CLOSE_LIST):
+ case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_CLOSE_LIST):
+ case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_CLOSE_LIST):
+ case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_CLOSE_LIST):
+ rc = xo_do_close(xop, name, new_state);
+ break;
+
+ open_instance:
+ case XSS_TRANSITION(XSS_OPEN_LIST, XSS_OPEN_INSTANCE):
+ rc = xo_do_open_instance(xop, flags, name);
+ break;
+
+ case XSS_TRANSITION(XSS_INIT, XSS_OPEN_INSTANCE):
+ case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_OPEN_INSTANCE):
+ rc = xo_do_open_list(xop, flags, name);
+ if (rc >= 0)
+ goto open_instance;
+ break;
+
+ case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_OPEN_INSTANCE):
+ if (on_marker) {
+ rc = xo_do_open_list(xop, flags, name);
+ } else {
+ rc = xo_do_close_instance(xop, NULL);
+ }
+ if (rc >= 0)
+ goto open_instance;
+ break;
+
+ case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_OPEN_INSTANCE):
+ if (on_marker)
+ goto marker_prevents_close;
+ rc = xo_do_close_leaf_list(xop, NULL);
+ if (rc >= 0)
+ goto open_instance;
+ break;
+
+ /*close_instance:*/
+ case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_CLOSE_INSTANCE):
+ if (on_marker)
+ goto marker_prevents_close;
+ rc = xo_do_close_instance(xop, name);
+ break;
+
+ case XSS_TRANSITION(XSS_INIT, XSS_CLOSE_INSTANCE):
+ /* This one makes no sense; ignore it */
+ xo_failure(xop, "xo_close_instance ignored when called from "
+ "initial state ('%s')", name ?: "(unknown)");
+ break;
+
+ case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_CLOSE_INSTANCE):
+ case XSS_TRANSITION(XSS_OPEN_LIST, XSS_CLOSE_INSTANCE):
+ if (on_marker)
+ goto marker_prevents_close;
+ rc = xo_do_close(xop, name, new_state);
+ break;
+
+ case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_CLOSE_INSTANCE):
+ if (on_marker)
+ goto marker_prevents_close;
+ rc = xo_do_close_leaf_list(xop, NULL);
+ if (rc >= 0)
+ rc = xo_do_close(xop, name, new_state);
+ break;
+
+ open_leaf_list:
+ case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_OPEN_LEAF_LIST):
+ case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_OPEN_LEAF_LIST):
+ case XSS_TRANSITION(XSS_INIT, XSS_OPEN_LEAF_LIST):
+ rc = xo_do_open_leaf_list(xop, flags, name);
+ break;
+
+ case XSS_TRANSITION(XSS_OPEN_LIST, XSS_OPEN_LEAF_LIST):
+ case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_OPEN_LEAF_LIST):
+ if (on_marker)
+ goto marker_prevents_close;
+ rc = xo_do_close_list(xop, NULL);
+ if (rc >= 0)
+ goto open_leaf_list;
+ break;
+
+ /*close_leaf_list:*/
+ case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_CLOSE_LEAF_LIST):
+ if (on_marker)
+ goto marker_prevents_close;
+ rc = xo_do_close_leaf_list(xop, name);
+ break;
+
+ case XSS_TRANSITION(XSS_INIT, XSS_CLOSE_LEAF_LIST):
+ /* Makes no sense; ignore */
+ xo_failure(xop, "xo_close_leaf_list ignored when called from "
+ "initial state ('%s')", name ?: "(unknown)");
+ break;
+
+ case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_CLOSE_LEAF_LIST):
+ case XSS_TRANSITION(XSS_OPEN_LIST, XSS_CLOSE_LEAF_LIST):
+ case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_CLOSE_LEAF_LIST):
+ if (on_marker)
+ goto marker_prevents_close;
+ rc = xo_do_close(xop, name, new_state);
+ break;
+
+ /*emit:*/
+ case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_EMIT):
+ case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_EMIT):
+ break;
+
+ case XSS_TRANSITION(XSS_OPEN_LIST, XSS_EMIT):
+ if (on_marker)
+ goto marker_prevents_close;
+ rc = xo_do_close(xop, NULL, XSS_CLOSE_LIST);
+ break;
+
+ case XSS_TRANSITION(XSS_INIT, XSS_EMIT):
+ break;
+
+ case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_EMIT):
+ if (on_marker)
+ goto marker_prevents_close;
+ rc = xo_do_close_leaf_list(xop, NULL);
+ break;
+
+ /*emit_leaf_list:*/
+ case XSS_TRANSITION(XSS_INIT, XSS_EMIT_LEAF_LIST):
+ case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_EMIT_LEAF_LIST):
+ case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_EMIT_LEAF_LIST):
+ rc = xo_do_open_leaf_list(xop, flags, name);
+ break;
+
+ case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_EMIT_LEAF_LIST):
+ break;
+
+ case XSS_TRANSITION(XSS_OPEN_LIST, XSS_EMIT_LEAF_LIST):
+ /*
+ * We need to be backward compatible with the pre-xo_open_leaf_list
+ * API, where both lists and leaf-lists were opened as lists. So
+ * if we find an open list that hasn't had anything written to it,
+ * we'll accept it.
+ */
+ break;
+
+ default:
+ xo_failure(xop, "unknown transition: (%u -> %u)",
+ xsp->xs_state, new_state);
+ }
+
+ return rc;
+
+ marker_prevents_close:
+ xo_failure(xop, "marker '%s' prevents transition from %s to %s",
+ xop->xo_stack[xop->xo_depth].xs_name,
+ xo_state_name(old_state), xo_state_name(new_state));
+ return -1;
+}
+
+int
+xo_open_marker_h (xo_handle_t *xop, const char *name)
+{
+ xop = xo_default(xop);
+
+ xo_depth_change(xop, name, 1, 0, XSS_MARKER,
+ xop->xo_stack[xop->xo_depth].xs_flags & XSF_MARKER_FLAGS);
+
+ return 0;
+}
+
+int
+xo_open_marker (const char *name)
+{
+ return xo_open_marker_h(NULL, name);
+}
+
+int
+xo_close_marker_h (xo_handle_t *xop, const char *name)
+{
+ xop = xo_default(xop);
+
+ return xo_do_close(xop, name, XSS_MARKER);
+}
+
+int
+xo_close_marker (const char *name)
+{
+ return xo_close_marker_h(NULL, name);
+}
+
+/*
+ * Record custom output functions into the xo handle, allowing
+ * integration with a variety of output frameworks.
+ */
+void
+xo_set_writer (xo_handle_t *xop, void *opaque, xo_write_func_t write_func,
+ xo_close_func_t close_func, xo_flush_func_t flush_func)
+{
+ xop = xo_default(xop);
+
+ xop->xo_opaque = opaque;
+ xop->xo_write = write_func;
+ xop->xo_close = close_func;
+ xop->xo_flush = flush_func;
+}
+
+void
+xo_set_allocator (xo_realloc_func_t realloc_func, xo_free_func_t free_func)
+{
+ xo_realloc = realloc_func;
+ xo_free = free_func;
+}
+
+int
+xo_flush_h (xo_handle_t *xop)
+{
+ static char div_close[] = "
";
+ int rc;
+
+ xop = xo_default(xop);
+
+ switch (xo_style(xop)) {
+ case XO_STYLE_HTML:
+ if (XOIF_ISSET(xop, XOIF_DIV_OPEN)) {
+ XOIF_CLEAR(xop, XOIF_DIV_OPEN);
+ xo_data_append(xop, div_close, sizeof(div_close) - 1);
+
+ if (XOF_ISSET(xop, XOF_PRETTY))
+ xo_data_append(xop, "\n", 1);
+ }
+ break;
+
+ case XO_STYLE_ENCODER:
+ xo_encoder_handle(xop, XO_OP_FLUSH, NULL, NULL);
+ }
+
+ rc = xo_write(xop);
+ if (rc >= 0 && xop->xo_flush)
+ if (xop->xo_flush(xop->xo_opaque) < 0)
+ return -1;
+
+ return rc;
+}
+
+int
+xo_flush (void)
+{
+ return xo_flush_h(NULL);
+}
+
+int
+xo_finish_h (xo_handle_t *xop)
+{
+ const char *cp = "";
+ xop = xo_default(xop);
+
+ if (!XOF_ISSET(xop, XOF_NO_CLOSE))
+ xo_do_close_all(xop, xop->xo_stack);
+
+ switch (xo_style(xop)) {
+ case XO_STYLE_JSON:
+ if (!XOF_ISSET(xop, XOF_NO_TOP)) {
+ if (XOIF_ISSET(xop, XOIF_TOP_EMITTED))
+ XOIF_CLEAR(xop, XOIF_TOP_EMITTED); /* Turn off before output */
+ else
+ cp = "{ ";
+ xo_printf(xop, "%*s%s}\n",xo_indent(xop), "", cp);
+ }
+ break;
+
+ case XO_STYLE_ENCODER:
+ xo_encoder_handle(xop, XO_OP_FINISH, NULL, NULL);
+ break;
+ }
+
+ return xo_flush_h(xop);
+}
+
+int
+xo_finish (void)
+{
+ return xo_finish_h(NULL);
+}
+
+/*
+ * xo_finish_atexit is suitable for atexit() calls, to force clear up
+ * and finalizing output.
+ */
+void
+xo_finish_atexit (void)
+{
+ (void) xo_finish_h(NULL);
+}
+
+/*
+ * 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)
+{
+ xop = xo_default(xop);
+
+ /*
+ * If the format string doesn't end with a newline, we pop
+ * one on ourselves.
+ */
+ int len = strlen(fmt);
+ if (len > 0 && fmt[len - 1] != '\n') {
+ char *newfmt = alloca(len + 2);
+ memcpy(newfmt, fmt, len);
+ newfmt[len] = '\n';
+ newfmt[len] = '\0';
+ fmt = newfmt;
+ }
+
+ switch (xo_style(xop)) {
+ case XO_STYLE_TEXT:
+ vfprintf(stderr, fmt, vap);
+ break;
+
+ case XO_STYLE_HTML:
+ va_copy(xop->xo_vap, vap);
+
+ xo_buf_append_div(xop, "error", 0, NULL, 0, fmt, strlen(fmt), NULL, 0);
+
+ if (XOIF_ISSET(xop, XOIF_DIV_OPEN))
+ xo_line_close(xop);
+
+ xo_write(xop);
+
+ va_end(xop->xo_vap);
+ bzero(&xop->xo_vap, sizeof(xop->xo_vap));
+ break;
+
+ case XO_STYLE_XML:
+ case XO_STYLE_JSON:
+ va_copy(xop->xo_vap, vap);
+
+ xo_open_container_h(xop, "error");
+ xo_format_value(xop, "message", 7, fmt, strlen(fmt), NULL, 0, 0);
+ xo_close_container_h(xop, "error");
+
+ va_end(xop->xo_vap);
+ bzero(&xop->xo_vap, sizeof(xop->xo_vap));
+ break;
+
+ case XO_STYLE_SDPARAMS:
+ case XO_STYLE_ENCODER:
+ break;
+ }
+}
+
+void
+xo_error_h (xo_handle_t *xop, const char *fmt, ...)
+{
+ va_list vap;
+
+ va_start(vap, fmt);
+ xo_error_hv(xop, fmt, vap);
+ va_end(vap);
+}
+
+/*
+ * Generate an error message, such as would be displayed on stderr
+ */
+void
+xo_error (const char *fmt, ...)
+{
+ va_list vap;
+
+ va_start(vap, fmt);
+ xo_error_hv(NULL, fmt, vap);
+ va_end(vap);
+}
+
+/*
+ * Parse any libxo-specific options from the command line, removing them
+ * so the main() argument parsing won't see them. We return the new value
+ * for argc or -1 for error. If an error occurred, the program should
+ * exit. A suitable error message has already been displayed.
+ */
+int
+xo_parse_args (int argc, char **argv)
+{
+ static char libxo_opt[] = "--libxo";
+ 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 + 1;
+
+ for (save = i = 1; i < argc; i++) {
+ if (argv[i] == NULL
+ || strncmp(argv[i], libxo_opt, sizeof(libxo_opt) - 1) != 0) {
+ if (save != i)
+ argv[save] = argv[i];
+ save += 1;
+ continue;
+ }
+
+ cp = argv[i] + sizeof(libxo_opt) - 1;
+ if (*cp == 0) {
+ cp = argv[++i];
+ if (cp == 0) {
+ xo_warnx("missing libxo option");
+ return -1;
+ }
+
+ if (xo_set_options(NULL, cp) < 0)
+ return -1;
+ } else if (*cp == ':') {
+ if (xo_set_options(NULL, cp) < 0)
+ return -1;
+
+ } else if (*cp == '=') {
+ if (xo_set_options(NULL, ++cp) < 0)
+ return -1;
+
+ } else if (*cp == '-') {
+ cp += 1;
+ if (strcmp(cp, "check") == 0) {
+ exit(XO_HAS_LIBXO);
+
+ } else {
+ xo_warnx("unknown libxo option: '%s'", argv[i]);
+ return -1;
+ }
+ } else {
+ xo_warnx("unknown libxo option: '%s'", argv[i]);
+ return -1;
+ }
+ }
+
+ argv[save] = NULL;
+ return save;
+}
+
+/*
+ * Debugging function that dumps the current stack of open libxo constructs,
+ * suitable for calling from the debugger.
+ */
+void
+xo_dump_stack (xo_handle_t *xop)
+{
+ int i;
+ xo_stack_t *xsp;
+
+ xop = xo_default(xop);
+
+ fprintf(stderr, "Stack dump:\n");
+
+ xsp = xop->xo_stack;
+ for (i = 1, xsp++; i <= xop->xo_depth; i++, xsp++) {
+ fprintf(stderr, " [%d] %s '%s' [%x]\n",
+ i, xo_state_name(xsp->xs_state),
+ xsp->xs_name ?: "--", xsp->xs_flags);
+ }
+}
+
+/*
+ * Record the program name used for error messages
+ */
+void
+xo_set_program (const char *name)
+{
+ xo_program = name;
+}
+
+void
+xo_set_version_h (xo_handle_t *xop, const char *version UNUSED)
+{
+ xop = xo_default(xop);
+
+ if (version == NULL || strchr(version, '"') != NULL)
+ return;
+
+ if (!xo_style_is_encoding(xop))
+ return;
+
+ switch (xo_style(xop)) {
+ case XO_STYLE_XML:
+ /* For XML, we record this as an attribute for the first tag */
+ xo_attr_h(xop, "__version", "%s", version);
+ break;
+
+ case XO_STYLE_JSON:
+ /*
+ * For JSON, we record the version string in our handle, and emit
+ * it in xo_emit_top.
+ */
+ xop->xo_version = xo_strndup(version, -1);
+ break;
+
+ case XO_STYLE_ENCODER:
+ xo_encoder_handle(xop, XO_OP_VERSION, NULL, version);
+ break;
+ }
+}
+
+/*
+ * Set the version number for the API content being carried thru
+ * the xo handle.
+ */
+void
+xo_set_version (const char *version)
+{
+ xo_set_version_h(NULL, version);
+}
+
+/*
+ * Generate a warning. Normally, this is a text message written to
+ * standard error. If the XOF_WARN_XML flag is set, then we generate
+ * XMLified content on standard output.
+ */
+void
+xo_emit_warn_hcv (xo_handle_t *xop, int as_warning, int code,
+ const char *fmt, va_list vap)
+{
+ xop = xo_default(xop);
+
+ if (fmt == NULL)
+ return;
+
+ xo_open_marker_h(xop, "xo_emit_warn_hcv");
+ xo_open_container_h(xop, as_warning ? "__warning" : "__error");
+
+ if (xo_program)
+ xo_emit("{wc:program}", xo_program);
+
+ if (xo_style(xop) == XO_STYLE_XML || xo_style(xop) == XO_STYLE_JSON) {
+ va_list ap;
+ xo_handle_t temp;
+
+ bzero(&temp, sizeof(temp));
+ temp.xo_style = XO_STYLE_TEXT;
+ xo_buf_init(&temp.xo_data);
+ xo_depth_check(&temp, XO_DEPTH);
+
+ va_copy(ap, vap);
+ (void) xo_emit_hv(&temp, fmt, ap);
+ va_end(ap);
+
+ xo_buffer_t *src = &temp.xo_data;
+ xo_format_value(xop, "message", 7, src->xb_bufp,
+ src->xb_curp - src->xb_bufp, NULL, 0, 0);
+
+ xo_free(temp.xo_stack);
+ xo_buf_cleanup(src);
+ }
+
+ (void) xo_emit_hv(xop, fmt, vap);
+
+ int len = strlen(fmt);
+ if (len > 0 && fmt[len - 1] != '\n') {
+ if (code > 0) {
+ const char *msg = strerror(code);
+ if (msg)
+ xo_emit_h(xop, ": {G:strerror}{g:error/%s}", msg);
+ }
+ xo_emit("\n");
+ }
+
+ xo_close_marker_h(xop, "xo_emit_warn_hcv");
+ xo_flush_h(xop);
+}
+
+void
+xo_emit_warn_hc (xo_handle_t *xop, int code, const char *fmt, ...)
+{
+ va_list vap;
+
+ va_start(vap, fmt);
+ xo_emit_warn_hcv(xop, 1, code, fmt, vap);
+ va_end(vap);
+}
+
+void
+xo_emit_warn_c (int code, const char *fmt, ...)
+{
+ va_list vap;
+
+ va_start(vap, fmt);
+ xo_emit_warn_hcv(NULL, 1, code, fmt, vap);
+ va_end(vap);
+}
+
+void
+xo_emit_warn (const char *fmt, ...)
+{
+ int code = errno;
+ va_list vap;
+
+ va_start(vap, fmt);
+ xo_emit_warn_hcv(NULL, 1, code, fmt, vap);
+ va_end(vap);
+}
+
+void
+xo_emit_warnx (const char *fmt, ...)
+{
+ va_list vap;
+
+ va_start(vap, fmt);
+ xo_emit_warn_hcv(NULL, 1, -1, fmt, vap);
+ va_end(vap);
+}
+
+void
+xo_emit_err_v (int eval, int code, const char *fmt, va_list vap)
+{
+ xo_emit_warn_hcv(NULL, 0, code, fmt, vap);
+ xo_finish();
+ exit(eval);
+}
+
+void
+xo_emit_err (int eval, const char *fmt, ...)
+{
+ int code = errno;
+ va_list vap;
+ va_start(vap, fmt);
+ xo_emit_err_v(0, code, fmt, vap);
+ va_end(vap);
+ exit(eval);
+}
+
+void
+xo_emit_errx (int eval, const char *fmt, ...)
+{
+ va_list vap;
+
+ va_start(vap, fmt);
+ xo_emit_err_v(0, -1, fmt, vap);
+ va_end(vap);
+ xo_finish();
+ exit(eval);
+}
+
+void
+xo_emit_errc (int eval, int code, const char *fmt, ...)
+{
+ va_list vap;
+
+ va_start(vap, fmt);
+ xo_emit_warn_hcv(NULL, 0, code, fmt, vap);
+ va_end(vap);
+ xo_finish();
+ exit(eval);
+}
+
+/*
+ * Get the opaque private pointer for an xo handle
+ */
+void *
+xo_get_private (xo_handle_t *xop)
+{
+ xop = xo_default(xop);
+ return xop->xo_private;
+}
+
+/*
+ * Set the opaque private pointer for an xo handle.
+ */
+void
+xo_set_private (xo_handle_t *xop, void *opaque)
+{
+ xop = xo_default(xop);
+ xop->xo_private = opaque;
+}
+
+/*
+ * Get the encoder function
+ */
+xo_encoder_func_t
+xo_get_encoder (xo_handle_t *xop)
+{
+ xop = xo_default(xop);
+ return xop->xo_encoder;
+}
+
+/*
+ * Record an encoder callback function in an xo handle.
+ */
+void
+xo_set_encoder (xo_handle_t *xop, xo_encoder_func_t encoder)
+{
+ xop = xo_default(xop);
+
+ xop->xo_style = XO_STYLE_ENCODER;
+ xop->xo_encoder = encoder;
+}
Property changes on: vendor/Juniper/libxo/dist/libxo/libxo.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo.h
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo.h (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo.h (revision 296962)
@@ -0,0 +1,596 @@
+/*
+ * Copyright (c) 2014-2015, Juniper Networks, Inc.
+ * All rights reserved.
+ * This SOFTWARE is licensed under the LICENSE provided in the
+ * ../Copyright file. By downloading, installing, copying, or otherwise
+ * using the SOFTWARE, you agree to be bound by the terms of that
+ * LICENSE.
+ * Phil Shafer, July 2014
+ */
+
+/**
+ * libxo provides a means of generating text, XML, JSON, and HTML output
+ * using a single set of function calls, maximizing the value of output
+ * while minimizing the cost/impact on the code.
+ *
+ * Full documentation is available in ./doc/libxo.txt or online at:
+ * http://juniper.github.io/libxo/libxo-manual.html
+ */
+
+#ifndef INCLUDE_XO_H
+#define INCLUDE_XO_H
+
+#include
+#include
+#include
+#include
+#include
+
+#ifdef __dead2
+#define NORETURN __dead2
+#else
+#define NORETURN
+#endif /* __dead2 */
+
+/*
+ * Normally we'd use the HAVE_PRINTFLIKE define triggered by the
+ * --enable-printflike option to configure, but we don't install
+ * our internal "xoconfig.h", and I'd rather not. Taking the
+ * coward's path, we'll turn it on inside a #if that allows
+ * others to turn it off where needed. Not ideal, but functional.
+ */
+#if !defined(NO_PRINTFLIKE) && !defined(__linux__)
+#define PRINTFLIKE(_x, _y) __printflike(_x, _y)
+#else
+#define PRINTFLIKE(_x, _y)
+#endif /* NO_PRINTFLIKE */
+
+/** Formatting types */
+typedef unsigned short xo_style_t;
+#define XO_STYLE_TEXT 0 /** Generate text output */
+#define XO_STYLE_XML 1 /** Generate XML output */
+#define XO_STYLE_JSON 2 /** Generate JSON output */
+#define XO_STYLE_HTML 3 /** Generate HTML output */
+#define XO_STYLE_SDPARAMS 4 /* Generate syslog structured data params */
+#define XO_STYLE_ENCODER 5 /* Generate calls to external encoder */
+
+/** Flags for libxo */
+typedef unsigned long long xo_xof_flags_t;
+#define XOF_BIT(_n) ((xo_xof_flags_t) 1 << (_n))
+#define XOF_CLOSE_FP XOF_BIT(0) /** Close file pointer on xo_close() */
+#define XOF_PRETTY XOF_BIT(1) /** Make 'pretty printed' output */
+#define XOF_LOG_SYSLOG XOF_BIT(2) /** Log (on stderr) our syslog content */
+#define XOF_RESV3 XOF_BIT(3) /* Unused */
+
+#define XOF_WARN XOF_BIT(4) /** Generate warnings for broken calls */
+#define XOF_XPATH XOF_BIT(5) /** Emit XPath attributes in HTML */
+#define XOF_INFO XOF_BIT(6) /** Emit additional info fields (HTML) */
+#define XOF_WARN_XML XOF_BIT(7) /** Emit warnings in XML (on stdout) */
+
+#define XOF_NO_ENV XOF_BIT(8) /** Don't look at LIBXO_OPTIONS env var */
+#define XOF_NO_VA_ARG XOF_BIT(9) /** Don't advance va_list w/ va_arg() */
+#define XOF_DTRT XOF_BIT(10) /** Enable "do the right thing" mode */
+#define XOF_KEYS XOF_BIT(11) /** Flag 'key' fields for xml and json */
+
+#define XOF_IGNORE_CLOSE XOF_BIT(12) /** Ignore errors on close tags */
+#define XOF_NOT_FIRST XOF_BIT(13) /* Not the first item (JSON) */
+#define XOF_NO_LOCALE XOF_BIT(14) /** Don't bother with locale */
+#define XOF_RESV15 XOF_BIT(15) /* Unused */
+
+#define XOF_NO_TOP XOF_BIT(16) /** Don't emit the top braces in JSON */
+#define XOF_RESV17 XOF_BIT(17) /* Unused */
+#define XOF_UNITS XOF_BIT(18) /** Encode units in XML */
+#define XOF_RESV19 XOF_BIT(19) /* Unused */
+
+#define XOF_UNDERSCORES XOF_BIT(20) /** Replace dashes with underscores (JSON)*/
+#define XOF_COLUMNS XOF_BIT(21) /** xo_emit should return a column count */
+#define XOF_FLUSH XOF_BIT(22) /** Flush after each xo_emit call */
+#define XOF_FLUSH_LINE XOF_BIT(23) /** Flush after each newline */
+
+#define XOF_NO_CLOSE XOF_BIT(24) /** xo_finish won't close open elements */
+#define XOF_COLOR_ALLOWED XOF_BIT(25) /** Allow color/effects to be enabled */
+#define XOF_COLOR XOF_BIT(26) /** Enable color and effects */
+#define XOF_NO_HUMANIZE XOF_BIT(27) /** Block the {h:} modifier */
+
+#define XOF_LOG_GETTEXT XOF_BIT(28) /** Log (stderr) gettext lookup strings */
+#define XOF_UTF8 XOF_BIT(29) /** Force text output to be UTF8 */
+
+/*
+ * The xo_info_t structure provides a mapping between names and
+ * additional data emitted via HTML.
+ */
+typedef struct xo_info_s {
+ const char *xi_name; /* Name of the element */
+ const char *xi_type; /* Type of field */
+ const char *xi_help; /* Description of field */
+} xo_info_t;
+
+#define XO_INFO_NULL NULL, NULL, NULL /* Use '{ XO_INFO_NULL }' to end lists */
+
+struct xo_handle_s; /* Opaque structure forward */
+typedef struct xo_handle_s xo_handle_t; /* Handle for XO output */
+
+typedef int (*xo_write_func_t)(void *, const char *);
+typedef void (*xo_close_func_t)(void *);
+typedef int (*xo_flush_func_t)(void *);
+typedef void *(*xo_realloc_func_t)(void *, size_t);
+typedef void (*xo_free_func_t)(void *);
+
+/*
+ * The formatter function mirrors "vsnprintf", with an additional argument
+ * of the xo handle. The caller should return the number of bytes _needed_
+ * to fit the data, even if this exceeds 'len'.
+ */
+typedef int (*xo_formatter_t)(xo_handle_t *, char *, int,
+ const char *, va_list);
+typedef void (*xo_checkpointer_t)(xo_handle_t *, va_list, int);
+
+xo_handle_t *
+xo_create (xo_style_t style, xo_xof_flags_t flags);
+
+xo_handle_t *
+xo_create_to_file (FILE *fp, xo_style_t style, xo_xof_flags_t flags);
+
+void
+xo_destroy (xo_handle_t *xop);
+
+void
+xo_set_writer (xo_handle_t *xop, void *opaque, xo_write_func_t write_func,
+ xo_close_func_t close_func, xo_flush_func_t flush_func);
+
+void
+xo_set_allocator (xo_realloc_func_t realloc_func, xo_free_func_t free_func);
+
+void
+xo_set_style (xo_handle_t *xop, xo_style_t style);
+
+xo_style_t
+xo_get_style (xo_handle_t *xop);
+
+int
+xo_set_style_name (xo_handle_t *xop, const char *style);
+
+int
+xo_set_options (xo_handle_t *xop, const char *input);
+
+xo_xof_flags_t
+xo_get_flags (xo_handle_t *xop);
+
+void
+xo_set_flags (xo_handle_t *xop, xo_xof_flags_t flags);
+
+void
+xo_clear_flags (xo_handle_t *xop, xo_xof_flags_t flags);
+
+void
+xo_set_info (xo_handle_t *xop, xo_info_t *infop, int count);
+
+void
+xo_set_formatter (xo_handle_t *xop, xo_formatter_t func, xo_checkpointer_t);
+
+void
+xo_set_depth (xo_handle_t *xop, int depth);
+
+int
+xo_emit_hv (xo_handle_t *xop, const char *fmt, va_list vap);
+
+int
+xo_emit_h (xo_handle_t *xop, const char *fmt, ...);
+
+int
+xo_emit (const char *fmt, ...);
+
+PRINTFLIKE(2, 0)
+static inline int
+xo_emit_hvp (xo_handle_t *xop, const char *fmt, va_list vap)
+{
+ return xo_emit_hv(xop, fmt, vap);
+}
+
+PRINTFLIKE(2, 3)
+static inline int
+xo_emit_hp (xo_handle_t *xop, const char *fmt, ...)
+{
+ va_list vap;
+ va_start(vap, fmt);
+ int rc = xo_emit_hv(xop, fmt, vap);
+ va_end(vap);
+ return rc;
+}
+
+PRINTFLIKE(1, 2)
+static inline int
+xo_emit_p (const char *fmt, ...)
+{
+ va_list vap;
+ va_start(vap, fmt);
+ int rc = xo_emit_hv(NULL, fmt, vap);
+ va_end(vap);
+ return rc;
+}
+
+int
+xo_open_container_h (xo_handle_t *xop, const char *name);
+
+int
+xo_open_container (const char *name);
+
+int
+xo_open_container_hd (xo_handle_t *xop, const char *name);
+
+int
+xo_open_container_d (const char *name);
+
+int
+xo_close_container_h (xo_handle_t *xop, const char *name);
+
+int
+xo_close_container (const char *name);
+
+int
+xo_close_container_hd (xo_handle_t *xop);
+
+int
+xo_close_container_d (void);
+
+int
+xo_open_list_h (xo_handle_t *xop, const char *name);
+
+int
+xo_open_list (const char *name);
+
+int
+xo_open_list_hd (xo_handle_t *xop, const char *name);
+
+int
+xo_open_list_d (const char *name);
+
+int
+xo_close_list_h (xo_handle_t *xop, const char *name);
+
+int
+xo_close_list (const char *name);
+
+int
+xo_close_list_hd (xo_handle_t *xop);
+
+int
+xo_close_list_d (void);
+
+int
+xo_open_instance_h (xo_handle_t *xop, const char *name);
+
+int
+xo_open_instance (const char *name);
+
+int
+xo_open_instance_hd (xo_handle_t *xop, const char *name);
+
+int
+xo_open_instance_d (const char *name);
+
+int
+xo_close_instance_h (xo_handle_t *xop, const char *name);
+
+int
+xo_close_instance (const char *name);
+
+int
+xo_close_instance_hd (xo_handle_t *xop);
+
+int
+xo_close_instance_d (void);
+
+int
+xo_open_marker_h (xo_handle_t *xop, const char *name);
+
+int
+xo_open_marker (const char *name);
+
+int
+xo_close_marker_h (xo_handle_t *xop, const char *name);
+
+int
+xo_close_marker (const char *name);
+
+int
+xo_attr_h (xo_handle_t *xop, const char *name, const char *fmt, ...);
+
+int
+xo_attr_hv (xo_handle_t *xop, const char *name, const char *fmt, va_list vap);
+
+int
+xo_attr (const char *name, const char *fmt, ...);
+
+void
+xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap);
+
+void
+xo_error_h (xo_handle_t *xop, const char *fmt, ...);
+
+void
+xo_error (const char *fmt, ...);
+
+int
+xo_flush_h (xo_handle_t *xop);
+
+int
+xo_flush (void);
+
+int
+xo_finish_h (xo_handle_t *xop);
+
+int
+xo_finish (void);
+
+void
+xo_finish_atexit (void);
+
+void
+xo_set_leading_xpath (xo_handle_t *xop, const char *path);
+
+void
+xo_warn_hc (xo_handle_t *xop, int code, const char *fmt, ...) PRINTFLIKE(3, 4);
+
+void
+xo_warn_c (int code, const char *fmt, ...) PRINTFLIKE(2, 3);
+
+void
+xo_warn (const char *fmt, ...) PRINTFLIKE(1, 2);
+
+void
+xo_warnx (const char *fmt, ...) PRINTFLIKE(1, 2);
+
+void
+xo_err (int eval, const char *fmt, ...) NORETURN PRINTFLIKE(2, 3);
+
+void
+xo_errx (int eval, const char *fmt, ...) NORETURN PRINTFLIKE(2, 3);
+
+void
+xo_errc (int eval, int code, const char *fmt, ...) NORETURN PRINTFLIKE(3, 4);
+
+void
+xo_message_hcv (xo_handle_t *xop, int code, const char *fmt, va_list vap) PRINTFLIKE(3, 0);
+
+void
+xo_message_hc (xo_handle_t *xop, int code, const char *fmt, ...) PRINTFLIKE(3, 4);
+
+void
+xo_message_c (int code, const char *fmt, ...) PRINTFLIKE(2, 3);
+
+void
+xo_message_e (const char *fmt, ...) PRINTFLIKE(1, 2);
+
+void
+xo_message (const char *fmt, ...) PRINTFLIKE(1, 2);
+
+void
+xo_emit_warn_hcv (xo_handle_t *xop, int as_warning, int code,
+ const char *fmt, va_list vap);
+
+void
+xo_emit_warn_hc (xo_handle_t *xop, int code, const char *fmt, ...);
+
+void
+xo_emit_warn_c (int code, const char *fmt, ...);
+
+void
+xo_emit_warn (const char *fmt, ...);
+
+void
+xo_emit_warnx (const char *fmt, ...);
+
+void
+xo_emit_err (int eval, const char *fmt, ...) NORETURN;
+
+void
+xo_emit_errx (int eval, const char *fmt, ...) NORETURN;
+
+void
+xo_emit_errc (int eval, int code, const char *fmt, ...) NORETURN;
+
+PRINTFLIKE(4, 0)
+static inline void
+xo_emit_warn_hcvp (xo_handle_t *xop, int as_warning, int code,
+ const char *fmt, va_list vap)
+{
+ xo_emit_warn_hcv(xop, as_warning, code, fmt, vap);
+}
+
+PRINTFLIKE(3, 4)
+static inline void
+xo_emit_warn_hcp (xo_handle_t *xop, int code, const char *fmt, ...)
+{
+ va_list vap;
+ va_start(vap, fmt);
+ xo_emit_warn_hcv(xop, 1, code, fmt, vap);
+ va_end(vap);
+}
+
+PRINTFLIKE(2, 3)
+static inline void
+xo_emit_warn_cp (int code, const char *fmt, ...)
+{
+ va_list vap;
+ va_start(vap, fmt);
+ xo_emit_warn_hcv(NULL, 1, code, fmt, vap);
+ va_end(vap);
+}
+
+PRINTFLIKE(1, 2)
+static inline void
+xo_emit_warn_p (const char *fmt, ...)
+{
+ int code = errno;
+ va_list vap;
+ va_start(vap, fmt);
+ xo_emit_warn_hcv(NULL, 1, code, fmt, vap);
+ va_end(vap);
+}
+
+PRINTFLIKE(1, 2)
+static inline void
+xo_emit_warnx_p (const char *fmt, ...)
+{
+ va_list vap;
+ va_start(vap, fmt);
+ xo_emit_warn_hcv(NULL, 1, -1, fmt, vap);
+ va_end(vap);
+}
+
+NORETURN PRINTFLIKE(2, 3)
+static inline void
+xo_emit_err_p (int eval, const char *fmt, ...)
+{
+ int code = errno;
+ va_list vap;
+ va_start(vap, fmt);
+ xo_emit_warn_hcv(NULL, 0, code, fmt, vap);
+ va_end(vap);
+
+ exit(eval);
+}
+
+PRINTFLIKE(2, 3)
+static inline void
+xo_emit_errx_p (int eval, const char *fmt, ...)
+{
+ va_list vap;
+ va_start(vap, fmt);
+ xo_emit_warn_hcv(NULL, 0, -1, fmt, vap);
+ va_end(vap);
+ exit(eval);
+}
+
+PRINTFLIKE(3, 4)
+static inline void
+xo_emit_errc_p (int eval, int code, const char *fmt, ...)
+{
+ va_list vap;
+ va_start(vap, fmt);
+ xo_emit_warn_hcv(NULL, 0, code, fmt, vap);
+ va_end(vap);
+ exit(eval);
+}
+
+void
+xo_emit_err_v (int eval, int code, const char *fmt, va_list vap) NORETURN PRINTFLIKE(3, 0);
+
+void
+xo_no_setlocale (void);
+
+/**
+ * @brief Lift libxo-specific arguments from a set of arguments
+ *
+ * libxo-enable programs typically use command line options to enable
+ * all the nifty-cool libxo features. xo_parse_args() makes this simple
+ * by pre-processing the command line arguments given to main(), handling
+ * and removing the libxo-specific ones, meaning anything starting with
+ * "--libxo". A full description of these arguments is in the base
+ * documentation.
+ * @param[in] argc Number of arguments (ala #main())
+ * @param[in] argc Array of argument strings (ala #main())
+ * @return New number of arguments, or -1 for failure.
+ */
+int
+xo_parse_args (int argc, char **argv);
+
+/**
+ * This is the "magic" number returned by libxo-supporting commands
+ * when passed the equally magic "--libxo-check" option. If you
+ * return this, we can (unsafely) assume that since you know the magic
+ * handshake, you'll happily handle future --libxo options and not do
+ * something violent like reboot the box or create another hole in the
+ * ozone layer.
+ */
+#define XO_HAS_LIBXO 121
+
+/**
+ * externs for libxo's version number strings
+ */
+extern const char xo_version[]; /** Base version triple string */
+extern const char xo_version_extra[]; /** Extra version magic content */
+
+/**
+ * @brief Dump the internal stack of a libxo handle.
+ *
+ * This diagnostic function is something I will ask you to call from
+ * your program when you write to tell me libxo has gone bat-stink
+ * crazy and has discarded your list or container or content. Output
+ * content will be what we lovingly call "developer entertainment".
+ * @param[in] xop A valid libxo handle, or NULL for the default handle
+ */
+void
+xo_dump_stack (xo_handle_t *xop);
+
+/**
+ * @brief Recode the name of the program, suitable for error output.
+ *
+ * libxo will record the given name for use while generating error
+ * messages. The contents are not copied, so the value must continue
+ * to point to a valid memory location. This allows the caller to change
+ * the value, but requires the caller to manage the memory. Typically
+ * this is called with argv[0] from main().
+ * @param[in] name The name of the current application program
+ */
+void
+xo_set_program (const char *name);
+
+/**
+ * @brief Add a version string to the output, where possible.
+ *
+ * Adds a version number to the output, suitable for tracking
+ * changes in the content. This is only important for the "encoding"
+ * format styles (XML and JSON) and allows a user of the data to
+ * discern which version of the data model is in use.
+ * @param[in] version The version number, encoded as a string
+ */
+void
+xo_set_version (const char *version);
+
+/**
+ * #xo_set_version with a handle.
+ * @param[in] xop A valid libxo handle, or NULL for the default handle
+ * @param[in] version The version number, encoded as a string
+ */
+void
+xo_set_version_h (xo_handle_t *xop, const char *version);
+
+void
+xo_open_log (const char *ident, int logopt, int facility);
+
+void
+xo_close_log (void);
+
+int
+xo_set_logmask (int maskpri);
+
+void
+xo_set_unit_test_mode (int value);
+
+void
+xo_syslog (int priority, const char *name, const char *message, ...);
+
+void
+xo_vsyslog (int priority, const char *name, const char *message, va_list args);
+
+typedef void (*xo_syslog_open_t)(void);
+typedef void (*xo_syslog_send_t)(const char *full_msg,
+ const char *v0_hdr, const char *text_only);
+typedef void (*xo_syslog_close_t)(void);
+
+void
+xo_set_syslog_handler (xo_syslog_open_t open_func, xo_syslog_send_t send_func,
+ xo_syslog_close_t close_func);
+
+void
+xo_set_syslog_enterprise_id (unsigned short eid);
+
+typedef void (*xo_simplify_field_func_t)(const char *, unsigned, int);
+
+char *
+xo_simplify_format (xo_handle_t *xop, const char *fmt, int with_numbers,
+ xo_simplify_field_func_t field_cb);
+
+#endif /* INCLUDE_XO_H */
Property changes on: vendor/Juniper/libxo/dist/libxo/xo.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_attr.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_attr.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_attr.3 (revision 296962)
@@ -0,0 +1,60 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd July, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_attr , xo_attr_h , xo_attr_hv
+.Nd Add attribute name/value pairs to formatted output
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft int
+.Fn xo_attr "const char *name" "const char *fmt" "..."
+.Ft int
+.Fn xo_attr_h "xo_handle_t *handle" "const char *name, const char *fmt" "..."
+.Ft int
+.Fn xo_attr_hv "xo_handle_t *handle" "const char *name" "const char *fmt" "va_list vap"
+.Sh DESCRIPTION
+The
+.Fn xo_attr
+function emits attributes for the XML output style. The attribute
+value is recorded in the
+.Fa handle
+and is attached to the next field that is emitted via a
+.Xr xo_emit 3
+call.
+.Pp
+The
+.Fa name
+parameter give the name of the attribute to be encoded. The
+.Fa fmt
+parameter gives a printf-style format string used to format the
+value of the attribute using any remaining arguments, or the
+.Fa vap
+parameter as passed to
+.Fn xo_attr_hv .
+.Bd -literal -offset indent
+ EXAMPLE:
+ xo_attr("seconds", "%ld", (unsigned long) login_time);
+ struct tm *tmp = localtime(login_time);
+ strftime(buf, sizeof(buf), "%R", tmp);
+ xo_emit("Logged in at {:login-time}\\n", buf);
+ XML:
+ 00:14
+.Ed
+.Pp
+Since attributes are only emitted in XML, their use should be limited
+to meta-data and additional or redundant representations of data
+already emitted in other form.
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_attr.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_buf.h
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_buf.h (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_buf.h (revision 296962)
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2015, Juniper Networks, Inc.
+ * All rights reserved.
+ * This SOFTWARE is licensed under the LICENSE provided in the
+ * ../Copyright file. By downloading, installing, copying, or otherwise
+ * using the SOFTWARE, you agree to be bound by the terms of that
+ * LICENSE.
+ * Phil Shafer, August 2015
+ */
+
+/*
+ * This file is an _internal_ part of the libxo plumbing, not suitable
+ * for external use. It is not considered part of the libxo API and
+ * will not be a stable part of that API. Mine, not your's, dude...
+ * The real hope is that something like this will become a standard part
+ * of libc and I can kill this off.
+ */
+
+#ifndef XO_BUF_H
+#define XO_BUF_H
+
+#define XO_BUFSIZ (8*1024) /* Initial buffer size */
+
+/*
+ * xo_buffer_t: a memory buffer that can be grown as needed. We
+ * use them for building format strings and output data.
+ */
+typedef struct xo_buffer_s {
+ char *xb_bufp; /* Buffer memory */
+ char *xb_curp; /* Current insertion point */
+ unsigned xb_size; /* Size of buffer */
+} xo_buffer_t;
+
+/*
+ * Initialize the contents of an xo_buffer_t.
+ */
+static inline void
+xo_buf_init (xo_buffer_t *xbp)
+{
+ xbp->xb_size = XO_BUFSIZ;
+ xbp->xb_bufp = xo_realloc(NULL, xbp->xb_size);
+ xbp->xb_curp = xbp->xb_bufp;
+}
+
+/*
+ * Reset the buffer to empty
+ */
+static inline void
+xo_buf_reset (xo_buffer_t *xbp)
+{
+ xbp->xb_curp = xbp->xb_bufp;
+}
+
+/*
+ * Return the number of bytes left in the buffer
+ */
+static inline int
+xo_buf_left (xo_buffer_t *xbp)
+{
+ return xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp);
+}
+
+/*
+ * See if the buffer to empty
+ */
+static inline int
+xo_buf_is_empty (xo_buffer_t *xbp)
+{
+ return (xbp->xb_curp == xbp->xb_bufp);
+}
+
+/*
+ * Return the current offset
+ */
+static inline unsigned
+xo_buf_offset (xo_buffer_t *xbp)
+{
+ return xbp ? (xbp->xb_curp - xbp->xb_bufp) : 0;
+}
+
+static inline char *
+xo_buf_data (xo_buffer_t *xbp, unsigned offset)
+{
+ if (xbp == NULL)
+ return NULL;
+ return xbp->xb_bufp + offset;
+}
+
+static inline char *
+xo_buf_cur (xo_buffer_t *xbp)
+{
+ if (xbp == NULL)
+ return NULL;
+ return xbp->xb_curp;
+}
+
+/*
+ * Initialize the contents of an xo_buffer_t.
+ */
+static inline void
+xo_buf_cleanup (xo_buffer_t *xbp)
+{
+ if (xbp->xb_bufp)
+ xo_free(xbp->xb_bufp);
+ bzero(xbp, sizeof(*xbp));
+}
+
+/*
+ * Does the buffer have room for the given number of bytes of data?
+ * If not, realloc the buffer to make room. If that fails, we
+ * return 0 to tell the caller they are in trouble.
+ */
+static inline int
+xo_buf_has_room (xo_buffer_t *xbp, int len)
+{
+ if (xbp->xb_curp + len >= xbp->xb_bufp + xbp->xb_size) {
+ int sz = xbp->xb_size + XO_BUFSIZ;
+ char *bp = xo_realloc(xbp->xb_bufp, sz);
+ if (bp == NULL)
+ return 0;
+
+ xbp->xb_curp = bp + (xbp->xb_curp - xbp->xb_bufp);
+ xbp->xb_bufp = bp;
+ xbp->xb_size = sz;
+ }
+
+ return 1;
+}
+
+/*
+ * Append the given string to the given buffer
+ */
+static inline void
+xo_buf_append (xo_buffer_t *xbp, const char *str, int len)
+{
+ if (!xo_buf_has_room(xbp, len))
+ return;
+
+ memcpy(xbp->xb_curp, str, len);
+ xbp->xb_curp += len;
+}
+
+/*
+ * Append the given NUL-terminated string to the given buffer
+ */
+static inline 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;
+}
+
+#endif /* XO_BUF_H */
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_buf.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_config.h
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_config.h (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_config.h (revision 296962)
@@ -0,0 +1,247 @@
+/* libxo/xo_config.h. Generated from xo_config.h.in by configure. */
+/* libxo/xo_config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
+ systems. This function is required for `alloca.c' support on those systems.
+ */
+/* #undef CRAY_STACKSEG_END */
+
+/* Define to 1 if using `alloca.c'. */
+/* #undef C_ALLOCA */
+
+/* Define to 1 if you have `alloca', as a function or macro. */
+#define HAVE_ALLOCA 1
+
+/* Define to 1 if you have and it should be used (not on Ultrix).
+ */
+/* #undef HAVE_ALLOCA_H */
+
+/* Define to 1 if you have the `asprintf' function. */
+#define HAVE_ASPRINTF 1
+
+/* Define to 1 if you have the `bzero' function. */
+#define HAVE_BZERO 1
+
+/* Define to 1 if you have the `ctime' function. */
+#define HAVE_CTIME 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_CTYPE_H 1
+
+/* Define to 1 if you have the declaration of `__isthreaded', and to 0 if you
+ don't. */
+#define HAVE_DECL___ISTHREADED 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `dlfunc' function. */
+#define HAVE_DLFUNC 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the `fdopen' function. */
+#define HAVE_FDOPEN 1
+
+/* Define to 1 if you have the `flock' function. */
+#define HAVE_FLOCK 1
+
+/* Define to 1 if you have the `getpass' function. */
+#define HAVE_GETPASS 1
+
+/* Define to 1 if you have the `getprogname' function. */
+#define HAVE_GETPROGNAME 1
+
+/* Define to 1 if you have the `getrusage' function. */
+#define HAVE_GETRUSAGE 1
+
+/* gettext(3) */
+/* #undef HAVE_GETTEXT */
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* humanize_number(3) */
+#define HAVE_HUMANIZE_NUMBER 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `crypto' library (-lcrypto). */
+#define HAVE_LIBCRYPTO 1
+
+/* Define to 1 if you have the `m' library (-lm). */
+#define HAVE_LIBM 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_LIBUTIL_H 1
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+ to 0 otherwise. */
+#define HAVE_MALLOC 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_MEMORY_H 1
+
+/* Support printflike */
+/* #undef HAVE_PRINTFLIKE */
+
+/* Define to 1 if your system has a GNU libc compatible `realloc' function,
+ and to 0 otherwise. */
+#define HAVE_REALLOC 1
+
+/* Define to 1 if you have the `srand' function. */
+#define HAVE_SRAND 1
+
+/* Define to 1 if you have the `sranddev' function. */
+#define HAVE_SRANDDEV 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the header file. */
+/* #undef HAVE_STDIO_EXT_H */
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the header file. */
+/* #undef HAVE_STDTIME_TZFILE_H */
+
+/* Define to 1 if you have the `strchr' function. */
+#define HAVE_STRCHR 1
+
+/* Define to 1 if you have the `strcspn' function. */
+#define HAVE_STRCSPN 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strspn' function. */
+#define HAVE_STRSPN 1
+
+/* Have struct sockaddr_un.sun_len */
+#define HAVE_SUN_LEN 1
+
+/* Define to 1 if you have the `sysctlbyname' function. */
+#define HAVE_SYSCTLBYNAME 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_SYSCTL_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_THREADS_H 1
+
+/* thread-local setting */
+#define HAVE_THREAD_LOCAL THREAD_LOCAL_before
+
+/* Define to 1 if you have the header file. */
+/* #undef HAVE_TZFILE_H */
+
+/* Define to 1 if you have the header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `__flbf' function. */
+/* #undef HAVE___FLBF */
+
+/* Enable debugging */
+/* #undef LIBXO_DEBUG */
+
+/* Enable text-only rendering */
+/* #undef LIBXO_TEXT_ONLY */
+
+/* Version number as dotted value */
+#define LIBXO_VERSION "0.4.3"
+
+/* Version number extra information */
+#define LIBXO_VERSION_EXTRA ""
+
+/* Version number as a number */
+#define LIBXO_VERSION_NUMBER 4003
+
+/* Version number as string */
+#define LIBXO_VERSION_STRING "4003"
+
+/* Enable local wcwidth implementation */
+#define LIBXO_WCWIDTH 1
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#define LT_OBJDIR ".libs/"
+
+/* Name of package */
+#define PACKAGE "libxo"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "phil@juniper.net"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "libxo"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "libxo 0.4.3"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libxo"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.4.3"
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at runtime.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+/* #undef STACK_DIRECTION */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "0.4.3"
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to rpl_malloc if the replacement function should be used. */
+/* #undef malloc */
+
+/* Define to rpl_realloc if the replacement function should be used. */
+/* #undef realloc */
+
+/* Define to `unsigned int' if does not define. */
+/* #undef size_t */
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_config.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_create.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_create.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_create.3 (revision 296962)
@@ -0,0 +1,67 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_create , xo_create_to_file , xo_destroy
+.Nd create and destroy libxo output handles
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft xo_handle_t *
+.Fn xo_create "unsigned style" "unsigned flags"
+.Ft xo_handle_t *
+.Fn xo_create_to_file "FILE *fp" "unsigned style" "unsigned flags"
+.Ft void
+.Fn xo_destroy "xo_handle_t *handle"
+.Sh DESCRIPTION
+A
+.Nm libxo
+handle can be allocated using the
+.Fn xo_create
+function.
+.Bd -literal -offset indent
+ Example:
+ xo_handle_t *xop = xo_create(XO_STYLE_JSON, XOF_WARN);
+ ....
+ xo_emit_h(xop, "testing\n");
+.Ed
+.Pp
+By default,
+.Nm libxo
+writes output to standard output.
+A convenience
+function is provided for situations when output should be written to a
+different file.
+.Pp
+Use the
+.Dv XOF_CLOSE_FP
+flag to trigger a call to
+.Xr fclose 3
+for the
+.Dv FILE
+pointer when the handle is destroyed.
+.Pp
+The
+.Fn xo_destroy
+function releases a handle and any resources it is
+using.
+Calling
+.Fn xo_destroy
+with a
+.Dv NULL
+handle will release any
+resources associated with the default handle.
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr xo_set_options 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_create.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_emit.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_emit.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_emit.3 (revision 296962)
@@ -0,0 +1,104 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_emit , xo_emit_h , xo_emit_hv
+.Nd emit formatted output based on format string and arguments
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft int
+.Fn xo_emit "const char *fmt" "..."
+.Ft int
+.Fn xo_emit_h "xo_handle_t *xop" "const char *fmt" "..."
+.Ft int
+.Fn xo_emit_hv "xo_handle_t *xop" "const char *fmt" "va_list vap"
+.Sh DESCRIPTION
+The
+.Fn xo_emit
+function emits formatted output using the description in a format
+string along with a set of zero or more arguments, in a style similar
+to
+.Xr printf 3
+but using a more complex format description string, as described in
+.Xr xo_format 5 .
+.Pp
+.Fn xo_emit
+uses the default output handle, as described in
+.Xr libxo 3 ,
+where
+.Fn xo_emit_h
+uses an explicit handle.
+.Fn xo_emit_hv
+accepts a
+.Fa va_list
+for additional flexibility.
+.Sh EXAMPLES
+In this example, a set of four values is emitted using the following
+source code:
+.Bd -literal -offset indent
+ xo_emit(" {:lines/%7ju} {:words/%7ju} "
+ "{:characters/%7ju} {d:filename/%s}\n",
+ linect, wordct, charct, file);
+.Ed
+Output can then be generated in various style, using
+the "--libxo" option:
+.Bd -literal -offset indent
+ % wc /etc/motd
+ 25 165 1140 /etc/motd
+ % wc --libxo xml,pretty,warn /etc/motd
+
+
+ 25
+ 165
+ 1140
+ /etc/motd
+
+
+ % wc --libxo json,pretty,warn /etc/motd
+ {
+ "wc": {
+ "file": [
+ {
+ "lines": 25,
+ "words": 165,
+ "characters": 1140,
+ "filename": "/etc/motd"
+ }
+ ]
+ }
+ }
+ % wc --libxo html,pretty,warn /etc/motd
+
+
+
25
+
+
165
+
+
1140
+
+
/etc/motd
+
+.Ed
+.Sh RETURN CODE
+.Nm
+returns a negative value on error. If the
+.Nm XOF_COLUMNS
+flag has been turned on for the specific handle using
+.Xr xo_set_flags 3 ,
+then the number of display columns consumed by the output will be returned.
+.Sh SEE ALSO
+.Xr xo_open_container 3 ,
+.Xr xo_open_list 3 ,
+.Xr xo_format 5 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_emit.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_emit_err.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_emit_err.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_emit_err.3 (revision 296962)
@@ -0,0 +1,72 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_emit_err , xo_emit_errc , xo_emit_errx
+.Nm xo_emit_warn , xo_emit_warnx , xo_emit_warn_c , xo_emit_warn_hc
+.Nd emit errors and warnings in multiple output styles
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft void
+.Fn xo_emit_warn "const char *fmt" "..."
+.Ft void
+.Fn xo_emit_warnx "const char *fmt" "..."
+.Ft void
+.Fn xo_emit_warn_c "int code" "const char *fmt" "..."
+.Ft void
+.Fn xo_emit_warn_hc "xo_handle_t *xop" "int code, const char *fmt" "..."
+.Ft void
+.Fn xo_emit_err "int eval" "const char *fmt" "..."
+.Ft void
+.Fn xo_emit_errc "int eval" "int code" "const char *fmt" "..."
+.Ft void
+.Fn xo_emit_errx "int eval" "const char *fmt" "..."
+.Sh DESCRIPTION
+Many programs make use of the standard library functions
+.Xr err 3
+and
+.Xr warn 3
+to generate errors and warnings for the user.
+.Nm libxo
+wants to
+pass that information via the current output style, and provides
+compatible functions to allow this.
+.Pp
+The
+.Fa fmt
+argument is one compatible with
+.Xr xo_emit 3
+which allows these functions make structured data.
+To generate unstructured data,
+use the
+.Xr xo_err 3
+functions.
+.Pp
+These functions display the program name, a colon, a formatted message
+based on the arguments, and then optionally a colon and an error
+message associated with either
+.Fa errno
+or the
+.Fa code
+parameter.
+.Bd -literal -offset indent
+ EXAMPLE:
+ if (open(filename, O_RDONLY) < 0)
+ xo_err(1, "cannot open file '%s'", filename);
+.Ed
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr xo_format 5 ,
+.Xr xo_err 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_emit_err.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_encoder.c
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_encoder.c (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_encoder.c (revision 296962)
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2015, Juniper Networks, Inc.
+ * All rights reserved.
+ * This SOFTWARE is licensed under the LICENSE provided in the
+ * ../Copyright file. By downloading, installing, copying, or otherwise
+ * using the SOFTWARE, you agree to be bound by the terms of that
+ * LICENSE.
+ * Phil Shafer, August 2015
+ */
+
+/**
+ * libxo includes a number of fixed encoding styles. But other
+ * external encoders are need to deal with new encoders. Rather
+ * than expose a swarm of libxo internals, we create a distinct
+ * API, with a simpler API than we use internally.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "xo_config.h"
+#include "xo.h"
+#include "xo_encoder.h"
+
+#ifdef HAVE_DLFCN_H
+#include
+#if !defined(HAVE_DLFUNC)
+#define dlfunc(_p, _n) dlsym(_p, _n)
+#endif
+#else /* HAVE_DLFCN_H */
+#define dlopen(_n, _f) NULL /* Fail */
+#define dlsym(_p, _n) NULL /* Fail */
+#define dlfunc(_p, _n) NULL /* Fail */
+#endif /* HAVE_DLFCN_H */
+
+static void xo_encoder_setup (void); /* Forward decl */
+
+/*
+ * Need a simple string collection
+ */
+typedef struct xo_string_node_s {
+ TAILQ_ENTRY(xo_string_node_s) xs_link; /* Next string */
+ char xs_data[0]; /* String data */
+} xo_string_node_t;
+
+typedef TAILQ_HEAD(xo_string_list_s, xo_string_node_s) xo_string_list_t;
+
+static inline void
+xo_string_list_init (xo_string_list_t *listp)
+{
+ if (listp->tqh_last == NULL)
+ TAILQ_INIT(listp);
+}
+
+static inline xo_string_node_t *
+xo_string_add (xo_string_list_t *listp, const char *str)
+{
+ if (listp == NULL || str == NULL)
+ return NULL;
+
+ xo_string_list_init(listp);
+ size_t len = strlen(str);
+ xo_string_node_t *xsp;
+
+ xsp = xo_realloc(NULL, sizeof(*xsp) + len + 1);
+ if (xsp) {
+ memcpy(xsp->xs_data, str, len);
+ xsp->xs_data[len] = '\0';
+ TAILQ_INSERT_TAIL(listp, xsp, xs_link);
+ }
+
+ return xsp;
+}
+
+#define XO_STRING_LIST_FOREACH(_xsp, _listp) \
+ xo_string_list_init(_listp); \
+ TAILQ_FOREACH(_xsp, _listp, xs_link)
+
+static inline void
+xo_string_list_clean (xo_string_list_t *listp)
+{
+ xo_string_node_t *xsp;
+
+ xo_string_list_init(listp);
+
+ for (;;) {
+ xsp = TAILQ_FIRST(listp);
+ if (xsp == NULL)
+ break;
+ TAILQ_REMOVE(listp, xsp, xs_link);
+ xo_free(xsp);
+ }
+}
+
+static xo_string_list_t xo_encoder_path;
+
+void
+xo_encoder_path_add (const char *path)
+{
+ xo_encoder_setup();
+
+ if (path)
+ xo_string_add(&xo_encoder_path, path);
+}
+
+/* ---------------------------------------------------------------------- */
+
+typedef struct xo_encoder_node_s {
+ TAILQ_ENTRY(xo_encoder_node_s) xe_link; /* Next session */
+ char *xe_name; /* Name for this encoder */
+ xo_encoder_func_t xe_handler; /* Callback function */
+ void *xe_dlhandle; /* dlopen handle */
+} xo_encoder_node_t;
+
+typedef TAILQ_HEAD(xo_encoder_list_s, xo_encoder_node_s) xo_encoder_list_t;
+
+#define XO_ENCODER_LIST_FOREACH(_xep, _listp) \
+ xo_encoder_list_init(_listp); \
+ TAILQ_FOREACH(_xep, _listp, xe_link)
+
+static xo_encoder_list_t xo_encoders;
+
+static void
+xo_encoder_list_init (xo_encoder_list_t *listp)
+{
+ if (listp->tqh_last == NULL)
+ TAILQ_INIT(listp);
+}
+
+static xo_encoder_node_t *
+xo_encoder_list_add (const char *name)
+{
+ if (name == NULL)
+ return NULL;
+
+ xo_encoder_node_t *xep = xo_realloc(NULL, sizeof(*xep));
+ if (xep) {
+ int len = strlen(name) + 1;
+ xep->xe_name = xo_realloc(NULL, len);
+ if (xep->xe_name == NULL) {
+ xo_free(xep);
+ return NULL;
+ }
+
+ memcpy(xep->xe_name, name, len);
+
+ TAILQ_INSERT_TAIL(&xo_encoders, xep, xe_link);
+ }
+
+ return xep;
+}
+
+void
+xo_encoders_clean (void)
+{
+ xo_encoder_node_t *xep;
+
+ xo_encoder_setup();
+
+ for (;;) {
+ xep = TAILQ_FIRST(&xo_encoders);
+ if (xep == NULL)
+ break;
+
+ TAILQ_REMOVE(&xo_encoders, xep, xe_link);
+
+ if (xep->xe_dlhandle)
+ dlclose(xep->xe_dlhandle);
+
+ xo_free(xep);
+ }
+
+ xo_string_list_clean(&xo_encoder_path);
+}
+
+static void
+xo_encoder_setup (void)
+{
+ static int initted;
+ if (!initted) {
+ initted = 1;
+
+ xo_string_list_init(&xo_encoder_path);
+ xo_encoder_list_init(&xo_encoders);
+
+ xo_encoder_path_add(XO_ENCODERDIR);
+ }
+}
+
+static xo_encoder_node_t *
+xo_encoder_find (const char *name)
+{
+ xo_encoder_node_t *xep;
+
+ xo_encoder_list_init(&xo_encoders);
+
+ XO_ENCODER_LIST_FOREACH(xep, &xo_encoders) {
+ if (strcmp(xep->xe_name, name) == 0)
+ return xep;
+ }
+
+ return NULL;
+}
+
+static xo_encoder_node_t *
+xo_encoder_discover (const char *name)
+{
+ void *dlp = NULL;
+ char buf[MAXPATHLEN];
+ xo_string_node_t *xsp;
+ xo_encoder_node_t *xep = NULL;
+
+ XO_STRING_LIST_FOREACH(xsp, &xo_encoder_path) {
+ static const char fmt[] = "%s/%s.enc";
+ char *dir = xsp->xs_data;
+ size_t len = snprintf(buf, sizeof(buf), fmt, dir, name);
+
+ if (len > sizeof(buf)) /* Should not occur */
+ continue;
+
+ dlp = dlopen((const char *) buf, RTLD_NOW);
+ if (dlp)
+ break;
+ }
+
+ if (dlp) {
+ /*
+ * If the library exists, find the initializer function and
+ * call it.
+ */
+ xo_encoder_init_func_t func;
+
+ func = (xo_encoder_init_func_t) dlfunc(dlp, XO_ENCODER_INIT_NAME);
+ if (func) {
+ xo_encoder_init_args_t xei;
+
+ bzero(&xei, sizeof(xei));
+
+ xei.xei_version = XO_ENCODER_VERSION;
+ int rc = func(&xei);
+ if (rc == 0 && xei.xei_handler) {
+ xep = xo_encoder_list_add(name);
+ if (xep) {
+ xep->xe_handler = xei.xei_handler;
+ xep->xe_dlhandle = dlp;
+ }
+ }
+ }
+
+ if (xep == NULL)
+ dlclose(dlp);
+ }
+
+ return xep;
+}
+
+void
+xo_encoder_register (const char *name, xo_encoder_func_t func)
+{
+ xo_encoder_setup();
+
+ xo_encoder_node_t *xep = xo_encoder_find(name);
+
+ if (xep) /* "We alla-ready got one" */
+ return;
+
+ xep = xo_encoder_list_add(name);
+ if (xep)
+ xep->xe_handler = func;
+}
+
+void
+xo_encoder_unregister (const char *name)
+{
+ xo_encoder_setup();
+
+ xo_encoder_node_t *xep = xo_encoder_find(name);
+ if (xep) {
+ TAILQ_REMOVE(&xo_encoders, xep, xe_link);
+ xo_free(xep);
+ }
+}
+
+int
+xo_encoder_init (xo_handle_t *xop, const char *name)
+{
+ xo_encoder_setup();
+
+ /* Can't have names containing '/' or ':' */
+ if (strchr(name, '/') != NULL || strchr(name, ':') != NULL)
+ return -1;
+
+ /*
+ * First we look on the list of known (registered) encoders.
+ * If we don't find it, we follow the set of paths to find
+ * the encoding library.
+ */
+ xo_encoder_node_t *xep = xo_encoder_find(name);
+ if (xep == NULL) {
+ xep = xo_encoder_discover(name);
+ if (xep == NULL)
+ return -1;
+ }
+
+ xo_set_encoder(xop, xep->xe_handler);
+
+ return xo_encoder_handle(xop, XO_OP_CREATE, NULL, NULL);
+}
+
+/*
+ * A couple of function varieties here, to allow for multiple
+ * use cases. This varient is for when the main program knows
+ * its own encoder needs.
+ */
+xo_handle_t *
+xo_encoder_create (const char *name, xo_xof_flags_t flags)
+{
+ xo_handle_t *xop;
+
+ xop = xo_create(XO_STYLE_ENCODER, flags);
+ if (xop) {
+ if (xo_encoder_init(xop, name)) {
+ xo_destroy(xop);
+ xop = NULL;
+ }
+ }
+
+ return xop;
+}
+
+int
+xo_encoder_handle (xo_handle_t *xop, xo_encoder_op_t op,
+ const char *name, const char *value)
+{
+ void *private = xo_get_private(xop);
+ xo_encoder_func_t func = xo_get_encoder(xop);
+
+ if (func == NULL)
+ return -1;
+
+ return func(xop, op, name, value, private);
+}
+
+const char *
+xo_encoder_op_name (xo_encoder_op_t op)
+{
+ static const char *names[] = {
+ /* 0 */ "unknown",
+ /* 1 */ "create",
+ /* 2 */ "open_container",
+ /* 3 */ "close_container",
+ /* 4 */ "open_list",
+ /* 5 */ "close_list",
+ /* 6 */ "open_leaf_list",
+ /* 7 */ "close_leaf_list",
+ /* 8 */ "open_instance",
+ /* 9 */ "close_instance",
+ /* 10 */ "string",
+ /* 11 */ "content",
+ /* 12 */ "finish",
+ /* 13 */ "flush",
+ /* 14 */ "destroy",
+ /* 15 */ "attr",
+ /* 16 */ "version",
+ };
+
+ if (op > sizeof(names) / sizeof(names[0]))
+ return "unknown";
+
+ return names[op];
+}
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_encoder.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_encoder.h
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_encoder.h (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_encoder.h (revision 296962)
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2015, Juniper Networks, Inc.
+ * All rights reserved.
+ * This SOFTWARE is licensed under the LICENSE provided in the
+ * ../Copyright file. By downloading, installing, copying, or otherwise
+ * using the SOFTWARE, you agree to be bound by the terms of that
+ * LICENSE.
+ * Phil Shafer, August 2015
+ */
+
+/*
+ * NOTE WELL: This file is needed to software that implements an
+ * external encoder for libxo that allows libxo data to be encoded in
+ * new and bizarre formats. General libxo code should _never_
+ * include this header file.
+ */
+
+#ifndef XO_ENCODER_H
+#define XO_ENCODER_H
+
+/*
+ * Expose libxo's memory allocation functions
+ */
+extern xo_realloc_func_t xo_realloc;
+extern xo_free_func_t xo_free;
+
+typedef unsigned xo_encoder_op_t;
+
+/* Encoder operations; names are in xo_encoder.c:xo_encoder_op_name() */
+#define XO_OP_UNKNOWN 0
+#define XO_OP_CREATE 1 /* Called when the handle is init'd */
+#define XO_OP_OPEN_CONTAINER 2
+#define XO_OP_CLOSE_CONTAINER 3
+#define XO_OP_OPEN_LIST 4
+#define XO_OP_CLOSE_LIST 5
+#define XO_OP_OPEN_LEAF_LIST 6
+#define XO_OP_CLOSE_LEAF_LIST 7
+#define XO_OP_OPEN_INSTANCE 8
+#define XO_OP_CLOSE_INSTANCE 9
+#define XO_OP_STRING 10 /* Quoted UTF-8 string */
+#define XO_OP_CONTENT 11 /* Other content */
+#define XO_OP_FINISH 12 /* Finish any pending output */
+#define XO_OP_FLUSH 13 /* Flush any buffered output */
+#define XO_OP_DESTROY 14 /* Clean up function */
+#define XO_OP_ATTRIBUTE 15 /* Attribute name/value */
+#define XO_OP_VERSION 16 /* Version string */
+
+#define XO_ENCODER_HANDLER_ARGS \
+ xo_handle_t *xop __attribute__ ((__unused__)), \
+ xo_encoder_op_t op __attribute__ ((__unused__)), \
+ const char *name __attribute__ ((__unused__)), \
+ const char *value __attribute__ ((__unused__)), \
+ void *private __attribute__ ((__unused__))
+
+typedef int (*xo_encoder_func_t)(XO_ENCODER_HANDLER_ARGS);
+
+typedef struct xo_encoder_init_args_s {
+ unsigned xei_version; /* Current version */
+ xo_encoder_func_t xei_handler; /* Encoding handler */
+} xo_encoder_init_args_t;
+
+#define XO_ENCODER_VERSION 1 /* Current version */
+
+#define XO_ENCODER_INIT_ARGS \
+ xo_encoder_init_args_t *arg __attribute__ ((__unused__))
+
+typedef int (*xo_encoder_init_func_t)(XO_ENCODER_INIT_ARGS);
+/*
+ * Each encoder library must define a function named xo_encoder_init
+ * that takes the arguments defined in XO_ENCODER_INIT_ARGS. It
+ * should return zero for success.
+ */
+#define XO_ENCODER_INIT_NAME_TOKEN xo_encoder_library_init
+#define XO_STRINGIFY(_x) #_x
+#define XO_STRINGIFY2(_x) XO_STRINGIFY(_x)
+#define XO_ENCODER_INIT_NAME XO_STRINGIFY2(XO_ENCODER_INIT_NAME_TOKEN)
+extern int XO_ENCODER_INIT_NAME_TOKEN (XO_ENCODER_INIT_ARGS);
+
+void
+xo_encoder_register (const char *name, xo_encoder_func_t func);
+
+void
+xo_encoder_unregister (const char *name);
+
+void *
+xo_get_private (xo_handle_t *xop);
+
+void
+xo_encoder_path_add (const char *path);
+
+void
+xo_set_private (xo_handle_t *xop, void *opaque);
+
+xo_encoder_func_t
+xo_get_encoder (xo_handle_t *xop);
+
+void
+xo_set_encoder (xo_handle_t *xop, xo_encoder_func_t encoder);
+
+int
+xo_encoder_init (xo_handle_t *xop, const char *name);
+
+xo_handle_t *
+xo_encoder_create (const char *name, xo_xof_flags_t flags);
+
+int
+xo_encoder_handle (xo_handle_t *xop, xo_encoder_op_t op,
+ const char *name, const char *value);
+
+void
+xo_encoders_clean (void);
+
+const char *
+xo_encoder_op_name (xo_encoder_op_t op);
+
+#endif /* XO_ENCODER_H */
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_encoder.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_err.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_err.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_err.3 (revision 296962)
@@ -0,0 +1,74 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_err , xo_errc , xo_errx
+.Nm xo_warn , xo_warnx , xo_warn_c , xo_warn_hc
+.Nd emit errors and warnings in multiple output styles
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft void
+.Fn xo_warn "const char *fmt" "..."
+.Ft void
+.Fn xo_warnx "const char *fmt" "..."
+.Ft void
+.Fn xo_warn_c "int code" "const char *fmt" "..."
+.Ft void
+.Fn xo_warn_hc "xo_handle_t *xop" "int code, const char *fmt" "..."
+.Ft void
+.Fn xo_err "int eval" "const char *fmt" "..."
+.Ft void
+.Fn xo_errc "int eval" "int code" "const char *fmt" "..."
+.Ft void
+.Fn xo_errx "int eval" "const char *fmt" "..."
+.Sh DESCRIPTION
+Many programs make use of the standard library functions
+.Xr err 3
+and
+.Xr warn 3
+to generate errors and warnings for the user.
+.Nm libxo
+wants to
+pass that information via the current output style, and provides
+compatible functions to allow this.
+.Pp
+The
+.Fa fmt
+argument is one compatible with
+.Xr printf 3
+rather than
+.Xr xo_emit 3
+to aid in simple conversion. This means
+these functions make unstructured data.
+To generate structured data,
+use the
+.Xr xo_emit_err 3
+functions.
+.Pp
+These functions display the program name, a colon, a formatted message
+based on the arguments, and then optionally a colon and an error
+message associated with either
+.Fa errno
+or the
+.Fa code
+parameter.
+.Bd -literal -offset indent
+ EXAMPLE:
+ if (open(filename, O_RDONLY) < 0)
+ xo_err(1, "cannot open file '%s'", filename);
+.Ed
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr xo_emit_err 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_err.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_error.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_error.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_error.3 (revision 296962)
@@ -0,0 +1,41 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_error
+.Nd generate simple error messages in multiple output styles
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft void
+.Fn xo_error "const char *fmt" "..."
+.Sh DESCRIPTION
+Use the
+.Fn xo_error
+function to generate error messages to standard error.
+The
+.Fa fmt
+argument is a string containing printf-style formatting
+instructions that describe the remaining arguments.
+.Pp
+When converting an application to
+.Nm libxo ,
+one can replace
+.Em "fprintf(stderr,...)"
+calls with
+.Fn xo_error
+calls.
+.Sh SEE ALSO
+.Xr printf 3 ,
+.Xr xo_emit 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_error.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_finish.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_finish.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_finish.3 (revision 296962)
@@ -0,0 +1,39 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_finish , xo_finish_h
+.Nd finish formatting output
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft void
+.Fn xo_finish "void"
+.Ft void
+.Fn xo_finish_h "xo_handle_t *xop"
+.Sh DESCRIPTION
+When the program is ready to exit or close a handle, a call to
+.Fn xo_finish
+is required.
+This flushes any buffered data, closes
+open
+.Nm libxo
+constructs, and completes any pending operations.
+.Pp
+Calling this function is
+.Em vital
+to the proper operation of libxo,
+especially for the non-TEXT output styles.
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_finish.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_flush.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_flush.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_flush.3 (revision 296962)
@@ -0,0 +1,35 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_flush , xo_flush_h
+.Nd flush formatted output from libxo handle
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft void
+.Fn xo_flush "void"
+.Ft void
+.Fn xo_flush_h "xo_handle_t *handle"
+.Sh DESCRIPTION
+.Nm libxo
+buffers data, both for performance and consistency, but also to
+allow some advanced features to work properly.
+At various times, the
+caller may wish to flush any data buffered within the library.
+The
+.Fn xo_flush
+function is used for this.
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_flush.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_humanize.h
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_humanize.h (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_humanize.h (revision 296962)
@@ -0,0 +1,169 @@
+/* $NetBSD: humanize_number.c,v 1.8 2004/07/27 01:56:24 enami Exp $ */
+
+/*
+ * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* humanize_number(3) */
+#define HN_DECIMAL 0x01
+#define HN_NOSPACE 0x02
+#define HN_B 0x04
+#define HN_DIVISOR_1000 0x08
+
+#define HN_GETSCALE 0x10
+#define HN_AUTOSCALE 0x20
+
+static int
+xo_humanize_number (char *buf, size_t len, int64_t bytes,
+ const char *suffix, int scale, int flags)
+{
+ const char *prefixes, *sep;
+ int b, i, r, maxscale, s1, s2, sign;
+ int64_t divisor, max;
+ // We multiply bytes by 100 to deal with rounding, so we need something
+ // big enough to hold LLONG_MAX * 100. On 64-bit we can use 128-bit wide
+ // integers with __int128_t, but on 32-bit we have to use long double.
+#ifdef __LP64__
+ __int128_t scalable = (__int128_t)bytes;
+#else
+ long double scalable = (long double)bytes;
+#endif
+ size_t baselen;
+
+ assert(buf != NULL);
+ assert(suffix != NULL);
+ assert(scale >= 0);
+
+ if (flags & HN_DIVISOR_1000) {
+ /* SI for decimal multiplies */
+ divisor = 1000;
+ if (flags & HN_B)
+ prefixes = "B\0k\0M\0G\0T\0P\0E";
+ else
+ prefixes = "\0\0k\0M\0G\0T\0P\0E";
+ } else {
+ /*
+ * binary multiplies
+ * XXX IEC 60027-2 recommends Ki, Mi, Gi...
+ */
+ divisor = 1024;
+ if (flags & HN_B)
+ prefixes = "B\0K\0M\0G\0T\0P\0E";
+ else
+ prefixes = "\0\0K\0M\0G\0T\0P\0E";
+ }
+
+#define SCALE2PREFIX(scale) (&prefixes[(scale) << 1])
+ maxscale = 7;
+
+ if (scale >= maxscale &&
+ (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0)
+ return (-1);
+
+ if (buf == NULL || suffix == NULL)
+ return (-1);
+
+ if (len > 0)
+ buf[0] = '\0';
+ if (bytes < 0) {
+ sign = -1;
+ scalable *= -100;
+ baselen = 3; /* sign, digit, prefix */
+ } else {
+ sign = 1;
+ scalable *= 100;
+ baselen = 2; /* digit, prefix */
+ }
+ if (flags & HN_NOSPACE)
+ sep = "";
+ else {
+ sep = " ";
+ baselen++;
+ }
+ baselen += strlen(suffix);
+
+ /* Check if enough room for `x y' + suffix + `\0' */
+ if (len < baselen + 1)
+ return (-1);
+
+ if (scale & (HN_AUTOSCALE | HN_GETSCALE)) {
+ /* See if there is additional columns can be used. */
+ for (max = 100, i = len - baselen; i-- > 0;)
+ max *= 10;
+
+ for (i = 0; scalable >= max && i < maxscale; i++)
+ scalable /= divisor;
+
+ if (scale & HN_GETSCALE)
+ return (i);
+ } else
+ for (i = 0; i < scale && i < maxscale; i++)
+ scalable /= divisor;
+
+ /* If a value <= 9.9 after rounding and ... */
+ if (scalable < 995 && i > 0 && flags & HN_DECIMAL) {
+ /* baselen + \0 + .N */
+ if (len < baselen + 1 + 2)
+ return (-1);
+ b = ((int)scalable + 5) / 10;
+ s1 = b / 10;
+ s2 = b % 10;
+ r = snprintf(buf, len, "%s%d%s%d%s%s%s",
+ ((sign == -1) ? "-" : ""),
+ s1, localeconv()->decimal_point, s2,
+ sep, SCALE2PREFIX(i), suffix);
+ } else
+ r = snprintf(buf, len, "%s%lld%s%s%s",
+ /* LONGLONG */
+ ((sign == -1) ? "-" : ""),
+ (long long)((scalable + 50) / 100),
+ sep, SCALE2PREFIX(i), suffix);
+
+ return (r);
+}
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_humanize.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_message.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_message.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_message.3 (revision 296962)
@@ -0,0 +1,68 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_message , xo_message_c , xo_message_hc , xo_message_hcv
+.Nd emit messages in multiple output styles
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft void
+.Fn xo_message "const char *fmt" "..."
+.Ft void
+.Fn xo_message_e "const char *fmt" "..."
+.Ft void
+.Fn xo_message_c "int code" "const char *fmt" "..."
+.Ft void
+.Fn xo_message_hc "xo_handle_t *xop" "int code, const char *fmt" "..."
+.Ft void
+.Fn xo_message_hcv "xo_handle_t *xop" "int code" "const char *fmt" "va_list vap"
+.Sh DESCRIPTION
+.Nm xo_message
+generates text message which lack any sort of structure.
+These functions should not be used under normal conditions, since
+they completely defeat the value of using libxo. They are provided
+for scenarios when the output's content is genuinely unknown and
+unusable.
+It is used in converting programs where err/warn where not used,
+and error messages went to
+.Nm stdout ,
+not
+.Nm stderr .
+Use of
+.Nm xo_message
+allows backwards compatibility with that output, but does not put
+the error in a useful form.
+.Pp
+The
+.Nm xo_message
+function generates output strings using the printf-style format string
+and arguments provided.
+If the format string does not end in a newline,
+.Nm xo_message_e
+will appear a colon, a space, and the error associated with the current
+.Nm errno
+value.
+.Nm xo_message_c behaves similarly for the value passed in the
+.Fa code
+parameter.
+.Nm xo_message_hc
+accepts a
+.Fa handle
+as opened by
+.Xr xo_create 3
+and
+.Nm xo_message_hcv accepts a va_list parameter of arguments.
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_message.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_no_setlocale.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_no_setlocale.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_no_setlocale.3 (revision 296962)
@@ -0,0 +1,43 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_no_setlocale
+.Nd prevent implicit call to setlocale
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft void
+.Fn xo_no_setlocale "void"
+.Sh DESCRIPTION
+.Nm libxo
+automatically initializes the locale based on the setting of the
+environment variables
+.Ev LC_CTYPE ,
+.Ev LANG ,
+and
+.Ev LC_ALL .
+The first of this
+list of variables is used and if none of the variables are set, the locale
+defaults to
+.Em UTF-8 .
+The caller may wish to avoid this behavior, and
+can do so by calling the
+.Fn xo_no_setlocale
+function.
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr xo_open_container 3 ,
+.Xr xo_open_list 3 ,
+.Xr xo_format 5 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_no_setlocale.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_open_container.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_open_container.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_open_container.3 (revision 296962)
@@ -0,0 +1,188 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_open_container , xo_open_container_h , xo_open_container_hd , xo_open_container_d
+.Nm xo_close_container , xo_close_container_h , xo_close_container_hd , xo_close_container_d
+.Nd open (and close) container constructs
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft int
+.Fn xo_open_container "const char *name"
+.Ft int
+.Fn xo_open_container_h "xo_handle_t *handle" "const char *name"
+.Ft int
+.Fn xo_open_container_hd "xo_handle_t *handle" "const char *name"
+.Ft int
+.Fn xo_open_container_d "const char *name"
+.Ft int
+.Fn xo_close_container "const char *name"
+.Ft int
+.Fn xo_close_container_h "xo_handle_t *handle" "const char *name"
+.Ft int
+.Fn xo_close_container_hd "xo_handle_t *handle"
+.Ft int
+.Fn xo_close_container_d "void"
+.Sh DESCRIPTION
+.Nm libxo
+represents two types of hierarchy:
+.Dq containers
+and
+.Dq lists .
+A container appears once under a given parent where a list contains
+instances that can appear multiple times.
+A container is used to hold
+related fields and to give the data organization and scope.
+The container has no value, but serves to
+contain other nodes.
+.Pp
+To open a container, call
+.Fn xo_open_container
+or
+.Fn xo_open_container_h .
+The former uses the default handle and
+the latter accepts a specific handle.
+.Pp
+To close a level, use the
+.Fn xo_close_container
+or
+.Fn xo_close_container_h
+functions.
+.Pp
+Each open call should have a matching close call.
+If the
+.Dv XOF_WARN
+flag is set and the name given does not match the name of
+the currently open
+container, a warning will be generated.
+.Bd -literal -offset indent -compact
+ Example:
+
+ xo_open_container("top");
+ xo_open_container("system");
+ xo_emit("{:host-name/%s%s%s", hostname,
+ domainname ? "." : "", domainname ?: "");
+ xo_close_container("system");
+ xo_close_container("top");
+
+ Sample Output:
+ Text:
+ my-host.example.org
+ XML:
+
+
+ my-host.example.org
+
+
+ JSON:
+ "top" : {
+ "system" : {
+ "host-name": "my-host.example.org"
+ }
+ }
+ HTML:
+ my-host.example.org
+.Ed
+.Sh EMITTING HIERARCHY
+To create a container, use the
+.Fn xo_open_container
+and
+.Fn xo_close_container
+set of functions.
+The
+.Fa handle
+parameter contains a handle such as returned by
+.Xr xo_create 3
+or
+.Dv NULL
+to use the default handle.
+The
+.Fa name
+parameter gives the name of the container, encoded in
+.Em UTF-8 .
+Since
+.Em ASCII
+is a proper subset of
+.Em UTF-8 ,
+traditional C strings can be used directly.
+.Pp
+The close functions with the
+.Dq _d
+suffix are used in
+.Dq \&Do The Right Thing
+mode, where the name of the open containers, lists, and
+instances are maintained internally by
+.Nm libxo
+to allow the caller to
+avoid keeping track of the open container name.
+.Pp
+Use the
+.Dv XOF_WARN
+flag to generate a warning if the name given on the
+close does not match the current open container.
+.Pp
+For TEXT and HTML output, containers are not rendered into output
+text, though for HTML they are used when the
+.Dv XOF_XPATH
+flag is set.
+.Pp
+.Bd -literal -offset indent -compact
+ EXAMPLE:
+ xo_open_container("system");
+ xo_emit("The host name is {:host-name}\n", hn);
+ xo_close_container("system");
+ XML:
+ foo
+.Ed
+.Sh DTRT MODE
+Some users may find tracking the names of open containers, lists, and
+instances inconvenient.
+.Nm libxo
+offers a
+.Dq \&Do The Right Thing
+mode, where
+.Nm libxo
+will track the names of open containers, lists, and instances so
+the close function can be called without a name.
+To enable
+.Em DTRT
+mode,
+turn on the
+.Dv XOF_DTRT
+flag prior to making any other
+.Nm libxo
+output.
+.Bd -literal -offset indent -compact
+ xo_set_flags(NULL, XOF_DTRT);
+.Ed
+Each open and close function has a version with the suffix
+.Dq _d ,
+which will close the open container, list, or instance:
+.Bd -literal -offset indent -compact
+ xo_open_container("top");
+ ...
+ xo_close_container_d();
+.Ed
+Note that the
+.Dv XOF_WARN
+flag will also cause
+.Nm libxo
+to track open
+containers, lists, and instances.
+A warning is generated when the name given to the close function
+and the name recorded do not match.
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_open_container.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_open_list.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_open_list.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_open_list.3 (revision 296962)
@@ -0,0 +1,158 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_open_list , xo_open_list_h , xo_open_list_hd , xo_open_list_d
+.Nm xo_open_instance , xo_open_instance_h , xo_open_instance_hd , xo_open_instance_d
+.Nm xo_close_instance , xo_close_instance_h , xo_close_instance_hd , xo_close_instnace_d
+.Nm xo_close_list , xo_close_list_h , xo_close_list_hd , xo_close_list_d
+.Nd open and close lists and instances
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft int
+.Fn xo_open_list_h "xo_handle_t *xop" "const char *name"
+.Ft int
+.Fn xo_open_list "const char *name"
+.Ft int
+.Fn xo_open_list_hd "xo_handle_t *xop" "const char *name"
+.Ft int
+.Fn xo_open_list_d "const char *name"
+.Ft int
+.Fn xo_open_instance_h "xo_handle_t *xop" "const char *name"
+.Ft int
+.Fn xo_open_instance "const char *name"
+.Ft int
+.Fn xo_open_instance_hd "xo_handle_t *xop" "const char *name"
+.Ft int
+.Fn xo_open_instance_d "const char *name"
+.Ft int
+.Fn xo_close_instance_h "xo_handle_t *xop" "const char *name"
+.Ft int
+.Fn xo_close_instance "const char *name"
+.Ft int
+.Fn xo_close_instance_hd "xo_handle_t *xop"
+.Ft int
+.Fn xo_close_instance_d "void"
+.Ft int
+.Fn xo_close_list_h "xo_handle_t *xop" "const char *name"
+.Ft int
+.Fn xo_close_list "const char *name"
+.Ft int
+.Fn xo_close_list_hd "xo_handle_t *xop"
+.Ft int
+.Fn xo_close_list_d "void"
+.Sh DESCRIPTION
+Lists are sequences of instances of homogeneous data objects.
+Two
+distinct levels of calls are needed to represent them in our output
+styles.
+Calls must be made to open and close a list, and for each
+instance of data in that list, calls must be make to open and close
+that instance.
+.Pp
+The name given to all calls must be identical, and it is strongly
+suggested that the name be singular, not plural, as a matter of
+style and usage expectations.
+.Pp
+A list is a set of one or more instances that appear under the same
+parent.
+The instances contain details about a specific object.
+One can think of instances as objects or records.
+A call is needed to
+open and close the list, while a distinct call is needed to open and
+close each instance of the list:
+.Bd -literal -offset indent -compact
+ xo_open_list("item");
+
+ for (ip = list; ip->i_title; ip++) {
+ xo_open_instance("item");
+ xo_emit("{L:Item} '{:name/%s}':\n", ip->i_title);
+ xo_close_instance("item");
+ }
+
+ xo_close_list("item");
+.Ed
+Getting the list and instance calls correct is critical to the proper
+generation of XML and JSON data.
+.Pp
+.Bd -literal -offset indent -compact
+ EXAMPLE:
+ xo_open_list("user");
+ for (i = 0; i < num_users; i++) {
+ xo_open_instance("user");
+ xo_emit("{k:name}:{:uid/%u}:{:gid/%u}:{:home}\n",
+ pw[i].pw_name, pw[i].pw_uid,
+ pw[i].pw_gid, pw[i].pw_dir);
+ xo_close_instance("user");
+ }
+ xo_close_list("user");
+ TEXT:
+ phil:1001:1001:/home/phil
+ pallavi:1002:1002:/home/pallavi
+ XML:
+
+ phil
+ 1001
+ 1001
+ /home/phil
+
+
+ pallavi
+ 1002
+ 1002
+ /home/pallavi
+
+ JSON:
+ user: [
+ {
+ "name": "phil",
+ "uid": 1001,
+ "gid": 1001,
+ "home": "/home/phil",
+ },
+ {
+ "name": "pallavi",
+ "uid": 1002,
+ "gid": 1002,
+ "home": "/home/pallavi",
+ }
+ ]
+.Ed
+.Pp
+.Sh LEAF LISTS
+In contrast to a list of instances, a "leaf list" is list of simple
+values.
+To emit a leaf list, call the
+.Fn xo_emit
+function using the ""l"" modifier:
+.Bd -literal -offset indent -compact
+ for (ip = list; ip->i_title; ip++) {
+ xo_emit("{Lwc:Item}{l:item}\n", ip->i_title);
+ }
+.Ed
+.Pp
+The name of the field must match the name of the leaf list.
+.Pp
+In JSON, leaf lists are rendered as arrays of values. In XML, they
+are rendered as multiple leaf elements.
+.Bd -literal -offset indent -compact
+ JSON:
+ "item": "hammer", "nail"
+ XML:
+ - hammer
+ - nail
+.Ed
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_open_list.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_open_marker.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_open_marker.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_open_marker.3 (revision 296962)
@@ -0,0 +1,105 @@
+.\" #
+.\" # Copyright (c) 2015, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, January 2015
+.\"
+.Dd January 22, 2015
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_open_marker , xo_open_marker_h , xo_close_marker , xo_close_marker_h
+.Nd prevent and allow closing of open constructs
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft int
+.Fn xo_open_marker "const char *name"
+.Ft int
+.Fn xo_open_marker_h "xo_handle_t *handle" "const char *name"
+.Ft int
+.Fn xo_close_marker "const char *name"
+.Ft int
+.Fn xo_close_marker_h "xo_handle_t *handle" "const char *name"
+.Sh DESCRIPTION
+.Nm libxo
+represents hierarchy using two constructs:
+.Dq containers
+and
+.Dq lists .
+A marker can be used to affect how open constructs are closed, either
+by preventing their (implicit or explicit) closure or by forcing their
+closure.
+While a marker is open, no other open constructs can be closed.
+When a marker is closed, all constructs open since the marker was opened
+will be closed.
+A marker is used to "freeze" any open constructs.
+Calls to
+.Fn xo_close_*
+functions that would normally close them will be ignored, effectively
+blocking their closure.
+However when
+.Fn xo_close_marker
+is called, any containers, lists, or leaf-lists open since the
+matching
+.Fn xo_open_marker
+call will be close and the marker discarded.
+Markers use names which are not user-visible, allowing the caller to
+choose appropriate internal names.
+The marker has no value and is not emitted in any form.
+.Pp
+To open a marker, call
+.Fn xo_open_marker
+or
+.Fn xo_open_marker_h .
+The former uses the default handle and
+the latter accepts a specific handle.
+.Pp
+To close a marker, use the
+.Fn xo_close_marker
+or
+.Fn xo_close_marker_h
+functions.
+.Pp
+Each open call must have a matching close call.
+.Pp
+In this example, the
+.Fn xo_close_container
+call on line [1] will be ignored, since the open marker "outer"
+will prevent close of any open constructs that precede it.
+The
+.Fn xo_close_marker
+call on line [2] will close the "system" container, since it was
+opened after the "outer" marker.
+.Bd -literal -offset indent -compact
+ Example:
+
+ xo_open_container("top");
+ xo_open_marker("outer");
+ xo_open_container("system");
+ xo_emit("{:host-name/%s%s%s", hostname,
+ domainname ? "." : "", domainname ?: "");
+ xo_close_container("top"); /* [1] */
+ xo_close_marker("outer"); /* [2] */
+ xo_close_container("top");
+.Ed
+.Pp
+In this example, the code whiffles through a list of fish, calling a
+function to emit details about each fish. The marker "fish-guts" is
+used to ensure that any constructs opened by the function are closed
+properly.
+.Bd -literal -offset indent
+ for (i = 0; fish[i]; i++) {
+ xo_open_instance("fish");
+ xo_open_marker("fish-guts");
+ dump_fish_details(i);
+ xo_close_marker("fish-guts");
+ }
+.Ed
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_open_marker.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_parse_args.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_parse_args.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_parse_args.3 (revision 296962)
@@ -0,0 +1,148 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_parse_args , xo_set_program
+.Nd detect, parse, and remove arguments for libxo
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft int
+.Fn xo_parse_args "int argc" "char **argv"
+.Ft int
+.Fn xo_set_program "const char *name"
+.Sh DESCRIPTION
+The
+.Fn xo_parse_args
+function is used to process command-line arguments.
+.Nm libxo
+specific
+options are processed and removed
+from the argument list so the calling application does not
+need to process them.
+If successful, a new value for argc is returned.
+On failure, a message it emitted and -1 is returned.
+.Bd -literal -offset indent
+ argc = xo_parse_args(argc, argv);
+ if (argc < 0)
+ exit(EXIT_FAILURE);
+.Ed
+.Pp
+Following the call to
+.Fn xo_parse_args ,
+the application can process the remaining arguments in a normal manner.
+.Pp
+.Nm libxo
+uses command line options to trigger rendering behavior.
+The following options are recognised:
+.Pp
+.Bl -tag -width "--libxo"
+.It
+\-\^\-libxo
+.It
+\-\^\-libxo=
+.It
+\-\^\-libxo:
+.El
+.Pp
+Options is a comma-separated list of tokens that correspond to output
+styles, flags, or features:
+.Pp
+.Bl -tag -width "12345678"
+.It Sy "Token Action"
+.It Dv dtrt
+Enable "Do The Right Thing" mode
+.It Dv html
+Emit HTML output
+.It Dv indent=xx
+Set the indentation level
+.It Dv info
+Add info attributes (HTML)
+.It Dv json
+Emit JSON output
+.It Dv keys
+Emit the key attribute for keys (XML)
+.It Dv log-gettext
+Log (via stderr) each
+.Xr gettext 3
+string lookup
+.It Dv log-syslog
+Log (via stderr) each syslog message (via
+.Xr xo_syslog 3 )
+.If Dv no-humanize
+Ignore the {h:} modifier (TEXT, HTML)
+.It Dv no-locale
+Do not initialize the locale setting
+.It Dv no-top
+Do not emit a top set of braces (JSON)
+.It Dv not-first
+Pretend the 1st output item was not 1st (JSON)
+.It Dv pretty
+Emit pretty-printed output
+.It Dv text
+Emit TEXT output
+.If Dv underscores
+Replace XML-friendly "-"s with JSON friendly "_"s e
+.It Dv units
+Add the 'units' (XML) or 'data-units (HTML) attribute
+.It Dv warn
+Emit warnings when libxo detects bad calls
+.It Dv warn-xml
+Emit warnings in XML
+.It Dv xml
+Emit XML output
+.It Dv xpath
+Add XPath expressions (HTML)
+.El
+.Pp
+The
+.Dq brief-options
+are single letter commands, designed for those with
+too little patience to use real tokens.
+No comma separator is used.
+.Bl -column "i"
+.It Sy "Token Action"
+.It "H " "Enable HTML output (XO_STYLE_HTML)"
+.It "I " "Enable info output (XOF_INFO)"
+.It "i " "Indent by "
+.It "J " "Enable JSON output (XO_STYLE_JSON)"
+.It "P " "Enable pretty-printed output (XOF_PRETTY)"
+.It "T " "Enable text output (XO_STYLE_TEXT)"
+.It "W " "Enable warnings (XOF_WARN)"
+.It "X " "Enable XML output (XO_STYLE_XML)"
+.It "x " "Enable XPath data (XOF_XPATH)"
+.El
+.Pp
+The
+.Fn xo_set_program
+function sets name of the program as reported by
+functions like
+.Fn xo_failure ,
+.Fn xo_warn ,
+.Fn xo_err ,
+etc.
+The program name is initialized by
+.Fn xo_parse_args ,
+but subsequent calls to
+.Fn xo_set_program
+can override this value.
+.Pp
+Note that the value is not copied, so the memory passed to
+.Fn xo_set_program
+(and
+.Fn xo_parse_args )
+must be maintained by the caller.
+.Pp
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_parse_args.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_set_allocator.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_set_allocator.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_set_allocator.3 (revision 296962)
@@ -0,0 +1,54 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_set_allocator
+.Nd set allocation functions for libxo
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Sy typedef void *(*xo_realloc_func_t)(void *, size_t);
+.Pp
+.Sy typedef void (*xo_free_func_t)(void *);
+.Ft void
+.Fn xo_set_allocator "xo_realloc_func_t realloc_func" "xo_free_func_t free_func"
+.Sh DESCRIPTION
+The
+.Fn xo_set_allocator
+function allows
+.Nm libxo
+to be used in environments
+where the standard
+.Xr realloc 3
+and
+.Xr free 3
+functions are not available.
+.Pp
+.Fa realloc_func
+should expect the same arguments as
+.Xr realloc 3
+and return
+a pointer to memory following the same convention.
+.Fa free_func
+will receive the same argument as
+.Xr free 3
+and should release it, as appropriate for the environment.
+.Pp
+By default, the standard
+.Xr realloc 3
+and
+.Xr free 3
+functions are used.
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_set_allocator.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_set_flags.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_set_flags.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_set_flags.3 (revision 296962)
@@ -0,0 +1,139 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_set_flags , xo_clear_flags
+.Nd set operational flags for a libxo handle
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft void
+.Fn xo_set_flags "xo_handle_t *handle" "unsigned flags"
+.Ft void
+.Fn xo_clear_flags "xo_handle_t *handle" "xo_xof_flags_t flags"
+.Sh DESCRIPTION
+Use the
+.Fn xo_set_flags
+function to set the flags for a
+.Nm libxo
+handle.
+To use the default handle, pass a
+.Dv NULL
+handle.
+.Pp
+The set of valid flags include:
+.Bl -tag -width "XOF_UNDERSCORES"
+.It Sy "Flag Description"
+.It Dv XOF_CLOSE_FP
+Close file pointer on
+.Xr xo_destroy 3 .
+This flag will trigger the call of the
+.Fn close_func
+(provided via
+.Xr xo_set_writer 3 )
+when the handle is destroyed.
+.It Dv XOF_COLOR
+Enable color and effects in output regardless of output device.
+.It Dv XOF_COLOR_ALLOWED
+Allow color and effects if the output device is a terminal.
+.It Dv XOF_INFO
+Display info data attributes (HTML)
+.It Dv XOF_KEYS
+Emit the key attribute (XML)
+.It Dv XOF_LOG_GETTEXT
+Log (via stderr) each
+.Xr gettext 3
+string lookup
+.It Dv XOF_LOG_SYSLOG
+Log (via stderr) each syslog message (via
+.Xr xo_syslog 3 )
+.It Dv XOF_NO_ENV
+Do not use the
+.Ev LIBXO_OPTIONS
+environment variable.
+.It Dv XOF_PRETTY
+Make 'pretty printed' output, with the
+addition of indentation and newlines to enhance the readability of
+XML, JSON, and HTML output.
+Text output is not affected.
+.It Dv XOF_UNDERSCORES
+Replaces hyphens with underscores
+.It Dv XOF_UNITS
+Display units (XML and HMTL)
+.It Dv XOF_WARN
+Generate warnings for broken calls, triggering diagnostic
+output (on standard error) when the library notices errors during
+operations, or with arguments to functions.
+Without warnings enabled, such conditions are ignored.
+Warnings allow developers to debug their interaction with
+.Nm libxo .
+The function
+.Fn xo_failure
+can be used as a breakpoint for a debugger,
+regardless of whether warnings are enabled.
+.It Dv XOF_WARN_XML
+Generate warnings in XML on stdout
+.It Dv XOF_XPATH
+Emit XPath expressions (HTML)
+.It Dv XOF_COLUMNS
+Force
+.Xr xo_emit 3
+to return columns used
+.It Dv XOF_FLUSH
+Flush output after each
+.Xr xo_emit 3
+call
+.El
+.Pp
+If the style is
+.Dv XO_STYLE_HTML ,
+the following additional flags can be
+used:
+.Bl -tag -width "XOF_UNDERSCORES"
+.It Sy "Flag Description"
+.It Dv XOF_XPATH
+Emit "data-xpath" attributes
+.It Dv XOF_INFO
+Emit additional informational fields for HTML
+output.
+See
+.Xr xo_set_info 3
+for details.
+.El
+.Pp
+The
+.Dv XOF_XPATH
+flag enables the emission of XPath expressions detailing
+the hierarchy of XML elements used to encode the data field, if the
+XPATH style of output were requested.
+.Pp
+If the style is
+.Dv XO_STYLE_XML ,
+the following additional flags can be
+used:
+.Bl -tag -width "XOF_UNDERSCORES"
+.It Sy "Flag Description"
+.It XOF_KEYS
+Add 'key' attribute to the XML encoding for
+field definitions that use the 'k' modifier.
+The key attribute has
+the value "key".
+.El
+.Pp
+The
+.Fn xo_clear_flags
+function turns off the given flags in a specific
+handle.
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_set_flags.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_set_info.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_set_info.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_set_info.3 (revision 296962)
@@ -0,0 +1,102 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_set_info
+.Nd set the field information data for libxo
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft void
+.Fn xo_set_info "xo_handle_t *handle" "xo_info_t *info" "int count"
+.Sh DESCRIPTION
+HTML data can include additional information in attributes that
+begin with "data-".
+To enable this, three things must occur:
+.Pp
+First the application must build an array of
+.Dv xo_info_t
+structures,
+one per tag.
+The array must be sorted by name, since
+.Nm libxo
+uses a
+binary search to find the entry that matches names from format
+instructions.
+.Pp
+The
+.Dv xo_info_t
+structure is defined in
+.In libxo/xo.h :
+.Bd -literal -offset indent
+ typedef struct xo_info_s {
+ const char *xi_name; /* Name of the element */
+ const char *xi_type; /* Type of field */
+ const char *xi_help; /* Description of field */
+ } xo_info_t;
+.Ed
+.Pp
+Second, the application must inform
+.Nm libxo
+about this information using the
+.Fn xo_set_info
+call.
+Like other
+.Nm libxo
+calls, passing
+.Dv NULL
+for the handle tells
+.Nm libxo
+to use the default handle.
+.Pp
+If the
+.Fa count
+is -1,
+.Nm libxo
+will count the elements of
+.Fa info ,
+but there
+must be an empty element at the end.
+More typically, the number is
+known to the application:
+.Bd -literal -offset indent
+ xo_info_t info[] = {
+ { "in-stock", "number", "Number of items in stock" },
+ { "name", "string", "Name of the item" },
+ { "on-order", "number", "Number of items on order" },
+ { "sku", "string", "Stock Keeping Unit" },
+ { "sold", "number", "Number of items sold" },
+ };
+ int info_count = (sizeof(info) / sizeof(info[0]));
+ ...
+ xo_set_info(NULL, info, info_count);
+.Ed
+.Pp
+Third, the emission of info must be triggered with the
+.Dv XOF_INFO
+flag
+using either the
+.Fn xo_set_flags
+function or the
+.Dq --libxo=info
+command line argument.
+.Pp
+The type and help values, if present, are emitted as the "data-type"
+and "data-help" attributes:
+.Bd -literal -offset indent
+ GRO-000-533
+.Ed
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_set_info.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_set_options.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_set_options.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_set_options.3 (revision 296962)
@@ -0,0 +1,31 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_set_options
+.Nd change options used by a libxo handle
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft int
+.Fn xo_set_options "xo_handle_t *xop" "const char *input"
+.Sh DESCRIPTION
+The
+.Fn xo_set_options
+function accepts a comma-separated list of styles
+and flags and enables them for a specific handle.
+The options are identical to those listed in
+.Xr xo_parse_args 3 .
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_set_options.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_set_style.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_set_style.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_set_style.3 (revision 296962)
@@ -0,0 +1,53 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_set_style , xo_set_style_name
+.Nd set the output style for a libxo handle
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft void
+.Fn xo_set_style "xo_handle_t *handle" "unsigned style"
+.Ft int
+.Fn xo_set_style_name "xo_handle_t *handle" "const char *style"
+.Sh DESCRIPTION
+Use the
+.Fn xo_set_style
+function to set the output style for a handle.
+To use the default handle, pass a
+.Dv NULL
+handle.
+The set of output styles used by
+.Nm libxo
+is:
+.Bl -column "XO_STYLE_TEXT12"
+.It Sy "Flag Description"
+.It "XO_STYLE_TEXT Traditional text output"
+.It "XO_STYLE_XML XML encoded data"
+.It "XO_STYLE_JSON JSON encoded data"
+.It "XO_STYLE_HTML HTML encoded data"
+.El
+.Pp
+The
+.Fn xo_set_style_name
+function can be used to set the style based on a name
+encoded as a string.
+The name can be any of the styles: "text", "xml", "json", or "html".
+.Bd -literal -offset indent
+ EXAMPLE:
+ xo_set_style_name(NULL, "html");
+.Ed
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_set_style.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_set_syslog_enterprise_id.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_set_syslog_enterprise_id.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_set_syslog_enterprise_id.3 (revision 296962)
@@ -0,0 +1,36 @@
+.\" #
+.\" # Copyright (c) 2015, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2015
+.\"
+.Dd July 20, 2015
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_set_syslog_enterprise_id
+.Nd Set the enterprise identifier for syslog content
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft void
+.Fn xo_set_syslog_enterprise_id "unsigned short eid"
+.Ft void
+.Sh DESCRIPTION
+The
+.Fn xo_set_syslog_enterprise_id
+function records an enterprise identifier used for subsequent
+.Xr xo_syslog 3
+calls.
+Enterprise IDs are
+defined by IANA, the Internet Assigned Numbers Authority:
+.Bd -literal -offset indent
+https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers
+.Ed
+.Sh SEE ALSO
+.Xr xo_syslog 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_set_syslog_enterprise_id.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_set_version.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_set_version.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_set_version.3 (revision 296962)
@@ -0,0 +1,34 @@
+.\" #
+.\" # Copyright (c) 2015, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_set_version , xo_set_version_h
+.Nd record content-version information in encoded output
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft void
+.Fn xo_set_version "const char *version"
+.Ft void
+.Fn xo_set_version_h "xo_handle_t *xop" "const char *version"
+.Sh DESCRIPTION
+The
+.Nm 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.
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_set_version.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_set_writer.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_set_writer.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_set_writer.3 (revision 296962)
@@ -0,0 +1,56 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_set_writer
+.Nd set custom writer functions for a libxo handle
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft void
+.Sy typedef int (*xo_write_func_t)(void *, const char *);
+.Pp
+.Sy typedef void (*xo_close_func_t)(void *);
+.Pp
+.Sy typedef int (*xo_flush_func_t)(void *);
+.Fn xo_set_writer "xo_handle_t *handle" "void *opaque"
+ "xo_write_func_t write_func"
+ "xo_close_func_t close_func"
+ "xo_flush_func_t flush_func"
+.Sh DESCRIPTION
+The
+.Fn xo_set_writer
+function allows custom
+.Dq write
+functions
+which can tailor how
+.Nm libxo
+writes data.
+An
+.Fa opaque
+argument is
+recorded and passed back to the
+.Fa write_func
+function, allowing the function
+to acquire context information.
+The
+.Fa close_func
+function can
+release this opaque data and any other resources as needed.
+The
+.Fa flush_func
+function should
+flush any pending data associated with the opaque pointer.
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_set_writer.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_syslog.3
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_syslog.3 (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_syslog.3 (revision 296962)
@@ -0,0 +1,79 @@
+.\" #
+.\" # Copyright (c) 2015, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2015
+.\"
+.Dd July 20, 2015
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_syslog , xo_vsyslog , xo_open_log , xo_close_log , xo_set_logmask
+.Nd create SYSLOG (RFC5424) log records using libxo formatting
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft void
+.Fn xo_syslog "int pri" "const char *name" "const char *fmt" "..."
+.Ft void
+.Fn xo_vsyslog "int pri" "const char *name" "const char *fmt" "va_list vap"
+.Ft void
+.Fn xo_close_log "void"
+.Ft void
+.Fn xo_open_log "const char *ident" "int logstat" "int logfac"
+.Ft int
+.Fn xo_set_logmask "int pmask"
+.Sh DESCRIPTION
+The
+.Fn xo_syslog
+function creates log entries following the standard defined in
+RFC5424.
+These messages are sent to the log
+.Xr syslogd 8
+daemon, where they can be filtered, forwarded, and archived.
+.Nm libxo
+format strings are used to create both the message text and the
+.Nm SD-PARAMS
+content, containing name/value pairs that can be parsed by suitable
+automation software.
+.Pp
+Refer to
+.Xr xo_format 5
+for basic information about formatting strings.
+.Nm xo_syslog
+encodes all value fields at SD-PARAMS within the syslog message.
+An exception is made for fields with the "{d:}" modifier; such fields
+appear in the message text only, with fields with the "{e:}" modifier
+appear as SD-PARAMS, but not in the message text.
+.Pp
+.Fn xo_vsyslog
+accepts a
+.Fa va_list
+for additional flexibility.
+.Pp
+.Fn xo_open_log ,
+.Fn xo_close_log , and
+.Fn xo_set_logmask
+are all analogous to their libs counterparts,
+.Xr openlog 3 ,
+.Xr closelog 3 , and
+.Xr setlogmask 3 .
+The extra underscores in the names are unfortunate, but keep
+consistency in
+.Nm libxo
+function names.
+.Sh EXAMPLES
+.Bd -literal -offset indent
+ xo_syslog(LOG_LOCAL4 | LOG_NOTICE, "ID47",
+ "{e:iut/%u}An {:event-source} {:event-id/%u} log entry",
+ iut, source, id);
+.Ed
+.Sh SEE ALSO
+.Xr xo_syslog 3 ,
+.Xr xo_set_syslog_enterprise_id 3 ,
+.Xr xo_format 5 ,
+.Xr libxo 3
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_syslog.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/xo_syslog.c
===================================================================
--- vendor/Juniper/libxo/dist/libxo/xo_syslog.c (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/xo_syslog.c (revision 296962)
@@ -0,0 +1,706 @@
+/*
+ * Copyright (c) 2015, Juniper Networks, Inc.
+ * All rights reserved.
+ * This SOFTWARE is licensed under the LICENSE provided in the
+ * ../Copyright file. By downloading, installing, copying, or otherwise
+ * using the SOFTWARE, you agree to be bound by the terms of that
+ * LICENSE.
+ * Phil Shafer, June 2015
+ */
+
+/*
+ * Portions of this file are:
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "xo_config.h"
+#include "xo.h"
+#include "xo_encoder.h" /* For xo_realloc */
+#include "xo_buf.h"
+
+/*
+ * SYSLOG (RFC 5424) requires an enterprise identifier. This turns
+ * out to be a fickle little issue. For a single-vendor box, the
+ * system should have a single EID that all software can use. When
+ * VendorX turns FreeBSD into a product, all software (kernel and
+ * utilities) should report VendorX's EID. But when software is
+ * installed on top of an external operating system, the application
+ * should report it's own EID, distinct from the base OS.
+ *
+ * To make this happen, the kernel should support a sysctl to assign a
+ * custom enterprise-id ("kern.syslog.enterprise_id"). libxo then
+ * allows an application to set a custom EID to override that system
+ * wide value, if needed.
+ *
+ * We try to set the stock IANA assigned Enterprise ID value for the
+ * vendors we know about (FreeBSD, macosx), but fallback to the
+ * "example" EID defined by IANA. See:
+ * https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers
+ */
+
+#define XO_SYSLOG_ENTERPRISE_ID "kern.syslog.enterprise_id"
+
+#if defined(__FreeBSD__)
+#define XO_DEFAULT_EID 2238
+#elif defined(__macosx__)
+#define XO_DEFAULT_EID 63
+#else
+#define XO_DEFAULT_EID 32473 /* Bail; use "example" number */
+#endif
+
+#ifdef _SC_HOST_NAME_MAX
+#define HOST_NAME_MAX _SC_HOST_NAME_MAX
+#else
+#define HOST_NAME_MAX 255
+#endif /* _SC_HOST_NAME_MAX */
+
+#ifndef UNUSED
+#define UNUSED __attribute__ ((__unused__))
+#endif /* UNUSED */
+
+static int xo_logfile = -1; /* fd for log */
+static int xo_status; /* connection xo_status */
+static int xo_opened; /* have done openlog() */
+static int xo_logstat = 0; /* xo_status bits, set by openlog() */
+static const char *xo_logtag = NULL; /* string to tag the entry with */
+static int xo_logfacility = LOG_USER; /* default facility code */
+static int xo_logmask = 0xff; /* mask of priorities to be logged */
+static pthread_mutex_t xo_syslog_mutex UNUSED = PTHREAD_MUTEX_INITIALIZER;
+static int xo_unit_test; /* Fake data for unit test */
+
+#define REAL_VOID(_x) \
+ do { int really_ignored = _x; if (really_ignored) { }} while (0)
+
+#if !defined(HAVE_DECL___ISTHREADED) || !HAVE_DECL___ISTHREADED
+#define __isthreaded 1
+#endif
+
+#define THREAD_LOCK() \
+ do { \
+ if (__isthreaded) pthread_mutex_lock(&xo_syslog_mutex); \
+ } while(0)
+#define THREAD_UNLOCK() \
+ do { \
+ if (__isthreaded) pthread_mutex_unlock(&xo_syslog_mutex); \
+ } while(0)
+
+static void xo_disconnect_log(void); /* disconnect from syslogd */
+static void xo_connect_log(void); /* (re)connect to syslogd */
+static void xo_open_log_unlocked(const char *, int, int);
+
+enum {
+ NOCONN = 0,
+ CONNDEF,
+ CONNPRIV,
+};
+
+static xo_syslog_open_t xo_syslog_open;
+static xo_syslog_send_t xo_syslog_send;
+static xo_syslog_close_t xo_syslog_close;
+
+static char xo_syslog_enterprise_id[12];
+
+/*
+ * Record an enterprise ID, which functions as a namespace for syslog
+ * messages. The value is pre-formatted into a string. This allows
+ * applications to customize their syslog message set, when needed.
+ */
+void
+xo_set_syslog_enterprise_id (unsigned short eid)
+{
+ snprintf(xo_syslog_enterprise_id, sizeof(xo_syslog_enterprise_id),
+ "%u", eid);
+}
+
+/*
+ * Handle the work of transmitting the syslog message
+ */
+static void
+xo_send_syslog (char *full_msg, char *v0_hdr,
+ char *text_only)
+{
+ if (xo_syslog_send) {
+ xo_syslog_send(full_msg, v0_hdr, text_only);
+ return;
+ }
+
+ int fd;
+ int full_len = strlen(full_msg);
+
+ /* Output to stderr if requested. */
+ if (xo_logstat & LOG_PERROR) {
+ struct iovec iov[3];
+ struct iovec *v = iov;
+ char newline[] = "\n";
+
+ v->iov_base = v0_hdr;
+ v->iov_len = strlen(v0_hdr);
+ v += 1;
+ v->iov_base = text_only;
+ v->iov_len = strlen(text_only);
+ v += 1;
+ v->iov_base = newline;
+ v->iov_len = 1;
+ v += 1;
+ REAL_VOID(writev(STDERR_FILENO, iov, 3));
+ }
+
+ /* Get connected, output the message to the local logger. */
+ if (!xo_opened)
+ xo_open_log_unlocked(xo_logtag, xo_logstat | LOG_NDELAY, 0);
+ xo_connect_log();
+
+ /*
+ * If the send() fails, there are two likely scenarios:
+ * 1) syslogd was restarted
+ * 2) /var/run/log is out of socket buffer space, which
+ * in most cases means local DoS.
+ * If the error does not indicate a full buffer, we address
+ * case #1 by attempting to reconnect to /var/run/log[priv]
+ * and resending the message once.
+ *
+ * If we are working with a privileged socket, the retry
+ * attempts end there, because we don't want to freeze a
+ * critical application like su(1) or sshd(8).
+ *
+ * Otherwise, we address case #2 by repeatedly retrying the
+ * send() to give syslogd a chance to empty its socket buffer.
+ */
+
+ if (send(xo_logfile, full_msg, full_len, 0) < 0) {
+ if (errno != ENOBUFS) {
+ /*
+ * Scenario 1: syslogd was restarted
+ * reconnect and resend once
+ */
+ xo_disconnect_log();
+ xo_connect_log();
+ if (send(xo_logfile, full_msg, full_len, 0) >= 0) {
+ return;
+ }
+ /*
+ * if the resend failed, fall through to
+ * possible scenario 2
+ */
+ }
+ while (errno == ENOBUFS) {
+ /*
+ * Scenario 2: out of socket buffer space
+ * possible DoS, fail fast on a privileged
+ * socket
+ */
+ if (xo_status == CONNPRIV)
+ break;
+ usleep(1);
+ if (send(xo_logfile, full_msg, full_len, 0) >= 0) {
+ return;
+ }
+ }
+ } else {
+ return;
+ }
+
+ /*
+ * Output the message to the console; try not to block
+ * as a blocking console should not stop other processes.
+ * Make sure the error reported is the one from the syslogd failure.
+ */
+ int flags = O_WRONLY | O_NONBLOCK;
+#ifdef O_CLOEXEC
+ flags |= O_CLOEXEC;
+#endif /* O_CLOEXEC */
+
+ if (xo_logstat & LOG_CONS
+ && (fd = open(_PATH_CONSOLE, flags, 0)) >= 0) {
+ struct iovec iov[2];
+ struct iovec *v = iov;
+ char crnl[] = "\r\n";
+ char *p;
+
+ p = strchr(full_msg, '>') + 1;
+ v->iov_base = p;
+ v->iov_len = full_len - (p - full_msg);
+ ++v;
+ v->iov_base = crnl;
+ v->iov_len = 2;
+ REAL_VOID(writev(fd, iov, 2));
+ (void) close(fd);
+ }
+}
+
+/* Should be called with mutex acquired */
+static void
+xo_disconnect_log (void)
+{
+ if (xo_syslog_close) {
+ xo_syslog_close();
+ return;
+ }
+
+ /*
+ * If the user closed the FD and opened another in the same slot,
+ * that's their problem. They should close it before calling on
+ * system services.
+ */
+ if (xo_logfile != -1) {
+ close(xo_logfile);
+ xo_logfile = -1;
+ }
+ xo_status = NOCONN; /* retry connect */
+}
+
+/* Should be called with mutex acquired */
+static void
+xo_connect_log (void)
+{
+ if (xo_syslog_open) {
+ xo_syslog_open();
+ return;
+ }
+
+ struct sockaddr_un saddr; /* AF_UNIX address of local logger */
+
+ if (xo_logfile == -1) {
+ int flags = SOCK_DGRAM;
+#ifdef SOCK_CLOEXEC
+ flags |= SOCK_CLOEXEC;
+#endif /* SOCK_CLOEXEC */
+ if ((xo_logfile = socket(AF_UNIX, flags, 0)) == -1)
+ return;
+ }
+ if (xo_logfile != -1 && xo_status == NOCONN) {
+#ifdef HAVE_SUN_LEN
+ saddr.sun_len = sizeof(saddr);
+#endif /* HAVE_SUN_LEN */
+ saddr.sun_family = AF_UNIX;
+
+ /*
+ * First try privileged socket. If no success,
+ * then try default socket.
+ */
+
+#ifdef _PATH_LOG_PRIV
+ (void) strncpy(saddr.sun_path, _PATH_LOG_PRIV,
+ sizeof saddr.sun_path);
+ if (connect(xo_logfile, (struct sockaddr *) &saddr,
+ sizeof(saddr)) != -1)
+ xo_status = CONNPRIV;
+#endif /* _PATH_LOG_PRIV */
+
+#ifdef _PATH_LOG
+ if (xo_status == NOCONN) {
+ (void) strncpy(saddr.sun_path, _PATH_LOG,
+ sizeof saddr.sun_path);
+ if (connect(xo_logfile, (struct sockaddr *)&saddr,
+ sizeof(saddr)) != -1)
+ xo_status = CONNDEF;
+ }
+#endif /* _PATH_LOG */
+
+#ifdef _PATH_OLDLOG
+ if (xo_status == NOCONN) {
+ /*
+ * Try the old "/dev/log" path, for backward
+ * compatibility.
+ */
+ (void) strncpy(saddr.sun_path, _PATH_OLDLOG,
+ sizeof saddr.sun_path);
+ if (connect(xo_logfile, (struct sockaddr *)&saddr,
+ sizeof(saddr)) != -1)
+ xo_status = CONNDEF;
+ }
+#endif /* _PATH_OLDLOG */
+
+ if (xo_status == NOCONN) {
+ (void) close(xo_logfile);
+ xo_logfile = -1;
+ }
+ }
+}
+
+static void
+xo_open_log_unlocked (const char *ident, int logstat, int logfac)
+{
+ if (ident != NULL)
+ xo_logtag = ident;
+ xo_logstat = logstat;
+ if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
+ xo_logfacility = logfac;
+
+ if (xo_logstat & LOG_NDELAY) /* open immediately */
+ xo_connect_log();
+
+ xo_opened = 1; /* ident and facility has been set */
+}
+
+void
+xo_open_log (const char *ident, int logstat, int logfac)
+{
+ THREAD_LOCK();
+ xo_open_log_unlocked(ident, logstat, logfac);
+ THREAD_UNLOCK();
+}
+
+
+void
+xo_close_log (void)
+{
+ THREAD_LOCK();
+ if (xo_logfile != -1) {
+ (void) close(xo_logfile);
+ xo_logfile = -1;
+ }
+ xo_logtag = NULL;
+ xo_status = NOCONN;
+ THREAD_UNLOCK();
+}
+
+/* xo_set_logmask -- set the log mask level */
+int
+xo_set_logmask (int pmask)
+{
+ int omask;
+
+ THREAD_LOCK();
+ omask = xo_logmask;
+ if (pmask != 0)
+ xo_logmask = pmask;
+ THREAD_UNLOCK();
+ return (omask);
+}
+
+void
+xo_set_syslog_handler (xo_syslog_open_t open_func,
+ xo_syslog_send_t send_func,
+ xo_syslog_close_t close_func)
+{
+ xo_syslog_open = open_func;
+ xo_syslog_send = send_func;
+ xo_syslog_close = close_func;
+}
+
+static size_t
+xo_snprintf (char *out, size_t outsize, const char *fmt, ...)
+{
+ int status;
+ size_t retval = 0;
+ va_list ap;
+ if (out && outsize) {
+ va_start(ap, fmt);
+ status = vsnprintf(out, outsize, fmt, ap);
+ if (status < 0) { /* this should never happen, */
+ *out = 0; /* handle it in the safest way possible if it does */
+ retval = 0;
+ } else {
+ retval = status;
+ retval = retval > outsize ? outsize : retval;
+ }
+ va_end(ap);
+ }
+ return retval;
+}
+
+static int
+xo_syslog_handle_write (void *opaque, const char *data)
+{
+ xo_buffer_t *xbp = opaque;
+ int len = strlen(data);
+ int left = xo_buf_left(xbp);
+
+ if (len > left - 1)
+ len = left - 1;
+
+ memcpy(xbp->xb_curp, data, len);
+ xbp->xb_curp += len;
+ *xbp->xb_curp = '\0';
+
+ return len;
+}
+
+static void
+xo_syslog_handle_close (void *opaque UNUSED)
+{
+}
+
+static int
+xo_syslog_handle_flush (void *opaque UNUSED)
+{
+ return 0;
+}
+
+void
+xo_set_unit_test_mode (int value)
+{
+ xo_unit_test = value;
+}
+
+void
+xo_vsyslog (int pri, const char *name, const char *fmt, va_list vap)
+{
+ int saved_errno = errno;
+ char tbuf[2048];
+ char *tp = NULL, *ep = NULL;
+ unsigned start_of_msg = 0;
+ char *v0_hdr = NULL;
+ xo_buffer_t xb;
+ static pid_t my_pid;
+ unsigned log_offset;
+
+ if (my_pid == 0)
+ my_pid = xo_unit_test ? 222 : getpid();
+
+ /* Check for invalid bits */
+ if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
+ xo_syslog(LOG_ERR | LOG_CONS | LOG_PERROR | LOG_PID,
+ "syslog-unknown-priority",
+ "syslog: unknown facility/priority: %#x", pri);
+ pri &= LOG_PRIMASK|LOG_FACMASK;
+ }
+
+ THREAD_LOCK();
+
+ /* Check priority against setlogmask values. */
+ if (!(LOG_MASK(LOG_PRI(pri)) & xo_logmask)) {
+ THREAD_UNLOCK();
+ return;
+ }
+
+ /* Set default facility if none specified. */
+ if ((pri & LOG_FACMASK) == 0)
+ pri |= xo_logfacility;
+
+ /* Create the primary stdio hook */
+ xb.xb_bufp = tbuf;
+ xb.xb_curp = tbuf;
+ xb.xb_size = sizeof(tbuf);
+
+ xo_handle_t *xop = xo_create(XO_STYLE_SDPARAMS, 0);
+ if (xop == NULL) {
+ THREAD_UNLOCK();
+ return;
+ }
+
+#ifdef HAVE_GETPROGNAME
+ if (xo_logtag == NULL)
+ xo_logtag = getprogname();
+#endif /* HAVE_GETPROGNAME */
+
+ xo_set_writer(xop, &xb, xo_syslog_handle_write, xo_syslog_handle_close,
+ xo_syslog_handle_flush);
+
+ /* Build the message; start by getting the time */
+ struct tm tm;
+ struct timeval tv;
+
+ /* Unit test hack: fake a fixed time */
+ if (xo_unit_test) {
+ tv.tv_sec = 1435085229;
+ tv.tv_usec = 123456;
+ } else
+ gettimeofday(&tv, NULL);
+
+ (void) localtime_r(&tv.tv_sec, &tm);
+
+ if (xo_logstat & LOG_PERROR) {
+ /*
+ * For backwards compatibility, we need to make the old-style
+ * message. This message can be emitted to the console/tty.
+ */
+ v0_hdr = alloca(2048);
+ tp = v0_hdr;
+ ep = v0_hdr + 2048;
+
+ if (xo_logtag != NULL)
+ tp += xo_snprintf(tp, ep - tp, "%s", xo_logtag);
+ if (xo_logstat & LOG_PID)
+ tp += xo_snprintf(tp, ep - tp, "[%d]", my_pid);
+ if (xo_logtag)
+ tp += xo_snprintf(tp, ep - tp, ": ");
+ }
+
+ log_offset = xb.xb_curp - xb.xb_bufp;
+
+ /* Add PRI, PRIVAL, and VERSION */
+ xb.xb_curp += xo_snprintf(xb.xb_curp, xo_buf_left(&xb), "<%d>1 ", pri);
+
+ /* Add TIMESTAMP with milliseconds and TZOFFSET */
+ xb.xb_curp += strftime(xb.xb_curp, xo_buf_left(&xb), "%FT%T", &tm);
+ xb.xb_curp += xo_snprintf(xb.xb_curp, xo_buf_left(&xb),
+ ".%03.3u", tv.tv_usec / 1000);
+ xb.xb_curp += strftime(xb.xb_curp, xo_buf_left(&xb), "%z ", &tm);
+
+ /*
+ * Add HOSTNAME; we rely on gethostname and don't fluff with
+ * ip addresses. Might need to revisit.....
+ */
+ char hostname[HOST_NAME_MAX];
+ hostname[0] = '\0';
+ if (xo_unit_test)
+ strcpy(hostname, "worker-host");
+ else
+ (void) gethostname(hostname, sizeof(hostname));
+
+ xb.xb_curp += xo_snprintf(xb.xb_curp, xo_buf_left(&xb), "%s ",
+ hostname[0] ? hostname : "-");
+
+ /* Add APP-NAME */
+ xb.xb_curp += xo_snprintf(xb.xb_curp, xo_buf_left(&xb), "%s ",
+ xo_logtag ?: "-");
+
+ /* Add PROCID */
+ xb.xb_curp += xo_snprintf(xb.xb_curp, xo_buf_left(&xb), "%d ", my_pid);
+
+ /*
+ * Add MSGID. The user should provide us with a name, which we
+ * prefix with the current enterprise ID, as learned from the kernel.
+ * If the kernel won't tell us, we use the stock/builtin number.
+ */
+ char *buf UNUSED = NULL;
+ const char *eid = xo_syslog_enterprise_id;
+ const char *at_sign = "@";
+
+ if (name == NULL) {
+ name = "-";
+ eid = at_sign = "";
+
+ } else if (*name == '@') {
+ /* Our convention is to prefix IANA-defined names with an "@" */
+ name += 1;
+ eid = at_sign = "";
+
+ } else if (eid[0] == '\0') {
+#ifdef HAVE_SYSCTLBYNAME
+ /*
+ * See if the kernel knows the sysctl for the enterprise ID
+ */
+ size_t size = 0;
+ if (sysctlbyname(XO_SYSLOG_ENTERPRISE_ID, NULL, &size, NULL, 0) == 0
+ && size > 0) {
+ buf = alloca(size);
+ if (sysctlbyname(XO_SYSLOG_ENTERPRISE_ID, buf, &size, NULL, 0) == 0
+ && size > 0)
+ eid = buf;
+ }
+#endif /* HAVE_SYSCTLBYNAME */
+
+ if (eid[0] == '\0') {
+ /* Fallback to our base default */
+ xo_set_syslog_enterprise_id(XO_DEFAULT_EID);
+ eid = xo_syslog_enterprise_id;
+ }
+ }
+
+ xb.xb_curp += xo_snprintf(xb.xb_curp, xo_buf_left(&xb), "%s [%s%s%s ",
+ name, name, at_sign, eid);
+
+ /*
+ * Now for the real content. We make two distinct passes thru the
+ * xo_emit engine, first for the SD-PARAMS and then for the text
+ * message.
+ */
+ va_list ap;
+ va_copy(ap, vap);
+
+ errno = saved_errno; /* Restore saved error value */
+ xo_emit_hv(xop, fmt, ap);
+ xo_flush_h(xop);
+
+ va_end(ap);
+
+ /* Trim trailing space */
+ if (xb.xb_curp[-1] == ' ')
+ xb.xb_curp -= 1;
+
+ /* Close the structured data (SD-ELEMENT) */
+ xb.xb_curp += xo_snprintf(xb.xb_curp, xo_buf_left(&xb), "] ");
+
+ /*
+ * Since our MSG is known to be UTF-8, we MUST prefix it with
+ * that most-annoying-of-all-UTF-8 features, the BOM (0xEF.BB.BF).
+ */
+ xb.xb_curp += xo_snprintf(xb.xb_curp, xo_buf_left(&xb),
+ "%c%c%c", 0xEF, 0xBB, 0xBF);
+
+ /* Save the start of the message */
+ if (xo_logstat & LOG_PERROR)
+ start_of_msg = xb.xb_curp - xb.xb_bufp;
+
+ xo_set_style(xop, XO_STYLE_TEXT);
+ xo_set_flags(xop, XOF_UTF8);
+
+ errno = saved_errno; /* Restore saved error value */
+ xo_emit_hv(xop, fmt, ap);
+ xo_flush_h(xop);
+
+ /* Remove a trailing newline */
+ if (xb.xb_curp[-1] == '\n')
+ *--xb.xb_curp = '\0';
+
+ if (xo_get_flags(xop) & XOF_LOG_SYSLOG)
+ fprintf(stderr, "xo: syslog: %s\n", xb.xb_bufp + log_offset);
+
+ xo_send_syslog(xb.xb_bufp, v0_hdr, xb.xb_bufp + start_of_msg);
+
+ xo_destroy(xop);
+
+ THREAD_UNLOCK();
+}
+
+/*
+ * syslog - print message on log file; output is intended for syslogd(8).
+ */
+void
+xo_syslog (int pri, const char *name, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ xo_vsyslog(pri, name, fmt, ap);
+ va_end(ap);
+}
Property changes on: vendor/Juniper/libxo/dist/libxo/xo_syslog.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/libxo/gen-wide.sh
===================================================================
--- vendor/Juniper/libxo/dist/libxo/gen-wide.sh (nonexistent)
+++ vendor/Juniper/libxo/dist/libxo/gen-wide.sh (revision 296962)
@@ -0,0 +1,76 @@
+#!/bin/sh
+
+FILE=$1
+
+SYMBOLS="
+xo_buffer_s
+xo_buffer_t
+xo_stack_s
+xo_stack_t
+xo_handle_s
+xo_handle_t
+xo_default_handle
+xo_default_inited
+xo_realloc
+xo_free
+xo_write_to_file
+xo_close_file
+xo_buf_init
+xo_init_handle
+xo_default_init
+xo_buf_has_room
+xo_printf
+xo_escape_xml
+xo_escape_json
+xo_buf_append
+xo_buf_escape
+xo_data_append
+xo_data_escape
+xo_default
+xo_indent
+xo_warn
+xo_create
+xo_create_to_file
+xo_destroy
+xo_set_style
+xo_set_flags
+xo_set_info
+xo_set_formatter
+xo_clear_flags
+xo_buf_indent
+xo_line_ensure_open
+xo_line_close
+xo_info_compare
+xo_info_find
+xo_format_data
+xo_buf_append_div
+xo_format_text
+xo_format_label
+xo_format_title
+xo_format_prep
+xo_format_value
+xo_format_decoration
+xo_format_padding
+xo_do_emit
+xo_emit_hv
+xo_emit_h
+xo_emit
+xo_attr_hv
+xo_attr_h
+xo_attr
+xo_depth_change
+xo_open_container_h
+xo_open_container
+xo_close_container_h
+xo_close_container
+xo_open_list_h
+xo_open_list
+xo_close_list_h
+xo_close_list
+xo_open_instance_h
+xo_open_instance
+xo_close_instance_h
+xo_close_instance
+xo_set_writer
+xo_set_allocator
+"
Property changes on: vendor/Juniper/libxo/dist/libxo/gen-wide.sh
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/.travis.yml
===================================================================
--- vendor/Juniper/libxo/dist/.travis.yml (nonexistent)
+++ vendor/Juniper/libxo/dist/.travis.yml (revision 296962)
@@ -0,0 +1,12 @@
+language: c
+
+script: printenv && uname -a && ls -l && /bin/sh -x ./bin/setup.sh && cd build && ../configure --enable-warnings && make && sudo make install && make test
+
+notifications:
+ recipients:
+ - libslax-noise@googlegroups.com
+
+branches:
+ only:
+ - master
+ - develop
Index: vendor/Juniper/libxo/dist/INSTALL.md
===================================================================
--- vendor/Juniper/libxo/dist/INSTALL.md (nonexistent)
+++ vendor/Juniper/libxo/dist/INSTALL.md (revision 296962)
@@ -0,0 +1,15 @@
+
+
+## Instructions for building libxo
+
+Instructions for building libxo are now available in the
+[wiki](http://juniper.github.io/libxo/libxo-manual.html#getting-libxo).
Index: vendor/Juniper/libxo/dist/Makefile.am
===================================================================
--- vendor/Juniper/libxo/dist/Makefile.am (nonexistent)
+++ vendor/Juniper/libxo/dist/Makefile.am (revision 296962)
@@ -0,0 +1,102 @@
+#
+# $Id$
+#
+# Copyright 2014, Juniper Networks, Inc.
+# All rights reserved.
+# This SOFTWARE is licensed under the LICENSE provided in the
+# ../Copyright file. By downloading, installing, copying, or otherwise
+# using the SOFTWARE, you agree to be bound by the terms of that
+# LICENSE.
+
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = libxo xo xopo xolint xohtml tests doc encoder
+bin_SCRIPTS=libxo-config
+dist_doc_DATA = Copyright
+
+EXTRA_DIST = \
+ libxo-config.in \
+ warnings.mk \
+ README.md \
+ INSTALL.md \
+ packaging/libxo.spec
+
+.PHONY: test tests
+
+test tests:
+ @(cd tests ; ${MAKE} test)
+
+errors:
+ @(cd tests/errors ; ${MAKE} test)
+
+docs:
+ @(cd doc ; ${MAKE} docs)
+
+
+DIST_FILES_DIR = ~/Dropbox/dist-files/
+GH_PAGES_DIR = gh-pages/
+GH_PAGES_DIR_VER = gh-pages/${PACKAGE_VERSION}
+PACKAGE_FILE = ${PACKAGE_TARNAME}-${PACKAGE_VERSION}.tar.gz
+
+upload: dist upload-docs
+ @echo "Remember to run:"
+ @echo " gt tag ${PACKAGE_VERSION}"
+
+upload-docs: docs
+ @echo "Uploading libxo-manual.html ... "
+ @-[ -d ${GH_PAGES_DIR} ] \
+ && echo "Updating manual on gh-pages ..." \
+ && mkdir -p ${GH_PAGES_DIR_VER} \
+ && cp doc/libxo-manual.html ${GH_PAGES_DIR} \
+ && cp doc/libxo-manual.html ${GH_PAGES_DIR_VER} \
+ && (cd ${GH_PAGES_DIR} \
+ && git add ${PACKAGE_VERSION} \
+ && git add libxo-manual.html \
+ && git commit -m 'new docs' \
+ libxo-manual.html ${PACKAGE_VERSION} \
+ && git push origin gh-pages ) ; true
+
+pkgconfigdir=$(libdir)/pkgconfig
+pkgconfig_DATA = packaging/${PACKAGE_NAME}.pc
+
+get-wiki:
+ git clone https://github.com/Juniper/${PACKAGE_NAME}.wiki.git wiki
+
+get-gh-pages:
+ git clone https://github.com/Juniper/${PACKAGE_NAME}.git \
+ gh-pages -b gh-pages
+
+UPDATE_PACKAGE_FILE = \
+ -e "s;__SHA1__;$$SHA1;" \
+ -e "s;__SHA256__;SHA256 (textproc/${PACKAGE_FILE}) = $$SHA256;" \
+ -e "s;__SIZE__;SIZE (textproc/${PACKAGE_FILE}) = $$SIZE;"
+
+GH_PACKAGING_DIR = ${PACKAGE_VERSION}/packaging
+GH_PAGES_PACKAGE_DIR = ${GH_PAGES_DIR}/${GH_PACKAGING_DIR}
+
+packages:
+ @-[ -d ${GH_PAGES_DIR} ] && set -x \
+ && echo "Updating packages on gh-pages ..." \
+ && SHA1="`openssl sha1 ${PACKAGE_FILE} | awk '{print $$2}'`" \
+ && SHA256="`openssl sha256 ${PACKAGE_FILE} | awk '{print $$2}'`" \
+ && SIZE="`ls -l ${PACKAGE_FILE} | awk '{print $$5}'`" \
+ && echo "... ${GH_PAGES_PACKAGE_DIR}/${PACKAGE_NAME}.rb ..." \
+ && sed ${UPDATE_PACKAGE_FILE} \
+ packaging/${PACKAGE_NAME}.rb.base \
+ > ${GH_PAGES_PACKAGE_DIR}/${PACKAGE_NAME}.rb \
+ && echo "... ${GH_PAGES_PACKAGE_DIR}/${PACKAGE_NAME}.spec ..." \
+ && cp packaging/${PACKAGE_NAME}.spec \
+ ${GH_PAGES_PACKAGE_DIR}/${PACKAGE_NAME}.spec \
+ && (cd ${GH_PAGES_DIR} \
+ && git add ${GH_PACKAGING_DIR} \
+ && git add ${GH_PACKAGING_DIR}/libxo.rb \
+ ${GH_PACKAGING_DIR}/libxo.spec \
+ && git commit -m 'new packaging data' \
+ ${GH_PACKAGING_DIR} \
+ && git push origin gh-pages ) ; true
+
+ANALYZE_DIR = ~/trash/libxo
+ANALYZE_CMD = scan-build-mp-3.6
+
+analyze:
+ ${ANALYZE_CMD} -o ${ANALYZE_DIR} ${MAKE}
Property changes on: vendor/Juniper/libxo/dist/Makefile.am
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/bin/Zaliases
===================================================================
--- vendor/Juniper/libxo/dist/bin/Zaliases (nonexistent)
+++ vendor/Juniper/libxo/dist/bin/Zaliases (revision 296962)
@@ -0,0 +1,29 @@
+set top_src=`pwd`
+alias Zautoreconf "(cd $top_src ; autoreconf)"
+
+set opts=' \
+--with-libslax-prefix=/Users/phil/work/root \
+--enable-debug \
+--enable-warnings \
+--enable-printflike \
+--with-gettext=/opt/local \
+--prefix ${HOME}/work/root \
+'
+set opts=`echo $opts`
+
+setenv CONFIGURE_OPTS "$opts"
+setenv ADB_PATH $top_src/build/libxo/.libs
+
+alias Zconfigure "(cd $top_src/build; ../configure $opts)"
+alias Zbuild "(cd $top_src/build; make \!* )"
+alias mi "(cd $top_src/build; make && make install); ."
+
+mkdir -p build
+cd build
+
+
+alias xx 'cc -I.. -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Werror -Waggregate-return -Wcast-align -Wcast-qual -Wchar-subscripts -Wcomment -Wformat -Wimplicit -Wmissing-declarations -Wnested-externs -Wparentheses -Wreturn-type -Wshadow -Wswitch -Wtrigraphs -Wuninitialized -Wunused -Wwrite-strings -fno-inline-functions-called-once -g -O2 -o xtest -DUNIT_TEST libxo.c'
+
+alias mm "make CFLAGS='-O0 -g'"
+
+alias mmi 'mm && mi'
Index: vendor/Juniper/libxo/dist/bin/setup.sh
===================================================================
--- vendor/Juniper/libxo/dist/bin/setup.sh (nonexistent)
+++ vendor/Juniper/libxo/dist/bin/setup.sh (revision 296962)
@@ -0,0 +1,33 @@
+#
+# Copyright 2013, Juniper Networks, Inc.
+# All rights reserved.
+# This SOFTWARE is licensed under the LICENSE provided in the
+# ../Copyright file. By downloading, installing, copying, or otherwise
+# using the SOFTWARE, you agree to be bound by the terms of that
+# LICENSE.
+
+
+if [ ! -f configure ]; then
+ vers=`autoreconf --version | head -1`
+ echo "Using" $vers
+
+ mkdir -p m4
+
+ autoreconf --install
+
+ if [ ! -f configure ]; then
+ echo "Failed to create configure script"
+ exit 1
+ fi
+fi
+
+echo "Creating build directory ..."
+mkdir build
+
+echo "Setup is complete. To build libslax:"
+
+echo " 1) Type 'cd build ; ../configure' to configure libslax"
+echo " 2) Type 'make' to build libslax"
+echo " 3) Type 'make install' to install libslax"
+
+exit 0
Property changes on: vendor/Juniper/libxo/dist/bin/setup.sh
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/bin/Makefile.am
===================================================================
--- vendor/Juniper/libxo/dist/bin/Makefile.am (nonexistent)
+++ vendor/Juniper/libxo/dist/bin/Makefile.am (revision 296962)
@@ -0,0 +1,29 @@
+#
+# Copyright 2013, Juniper Networks, Inc.
+# All rights reserved.
+# This SOFTWARE is licensed under the LICENSE provided in the
+# ../Copyright file. By downloading, installing, copying, or otherwise
+# using the SOFTWARE, you agree to be bound by the terms of that
+# LICENSE.
+
+ACLOCAL_AMFLAGS = -I m4
+
+EXTRA_DIST = gt setup.sh
+
+GT_INSTALL_DIR = ${prefix}/bin
+GT_INSTALL_FILES = gt
+
+install-data-hook:
+ @echo "Installing gt ... "
+ @-mkdir -p ${GT_INSTALL_DIR}
+ @for file in ${GT_INSTALL_FILES} ; do \
+ if [ -f $$file ]; then \
+ rfile=$$file ; \
+ else \
+ rfile=${srcdir}/$$file ; \
+ fi ; \
+ mdir=${GT_INSTALL_DIR}/ ; \
+ mkdir -p $$mdir ; \
+ cp $$rfile $$mdir/ ; \
+ done
+ @${CHMOD} a+x ${GT_INSTALL_DIR}/gt
Property changes on: vendor/Juniper/libxo/dist/bin/Makefile.am
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/configure.ac
===================================================================
--- vendor/Juniper/libxo/dist/configure.ac (nonexistent)
+++ vendor/Juniper/libxo/dist/configure.ac (revision 296962)
@@ -0,0 +1,452 @@
+#
+# $Id$
+#
+# See ./INSTALL for more info
+#
+
+#
+# Release numbering: even numbered dot releases are official ones, and
+# odd numbers are development ones. The svn version of this file will
+# only (ONLY!) ever (EVER!) contain odd numbers, so I'll always know if
+# a particular user has the dist or svn release.
+#
+
+AC_PREREQ(2.2)
+AC_INIT([libxo], [0.4.5], [phil@juniper.net])
+AM_INIT_AUTOMAKE([-Wall -Werror foreign -Wno-portability])
+
+# Support silent build rules. Requires at least automake-1.11.
+# Disable with "configure --disable-silent-rules" or "make V=1"
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+AC_PROG_CC
+AM_PROG_AR
+AC_PROG_INSTALL
+AC_CONFIG_MACRO_DIR([m4])
+AC_PROG_LN_S
+
+# Must be after AC_PROG_AR
+LT_INIT([dlopen shared])
+
+AC_PATH_PROG(BASENAME, basename, /usr/bin/basename)
+AC_PATH_PROG(BISON, bison, /usr/bin/bison)
+AC_PATH_PROG(CAT, cat, /bin/cat)
+AC_PATH_PROG(CHMOD, chmod, /bin/chmod)
+AC_PATH_PROG(CP, cp, /bin/cp)
+AC_PATH_PROG(DIFF, diff, /usr/bin/diff)
+AC_PATH_PROG(MKDIR, mkdir, /bin/mkdir)
+AC_PATH_PROG(MV, mv, /bin/mv)
+AC_PATH_PROG(RM, rm, /bin/rm)
+AC_PATH_PROG(SED, sed, /bin/sed)
+
+AC_STDC_HEADERS
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_INLINE
+AC_TYPE_SIZE_T
+
+# Checks for library functions.
+AC_FUNC_ALLOCA
+AC_FUNC_MALLOC
+AC_FUNC_REALLOC
+AC_CHECK_FUNCS([bzero memmove strchr strcspn strerror strspn])
+AC_CHECK_FUNCS([sranddev srand strlcpy])
+AC_CHECK_FUNCS([fdopen getrusage])
+AC_CHECK_FUNCS([gettimeofday ctime])
+AC_CHECK_FUNCS([getpass])
+AC_CHECK_FUNCS([getprogname])
+AC_CHECK_FUNCS([sysctlbyname])
+AC_CHECK_FUNCS([flock])
+AC_CHECK_FUNCS([asprintf])
+AC_CHECK_FUNCS([__flbf])
+AC_CHECK_FUNCS([sysctlbyname])
+
+
+AC_CHECK_HEADERS([dlfcn.h])
+AC_CHECK_HEADERS([dlfcn.h])
+AC_CHECK_HEADERS([stdio_ext.h])
+AC_CHECK_HEADERS([tzfile.h])
+AC_CHECK_HEADERS([stdtime/tzfile.h])
+AC_CHECK_FUNCS([dlfunc])
+
+AC_CHECK_HEADERS([sys/time.h])
+AC_CHECK_HEADERS([ctype.h errno.h stdio.h stdlib.h])
+AC_CHECK_HEADERS([string.h sys/param.h unistd.h ])
+AC_CHECK_HEADERS([sys/sysctl.h])
+AC_CHECK_HEADERS([threads.h])
+
+dnl humanize_number(3) is a great function, but it's not standard.
+dnl Note Macosx has the function in libutil.a but doesn't ship the
+dnl header file, so I'll need to carry my own implementation. See:
+dnl https://devforums.apple.com/thread/271121
+AC_CHECK_HEADERS([libutil.h])
+AC_CHECK_LIB([util], [humanize_number],
+ [HAVE_HUMANIZE_NUMBER=$ac_cv_header_libutil_h],
+ [HAVE_HUMANIZE_NUMBER=no])
+
+AC_MSG_RESULT(humanize_number results: :${HAVE_HUMANIZE_NUMBER}:${ac_cv_header_libutil_h}:)
+
+if test "$HAVE_HUMANIZE_NUMBER" = "yes"; then
+ AC_DEFINE([HAVE_HUMANIZE_NUMBER], [1], [humanize_number(3)])
+fi
+
+AM_CONDITIONAL([HAVE_HUMANIZE_NUMBER], [test "$HAVE_HUMANIZE_NUMBER" = "yes"])
+
+AC_ARG_ENABLE([gettext],
+ [ --disable-gettext Turn off support for gettext],
+ [GETTEXT_ENABLE=$enableval],
+ [GETTEXT_ENABLE=yes])
+
+dnl Looking for gettext(), assumably in libintl
+AC_ARG_WITH(gettext,
+ [ --with-gettext=[PFX] Specify location of gettext installation],
+ [GETTEXT_PREFIX=$withval],
+ [GETTEXT_PREFIX=/usr],
+)
+
+HAVE_GETTEXT=no
+
+if test "$GETTEXT_ENABLE" != "no"; then
+
+ AC_MSG_CHECKING([gettext in ${GETTEXT_PREFIX}])
+
+ _save_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS -I${GETTEXT_PREFIX}/include -L${GETTEXT_PREFIX}/lib -Werror -lintl"
+ AC_LINK_IFELSE([AC_LANG_SOURCE([[#include ]
+ [int main() {char *cp = dgettext(NULL, "xx"); return 0; }]])],
+ [HAVE_GETTEXT=yes],
+ [HAVE_GETTEXT=no])
+ CFLAGS="$_save_cflags"
+
+ AC_MSG_RESULT([$HAVE_GETTEXT])
+
+ if test "$HAVE_GETTEXT" != "yes"; then
+ GETTEXT_PREFIX=/opt/local
+ AC_MSG_CHECKING([gettext in ${GETTEXT_PREFIX}])
+
+ _save_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS -I${GETTEXT_PREFIX}/include -L${GETTEXT_PREFIX}/lib -Werror -lintl"
+ AC_LINK_IFELSE([AC_LANG_SOURCE([[#include ]
+ [int main() {char *cp = dgettext(NULL, "xx"); return 0; }]])],
+ [HAVE_GETTEXT=yes],
+ [HAVE_GETTEXT=no])
+ CFLAGS="$_save_cflags"
+
+ AC_MSG_RESULT([$HAVE_GETTEXT])
+ fi
+fi
+
+if test "$HAVE_GETTEXT" = "yes"; then
+ AC_DEFINE([HAVE_GETTEXT], [1], [gettext(3)])
+ GETTEXT_CFLAGS="-I${GETTEXT_PREFIX}/include"
+ GETTEXT_LIBS="-L${GETTEXT_PREFIX}/lib -lintl"
+else
+ GETTEXT_PREFIX=none
+ GETTEXT_CFLAGS=
+ GETTEXT_LIBS=
+fi
+AC_SUBST(GETTEXT_CFLAGS)
+AC_SUBST(GETTEXT_LIBS)
+
+GETTEXT_BINDIR=${GETTEXT_PREFIX}/bin
+AC_SUBST(GETTEXT_BINDIR)
+GETTEXT_LIBDIR=${GETTEXT_PREFIX}/lib
+AC_SUBST(GETTEXT_LIBDIR)
+
+AM_CONDITIONAL([HAVE_GETTEXT], [test "$HAVE_GETTEXT" = "yes"])
+
+dnl Looking for how to do thread-local variables
+AC_ARG_WITH(threads,
+ [ --with-threads=[STYLE] Specify style of thread-local support (none)],
+ [THREAD_LOCAL=$withval],
+ [THREAD_LOCAL=unknown],
+)
+
+AC_MSG_CHECKING([thread-locals are ${THREAD_LOCAL}])
+
+if test "$THREAD_LOCAL" = "unknown"; then
+ AC_LINK_IFELSE([AC_LANG_SOURCE([[]
+ [__thread int foo; int main() { foo++; return foo; }]])],
+ [THREAD_LOCAL=before],
+ [THREAD_LOCAL=unknown])
+
+ AC_MSG_RESULT([$THREAD_LOCAL])
+fi
+
+if test "$THREAD_LOCAL" = "unknown"; then
+ AC_LINK_IFELSE([AC_LANG_SOURCE([[]
+ [int __thread foo; int main() { foo++; return foo; }]])],
+ [THREAD_LOCAL=after],
+ [THREAD_LOCAL=unknown])
+ AC_MSG_RESULT([$THREAD_LOCAL])
+fi
+
+if test "$THREAD_LOCAL" = "unknown"; then
+ AC_LINK_IFELSE([AC_LANG_SOURCE([[]
+ [__declspec(int) foo; int main() { foo++; return foo; }]])],
+ [THREAD_LOCAL=declspec],
+ [THREAD_LOCAL=unknown])
+ AC_MSG_RESULT([$THREAD_LOCAL])
+fi
+
+if test "$THREAD_LOCAL" != "unknown"; then
+ AC_DEFINE_UNQUOTED([HAVE_THREAD_LOCAL],
+ THREAD_LOCAL_${THREAD_LOCAL}, [thread-local setting])
+fi
+
+dnl Looking for libcrypto....
+AC_CHECK_LIB([crypto], [MD5_Init])
+AM_CONDITIONAL([HAVE_LIBCRYPTO], [test "$HAVE_LIBCRYPTO" != "no"])
+
+AC_CHECK_MEMBER([struct sockaddr_un.sun_len],
+ [HAVE_SUN_LEN=yes ;
+ AC_DEFINE([HAVE_SUN_LEN], [1], [Have struct sockaddr_un.sun_len])],
+ [HAS_SUN_LEN=no], [[#include ]])
+
+AC_CHECK_DECLS([__isthreaded], [], [], [#include ])
+HAVE_ISTHREADED=${ac_cv_have_decl___isthreaded}
+
+dnl
+dnl Some packages need to be checked against version numbers so we
+dnl define a function here for later use
+dnl
+AC_DEFUN([VERSION_TO_NUMBER],
+[`$1 | sed -e 's/lib.* //' | awk 'BEGIN { FS = "."; } { printf "%d", ([$]1 * 1000 + [$]2) * 1000 + [$]3;}'`])
+
+LIBSLAX_CONFIG_PREFIX=""
+LIBSLAX_SRC=""
+
+AC_ARG_WITH(libslax-prefix,
+ [ --with-libslax-prefix=[PFX] Specify location of libslax config],
+ LIBSLAX_CONFIG_PREFIX=$withval
+)
+
+AC_MSG_CHECKING(for libslax)
+if test "x$LIBSLAX_CONFIG_PREFIX" != "x"
+then
+ SLAX_CONFIG=${LIBSLAX_CONFIG_PREFIX}/bin/slax-config
+else
+ SLAX_CONFIG=slax-config
+fi
+
+dnl
+dnl make sure slax-config is executable,
+dnl test version and init our variables
+dnl
+
+if ${SLAX_CONFIG} --libs > /dev/null 2>&1
+then
+ LIBSLAX_VERSION=`$SLAX_CONFIG --version`
+ SLAX_BINDIR="`$SLAX_CONFIG --bindir | head -1`"
+ SLAX_OXTRADOCDIR="`$SLAX_CONFIG --oxtradoc | head -1`"
+ AC_MSG_RESULT($LIBSLAX_VERSION found)
+ HAVE_OXTRADOC=yes
+else
+ LIBSLAX_VERSION=
+ SLAX_BINDIR=
+ SLAX_OXTRADOCDIR=
+ AC_MSG_RESULT([no])
+ HAVE_OXTRADOC=no
+fi
+AM_CONDITIONAL([HAVE_OXTRADOC], [test "$HAVE_OXTRADOC" != "no"])
+
+AC_SUBST(SLAX_BINDIR)
+AC_SUBST(SLAX_OXTRADOCDIR)
+
+AC_MSG_CHECKING([whether to build with warnings])
+AC_ARG_ENABLE([warnings],
+ [ --enable-warnings Turn on compiler warnings],
+ [LIBXO_WARNINGS=$enableval],
+ [LIBXO_WARNINGS=no])
+AC_MSG_RESULT([$LIBXO_WARNINGS])
+AM_CONDITIONAL([LIBXO_WARNINGS_HIGH], [test "$LIBXO_WARNINGS" != "no"])
+
+AC_MSG_CHECKING([whether to build with debugging])
+AC_ARG_ENABLE([debug],
+ [ --enable-debug Turn on debugging],
+ [LIBXO_DEBUG=yes; AC_DEFINE([LIBXO_DEBUG], [1], [Enable debugging])],
+ [LIBXO_DEBUG=no])
+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_MSG_CHECKING([whether to build with local wcwidth implementation])
+AC_ARG_ENABLE([wcwidth],
+ [ --disable-wcwidth Disable local wcwidth implementation],
+ [LIBXO_WCWIDTH=$enableval],
+ [LIBXO_WCWIDTH=yes])
+AC_MSG_RESULT([$LIBXO_WCWIDTH])
+if test "${LIBXO_WCWIDTH}" != "no"; then
+ AC_DEFINE([LIBXO_WCWIDTH], [1], [Enable local wcwidth implementation])
+fi
+
+AC_CHECK_LIB([m], [lrint])
+AM_CONDITIONAL([HAVE_LIBM], [test "$HAVE_LIBM" != "no"])
+
+AC_MSG_CHECKING([compiler for gcc])
+HAVE_GCC=no
+if test "${CC}" != ""; then
+ HAVE_GCC=`${CC} --version 2>&1 | grep GCC`
+ if test "${HAVE_GCC}" != ""; then
+ HAVE_GCC=yes
+ else
+ HAVE_GCC=no
+ fi
+fi
+AC_MSG_RESULT([$HAVE_GCC])
+AM_CONDITIONAL([HAVE_GCC], [test "$HAVE_GCC" = "yes"])
+
+AC_MSG_CHECKING([whether to build with printflike])
+AC_ARG_ENABLE([printflike],
+ [ --enable-printflike Enable use of GCC __printflike attribute],
+ [HAVE_PRINTFLIKE=yes;
+ AC_DEFINE([HAVE_PRINTFLIKE], [1], [Support printflike])],
+ [HAVE_PRINTFLIKE=no])
+AC_MSG_RESULT([$HAVE_PRINTFLIKE])
+AM_CONDITIONAL([HAVE_PRINTFLIKE], [test "$HAVE_PRINTFLIKE" != ""])
+
+AC_MSG_CHECKING([whether to build with LIBXO_OPTIONS])
+AC_ARG_ENABLE([libxo-options],
+ [ --disable-libxo-options Turn off support for LIBXO_OPTIONS],
+ [LIBXO_OPTS=$enableval],
+ [LIBXO_OPTS=yes])
+AC_MSG_RESULT([$LIBXO_OPTS])
+AM_CONDITIONAL([NO_LIBXO_OPTIONS], [test "$LIBXO_OPTS" != "yes"])
+
+case $host_os in
+ darwin*)
+ LIBTOOL=glibtool
+ XO_LIBEXT=dylib
+ ;;
+ Linux*|linux*)
+ CFLAGS="-D_GNU_SOURCE $CFLAGS"
+ LDFLAGS=-ldl
+ XO_LIBEXT=so
+ ;;
+ cygwin*|CYGWIN*)
+ LDFLAGS=-no-undefined
+ XO_LIBEXT=ddl
+ ;;
+esac
+
+case $prefix in
+ NONE)
+ prefix=/usr/local
+ ;;
+esac
+
+XO_LIBS=-lxo
+XO_SRCDIR=${srcdir}
+XO_LIBDIR=${libdir}
+XO_BINDIR=${bindir}
+XO_INCLUDEDIR=${includedir}
+
+AC_SUBST(XO_SRCDIR)
+AC_SUBST(XO_LIBDIR)
+AC_SUBST(XO_BINDIR)
+AC_SUBST(XO_INCLUDEDIR)
+AC_SUBST(XO_LIBEXT)
+
+AC_ARG_WITH(encoder-dir,
+ [ --with-encoder-dir=[DIR] Specify location of encoder libraries],
+ [XO_ENCODERDIR=$withval],
+ [XO_ENCODERDIR=$libdir/libxo/encoder]
+)
+AC_SUBST(XO_ENCODERDIR)
+
+AC_ARG_WITH(share-dir,
+ [ --with-share-dir=[DIR] Specify location of shared files],
+ [XO_SHAREDIR=$withval],
+ [XO_SHAREDIR=$datarootdir/libxo]
+)
+XO_SHAREDIR=`echo $XO_SHAREDIR | sed "s;\\${prefix};$prefix;"`
+AC_SUBST(XO_SHAREDIR)
+
+dnl for the spec file
+RELDATE=`date +'%Y-%m-%d%n'`
+AC_SUBST(RELDATE)
+
+AC_MSG_RESULT(Using configure dir $ac_abs_confdir)
+
+if test -d $ac_abs_confdir/.git ; then
+ extra=`git branch | awk '/\*/ { print $2 }'`
+ if test "$extra" != "" -a "$extra" != "master"
+ then
+ LIBXO_VERSION_EXTRA="-git-$extra"
+ fi
+fi
+
+LIBXO_VERSION=$PACKAGE_VERSION
+LIBXO_VERSION_NUMBER=VERSION_TO_NUMBER(echo $PACKAGE_VERSION)
+AC_SUBST(LIBXO_VERSION)
+AC_SUBST(LIBXO_VERSION_NUMBER)
+AC_SUBST(LIBXO_VERSION_EXTRA)
+
+AC_DEFINE_UNQUOTED(LIBXO_VERSION, ["$LIBXO_VERSION"],
+ [Version number as dotted value])
+AC_DEFINE_UNQUOTED(LIBXO_VERSION_NUMBER, [$LIBXO_VERSION_NUMBER],
+ [Version number as a number])
+AC_DEFINE_UNQUOTED(LIBXO_VERSION_STRING, ["$LIBXO_VERSION_NUMBER"],
+ [Version number as string])
+AC_DEFINE_UNQUOTED(LIBXO_VERSION_EXTRA, ["$LIBXO_VERSION_EXTRA"],
+ [Version number extra information])
+
+AC_CONFIG_HEADERS([libxo/xo_config.h])
+AC_CONFIG_FILES([
+ Makefile
+ libxo-config
+ xohtml/xohtml.sh
+ libxo/Makefile
+ libxo/add.man
+ encoder/Makefile
+ encoder/cbor/Makefile
+ encoder/test/Makefile
+ xo/Makefile
+ xolint/Makefile
+ xohtml/Makefile
+ xopo/Makefile
+ packaging/libxo.pc
+ doc/Makefile
+ tests/Makefile
+ tests/core/Makefile
+ tests/gettext/Makefile
+ tests/xo/Makefile
+ packaging/libxo.spec
+ packaging/libxo.rb.base
+])
+AC_OUTPUT
+
+AC_MSG_NOTICE([summary of build options:
+
+ libxo version: ${VERSION} ${LIBXO_VERSION_EXTRA}
+ host type: ${host} / ${host_os}
+ install prefix: ${prefix}
+ srcdir: ${XO_SRCDIR}
+ libdir: ${XO_LIBDIR}
+ bindir: ${XO_BINDIR}
+ includedir: ${XO_INCLUDEDIR}
+ share dir: ${XO_SHAREDIR}
+ extensions dir: ${XO_ENCODERDIR}
+ oxtradoc dir: ${SLAX_OXTRADOCDIR}
+
+ compiler: ${CC} (${HAVE_GCC:-no})
+ compiler flags: ${CFLAGS}
+ library types: Shared=${enable_shared}, Static=${enable_static}
+
+ warnings: ${LIBXO_WARNINGS:-no}
+ debug: ${LIBXO_DEBUG:-no}
+ printf-like: ${HAVE_PRINTFLIKE:-no}
+ libxo-options: ${LIBXO_OPTS:-no}
+ text-only: ${LIBXO_TEXT_ONLY:-no}
+ gettext: ${HAVE_GETTEXT:-no} (${GETTEXT_PREFIX})
+ isthreaded: ${HAVE_ISTHREADED:-no}
+ thread-local: ${THREAD_LOCAL:-no}
+ local wcwidth: ${LIBXO_WCWIDTH:-no}
+])
Index: vendor/Juniper/libxo/dist/doc/Makefile.am
===================================================================
--- vendor/Juniper/libxo/dist/doc/Makefile.am (nonexistent)
+++ vendor/Juniper/libxo/dist/doc/Makefile.am (revision 296962)
@@ -0,0 +1,70 @@
+#
+# $Id$
+#
+# Copyright 2014, Juniper Networks, Inc.
+# All rights reserved.
+# This SOFTWARE is licensed under the LICENSE provided in the
+# ../Copyright file. By downloading, installing, copying, or otherwise
+# using the SOFTWARE, you agree to be bound by the terms of that
+# LICENSE.
+
+if HAVE_OXTRADOC
+OXTRADOC_DIR = ${SLAX_OXTRADOCDIR}
+OXTRADOC_PREFIX = ${OXTRADOC_DIR}
+OXTRADOC = ${OXTRADOC_DIR}/oxtradoc
+SLAXPROC_BINDIR = ${SLAX_BINDIR}
+
+XML2RFC = ${OXTRADOC_DIR}/xml2rfc.tcl
+XML2HTMLDIR = ${OXTRADOC_DIR}
+XML2HTMLBIN = ${XML2HTMLDIR}/rfc2629-to-html.slax
+SLAXPROC = ${SLAX_BINDIR}/slaxproc
+
+SLAXPROC_ARGS = \
+ -a oxtradoc-dir ${OXTRADOC_DIR} \
+ -a oxtradoc-install-dir ${OXTRADOC_DIR} \
+ -a anchor-prefix docs
+
+SLAXPROC_ARGS_INLINE = \
+ -a oxtradoc-inline yes
+
+SLAXPROC_ARGS += ${SLAXPROC_ARGS_INLINE}
+
+XML2HTML = \
+ ${SLAXPROC} -g -e -I ${OXTRADOC_DIR} -I . \
+ ${SLAXPROC_ARGS} \
+ ${XML2HTMLBIN}
+
+OX_ARGS = -P ${OXTRADOC_PREFIX} -L ${OXTRADOC_PREFIX}
+OX_ARGS += -S ${SLAXPROC} -p doc
+OX_CMD = ${PERL} ${PERLOPTS} ${OXTRADOC} ${OX_ARGS}
+OXTRADOC_CMD = ${OX_CMD}
+
+OUTPUT = libxo-manual
+INPUT = libxo
+
+EXTRA_DIST = \
+ ${INPUT}.txt \
+ ${OUTPUT}.html \
+ ${OUTPUT}.txt
+
+doc docs: ${OUTPUT}.txt ${OUTPUT}.html
+
+${OUTPUT}.txt: ${INPUT}.txt ${OXTRADOC} xolint.txt
+ ${OXTRADOC_CMD} -m text -o $@ $<
+
+${OUTPUT}.html: ${INPUT}.txt ${OXTRADOC} ${XML2HTMLBIN} xolint.txt
+ ${OXTRADOC_CMD} -m html -o $@ $<
+
+xolint.txt: ${top_srcdir}/xolint/xolint.pl
+ perl ${top_srcdir}/xolint/xolint.pl -D > xolint.txt
+
+CLEANFILES = \
+xolint.txt \
+${INPUT}.xml \
+${INPUT}.txt \
+${INPUT}.fxml \
+${INPUT}.html
+else
+doc docs:
+ @${ECHO} "The 'oxtradoc' tool is not installed; see libslax.org"
+endif
Property changes on: vendor/Juniper/libxo/dist/doc/Makefile.am
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/doc/libxo.txt
===================================================================
--- vendor/Juniper/libxo/dist/doc/libxo.txt (nonexistent)
+++ vendor/Juniper/libxo/dist/doc/libxo.txt (revision 296962)
@@ -0,0 +1,3757 @@
+#
+# Copyright (c) 2014, Juniper Networks, Inc.
+# All rights reserved.
+# This SOFTWARE is licensed under the LICENSE provided in the
+# ../Copyright file. By downloading, installing, copying, or
+# using the SOFTWARE, you agree to be bound by the terms of that
+# LICENSE.
+# Phil Shafer, July 2014
+#
+
+* Overview
+
+libxo - A Library for Generating Text, XML, JSON, and HTML Output
+
+You want to prepare for the future, but you need to live in the
+present. You'd love a flying car, but need to get to work today. You
+want to support features like XML, JSON, and HTML rendering to allow
+integration with NETCONF, REST, and web browsers, but you need to make
+text output for command line users. And you don't want multiple code
+paths that can't help but get out of sync. None of this "if (xml)
+{... } else {...}" logic. And ifdefs are right out. But you'd
+really, really like all the fancy features that modern encoding
+formats can provide. libxo can help.
+
+The libxo library allows an application to generate text, XML, JSON,
+and HTML output using a common set of function calls. The application
+decides at run time which output style should be produced. The
+application calls a function "xo_emit" to product output that is
+described in a format string. A "field descriptor" tells libxo what
+the field is and what it means. Each field descriptor is placed in
+braces with a printf-like format string (^format-strings^):
+
+ xo_emit(" {:lines/%7ju} {:words/%7ju} "
+ "{:characters/%7ju} {d:filename/%s}\n",
+ linect, wordct, charct, file);
+
+Each field can have a role, with the 'value' role being the default,
+and the role tells libxo how and when to render that field. Output
+can then be generated in various style, using the "--libxo" option:
+
+ % wc /etc/motd
+ 25 165 1140 /etc/motd
+ % wc --libxo xml,pretty,warn /etc/motd
+
+
+ 25
+ 165
+ 1140
+ /etc/motd
+
+
+ % wc --libxo json,pretty,warn /etc/motd
+ {
+ "wc": {
+ "file": [
+ {
+ "lines": 25,
+ "words": 165,
+ "characters": 1140,
+ "filename": "/etc/motd"
+ }
+ ]
+ }
+ }
+ % wc --libxo html,pretty,warn /etc/motd
+
+
+
25
+
+
165
+
+
1140
+
+
/etc/motd
+
+
+** Getting libxo
+
+libxo lives on github as:
+
+ https://github.com/Juniper/libxo
+
+The latest release of libxo is available at:
+
+ https://github.com/Juniper/libxo/releases
+
+We are following the branching scheme from
+^http://nvie.com/posts/a-successful-git-branching-model/^ which means
+we will do development under the "develop" branch, and release from
+the "master" branch. To clone a developer tree, run the following
+command:
+
+ git clone https://github.com/Juniper/libxo.git -b develop
+
+We're using semantic release numbering, as defined in
+^http://semver.org/spec/v2.0.0.html^.
+
+libxo is open source, distributed under the BSD license. It shipped
+as part of the FreeBSD operating system starting with release 11.0.
+
+Issues, problems, and bugs should be directly to the issues page on
+our github site.
+
+*** Downloading libxo Source Code
+
+You can retrieve the source for libxo in two ways:
+
+A) Use a "distfile" for a specific release. We use
+github to maintain our releases. Visit
+github release page (^https://github.com/Juniper/libxo/releases^)
+to see the list of releases. To download the latest, look for the
+release with the green "Latest release" button and the green
+"libxo-RELEASE.tar.gz" button under that section.
+
+After downloading that release's distfile, untar it as follows:
+
+ tar -zxf libxo-RELEASE.tar.gz
+ cd libxo-RELEASE
+
+[Note: for Solaris users, your "tar" command lacks the "-z" flag,
+so you'll need to substitute "gzip -dc "file" | tar xf -" instead of
+"tar -zxf "file"".]
+
+B) Use the current build from github. This gives you the most recent
+source code, which might be less stable than a specific release. To
+build libxo from the git repo:
+
+ git clone https://github.com/Juniper/libxo.git
+ cd libxo
+
+_BE AWARE_: The github repository does _not_ contain the files
+generated by "autoreconf", with the notable exception of the "m4"
+directory. Since these files (depcomp, configure, missing,
+install-sh, etc) are generated files, we keep them out of the source
+code repository.
+
+This means that if you download the a release distfile, these files
+will be ready and you'll just need to run "configure", but if you
+download the source code from svn, then you'll need to run
+"autoreconf" by hand. This step is done for you by the "setup.sh"
+script, described in the next section.
+
+*** Building libxo
+
+To build libxo, you'll need to set up the build, run the "configure"
+script, run the "make" command, and run the regression tests.
+
+The following is a summary of the commands needed. These commands are
+explained in detail in the rest of this section.
+
+ sh bin/setup.sh
+ cd build
+ ../configure
+ make
+ make test
+ sudo make install
+
+The following sections will walk thru each of these steps with
+additional details and options, but the above directions should be all
+that's needed.
+
+**** Setting up the build
+
+[If you downloaded a distfile, you can skip this step.]
+
+Run the "setup.sh" script to set up the build. This script runs the
+"autoreconf" command to generate the "configure" script and other
+generated files.
+
+ sh bin/setup.sh
+
+Note: We're are currently using autoreconf version 2.69.
+
+**** Running the "configure" Script
+
+Configure (and autoconf in general) provides a means of building
+software in diverse environments. Our configure script supports
+a set of options that can be used to adjust to your operating
+environment. Use "configure --help" to view these options.
+
+We use the "build" directory to keep object files and generated files
+away from the source tree.
+
+To run the configure script, change into the "build" directory, and
+run the "configure" script. Add any required options to the
+"../configure" command line.
+
+ cd build
+ ../configure
+
+Expect to see the "configure" script generate the following error:
+
+ /usr/bin/rm: cannot remove `libtoolT': No such file or directory
+
+This error is harmless and can be safely ignored.
+
+By default, libxo installs architecture-independent files, including
+extension library files, in the /usr/local directories. To specify an
+installation prefix other than /usr/local for all installation files,
+include the --prefix=prefix option and specify an alternate
+location. To install just the extension library files in a different,
+user-defined location, include the --with-extensions-dir=dir option
+and specify the location where the extension libraries will live.
+
+ cd build
+ ../configure [OPTION]... [VAR=VALUE]...
+
+**** Running the "make" command
+
+Once the "configure" script is run, build the images using the "make"
+command:
+
+ make
+
+**** Running the Regression Tests
+
+libxo includes a set of regression tests that can be run to ensure
+the software is working properly. These test are optional, but will
+help determine if there are any issues running libxo on your
+machine. To run the regression tests:
+
+ make test
+
+**** Installing libxo
+
+Once the software is built, you'll need to install libxo using the
+"make install" command. If you are the root user, or the owner of the
+installation directory, simply issue the command:
+
+ make install
+
+If you are not the "root" user and are using the "sudo" package, use:
+
+ sudo make install
+
+Verify the installation by viewing the output of "xo --version":
+
+ % xo --version
+ libxo version 0.3.5-git-develop
+ xo version 0.3.5-git-develop
+
+* Formatting with libxo
+
+Most unix commands emit text output aimed at humans. It is designed
+to be parsed and understood by a user. Humans are gifted at
+extracting details and pattern matching in such output. Often
+programmers need to extract information from this human-oriented
+output. Programmers use tools like grep, awk, and regular expressions
+to ferret out the pieces of information they need. Such solutions are
+fragile and require maintenance when output contents change or evolve,
+along with testing and validation.
+
+Modern tool developers favor encoding schemes like XML and JSON,
+which allow trivial parsing and extraction of data. Such formats are
+simple, well understood, hierarchical, easily parsed, and often
+integrate easier with common tools and environments. Changes to
+content can be done in ways that do not break existing users of the
+data, which can reduce maintenance costs and increase feature velocity.
+
+In addition, modern reality means that more output ends up in web
+browsers than in terminals, making HTML output valuable.
+
+libxo allows a single set of function calls in source code to generate
+traditional text output, as well as XML and JSON formatted data. HTML
+can also be generated; "" elements surround the traditional text
+output, with attributes that detail how to render the data.
+
+A single libxo function call in source code is all that's required:
+
+ xo_emit("Connecting to {:host}.{:domain}...\n", host, domain);
+
+ TEXT:
+ Connecting to my-box.example.com...
+ XML:
+
my-box
+
example.com
+ JSON:
+ "host": "my-box",
+ "domain": "example.com"
+ HTML:
+
+
Connecting to
+
my-box
+
.
+
example.com
+
...
+
+
+** Encoding Styles
+
+There are four encoding styles supported by libxo:
+
+- TEXT output can be display on a terminal session, allowing
+compatibility with traditional command line usage.
+- XML output is suitable for tools like XPath and protocols like
+NETCONF.
+- JSON output can be used for RESTful APIs and integration with
+languages like Javascript and Python.
+- HTML can be matched with a small CSS file to permit rendering in any
+HTML5 browser.
+
+In general, XML and JSON are suitable for encoding data, while TEXT is
+suited for terminal output and HTML is suited for display in a web
+browser (see ^xohtml^).
+
+*** Text Output
+
+Most traditional programs generate text output on standard output,
+with contents like:
+
+ 36 ./src
+ 40 ./bin
+ 90 .
+
+In this example (taken from du source code), the code to generate this
+data might look like:
+
+ printf("%d\t%s\n", num_blocks, path);
+
+Simple, direct, obvious. But it's only making text output. Imagine
+using a single code path to make TEXT, XML, JSON or HTML, deciding at
+run time which to generate.
+
+libxo expands on the idea of printf format strings to make a single
+format containing instructions for creating multiple output styles:
+
+ xo_emit("{:blocks/%d}\t{:path/%s}\n", num_blocks, path);
+
+This line will generate the same text output as the earlier printf
+call, but also has enough information to generate XML, JSON, and HTML.
+
+The following sections introduce the other formats.
+
+*** XML Output
+
+XML output consists of a hierarchical set of elements, each encoded
+with a start tag and an end tag. The element should be named for data
+value that it is encoding:
+
+
-
+
36
+ ./src
+
+
-
+
40
+ ./bin
+
+
-
+
90
+ .
+
+
+XML is a W3C standard for encoding data. See w3c.org/TR/xml for
+additional information.
+
+*** JSON Output
+
+JSON output consists of a hierarchical set of objects and lists, each
+encoded with a quoted name, a colon, and a value. If the value is a
+string, it must be quoted, but numbers are not quoted. Objects are
+encoded using braces; lists are encoded using square brackets.
+Data inside objects and lists is separated using commas:
+
+ items: [
+ { "blocks": 36, "path" : "./src" },
+ { "blocks": 40, "path" : "./bin" },
+ { "blocks": 90, "path" : "./" }
+ ]
+
+*** HTML Output
+
+HTML output is designed to allow the output to be rendered in a web
+browser with minimal effort. Each piece of output data is rendered
+inside a
element, with a class name related to the role of the
+data. By using a small set of class attribute values, a CSS
+stylesheet can render the HTML into rich text that mirrors the
+traditional text content.
+
+Additional attributes can be enabled to provide more details about the
+data, including data type, description, and an XPath location.
+
+
+
+
+
+** Format Strings @format-strings@
+
+libxo uses format strings to control the rendering of data into the
+various output styles. Each format string contains a set of zero or
+more field descriptions, which describe independent data fields. Each
+field description contains a set of modifiers, a content string, and
+zero, one, or two format descriptors. The modifiers tell libxo what
+the field is and how to treat it, while the format descriptors are
+formatting instructions using printf-style format strings, telling
+libxo how to format the field. The field description is placed inside
+a set of braces, with a colon (":") after the modifiers and a slash
+("/") before each format descriptors. Text may be intermixed with
+field descriptions within the format string.
+
+The field description is given as follows:
+
+ '{' [ role | modifier ]* [',' long-names ]* ':' [ content ]
+ [ '/' field-format [ '/' encoding-format ]] '}'
+
+The role describes the function of the field, while the modifiers
+enable optional behaviors. The contents, field-format, and
+encoding-format are used in varying ways, based on the role. These
+are described in the following sections.
+
+In the following example, three field descriptors appear. The first
+is a padding field containing three spaces of padding, the second is a
+label ("In stock"), and the third is a value field ("in-stock"). The
+in-stock field has a "%u" format that will parse the next argument
+passed to the xo_emit function as an unsigned integer.
+
+ xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\n", 65);
+
+This single line of code can generate text (" In stock: 65\n"), XML
+("
65 "), JSON ('"in-stock": 6'), or HTML (too
+lengthy to be listed here).
+
+While roles and modifiers typically use single character for brevity,
+there are alternative names for each which allow more verbose
+formatting strings. These names must be preceded by a comma, and may
+follow any single-character values:
+
+ xo_emit("{L,white,colon:In stock}{,key:in-stock/%u}\n", 65);
+
+*** Field Roles
+
+Field roles are optional, and indicate the role and formatting of the
+content. The roles are listed below; only one role is permitted:
+
+|---+--------------+-------------------------------------------------|
+| R | Name | Description |
+|---+--------------+-------------------------------------------------|
+| C | color | Field has color and effect controls |
+| D | decoration | Field is non-text (e.g., colon, comma) |
+| E | error | Field is an error message |
+| G | gettext | Call gettext(3) on the format string |
+| L | label | Field is text that prefixes a value |
+| N | note | Field is text that follows a value |
+| P | padding | Field is spaces needed for vertical alignment |
+| T | title | Field is a title value for headings |
+| U | units | Field is the units for the previous value field |
+| V | value | Field is the name of field (the default) |
+| W | warning | Field is a warning message |
+| [ | start-anchor | Begin a section of anchored variable-width text |
+| ] | stop-anchor | End a section of anchored variable-width text |
+|---+--------------+-------------------------------------------------|
+
+ EXAMPLE:
+ xo_emit("{L:Free}{D::}{P: }{:free/%u} {U:Blocks}\n",
+ free_blocks);
+
+When a role is not provided, the "value" role is used as the default.
+
+Roles and modifiers can also use more verbose names, when preceeded by
+a comma:
+
+ EXAMPLE:
+ xo_emit("{,label:Free}{,decoration::}{,padding: }"
+ "{,value:free/%u} {,units:Blocks}\n",
+ free_blocks);
+
+**** The Color Role ({C:}) @color-role@
+
+Colors and effects control how text values are displayed; they are
+used for display styles (TEXT and HTML).
+
+ xo_emit("{C:bold}{:value}{C:no-bold}\n", value);
+
+Colors and effects remain in effect until modified by other "C"-role
+fields.
+
+ xo_emit("{C:bold}{C:inverse}both{C:no-bold}only inverse\n");
+
+If the content is empty, the "reset" action is performed.
+
+ xo_emit("{C:both,underline}{:value}{C:}\n", value);
+
+The content should be a comma-separated list of zero or more colors or
+display effects.
+
+ xo_emit("{C:bold,inverse}Ugly{C:no-bold,no-inverse}\n");
+
+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:/%s%s}{:value}{C:}", need_bold ? "bold" : "",
+ need_underline ? "underline" : "", value);
+
+Color names are prefixed with either "fg-" or "bg-" to change the
+foreground and background colors, respectively.
+
+ xo_emit("{C:/fg-%s,bg-%s}{Lwc:Cost}{:cost/%u}{C:reset}\n",
+ fg_color, bg_color, cost);
+
+The following table lists the supported effects:
+
+|---------------+-------------------------------------------------|
+| 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 | Description |
+|---------+--------------------------------------------|
+| black | |
+| blue | |
+| cyan | |
+| default | Default color for foreground or background |
+| green | |
+| magenta | |
+| red | |
+| white | |
+| yellow | |
+|---------+--------------------------------------------|
+
+**** The Decoration Role ({D:})
+
+Decorations are typically punctuation marks such as colons,
+semi-colons, and commas used to decorate the text and make it simpler
+for human readers. By marking these distinctly, HTML usage scenarios
+can use CSS to direct their display parameters.
+
+ xo_emit("{D:((}{:name}{D:))}\n", name);
+
+**** The Gettext Role ({G:}) @gettext-role@
+
+libxo supports internationalization (i18n) through its use of
+gettext(3). Use the "{G:}" role to request that the remaining part of
+the format string, following the "{G:}" field, be handled using
+gettext().
+
+Since gettext() uses the string as the key into the message catalog,
+libxo uses a simplified version of the format string that removes
+unimportant field formatting and modifiers, stopping minor formatting
+changes from impacting the expensive translation process. A developer
+change such as changing "/%06d" to "/%08d" should not force hand
+inspection of all .po files.
+
+The simplified version can be generated for a single message using the
+"xopo -s
" command, or an entire .pot can be translated using
+the "xopo -f -o " command.
+
+ xo_emit("{G:}Invalid token\n");
+
+The {G:} role allows a domain name to be set. gettext calls will
+continue to use that domain name until the current format string
+processing is complete, enabling a library function to emit strings
+using it's own catalog. The domain name can be either static as the
+content of the field, or a format can be used to get the domain name
+from the arguments.
+
+ xo_emit("{G:libc}Service unavailable in restricted mode\n");
+
+See ^howto-i18n^ for additional details.
+
+**** The Label Role ({L:})
+
+Labels are text that appears before a value.
+
+ xo_emit("{Lwc:Cost}{:cost/%u}\n", cost);
+
+**** The Note Role ({N:})
+
+Notes are text that appears after a value.
+
+ xo_emit("{:cost/%u} {N:per year}\n", cost);
+
+**** The Padding Role ({P:}) @padding-role@
+
+Padding represents whitespace used before and between fields.
+
+The padding 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("{P: }{Lwc:Cost}{:cost/%u}\n", cost);
+ xo_emit("{P:/%30s}{Lwc:Cost}{:cost/%u}\n", "", cost);
+
+**** The Title Role ({T:})
+
+Title are heading or column headers that are meant to be displayed to
+the user. The title 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("{T:Interface Statistics}\n");
+ xo_emit("{T:/%20.20s}{T:/%6.6s}\n", "Item Name", "Cost");
+
+Title fields have an extra convenience feature; if both content and
+format are specified, instead of looking to the argument list for a
+value, the content is used, allowing a mixture of format and content
+within the field descriptor:
+
+ xo_emit("{T:Name/%20s}{T:Count/%6s}\n");
+
+Since the incoming argument is a string, the format must be "%s" or
+something suitable.
+
+**** The Units Role ({U:})
+
+Units are the dimension by which values are measured, such as degrees,
+miles, bytes, and decibels. The units field carries this information
+for the previous value field.
+
+ xo_emit("{Lwc:Distance}{:distance/%u}{Uw:miles}\n", miles);
+
+Note that the sense of the 'w' modifier is reversed for units;
+a blank is added before the contents, rather than after it.
+
+When the XOF_UNITS flag is set, units are rendered in XML as the
+"units" attribute:
+
+ 50
+
+Units can also be rendered in HTML as the "data-units" attribute:
+
+ 50
+
+**** The Value Role ({V:} and {:})
+
+The value role is used to represent the a data value that is
+interesting for the non-display output styles (XML and JSON). Value
+is the default role; if no other role designation is given, the field
+is a value. The field name must appear within the field descriptor,
+followed by one or two format descriptors. The first format
+descriptor is used for display styles (TEXT and HTML), while the
+second one is used for encoding styles (XML and JSON). If no second
+format is given, the encoding format defaults to the first format,
+with any minimum width removed. If no first format is given, both
+format descriptors default to "%s".
+
+ xo_emit("{:length/%02u}x{:width/%02u}x{:height/%02u}\n",
+ length, width, height);
+ xo_emit("{:author} wrote \"{:poem}\" in {:year/%4d}\n,
+ author, poem, year);
+
+**** The Anchor Roles ({[:} and {]:}) @anchor-role@
+
+The anchor roles allow a set of strings by be padded as a group,
+but still be visible to xo_emit as distinct fields. Either the start
+or stop anchor can give a field width and it can be either directly in
+the descriptor or passed as an argument. Any fields between the start
+and stop anchor are padded to meet the minimum width given.
+
+To give a width directly, encode it as the content of the anchor tag:
+
+ xo_emit("({[:10}{:min/%d}/{:max/%d}{]:})\n", min, max);
+
+To pass a width as an argument, use "%d" as the format, which must
+appear after the "/". Note that only "%d" is supported for widths.
+Using any other value could ruin your day.
+
+ xo_emit("({[:/%d}{:min/%d}/{:max/%d}{]:})\n", width, min, max);
+
+If the width is negative, padding will be added on the right, suitable
+for left justification. Otherwise the padding will be added to the
+left of the fields between the start and stop anchors, suitable for
+right justification. If the width is zero, nothing happens. If the
+number of columns of output between the start and stop anchors is less
+than the absolute value of the given width, nothing happens.
+
+Widths over 8k are considered probable errors and not supported. If
+XOF_WARN is set, a warning will be generated.
+
+*** Field Modifiers
+
+Field modifiers are flags which modify the way content emitted for
+particular output styles:
+
+|---+---------------+-------------------------------------------------|
+| M | Name | Description |
+|---+---------------+-------------------------------------------------|
+| c | colon | A colon (":") is appended after the label |
+| d | display | Only emit field for display styles (text/HTML) |
+| e | encoding | Only emit for encoding styles (XML/JSON) |
+| g | gettext | Call gettext on field's render content |
+| h | humanize (hn) | Format large numbers in human-readable style |
+| | hn-space | Humanize: Place space between numeric and unit |
+| | hn-decimal | Humanize: Add a decimal digit, if number < 10 |
+| | hn-1000 | Humanize: Use 1000 as divisor instead of 1024 |
+| k | key | Field is a key, suitable for XPath predicates |
+| l | leaf-list | Field is a leaf-list |
+| n | no-quotes | Do not quote the field when using JSON style |
+| p | plural | Gettext: Use comma-separated plural form |
+| q | quotes | Quote the field when using JSON style |
+| t | trim | Trim leading and trailing whitespace |
+| w | white | A blank (" ") is appended after the label |
+|---+---------------+-------------------------------------------------|
+
+Roles and modifiers can also use more verbose names, when preceeded by
+a comma. For example, the modifier string "Lwc" (or "L,white,colon")
+means the field has a label role (text that describes the next field)
+and should be followed by a colon ('c') and a space ('w'). The
+modifier string "Vkq" (or ":key,quote") means the field has a value
+role (the default role), that it is a key for the current instance,
+and that the value should be quoted when encoded for JSON.
+
+**** The Colon Modifier ({c:})
+
+The colon modifier appends a single colon to the data value:
+
+ EXAMPLE:
+ xo_emit("{Lc:Name}{:name}\n", "phil");
+ TEXT:
+ Name:phil
+
+The colon modifier is only used for the TEXT and HTML output
+styles. It is commonly combined with the space modifier ('{w:}').
+It is purely a convenience feature.
+
+**** The Display Modifier ({d:})
+
+The display modifier indicated the field should only be generated for
+the display output styles, TEXT and HTML.
+
+ EXAMPLE:
+ xo_emit("{Lcw:Name}{d:name} {:id/%d}\n", "phil", 1);
+ TEXT:
+ Name: phil 1
+ XML:
+ 1
+
+The display modifier is the opposite of the encoding modifier, and
+they are often used to give to distinct views of the underlying data.
+
+**** The Encoding Modifier ({e:}) @e-modifier@
+
+The display modifier indicated the field should only be generated for
+the display output styles, TEXT and HTML.
+
+ EXAMPLE:
+ xo_emit("{Lcw:Name}{:name} {e:id/%d}\n", "phil", 1);
+ TEXT:
+ Name: phil
+ XML:
+ phil 1
+
+The encoding modifier is the opposite of the display modifier, and
+they are often used to give to distinct views of the underlying data.
+
+**** The Gettext Modifier ({g:}) @gettext-modifier@
+
+The gettext modifier is used to translate individual fields using the
+gettext domain (typically set using the "{G:}" role) and current
+language settings. Once libxo renders the field value, it is passed
+to gettext(3), where it is used as a key to find the native language
+translation.
+
+In the following example, the strings "State" and "full" are passed
+to gettext() to find locale-based translated strings.
+
+ xo_emit("{Lgwc:State}{g:state}\n", "full");
+
+See ^gettext-role^, ^plural-modifier^, and ^howto-i18n^ for additional
+details.
+
+**** The Humanize Modifier ({h:})
+
+The humanize modifier is used to render large numbers as in a
+human-readable format. While numbers like "44470272" are completely
+readable to computers and savants, humans will generally find "44M"
+more meaningful.
+
+"hn" can be used as an alias for "humanize".
+
+The humanize modifier only affects display styles (TEXT and HMTL).
+The "no-humanize" option (See ^LIBXO_OPTIONS^) will block the function of
+the humanize modifier.
+
+There are a number of modifiers that affect details of humanization.
+These are only available in as full names, not single characters. The
+"hn-space" modifier places a space between the number and any
+multiplier symbol, such as "M" or "K" (ex: "44 K"). The "hn-decimal"
+modifier will add a decimal point and a single tenths digit when the number is
+less than 10 (ex: "4.4K"). The "hn-1000" modifier will use 1000 as divisor
+instead of 1024, following the JEDEC-standard instead of the more
+natural binary powers-of-two tradition.
+
+ EXAMPLE:
+ xo_emit("{h:input/%u}, {h,hn-space:output/%u}, "
+ "{h,hn-decimal:errors/%u}, {h,hn-1000:capacity/%u}, "
+ "{h,hn-decimal:remaining/%u}\n",
+ input, output, errors, capacity, remaining);
+ TEXT:
+ 21, 57 K, 96M, 44M, 1.2G
+
+In the HTML style, the original numeric value is rendered in the
+"data-number" attribute on the element:
+
+
96M
+
+**** The Key Modifier ({k:})
+
+The key modifier is used to indicate that a particular field helps
+uniquely identify an instance of list data.
+
+ EXAMPLE:
+ xo_open_list("user");
+ for (i = 0; i < num_users; i++) {
+ xo_open_instance("user");
+ xo_emit("User {k:name} has {:count} tickets\n",
+ user[i].u_name, user[i].u_tickets);
+ xo_close_instance("user");
+ }
+ xo_close_list("user");
+
+Currently the key modifier is only used when generating XPath value
+for the HTML output style when XOF_XPATH is set, but other uses are
+likely in the near future.
+
+**** The Leaf-List Modifier ({l:})
+
+The leaf-list modifier is used to distinguish lists where each
+instance consists of only a single value. In XML, these are
+rendered as single elements, where JSON renders them as arrays.
+
+ EXAMPLE:
+ for (i = 0; i < num_users; i++) {
+ xo_emit("Member {l:user}\n", user[i].u_name);
+ }
+ XML:
+
phil
+
pallavi
+ JSON:
+ "user": [ "phil", "pallavi" ]
+
+The name of the field must match the name of the leaf list.
+
+**** The No-Quotes Modifier ({n:})
+
+The no-quotes modifier (and its twin, the 'quotes' modifier) affect
+the quoting of values in the JSON output style. JSON uses quotes for
+string value, but no quotes for numeric, boolean, and null data.
+xo_emit applies a simple heuristic to determine whether quotes are
+needed, but often this needs to be controlled by the caller.
+
+ EXAMPLE:
+ const char *bool = is_true ? "true" : "false";
+ xo_emit("{n:fancy/%s}", bool);
+ JSON:
+ "fancy": true
+
+**** The Plural Modifier ({p:}) @plural-modifier@
+
+The plural modifier selects the appropriate plural form of an
+expression based on the most recent number emitted and the current
+language settings. The contents of the field should be the singular
+and plural English values, separated by a comma:
+
+ xo_emit("{:bytes} {Ngp:byte,bytes}\n", bytes);
+
+The plural modifier is meant to work with the gettext modifier ({g:})
+but can work independently. See ^gettext-modifier^.
+
+When used without the gettext modifier or when the message does not
+appear in the message catalog, the first token is chosen when the last
+numeric value is equal to 1; otherwise the second value is used,
+mimicking the simple pluralization rules of English.
+
+When used with the gettext modifier, the ngettext(3) function is
+called to handle the heavy lifting, using the message catalog to
+convert the singular and plural forms into the native language.
+
+**** The Quotes Modifier ({q:})
+
+The quotes modifier (and its twin, the 'no-quotes' modifier) affect
+the quoting of values in the JSON output style. JSON uses quotes for
+string value, but no quotes for numeric, boolean, and null data.
+xo_emit applies a simple heuristic to determine whether quotes are
+needed, but often this needs to be controlled by the caller.
+
+ EXAMPLE:
+ xo_emit("{q:time/%d}", 2014);
+ JSON:
+ "year": "2014"
+
+**** The White Space Modifier ({w:})
+
+The white space modifier appends a single space to the data value:
+
+ EXAMPLE:
+ xo_emit("{Lw:Name}{:name}\n", "phil");
+ TEXT:
+ Name phil
+
+The white space modifier is only used for the TEXT and HTML output
+styles. It is commonly combined with the colon modifier ('{c:}').
+It is purely a convenience feature.
+
+Note that the sense of the 'w' modifier is reversed for the units role
+({Uw:}); a blank is added before the contents, rather than after it.
+
+*** Field Formatting
+
+The field format is similar to the format string for printf(3). Its
+use varies based on the role of the field, but generally is used to
+format the field's contents.
+
+If the format string is not provided for a value field, it defaults to
+"%s".
+
+Note a field definition can contain zero or more printf-style
+'directives', which are sequences that start with a '%' and end with
+one of following characters: "diouxXDOUeEfFgGaAcCsSp". Each directive
+is matched by one of more arguments to the xo_emit function.
+
+The format string has the form:
+
+ '%' format-modifier * format-character
+
+The format- modifier can be:
+- a '#' character, indicating the output value should be prefixed with
+'0x', typically to indicate a base 16 (hex) value.
+- a minus sign ('-'), indicating the output value should be padded on
+the right instead of the left.
+- a leading zero ('0') indicating the output value should be padded on the
+left with zeroes instead of spaces (' ').
+- one or more digits ('0' - '9') indicating the minimum width of the
+argument. If the width in columns of the output value is less that
+the minumum width, the value will be padded to reach the minimum.
+- a period followed by one or more digits indicating the maximum
+number of bytes which will be examined for a string argument, or the maximum
+width for a non-string argument. When handling ASCII strings this
+functions as the field width but for multi-byte characters, a single
+character may be composed of multiple bytes.
+xo_emit will never dereference memory beyond the given number of bytes.
+- a second period followed by one or more digits indicating the maximum
+width for a string argument. This modifier cannot be given for non-string
+arguments.
+- one or more 'h' characters, indicating shorter input data.
+- one or more 'l' characters, indicating longer input data.
+- a 'z' character, indicating a 'size_t' argument.
+- a 't' character, indicating a 'ptrdiff_t' argument.
+- a ' ' character, indicating a space should be emitted before
+positive numbers.
+- a '+' character, indicating sign should emitted before any number.
+
+Note that 'q', 'D', 'O', and 'U' are considered deprecated and will be
+removed eventually.
+
+The format character is described in the following table:
+
+|-----+-----------------+----------------------|
+| Ltr | Argument Type | Format |
+|-----+-----------------+----------------------|
+| d | int | base 10 (decimal) |
+| i | int | base 10 (decimal) |
+| o | int | base 8 (octal) |
+| u | unsigned | base 10 (decimal) |
+| x | unsigned | base 16 (hex) |
+| X | unsigned long | base 16 (hex) |
+| D | long | base 10 (decimal) |
+| O | unsigned long | base 8 (octal) |
+| U | unsigned long | base 10 (decimal) |
+| e | double | [-]d.ddde+-dd |
+| E | double | [-]d.dddE+-dd |
+| f | double | [-]ddd.ddd |
+| F | double | [-]ddd.ddd |
+| g | double | as 'e' or 'f' |
+| G | double | as 'E' or 'F' |
+| a | double | [-]0xh.hhhp[+-]d |
+| A | double | [-]0Xh.hhhp[+-]d |
+| c | unsigned char | a character |
+| C | wint_t | a character |
+| s | char * | a UTF-8 string |
+| S | wchar_t * | a unicode/WCS string |
+| p | void * | '%#lx' |
+|-----+-----------------+----------------------|
+
+The 'h' and 'l' modifiers affect the size and treatment of the
+argument:
+
+|-----+-------------+--------------------|
+| Mod | d, i | o, u, x, X |
+|-----+-------------+--------------------|
+| hh | signed char | unsigned char |
+| h | short | unsigned short |
+| l | long | unsigned long |
+| ll | long long | unsigned long long |
+| j | intmax_t | uintmax_t |
+| t | ptrdiff_t | ptrdiff_t |
+| z | size_t | size_t |
+| q | quad_t | u_quad_t |
+|-----+-------------+--------------------|
+
+*** UTF-8 and Locale Strings
+
+For strings, the 'h' and 'l' modifiers affect the interpretation of
+the bytes pointed to argument. The default '%s' string is a 'char *'
+pointer to a string encoded as UTF-8. Since UTF-8 is compatible with
+ASCII data, a normal 7-bit ASCII string can be used. '%ls' expects a
+'wchar_t *' pointer to a wide-character string, encoded as a 32-bit
+Unicode values. '%hs' expects a 'char *' pointer to a multi-byte
+string encoded with the current locale, as given by the LC_CTYPE,
+LANG, or LC_ALL environment varibles. The first of this list of
+variables is used and if none of the variables are set, the locale
+defaults to "UTF-8".
+
+For example, a function is passed a locale-base name, a hat size,
+and a time value. The hat size is formatted in a UTF-8 (ASCII)
+string, and the time value is formatted into a wchar_t string.
+
+ void print_order (const char *name, int size,
+ struct tm *timep) {
+ char buf[32];
+ const char *size_val = "unknown";
+
+ if (size > 0)
+ snprintf(buf, sizeof(buf), "%d", size);
+ size_val = buf;
+ }
+
+ wchar_t when[32];
+ wcsftime(when, sizeof(when), L"%d%b%y", timep);
+
+ xo_emit("The hat for {:name/%hs} is {:size/%s}.\n",
+ name, size_val);
+ xo_emit("It was ordered on {:order-time/%ls}.\n",
+ when);
+ }
+
+It is important to note that xo_emit will perform the conversion
+required to make appropriate output. Text style output uses the
+current locale (as described above), while XML, JSON, and HTML use
+UTF-8.
+
+UTF-8 and locale-encoded strings can use multiple bytes to encode one
+column of data. The traditional "precision'" (aka "max-width") value
+for "%s" printf formatting becomes overloaded since it specifies both
+the number of bytes that can be safely referenced and the maximum
+number of columns to emit. xo_emit uses the precision as the former,
+and adds a third value for specifying the maximum number of columns.
+
+In this example, the name field is printed with a minimum of 3 columns
+and a maximum of 6. Up to ten bytes of data at the location given by
+'name' are in used in filling those columns.
+
+ xo_emit("{:name/%3.10.6s}", name);
+
+*** Characters Outside of Field Definitions
+
+Characters in the format string that are not part of a field
+definition are copied to the output for the TEXT style, and are
+ignored for the JSON and XML styles. For HTML, these characters are
+placed in a
with class "text".
+
+ EXAMPLE:
+ xo_emit("The hat is {:size/%s}.\n", size_val);
+ TEXT:
+ The hat is extra small.
+ XML:
+
extra small
+ JSON:
+ "size": "extra small"
+ HTML:
+
The hat is
+
extra small
+
.
+
+*** "%m" Is Supported
+
+libxo supports the '%m' directive, which formats the error message
+associated with the current value of "errno". It is the equivalent
+of "%s" with the argument strerror(errno).
+
+ xo_emit("{:filename} cannot be opened: {:error/%m}", filename);
+ xo_emit("{:filename} cannot be opened: {:error/%s}",
+ filename, strerror(errno));
+
+*** "%n" Is Not Supported
+
+libxo does not support the '%n' directive. It's a bad idea and we
+just don't do it.
+
+*** The Encoding Format (eformat)
+
+The "eformat" string is the format string used when encoding the field
+for JSON and XML. If not provided, it defaults to the primary format
+with any minimum width removed. If the primary is not given, both
+default to "%s".
+
+*** Content Strings
+
+For padding and labels, the content string is considered the content,
+unless a format is given.
+
+*** Argument Validation @printf-like@
+
+Many compilers and tool chains support validation of printf-like
+arguments. When the format string fails to match the argument list,
+a warning is generated. This is a valuable feature and while the
+formatting strings for libxo differ considerably from printf, many of
+these checks can still provide build-time protection against bugs.
+
+libxo provide variants of functions that provide this ability, if the
+"--enable-printflike" option is passed to the "configure" script.
+These functions use the "_p" suffix, like "xo_emit_p()",
+xo_emit_hp()", etc.
+
+The following are features of libxo formatting strings that are
+incompatible with printf-like testing:
+
+- implicit formats, where "{:tag}" has an implicit "%s";
+- the "max" parameter for strings, where "{:tag/%4.10.6s}" means up to
+ten bytes of data can be inspected to fill a minimum of 4 columns and
+a maximum of 6;
+- percent signs in strings, where "{:filled}%" makes a single,
+trailing percent sign;
+- the "l" and "h" modifiers for strings, where "{:tag/%hs}" means
+locale-based string and "{:tag/%ls}" means a wide character string;
+- distinct encoding formats, where "{:tag/#%s/%s}" means the display
+styles (text and HTML) will use "#%s" where other styles use "%s";
+
+If none of these features are in use by your code, then using the "_p"
+variants might be wise.
+
+|------------------+------------------------|
+| Function | printf-like Equivalent |
+|------------------+------------------------|
+| xo_emit_hv | xo_emit_hvp |
+| xo_emit_h | xo_emit_hp |
+| xo_emit | xo_emit_p |
+| xo_emit_warn_hcv | xo_emit_warn_hcvp |
+| xo_emit_warn_hc | xo_emit_warn_hcp |
+| xo_emit_warn_c | xo_emit_warn_cp |
+| xo_emit_warn | xo_emit_warn_p |
+| xo_emit_warnx_ | xo_emit_warnx_p |
+| xo_emit_err | xo_emit_err_p |
+| xo_emit_errx | xo_emit_errx_p |
+| xo_emit_errc | xo_emit_errc_p |
+|------------------+------------------------|
+
+*** Example
+
+In this example, the value for the number of items in stock is emitted:
+
+ xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\n",
+ instock);
+
+This call will generate the following output:
+
+ TEXT:
+ In stock: 144
+ XML:
+
144
+ JSON:
+ "in-stock": 144,
+ HTML:
+
+
+
In stock
+
:
+
+
144
+
+
+Clearly HTML wins the verbosity award, and this output does
+not include XOF_XPATH or XOF_INFO data, which would expand the
+penultimate line to:
+
+
144
+
+** Command-line Arguments
+
+libxo uses command line options to trigger rendering behavior. The
+following options are recognised:
+
+- --libxo
+- --libxo=
+- --libxo:
+
+Options is a comma-separated list of tokens that correspond to output
+styles, flags, or features:
+
+|-------------+-------------------------------------------------------|
+| Token | Action |
+|-------------+-------------------------------------------------------|
+| color | Enable colors/effects for display styles (TEXT, HTML) |
+| dtrt | Enable "Do The Right Thing" mode |
+| html | Emit HTML output |
+| indent=xx | Set the indentation level |
+| info | Add info attributes (HTML) |
+| json | Emit JSON output |
+| keys | Emit the key attribute for keys (XML) |
+| log-gettext | Log (via stderr) each gettext(3) string lookup |
+| log-syslog | Log (via stderr) each syslog message (via xo_syslog) |
+| no-humanize | Ignore the {h:} modifier (TEXT, HTML) |
+| no-locale | Do not initialize the locale setting |
+| no-top | Do not emit a top set of braces (JSON) |
+| not-first | Pretend the 1st output item was not 1st (JSON) |
+| pretty | Emit pretty-printed output |
+| text | Emit TEXT output |
+| underscores | Replace XML-friendly "-"s with JSON friendly "_"s e |
+| units | Add the 'units' (XML) or 'data-units (HTML) attribute |
+| warn | Emit warnings when libxo detects bad calls |
+| warn-xml | Emit warnings in XML |
+| xml | Emit XML output |
+| xpath | Add XPath expressions (HTML) |
+|-------------+-------------------------------------------------------|
+
+The brief options are detailed in ^LIBXO_OPTIONS^.
+
+** Representing Hierarchy
+
+For XML and JSON, individual fields appear inside hierarchies which
+provide context and meaning to the fields. Unfortunately, these
+encoding have a basic disconnect between how lists is similar objects
+are represented.
+
+XML encodes lists as set of sequential elements:
+
+ phil
+ pallavi
+ sjg
+
+JSON encodes lists using a single name and square brackets:
+
+ "user": [ "phil", "pallavi", "sjg" ]
+
+This means libxo needs three distinct indications of hierarchy: one
+for containers of hierarchy appear only once for any specific parent,
+one for lists, and one for each item in a list.
+
+*** Containers
+
+A "container" is an element of a hierarchy that appears only once
+under any specific parent. The container has no value, but serves to
+contain other nodes.
+
+To open a container, call xo_open_container() or
+xo_open_container_h(). The former uses the default handle and
+the latter accepts a specific handle.
+
+ int xo_open_container_h (xo_handle_t *xop, const char *name);
+ int xo_open_container (const char *name);
+
+To close a level, use the xo_close_container() or
+xo_close_container_h() functions:
+
+ int xo_close_container_h (xo_handle_t *xop, const char *name);
+ int xo_close_container (const char *name);
+
+Each open call must have a matching close call. If the XOF_WARN flag
+is set and the name given does not match the name of the currently open
+container, a warning will be generated.
+
+ Example:
+
+ xo_open_container("top");
+ xo_open_container("system");
+ xo_emit("{:host-name/%s%s%s", hostname,
+ domainname ? "." : "", domainname ?: "");
+ xo_close_container("system");
+ xo_close_container("top");
+
+ Sample Output:
+ Text:
+ my-host.example.org
+ XML:
+
+
+ my-host.example.org
+
+
+ JSON:
+ "top" : {
+ "system" : {
+ "host-name": "my-host.example.org"
+ }
+ }
+ HTML:
+ my-host.example.org
+
+*** Lists and Instances
+
+A list is set of one or more instances that appear under the same
+parent. The instances contain details about a specific object. One
+can think of instances as objects or records. A call is needed to
+open and close the list, while a distinct call is needed to open and
+close each instance of the list:
+
+ xo_open_list("item");
+
+ for (ip = list; ip->i_title; ip++) {
+ xo_open_instance("item");
+ xo_emit("{L:Item} '{:name/%s}':\n", ip->i_title);
+ xo_close_instance("item");
+ }
+
+ xo_close_list("item");
+
+Getting the list and instance calls correct is critical to the proper
+generation of XML and JSON data.
+
+*** DTRT Mode
+
+Some users may find tracking the names of open containers, lists, and
+instances inconvenient. libxo offers a "Do The Right Thing" mode, where
+libxo will track the names of open containers, lists, and instances so
+the close function can be called without a name. To enable DTRT mode,
+turn on the XOF_DTRT flag prior to making any other libxo output.
+
+ xo_set_flags(NULL, XOF_DTRT);
+
+Each open and close function has a version with the suffix "_d", which
+will close the open container, list, or instance:
+
+ xo_open_container("top");
+ ...
+ xo_close_container_d();
+
+This also works for lists and instances:
+
+ xo_open_list("item");
+ for (...) {
+ xo_open_instance("item");
+ xo_emit(...);
+ xo_close_instance_d();
+ }
+ xo_close_list_d();
+
+Note that the XOF_WARN flag will also cause libxo to track open
+containers, lists, and instances. A warning is generated when the
+name given to the close function and the name recorded do not match.
+
+*** Markers
+
+Markers are used to protect and restore the state of open constructs.
+While a marker is open, no other open constructs can be closed. When
+a marker is closed, all constructs open since the marker was opened
+will be closed.
+
+Markers use names which are not user-visible, allowing the caller to
+choose appropriate internal names.
+
+In this example, the code whiffles through a list of fish, calling a
+function to emit details about each fish. The marker "fish-guts" is
+used to ensure that any constructs opened by the function are closed
+properly.
+
+ for (i = 0; fish[i]; i++) {
+ xo_open_instance("fish");
+ xo_open_marker("fish-guts");
+ dump_fish_details(i);
+ xo_close_marker("fish-guts");
+ }
+
+** Handles @handles@
+
+libxo uses "handles" to control its rendering functionality. The
+handle contains state and buffered data, as well as callback functions
+to process data.
+
+A default handle is used when a NULL is passed to functions accepting
+a handle. This handle is initialized to write its data to stdout
+using the default style of text (XO_STYLE_TEXT).
+
+For the convenience of callers, the libxo library includes handle-less
+functions that implicitly use the default handle. Any function that
+takes a handle will use the default handle is a value of NULL is
+passed in place of a valid handle.
+
+For example, the following are equivalent:
+
+ xo_emit("test");
+ xo_emit_h(NULL, "test");
+
+Handles are created using xo_create() and destroy using xo_destroy().
+
+** UTF-8
+
+All strings for libxo must be UTF-8. libxo will handle turning them
+into locale-based strings for display to the user.
+
+The only exception is argument formatted using the "%ls" format, which
+require a wide character string (wchar_t *) as input. libxo will
+convert these arguments as needed to either UTF-8 (for XML, JSON, and
+HTML styles) or locale-based strings for display in text style.
+
+ xo_emit("Alll strings are utf-8 content {:tag/%ls}",
+ L"except for wide strings");
+
+"%S" is equivalent to "%ls".
+
+* The libxo API
+
+This section gives details about the functions in libxo, how to call
+them, and the actions they perform.
+
+** Handles
+
+Handles give an abstraction for libxo that encapsulates the state of a
+stream of output. Handles have the data type "xo_handle_t" and are
+opaque to the caller.
+
+The library has a default handle that is automatically initialized.
+By default, this handle will send text style output to standard output.
+The xo_set_style and xo_set_flags functions can be used to change this
+behavior.
+
+Many libxo functions take a handle as their first parameter; most that
+do not use the default handle. Any function taking a handle can
+be passed NULL to access the default handle.
+
+For the typical command that is generating output on standard output,
+there is no need to create an explicit handle, but they are available
+when needed, e.g., for daemons that generate multiple streams of
+output.
+
+*** xo_create
+
+A handle can be allocated using the xo_create() function:
+
+ xo_handle_t *xo_create (unsigned style, unsigned flags);
+
+ Example:
+ xo_handle_t *xop = xo_create(XO_STYLE_JSON, XOF_WARN);
+ ....
+ xo_emit_h(xop, "testing\n");
+
+See also ^styles^ and ^flags^.
+
+*** xo_create_to_file
+
+By default, libxo writes output to standard output. A convenience
+function is provided for situations when output should be written to
+a different file:
+
+ xo_handle_t *xo_create_to_file (FILE *fp, unsigned style,
+ unsigned flags);
+
+Use the XOF_CLOSE_FP flag to trigger a call to fclose() for
+the FILE pointer when the handle is destroyed.
+
+*** xo_set_writer
+
+The xo_set_writer function allows custom 'write' functions
+which can tailor how libxo writes data. An opaque argument is
+recorded and passed back to the write function, allowing the function
+to acquire context information. The 'close' function can
+release this opaque data and any other resources as needed.
+The flush function can flush buffered data associated with the opaque
+object.
+
+ void xo_set_writer (xo_handle_t *xop, void *opaque,
+ xo_write_func_t write_func,
+ xo_close_func_t close_func);
+ xo_flush_func_t flush_func);
+
+*** xo_set_style
+
+To set the style, use the xo_set_style() function:
+
+ void xo_set_style(xo_handle_t *xop, unsigned style);
+
+To use the default handle, pass a NULL handle:
+
+ xo_set_style(NULL, XO_STYLE_XML);
+
+**** Output Styles (XO_STYLE_*) @styles@
+
+The libxo functions accept a set of output styles:
+
+|---------------+-------------------------|
+| Flag | Description |
+|---------------+-------------------------|
+| XO_STYLE_TEXT | Traditional text output |
+| XO_STYLE_XML | XML encoded data |
+| XO_STYLE_JSON | JSON encoded data |
+| XO_STYLE_HTML | HTML encoded data |
+|---------------+-------------------------|
+
+**** xo_set_style_name
+
+The xo_set_style_name() can be used to set the style based on a name
+encoded as a string:
+
+ int xo_set_style_name (xo_handle_t *xop, const char *style);
+
+The name can be any of the styles: "text", "xml", "json", or "html".
+
+ EXAMPLE:
+ xo_set_style_name(NULL, "html");
+
+*** xo_set_flags
+
+To set the flags, use the xo_set_flags() function:
+
+ void xo_set_flags(xo_handle_t *xop, unsigned flags);
+
+To use the default handle, pass a NULL handle:
+
+ xo_set_style(NULL, XO_STYLE_XML);
+
+**** Flags (XOF_*) @flags@
+
+The set of valid flags include:
+
+|-------------------+----------------------------------------|
+| Flag | Description |
+|-------------------+----------------------------------------|
+| XOF_CLOSE_FP | Close file pointer on xo_destroy() |
+| XOF_COLOR | Enable color and effects in output |
+| XOF_COLOR_ALLOWED | Allow color/effect for terminal output |
+| XOF_DTRT | Enable "do the right thing" mode |
+| XOF_INFO | Display info data attributes (HTML) |
+| XOF_KEYS | Emit the key attribute (XML) |
+| XOF_NO_ENV | Do not use the LIBXO_OPTIONS env var |
+| XOF_NO_HUMANIZE | Display humanization (TEXT, HTML) |
+| XOF_PRETTY | Make 'pretty printed' output |
+| XOF_UNDERSCORES | Replaces hyphens with underscores |
+| XOF_UNITS | Display units (XML, HMTL) |
+| XOF_WARN | Generate warnings for broken calls |
+| XOF_WARN_XML | Generate warnings in XML on stdout |
+| XOF_XPATH | Emit XPath expressions (HTML) |
+| XOF_COLUMNS | Force xo_emit to return columns used |
+| XOF_FLUSH | Flush output after each xo_emit call |
+|-------------------+----------------------------------------|
+
+The XOF_CLOSE_FP flag will trigger the call of the close_func
+(provided via xo_set_writer()) when the handle is destroyed.
+
+The XOF_COLOR flag enables color and effects in output regardless of
+output device, while the XOF_COLOR_ALLOWED flag allows color and
+effects only if the output device is a terminal.
+
+The XOF_PRETTY flag requests 'pretty printing', which will trigger the
+addition of indentation and newlines to enhance the readability of
+XML, JSON, and HTML output. Text output is not affected.
+
+The XOF_WARN flag requests that warnings will trigger diagnostic
+output (on standard error) when the library notices errors during
+operations, or with arguments to functions. Without warnings enabled,
+such conditions are ignored.
+
+Warnings allow developers to debug their interaction with libxo.
+The function "xo_failure" can used as a breakpoint for a debugger,
+regardless of whether warnings are enabled.
+
+If the style is XO_STYLE_HTML, the following additional flags can be
+used:
+
+|---------------+-----------------------------------------|
+| Flag | Description |
+|---------------+-----------------------------------------|
+| XOF_XPATH | Emit "data-xpath" attributes |
+| XOF_INFO | Emit additional info fields |
+|---------------+-----------------------------------------|
+
+The XOF_XPATH flag enables the emission of XPath expressions detailing
+the hierarchy of XML elements used to encode the data field, if the
+XPATH style of output were requested.
+
+The XOF_INFO flag encodes additional informational fields for HTML
+output. See ^info^ for details.
+
+If the style is XO_STYLE_XML, the following additional flags can be
+used:
+
+|---------------+-----------------------------------------|
+| Flag | Description |
+|---------------+-----------------------------------------|
+| XOF_KEYS | Flag 'key' fields for xml |
+|---------------+-----------------------------------------|
+
+The XOF_KEYS flag adds 'key' attribute to the XML encoding for
+field definitions that use the 'k' modifier. The key attribute has
+the value "key":
+
+ xo_emit("{k:name}", item);
+
+ XML:
+ truck
+
+**** xo_clear_flags
+
+The xo_clear_flags() function turns off the given flags in a specific
+handle.
+
+ void xo_clear_flags (xo_handle_t *xop, xo_xof_flags_t flags);
+
+**** xo_set_options
+
+The xo_set_options() function accepts a comma-separated list of styles
+and flags and enables them for a specific handle.
+
+ int xo_set_options (xo_handle_t *xop, const char *input);
+
+The options are identical to those listed in ^command-line-arguments^.
+
+*** xo_destroy
+
+The xo_destroy function releases a handle and any resources it is
+using. Calling xo_destroy with a NULL handle will release any
+resources associated with the default handle.
+
+ void xo_destroy(xo_handle_t *xop);
+
+** Emitting Content (xo_emit)
+
+The following functions are used to emit output:
+
+ int xo_emit (const char *fmt, ...);
+ int xo_emit_h (xo_handle_t *xop, const char *fmt, ...);
+ int xo_emit_hv (xo_handle_t *xop, const char *fmt, va_list vap);
+
+The "fmt" argument is a string containing field descriptors as
+specified in ^format-strings^. The use of a handle is optional and
+NULL can be passed to access the internal 'default' handle. See
+^handles^.
+
+The remaining arguments to xo_emit() and xo_emit_h() are a set of
+arguments corresponding to the fields in the format string. Care must
+be taken to ensure the argument types match the fields in the format
+string, since an inappropriate cast can ruin your day. The vap
+argument to xo_emit_hv() points to a variable argument list that can
+be used to retrieve arguments via va_arg().
+
+*** Attributes (xo_attr) @xo_attr@
+
+The xo_attr() function emits attributes for the XML output style.
+
+
+ int xo_attr (const char *name, const char *fmt, ...);
+ int xo_attr_h (xo_handle_t *xop, const char *name,
+ const char *fmt, ...);
+ int xo_attr_hv (xo_handle_t *xop, const char *name,
+ const char *fmt, va_list vap);
+
+The name parameter give the name of the attribute to be encoded. The
+fmt parameter gives a printf-style format string used to format the
+value of the attribute using any remaining arguments, or the vap
+parameter passed to xo_attr_hv().
+
+ EXAMPLE:
+ xo_attr("seconds", "%ld", (unsigned long) login_time);
+ struct tm *tmp = localtime(login_time);
+ strftime(buf, sizeof(buf), "%R", tmp);
+ xo_emit("Logged in at {:login-time}\n", buf);
+ XML:
+ 00:14
+
+xo_attr is placed on the next container, instance, leaf, or leaf list
+that is emitted.
+
+Since attributes are only emitted in XML, their use should be limited
+to meta-data and additional or redundant representations of data
+already emitted in other form.
+
+*** Flushing Output (xo_flush)
+
+libxo buffers data, both for performance and consistency, but also to
+allow some advanced features to work properly. At various times, the
+caller may wish to flush any data buffered within the library. The
+xo_flush() call is used for this:
+
+ void xo_flush (void);
+ void xo_flush_h (xo_handle_t *xop);
+
+Calling xo_flush also triggers the flush function associated with the
+handle. For the default handle, this is equivalent to
+"fflush(stdio);".
+
+*** Finishing Output (xo_finish)
+
+When the program is ready to exit or close a handle, a call to
+xo_finish() is required. This flushes any buffered data, closes
+open libxo constructs, and completes any pending operations.
+
+ int xo_finish (void);
+ int xo_finish_h (xo_handle_t *xop);
+ void xo_finish_atexit (void);
+
+Calling this function is vital to the proper operation of libxo,
+especially for the non-TEXT output styles.
+
+xo_finish_atexit is suitable for use with atexit(3).
+
+** Emitting Hierarchy
+
+libxo represents to types of hierarchy: containers and lists. A
+container appears once under a given parent where a list contains
+instances that can appear multiple times. A container is used to hold
+related fields and to give the data organization and scope.
+
+To create a container, use the xo_open_container and
+xo_close_container functions:
+
+ int xo_open_container (const char *name);
+ int xo_open_container_h (xo_handle_t *xop, const char *name);
+ int xo_open_container_hd (xo_handle_t *xop, const char *name);
+ int xo_open_container_d (const char *name);
+
+ int xo_close_container (const char *name);
+ int xo_close_container_h (xo_handle_t *xop, const char *name);
+ int xo_close_container_hd (xo_handle_t *xop);
+ int xo_close_container_d (void);
+
+The name parameter gives the name of the container, encoded in UTF-8.
+Since ASCII is a proper subset of UTF-8, traditional C strings can be
+used directly.
+
+The close functions with the "_d" suffix are used in "Do The Right
+Thing" mode, where the name of the open containers, lists, and
+instances are maintained internally by libxo to allow the caller to
+avoid keeping track of the open container name.
+
+Use the XOF_WARN flag to generate a warning if the name given on the
+close does not match the current open container.
+
+For TEXT and HTML output, containers are not rendered into output
+text, though for HTML they are used when the XOF_XPATH flag is set.
+
+ EXAMPLE:
+ xo_open_container("system");
+ xo_emit("The host name is {:host-name}\n", hn);
+ xo_close_container("system");
+ XML:
+ foo
+
+*** Lists and Instances
+
+Lists are sequences of instances of homogeneous data objects. Two
+distinct levels of calls are needed to represent them in our output
+styles. Calls must be made to open and close a list, and for each
+instance of data in that list, calls must be make to open and close
+that instance.
+
+The name given to all calls must be identical, and it is strongly
+suggested that the name be singular, not plural, as a matter of
+style and usage expectations.
+
+ EXAMPLE:
+ xo_open_list("user");
+ for (i = 0; i < num_users; i++) {
+ xo_open_instance("user");
+ xo_emit("{k:name}:{:uid/%u}:{:gid/%u}:{:home}\n",
+ pw[i].pw_name, pw[i].pw_uid,
+ pw[i].pw_gid, pw[i].pw_dir);
+ xo_close_instance("user");
+ }
+ xo_close_list("user");
+ TEXT:
+ phil:1001:1001:/home/phil
+ pallavi:1002:1002:/home/pallavi
+ XML:
+
+ phil
+ 1001
+ 1001
+ /home/phil
+
+
+ pallavi
+ 1002
+ 1002
+ /home/pallavi
+
+ JSON:
+ user: [
+ {
+ "name": "phil",
+ "uid": 1001,
+ "gid": 1001,
+ "home": "/home/phil",
+ },
+ {
+ "name": "pallavi",
+ "uid": 1002,
+ "gid": 1002,
+ "home": "/home/pallavi",
+ }
+ ]
+
+** Support Functions
+
+*** Parsing Command-line Arguments (xo_parse_args) @xo_parse_args@
+
+The xo_parse_args() function is used to process a program's
+arguments. libxo-specific options are processed and removed
+from the argument list so the calling application does not
+need to process them. If successful, a new value for argc
+is returned. On failure, a message it emitted and -1 is returned.
+
+ argc = xo_parse_args(argc, argv);
+ if (argc < 0)
+ exit(EXIT_FAILURE);
+
+Following the call to xo_parse_args, the application can process the
+remaining arguments in a normal manner. See ^command-line-arguments^
+for a description of valid arguments.
+
+*** xo_set_program
+
+The xo_set_program function sets name of the program as reported by
+functions like xo_failure, xo_warn, xo_err, etc. The program name is
+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
+begin with "data-". To enable this, three things must occur:
+
+First the application must build an array of xo_info_t structures,
+one per tag. The array must be sorted by name, since libxo uses a
+binary search to find the entry that matches names from format
+instructions.
+
+Second, the application must inform libxo about this information using
+the xo_set_info() call:
+
+ typedef struct xo_info_s {
+ const char *xi_name; /* Name of the element */
+ const char *xi_type; /* Type of field */
+ const char *xi_help; /* Description of field */
+ } xo_info_t;
+
+ void xo_set_info (xo_handle_t *xop, xo_info_t *infop, int count);
+
+Like other libxo calls, passing NULL for the handle tells libxo to use
+the default handle.
+
+If the count is -1, libxo will count the elements of infop, but there
+must be an empty element at the end. More typically, the number is
+known to the application:
+
+ xo_info_t info[] = {
+ { "in-stock", "number", "Number of items in stock" },
+ { "name", "string", "Name of the item" },
+ { "on-order", "number", "Number of items on order" },
+ { "sku", "string", "Stock Keeping Unit" },
+ { "sold", "number", "Number of items sold" },
+ };
+ int info_count = (sizeof(info) / sizeof(info[0]));
+ ...
+ xo_set_info(NULL, info, info_count);
+
+Third, the emission of info must be triggered with the XOF_INFO flag
+using either the xo_set_flags() function or the "--libxo=info" command
+line argument.
+
+The type and help values, if present, are emitted as the "data-type"
+and "data-help" attributes:
+
+ GRO-000-533
+
+*** Memory Allocation
+
+The xo_set_allocator function allows libxo to be used in environments
+where the standard realloc() and free() functions are not available.
+
+ void xo_set_allocator (xo_realloc_func_t realloc_func,
+ xo_free_func_t free_func);
+
+realloc_func should expect the same arguments as realloc(3) and return
+a pointer to memory following the same convention. free_func will
+receive the same argument as free(3) and should release it, as
+appropriate for the environment.
+
+By default, the standard realloc() and free() functions are used.
+
+*** LIBXO_OPTIONS @LIBXO_OPTIONS@
+
+The environment variable "LIBXO_OPTIONS" can be set to a string of
+options:
+
+|--------+---------------------------------------------|
+| Option | Action |
+|--------+---------------------------------------------|
+| c | Enable color/effects for TEXT/HTML |
+| F | Force line-buffered flushing |
+| H | Enable HTML output (XO_STYLE_HTML) |
+| I | Enable info output (XOF_INFO) |
+| i | Indent by |
+| J | Enable JSON output (XO_STYLE_JSON) |
+| k | Add keys to XPATH expressions in HTML |
+| n | Disable humanization (TEXT, HTML) |
+| P | Enable pretty-printed output (XOF_PRETTY) |
+| T | Enable text output (XO_STYLE_TEXT) |
+| U | Add units to HTML output |
+| u | Change "-"s to "_"s in element names (JSON) |
+| W | Enable warnings (XOF_WARN) |
+| X | Enable XML output (XO_STYLE_XML) |
+| x | Enable XPath data (XOF_XPATH) |
+|--------+---------------------------------------------|
+
+For example, warnings can be enabled by:
+
+ % env LIBXO_OPTIONS=W my-app
+
+Complete HTML output can be generated with:
+
+ % env LIBXO_OPTIONS=HXI my-app
+
+Since environment variables are inherited, child processes will have
+the same options, which may be undesirable, making the use of the
+"--libxo" option is preferable in most situations.
+
+*** Errors, Warnings, and Messages
+
+Many programs make use of the standard library functions err() and
+warn() to generate errors and warnings for the user. libxo wants to
+pass that information via the current output style, and provides
+compatible functions to allow this:
+
+ void xo_warn (const char *fmt, ...);
+ void xo_warnx (const char *fmt, ...);
+ void xo_warn_c (int code, const char *fmt, ...);
+ void xo_warn_hc (xo_handle_t *xop, int code,
+ const char *fmt, ...);
+ void xo_err (int eval, const char *fmt, ...);
+ void xo_errc (int eval, int code, const char *fmt, ...);
+ void xo_errx (int eval, const char *fmt, ...);
+ void xo_message (const char *fmt, ...);
+ void xo_message_c (int code, const char *fmt, ...);
+ void xo_message_hc (xo_handle_t *xop, int code,
+ const char *fmt, ...);
+ void xo_message_hcv (xo_handle_t *xop, int code,
+ const char *fmt, va_list vap);
+
+These functions display the program name, a colon, a formatted message
+based on the arguments, and then optionally a colon and an error
+message associated with either "errno" or the "code" parameter.
+
+ EXAMPLE:
+ if (open(filename, O_RDONLY) < 0)
+ xo_err(1, "cannot open file '%s'", filename);
+
+*** xo_error
+
+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 puts
+the error into XML or JSON elements:
+
+ EXAMPLE::
+ xo_error("Does not %s", "compute");
+ XML::
+ Does not compute
+ JSON::
+ "error": { "message": "Does not compute" }
+
+*** xo_no_setlocale
+
+libxo automatically initializes the locale based on setting of the
+environment variables LC_CTYPE, LANG, and LC_ALL. The first of this
+list of variables is used and if none of the variables, the locale
+defaults to "UTF-8". The caller may wish to avoid this behavior, and
+can do so by calling the xo_no_setlocale() function.
+
+ void xo_no_setlocale (void);
+
+** Emitting syslog Messages
+
+syslog is the system logging facility used throughout the unix world.
+Messages are sent from commands, applications, and daemons to a
+hierarchy of servers, where they are filtered, saved, and forwarded
+based on configuration behaviors.
+
+syslog is an older protocol, originally documented only in source
+code. By the time RFC 3164 published, variation and mutation left the
+leading "" string as only common content. RFC 5424 defines a new
+version (version 1) of syslog and introduces structured data into the
+messages. Structured data is a set of name/value pairs transmitted
+distinctly alongside the traditional text message, allowing filtering
+on precise values instead of regular expressions.
+
+These name/value pairs are scoped by a two-part identifier; an
+enterprise identifier names the party responsible for the message
+catalog and a name identifying that message. Enterprise IDs are
+defined by IANA, the Internet Assigned Numbers Authority:
+
+https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers
+
+Use the ^xo_set_syslog_enterprise_id^() function to set the Enterprise
+ID, as needed.
+
+The message name should follow the conventions in ^good-field-names^,
+as should the fields within the message.
+
+ /* Both of these calls are optional */
+ xo_set_syslog_enterprise_id(32473);
+ xo_open_log("my-program", 0, LOG_DAEMON);
+
+ /* Generate a syslog message */
+ xo_syslog(LOG_ERR, "upload-failed",
+ "error <%d> uploading file '{:filename}' "
+ "as '{:target/%s:%s}'",
+ code, filename, protocol, remote);
+
+ xo_syslog(LOG_INFO, "poofd-invalid-state",
+ "state {:current/%u} is invalid {:connection/%u}",
+ state, conn);
+
+The developer should be aware that the message name may be used in the
+future to allow access to further information, including
+documentation. Care should be taken to choose quality, descriptive
+names.
+
+*** Priority, Facility, and Flags @priority@
+
+The xo_syslog, xo_vsyslog, and xo_open_log functions accept a set of
+flags which provide the priority of the message, the source facility,
+and some additional features. These values are OR'd together to
+create a single integer argument:
+
+ xo_syslog(LOG_ERR | LOG_AUTH, "login-failed",
+ "Login failed; user '{:user}' from host '{:address}'",
+ user, addr);
+
+These values are defined in .
+
+The priority value indicates the importance and potential impact of
+each message.
+
+|-------------+-------------------------------------------------------|
+| Priority | Description |
+|-------------+-------------------------------------------------------|
+| LOG_EMERG | A panic condition, normally broadcast to all users |
+| LOG_ALERT | A condition that should be corrected immediately |
+| LOG_CRIT | Critical conditions |
+| LOG_ERR | Generic errors |
+| LOG_WARNING | Warning messages |
+| LOG_NOTICE | Non-error conditions that might need special handling |
+| LOG_INFO | Informational messages |
+| LOG_DEBUG | Developer-oriented messages |
+|-------------+-------------------------------------------------------|
+
+The facility value indicates the source of message, in fairly generic
+terms.
+
+|---------------+-------------------------------------------------|
+| Facility | Description |
+|---------------+-------------------------------------------------|
+| LOG_AUTH | The authorization system (e.g. login(1)) |
+| LOG_AUTHPRIV | As LOG_AUTH, but logged to a privileged file |
+| LOG_CRON | The cron daemon: cron(8) |
+| LOG_DAEMON | System daemons, not otherwise explicitly listed |
+| LOG_FTP | The file transfer protocol daemons |
+| LOG_KERN | Messages generated by the kernel |
+| LOG_LPR | The line printer spooling system |
+| LOG_MAIL | The mail system |
+| LOG_NEWS | The network news system |
+| LOG_SECURITY | Security subsystems, such as ipfw(4) |
+| LOG_SYSLOG | Messages generated internally by syslogd(8) |
+| LOG_USER | Messages generated by user processes (default) |
+| LOG_UUCP | The uucp system |
+| LOG_LOCAL0..7 | Reserved for local use |
+|---------------+-------------------------------------------------|
+
+In addition to the values listed above, xo_open_log accepts a set of
+addition flags requesting specific behaviors.
+
+|------------+----------------------------------------------------|
+| Flag | Description |
+|------------+----------------------------------------------------|
+| LOG_CONS | If syslogd fails, attempt to write to /dev/console |
+| LOG_NDELAY | Open the connection to syslogd(8) immediately |
+| LOG_PERROR | Write the message also to standard error output |
+| LOG_PID | Log the process id with each message |
+|------------+----------------------------------------------------|
+
+*** xo_syslog
+
+Use the xo_syslog function to generate syslog messages by calling it
+with a log priority and facility, a message name, a format string, and
+a set of arguments. The priority/facility argument are discussed
+above, as is the message name.
+
+The format string follows the same conventions as xo_emit's format
+string, with each field being rendered as an SD-PARAM pair.
+
+ xo_syslog(LOG_ERR, "poofd-missing-file",
+ "'{:filename}' not found: {:error/%m}", filename);
+
+ ... [poofd-missing-file@32473 filename="/etc/poofd.conf"
+ error="Permission denied"] '/etc/poofd.conf' not
+ found: Permission denied
+
+*** Support functions
+
+**** xo_vsyslog
+
+xo_vsyslog is identical in function to xo_syslog, but takes the set of
+arguments using a va_list.
+
+ void my_log (const char *name, const char *fmt, ...)
+ {
+ va_list vap;
+ va_start(vap, fmt);
+ xo_vsyslog(LOG_ERR, name, fmt, vap);
+ va_end(vap);
+ }
+
+**** xo_open_log
+
+xo_open_log functions similar to openlog(3), allowing customization of
+the program name, the log facility number, and the additional option
+flags described in ^priority^.
+
+ void
+ xo_open_log (const char *ident, int logopt, int facility);
+
+**** xo_close_log
+
+xo_close_log functions similar to closelog(3), closing the log file
+and releasing any associated resources.
+
+ void
+ xo_close_log (void);
+
+**** xo_set_logmask
+
+xo_set_logmask function similar to setlogmask(3), restricting the set
+of generated log event to those whose associated bit is set in
+maskpri. Use LOG_MASK(pri) to find the appropriate bit, or
+LOG_UPTO(toppri) to create a mask for all priorities up to and
+including toppri.
+
+ int
+ xo_set_logmask (int maskpri);
+
+ Example:
+ setlogmask(LOG_UPTO(LOG_WARN));
+
+**** xo_set_syslog_enterprise_id
+
+Use the xo_set_syslog_enterprise_id to supply a platform- or
+application-specific enterprise id. This value is used in any
+future syslog messages.
+
+Ideally, the operating system should supply a default value via the
+"kern.syslog.enterprise_id" sysctl value. Lacking that, the
+application should provide a suitable value.
+
+ void
+ xo_set_syslog_enterprise_id (unsigned short eid);
+
+Enterprise IDs are administered by IANA, the Internet Assigned Number
+Authority. The complete list is EIDs on their web site:
+
+ https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers
+
+New EIDs can be requested from IANA using the following page:
+
+ http://pen.iana.org/pen/PenApplication.page
+
+Each software development organization that defines a set of syslog
+messages should register their own EID and use that value in their
+software to ensure that messages can be uniquely identified by the
+combination of EID + message name.
+
+** Creating Custom Encoders
+
+The number of encoding schemes in current use is staggering, with new
+and distinct schemes appearing daily. While libxo provide XML, JSON,
+HMTL, and text natively, there are requirements for other encodings.
+
+Rather than bake support for all possible encoders into libxo, the API
+allows them to be defined externally. libxo can then interfaces with
+these encoding modules using a simplistic API. libxo processes all
+functions calls, handles state transitions, performs all formatting,
+and then passes the results as operations to a customized encoding
+function, which implements specific encoding logic as required. This
+means your encoder doesn't need to detect errors with unbalanced
+open/close operations but can rely on libxo to pass correct data.
+
+By making a simple API, libxo internals are not exposed, insulating the
+encoder and the library from future or internal changes.
+
+The three elements of the API are:
+- loading
+- initialization
+- operations
+
+The following sections provide details about these topics.
+
+libxo source contain an encoder for Concise Binary Object
+Representation, aka CBOR (RFC 7049) which can be used as used as an
+example for the API.
+
+*** Loading Encoders
+
+Encoders can be registered statically or discovered dynamically.
+Applications can choose to call the xo_encoder_register()
+function to explicitly register encoders, but more typically they are
+built as shared libraries, placed in the libxo/extensions directory,
+and loaded based on name. libxo looks for a file with the name of the encoder
+and an extension of ".enc". This can be a file or a symlink to the
+shared library file that supports the encoder.
+
+ % ls -1 lib/libxo/extensions/*.enc
+ lib/libxo/extensions/cbor.enc
+ lib/libxo/extensions/test.enc
+
+*** Encoder Initialization
+
+Each encoder must export a symbol used to access the library, which
+must have the following signature:
+
+ int xo_encoder_library_init (XO_ENCODER_INIT_ARGS);
+
+XO_ENCODER_INIT_ARGS is a macro defined in xo_encoder.h that defines
+an argument called "arg", a pointer of the type
+xo_encoder_init_args_t. This structure contains two fields:
+
+- xei_version is the version number of the API as implemented within
+libxo. This version is currently as 1 using XO_ENCODER_VERSION. This
+number can be checked to ensure compatibility. The working assumption
+is that all versions should be backward compatible, but each side may
+need to accurately know the version supported by the other side.
+xo_encoder_library_init can optionally check this value, and must then
+set it to the version number used by the encoder, allowing libxo to
+detect version differences and react accordingly. For example, if
+version 2 adds new operations, then libxo will know that an encoding
+library that set xei_version to 1 cannot be expected to handle those
+new operations.
+
+- xei_handler must be set to a pointer to a function of type
+xo_encoder_func_t, as defined in xo_encoder.h. This function
+takes a set of parameters:
+-- xop is a pointer to the opaque xo_handle_t structure
+-- op is an integer representing the current operation
+-- name is a string whose meaning differs by operation
+-- value is a string whose meaning differs by operation
+-- private is an opaque structure provided by the encoder
+
+Additional arguments may be added in the future, so handler functions
+should use the XO_ENCODER_HANDLER_ARGS macro. An appropriate
+"extern" declaration is provided to help catch errors.
+
+Once the encoder initialization function has completed processing, it
+should return zero to indicate that no error has occurred. A non-zero
+return code will cause the handle initialization to fail.
+
+*** Operations
+
+The encoder API defines a set of operations representing the
+processing model of libxo. Content is formatted within libxo, and
+callbacks are made to the encoder's handler function when data is
+ready to be processed.
+
+|-----------------------+---------------------------------------|
+| Operation | Meaning (Base function) |
+|-----------------------+---------------------------------------|
+| XO_OP_CREATE | Called when the handle is created |
+| XO_OP_OPEN_CONTAINER | Container opened (xo_open_container) |
+| XO_OP_CLOSE_CONTAINER | Container closed (xo_close_container) |
+| XO_OP_OPEN_LIST | List opened (xo_open_list) |
+| XO_OP_CLOSE_LIST | List closed (xo_close_list) |
+| XO_OP_OPEN_LEAF_LIST | Leaf list opened (xo_open_leaf_list) |
+| XO_OP_CLOSE_LEAF_LIST | Leaf list closed (xo_close_leaf_list) |
+| XO_OP_OPEN_INSTANCE | Instance opened (xo_open_instance) |
+| XO_OP_CLOSE_INSTANCE | Instance closed (xo_close_instance) |
+| XO_OP_STRING | Field with Quoted UTF-8 string |
+| XO_OP_CONTENT | Field with content |
+| XO_OP_FINISH | Finish any pending output |
+| XO_OP_FLUSH | Flush any buffered output |
+| XO_OP_DESTROY | Clean up resources |
+| XO_OP_ATTRIBUTE | An attribute name/value pair |
+| XO_OP_VERSION | A version string |
+|-----------------------+---------------------------------------|
+
+For all the open and close operations, the name parameter holds the
+name of the construct. For string, content, and attribute operations,
+the name parameter is the name of the field and the value parameter is
+the value. "string" are differentiated from "content" to allow differing
+treatment of true, false, null, and numbers from real strings, though
+content values are formatted as strings before the handler is called.
+For version operations, the value parameter contains the version.
+
+All strings are encoded in UTF-8.
+
+* The "xo" Utility
+
+The "xo" utility allows command line access to the functionality of
+the libxo library. Using "xo", shell scripts can emit XML, JSON, and
+HTML using the same commands that emit text output.
+
+The style of output can be selected using a specific option: "-X" for
+XML, "-J" for JSON, "-H" for HTML, or "-T" for TEXT, which is the
+default. The "--style ardinalyay ammetersgray Ermissionpay eniedday 6 otuslay-oyay-eltayay
\ No newline at end of file
Index: vendor/Juniper/libxo/dist/tests/gettext/saved/gt_01.XP.err
===================================================================
Index: vendor/Juniper/libxo/dist/tests/gettext/saved/gt_01.XP.out
===================================================================
--- vendor/Juniper/libxo/dist/tests/gettext/saved/gt_01.XP.out (nonexistent)
+++ vendor/Juniper/libxo/dist/tests/gettext/saved/gt_01.XP.out (revision 296962)
@@ -0,0 +1,49 @@
+
+ amingflay
+ ordsway
+ urningbay
+ ymay
+ ouchcay
+ amingflay
+ ordsway
+ urningbay
+ ymay
+ ouchcay
+ 0
+ 1
+ 2
+ 3
+ 4
+ 1234
+ 1234
+ foop
+ 4321
+ 32
+ 1234
+ foop
+ 4321
+ 32
+ 1234
+ foop
+ 4321
+ 32
+ 3
+ 1.2.3
+ Tue Jun 23 18:47:09 UTC 2015
+ <__warning>
+ gt_01.test
+ Nableuay otay ectulatobjay orwardfay elocipingvay
+ ectulatobjay
+ Ermissionpay eniedday
+
+ <__warning>
+ gt_01.test
+ automaticyay ynchronizationsay ofyay ardinalyay ammetersgray ailedfay
+
+ ardinalyay
+ ammetersgray
+ Ermissionpay eniedday
+
+ 6
+ otuslay-oyay-eltayay
+
Index: vendor/Juniper/libxo/dist/tests/gettext/strerror.pot
===================================================================
--- vendor/Juniper/libxo/dist/tests/gettext/strerror.pot (nonexistent)
+++ vendor/Juniper/libxo/dist/tests/gettext/strerror.pot (revision 296962)
@@ -0,0 +1,468 @@
+#
+# Copyright (c) 1982, 1985, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 4. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# List of system errors ala strerror() and sys_errlist
+# Phil Shafer , 2015.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2015-07-01 16:15-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: LANGUAGE \n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Received {:received} {N:byte,bytes} from {:from}#{:port} in {:time} ms\n"
+msgstr ""
+
+# 0 - ENOERROR
+msgid "No error: 0"
+msgstr ""
+
+# 1 - EPERM
+msgid "Operation not permitted"
+msgstr ""
+
+# 2 - ENOENT
+msgid "No such file or directory"
+msgstr ""
+
+# 3 - ESRCH
+msgid "No such process"
+msgstr ""
+
+# 4 - EINTR
+msgid "Interrupted system call"
+msgstr ""
+
+# 5 - EIO
+msgid "Input/output error"
+msgstr ""
+
+# 6 - ENXIO
+msgid "Device not configured"
+msgstr ""
+
+# 7 - E2BIG
+msgid "Argument list too long"
+msgstr ""
+
+# 8 - ENOEXEC
+msgid "Exec format error"
+msgstr ""
+
+# 9 - EBADF
+msgid "Bad file descriptor"
+msgstr ""
+
+# 10 - ECHILD
+msgid "No child processes"
+msgstr ""
+
+# 11 - EDEADLK
+msgid "Resource deadlock avoided"
+msgstr ""
+
+# 12 - ENOMEM
+msgid "Cannot allocate memory"
+msgstr ""
+
+# 13 - EACCES
+msgid "Permission denied"
+msgstr ""
+
+# 14 - EFAULT
+msgid "Bad address"
+msgstr ""
+
+# 15 - ENOTBLK
+msgid "Block device required"
+msgstr ""
+
+# 16 - EBUSY
+msgid "Device busy"
+msgstr ""
+
+# 17 - EEXIST
+msgid "File exists"
+msgstr ""
+
+# 18 - EXDEV
+msgid "Cross-device link"
+msgstr ""
+
+# 19 - ENODEV
+msgid "Operation not supported by device"
+msgstr ""
+
+# 20 - ENOTDIR
+msgid "Not a directory"
+msgstr ""
+
+# 21 - EISDIR
+msgid "Is a directory"
+msgstr ""
+
+# 22 - EINVAL
+msgid "Invalid argument"
+msgstr ""
+
+# 23 - ENFILE
+msgid "Too many open files in system"
+msgstr ""
+
+# 24 - EMFILE
+msgid "Too many open files"
+msgstr ""
+
+# 25 - ENOTTY
+msgid "Inappropriate ioctl for device"
+msgstr ""
+
+# 26 - ETXTBSY
+msgid "Text file busy"
+msgstr ""
+
+# 27 - EFBIG
+msgid "File too large"
+msgstr ""
+
+# 28 - ENOSPC
+msgid "No space left on device"
+msgstr ""
+
+# 29 - ESPIPE
+msgid "Illegal seek"
+msgstr ""
+
+# 30 - EROFS
+msgid "Read-only file system"
+msgstr ""
+
+# 31 - EMLINK
+msgid "Too many links"
+msgstr ""
+
+# 32 - EPIPE
+msgid "Broken pipe"
+msgstr ""
+
+#
+# math software
+#
+
+# 33 - EDOM
+msgid "Numerical argument out of domain"
+msgstr ""
+
+# 34 - ERANGE
+msgid "Result too large"
+msgstr ""
+
+#
+# non-blocking and interrupt i/o
+#
+
+# 35 - EAGAIN
+# 35 - EWOULDBLOCK
+msgid "Resource temporarily unavailable"
+msgstr ""
+
+# 36 - EINPROGRESS
+msgid "Operation now in progress"
+msgstr ""
+
+# 37 - EALREADY
+msgid "Operation already in progress"
+msgstr ""
+
+
+#
+# ipc/network software -- argument errors
+#
+
+# 38 - ENOTSOCK
+msgid "Socket operation on non-socket"
+msgstr ""
+
+# 39 - EDESTADDRREQ
+msgid "Destination address required"
+msgstr ""
+
+# 40 - EMSGSIZE
+msgid "Message too long"
+msgstr ""
+
+# 41 - EPROTOTYPE
+msgid "Protocol wrong type for socket"
+msgstr ""
+
+# 42 - ENOPROTOOPT
+msgid "Protocol not available"
+msgstr ""
+
+# 43 - EPROTONOSUPPORT
+msgid "Protocol not supported"
+msgstr ""
+
+# 44 - ESOCKTNOSUPPORT
+msgid "Socket type not supported"
+msgstr ""
+
+# 45 - EOPNOTSUPP
+msgid "Operation not supported"
+msgstr ""
+
+# 46 - EPFNOSUPPORT
+msgid "Protocol family not supported"
+msgstr ""
+
+# 47 - EAFNOSUPPORT
+msgid "Address family not supported by protocol family"
+msgstr ""
+
+# 48 - EADDRINUSE
+msgid "Address already in use"
+msgstr ""
+
+# 49 - EADDRNOTAVAIL
+msgid "Can't assign requested address"
+msgstr ""
+
+#
+# ipc/network software -- operational errors
+#
+
+# 50 - ENETDOWN
+msgid "Network is down"
+msgstr ""
+
+# 51 - ENETUNREACH
+msgid "Network is unreachable"
+msgstr ""
+
+# 52 - ENETRESET
+msgid "Network dropped connection on reset"
+msgstr ""
+
+# 53 - ECONNABORTED
+msgid "Software caused connection abort"
+msgstr ""
+
+# 54 - ECONNRESET
+msgid "Connection reset by peer"
+msgstr ""
+
+# 55 - ENOBUFS
+msgid "No buffer space available"
+msgstr ""
+
+# 56 - EISCONN
+msgid "Socket is already connected"
+msgstr ""
+
+# 57 - ENOTCONN
+msgid "Socket is not connected"
+msgstr ""
+
+# 58 - ESHUTDOWN
+msgid "Can't send after socket shutdown"
+msgstr ""
+
+# 59 - ETOOMANYREFS
+msgid "Too many references: can't splice"
+msgstr ""
+
+# 60 - ETIMEDOUT
+msgid "Operation timed out"
+msgstr ""
+
+# 61 - ECONNREFUSED
+msgid "Connection refused"
+msgstr ""
+
+# 62 - ELOOP
+msgid "Too many levels of symbolic links"
+msgstr ""
+
+# 63 - ENAMETOOLONG
+msgid "File name too long"
+msgstr ""
+
+#
+# should be rearranged
+#
+
+# 64 - EHOSTDOWN
+msgid "Host is down"
+msgstr ""
+
+# 65 - EHOSTUNREACH
+msgid "No route to host"
+msgstr ""
+
+# 66 - ENOTEMPTY
+msgid "Directory not empty"
+msgstr ""
+
+#
+# quotas & mush
+#
+
+# 67 - EPROCLIM
+msgid "Too many processes"
+msgstr ""
+
+# 68 - EUSERS
+msgid "Too many users"
+msgstr ""
+
+# 69 - EDQUOT
+msgid "Disc quota exceeded"
+msgstr ""
+
+#
+# Network File System
+#
+
+# 70 - ESTALE
+msgid "Stale NFS file handle"
+msgstr ""
+
+# 71 - EREMOTE
+msgid "Too many levels of remote in path"
+msgstr ""
+
+# 72 - EBADRPC
+msgid "RPC struct is bad"
+msgstr ""
+
+# 73 - ERPCMISMATCH
+msgid "RPC version wrong"
+msgstr ""
+
+# 74 - EPROGUNAVAIL
+msgid "RPC prog. not avail"
+msgstr ""
+
+# 75 - EPROGMISMATCH
+msgid "Program version wrong"
+msgstr ""
+
+# 76 - EPROCUNAVAIL
+msgid "Bad procedure for program"
+msgstr ""
+
+# 77 - ENOLCK
+msgid "No locks available"
+msgstr ""
+
+# 78 - ENOSYS
+msgid "Function not implemented"
+msgstr ""
+
+# 79 - EFTYPE
+msgid "Inappropriate file type or format"
+msgstr ""
+
+# 80 - EAUTH
+msgid "Authentication error"
+msgstr ""
+
+# 81 - ENEEDAUTH
+msgid "Need authenticator"
+msgstr ""
+
+# 82 - EIDRM
+msgid "Identifier removed"
+msgstr ""
+
+# 83 - ENOMSG
+msgid "No message of desired type"
+msgstr ""
+
+# 84 - EOVERFLOW
+msgid "Value too large to be stored in data type"
+msgstr ""
+
+# 85 - ECANCELED
+msgid "Operation canceled"
+msgstr ""
+
+# 86 - EILSEQ
+msgid "Illegal byte sequence"
+msgstr ""
+
+# 87 - ENOATTR
+msgid "Attribute not found"
+msgstr ""
+
+#
+# General
+#
+
+# 88 - EDOOFUS
+msgid "Programming error"
+msgstr ""
+
+# 89 - EBADMSG
+msgid "Bad message"
+msgstr ""
+
+# 90 - EMULTIHOP
+msgid "Multihop attempted"
+msgstr ""
+
+# 91 - ENOLINK
+msgid "Link has been severed"
+msgstr ""
+
+# 92 - EPROTO
+msgid "Protocol error"
+msgstr ""
+
+# 93 - ENOTCAPABLE
+msgid "Capabilities insufficient"
+msgstr ""
+
+# 94 - ECAPMODE
+msgid "Not permitted in capability mode"
+msgstr ""
+
+# 95 - ENOTRECOVERABLE
+msgid "State not recoverable"
+msgstr ""
+
+# 96 - EOWNERDEAD
+msgid "Previous owner died"
+msgstr ""
Index: vendor/Juniper/libxo/dist/tests/xo/Makefile.am
===================================================================
--- vendor/Juniper/libxo/dist/tests/xo/Makefile.am (nonexistent)
+++ vendor/Juniper/libxo/dist/tests/xo/Makefile.am (revision 296962)
@@ -0,0 +1,90 @@
+#
+# $Id$
+#
+# Copyright 2014, Juniper Networks, Inc.
+# All rights reserved.
+# This SOFTWARE is licensed under the LICENSE provided in the
+# ../Copyright file. By downloading, installing, copying, or otherwise
+# using the SOFTWARE, you agree to be bound by the terms of that
+# LICENSE.
+
+AM_CFLAGS = -I${top_srcdir} -I${top_srcdir}/libxo
+
+# Ick: maintained by hand!
+TEST_CASES = \
+xo_01.sh
+
+X=\
+xo_02.sh \
+xo_03.sh \
+xo_04.sh \
+xo_05.sh \
+xo_06.sh
+
+# TEST_CASES := $(shell cd ${srcdir} ; echo *.c )
+
+EXTRA_DIST = \
+ ${TEST_CASES} \
+ ${addprefix saved/, ${TEST_CASES:.sh=.T.err}} \
+ ${addprefix saved/, ${TEST_CASES:.sh=.T.out}} \
+ ${addprefix saved/, ${TEST_CASES:.sh=.XP.err}} \
+ ${addprefix saved/, ${TEST_CASES:.sh=.XP.out}} \
+ ${addprefix saved/, ${TEST_CASES:.sh=.JP.err}} \
+ ${addprefix saved/, ${TEST_CASES:.sh=.JP.out}} \
+ ${addprefix saved/, ${TEST_CASES:.sh=.HP.err}} \
+ ${addprefix saved/, ${TEST_CASES:.sh=.HP.out}} \
+ ${addprefix saved/, ${TEST_CASES:.sh=.X.err}} \
+ ${addprefix saved/, ${TEST_CASES:.sh=.X.out}} \
+ ${addprefix saved/, ${TEST_CASES:.sh=.J.err}} \
+ ${addprefix saved/, ${TEST_CASES:.sh=.J.out}} \
+ ${addprefix saved/, ${TEST_CASES:.sh=.H.err}} \
+ ${addprefix saved/, ${TEST_CASES:.sh=.H.out}} \
+ ${addprefix saved/, ${TEST_CASES:.sh=.HIPx.err}} \
+ ${addprefix saved/, ${TEST_CASES:.sh=.HIPx.out}}
+
+S2O = | ${SED} '1,/@@/d'
+
+all:
+
+#TEST_TRACE = set -x ;
+
+XO=../../xo/xo
+
+TEST_ONE = \
+ LIBXO_OPTIONS=:W$$fmt \
+ ${CHECKER} sh ${srcdir}/$$base.sh ${XO} ${TEST_OPTS} \
+ > out/$$base.$$fmt.out 2> out/$$base.$$fmt.err ; \
+ ${DIFF} -Nu ${srcdir}/saved/$$base.$$fmt.out out/$$base.$$fmt.out ${S2O} ; \
+ ${DIFF} -Nu ${srcdir}/saved/$$base.$$fmt.err out/$$base.$$fmt.err ${S2O}
+
+TEST_FORMATS = T XP JP HP X J H HIPx
+
+test tests: ${bin_PROGRAMS}
+ @${MKDIR} -p out
+ -@ ${TEST_TRACE} (for test in ${TEST_CASES} ; do \
+ base=`${BASENAME} $$test .sh` ; \
+ (for fmt in ${TEST_FORMATS}; do \
+ echo "... $$test ... $$fmt ..."; \
+ ${TEST_ONE}; \
+ true; \
+ done) \
+ done)
+
+one:
+ -@(test=${TEST_CASE}; data=${TEST_DATA}; ${TEST_ONE} ; true)
+
+accept:
+ -@(for test in ${TEST_CASES} ; do \
+ base=`${BASENAME} $$test .sh` ; \
+ (for fmt in ${TEST_FORMATS}; do \
+ echo "... $$test ... $$fmt ..."; \
+ ${CP} out/$$base.$$fmt.out ${srcdir}/saved/$$base.$$fmt.out ; \
+ ${CP} out/$$base.$$fmt.err ${srcdir}/saved/$$base.$$fmt.err ; \
+ done) \
+ done)
+
+CLEANFILES =
+CLEANDIRS = out
+
+clean-local:
+ rm -rf ${CLEANDIRS}
Property changes on: vendor/Juniper/libxo/dist/tests/xo/Makefile.am
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.H.err
===================================================================
Index: vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.H.out
===================================================================
--- vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.H.out (nonexistent)
+++ vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.H.out (revision 296962)
@@ -0,0 +1 @@
+Item
one
is
number
001
,
color
:
red
Item
two
is
number
002
,
color
:
blue
Item
three
is
number
003
,
color
:
green
Item
four
is
number
004
,
color
:
yellow
\ No newline at end of file
Index: vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.HIPx.err
===================================================================
Index: vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.HIPx.out
===================================================================
--- vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.HIPx.out (nonexistent)
+++ vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.HIPx.out (revision 296962)
@@ -0,0 +1,52 @@
+
+
Item
+
one
+
is
+
number
+
+
001
+
,
+
color
+
:
+
+
red
+
+
+
Item
+
two
+
is
+
number
+
+
002
+
,
+
color
+
:
+
+
blue
+
+
+
Item
+
three
+
is
+
number
+
+
003
+
,
+
color
+
:
+
+
green
+
+
+
Item
+
four
+
is
+
number
+
+
004
+
,
+
color
+
:
+
+
yellow
+
Index: vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.HP.err
===================================================================
Index: vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.HP.out
===================================================================
--- vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.HP.out (nonexistent)
+++ vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.HP.out (revision 296962)
@@ -0,0 +1,52 @@
+
+
Item
+
one
+
is
+
number
+
+
001
+
,
+
color
+
:
+
+
red
+
+
+
Item
+
two
+
is
+
number
+
+
002
+
,
+
color
+
:
+
+
blue
+
+
+
Item
+
three
+
is
+
number
+
+
003
+
,
+
color
+
:
+
+
green
+
+
+
Item
+
four
+
is
+
number
+
+
004
+
,
+
color
+
:
+
+
yellow
+
Index: vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.J.err
===================================================================
Index: vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.J.out
===================================================================
--- vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.J.out (nonexistent)
+++ vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.J.out (revision 296962)
@@ -0,0 +1 @@
+"top": {"item": {"name":"one","value":1,"color":"red"}, "item": {"name":"two","value":2,"color":"blue"}, "item": {"name":"three","value":3,"color":"green"}, "item": {"name":"four","value":4,"color":"yellow"}}
Index: vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.JP.err
===================================================================
Index: vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.JP.out
===================================================================
--- vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.JP.out (nonexistent)
+++ vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.JP.out (revision 296962)
@@ -0,0 +1,22 @@
+"top": {
+ "item": {
+ "name": "one",
+ "value": 1,
+ "color": "red"
+ },
+ "item": {
+ "name": "two",
+ "value": 2,
+ "color": "blue"
+ },
+ "item": {
+ "name": "three",
+ "value": 3,
+ "color": "green"
+ },
+ "item": {
+ "name": "four",
+ "value": 4,
+ "color": "yellow"
+ }
+}
Index: vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.T.err
===================================================================
Index: vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.T.out
===================================================================
--- vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.T.out (nonexistent)
+++ vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.T.out (revision 296962)
@@ -0,0 +1,4 @@
+Item one is number 001, color: red
+Item two is number 002, color: blue
+Item three is number 003, color: green
+Item four is number 004, color: yellow
Index: vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.X.err
===================================================================
Index: vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.X.out
===================================================================
--- vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.X.out (nonexistent)
+++ vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.X.out (revision 296962)
@@ -0,0 +1 @@
+one 1 red two 2 blue three 3 green four 4 yellow
\ No newline at end of file
Index: vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.XP.err
===================================================================
Index: vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.XP.out
===================================================================
--- vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.XP.out (nonexistent)
+++ vendor/Juniper/libxo/dist/tests/xo/saved/xo_01.XP.out (revision 296962)
@@ -0,0 +1,22 @@
+
+ -
+
one
+ 1
+ red
+
+ -
+
two
+ 2
+ blue
+
+ -
+
three
+ 3
+ green
+
+ -
+
four
+ 4
+ yellow
+
+
Index: vendor/Juniper/libxo/dist/tests/xo/xo_01.sh
===================================================================
--- vendor/Juniper/libxo/dist/tests/xo/xo_01.sh (nonexistent)
+++ vendor/Juniper/libxo/dist/tests/xo/xo_01.sh (revision 296962)
@@ -0,0 +1,27 @@
+#
+# $Id$
+#
+# Copyright 2014, Juniper Networks, Inc.
+# All rights reserved.
+# This SOFTWARE is licensed under the LICENSE provided in the
+# ../Copyright file. By downloading, installing, copying, or otherwise
+# using the SOFTWARE, you agree to be bound by the terms of that
+# LICENSE.
+
+XO=$1
+shift
+
+XOP="${XO} --warn --depth 1 --leading-xpath /top"
+
+${XO} --open top
+
+NF=
+for i in one:1:red two:2:blue three:3:green four:4:yellow ; do
+ set `echo $i | sed 's/:/ /g'`
+ ${XOP} ${NF} --wrap item \
+ 'Item {k:name} is {Lw:number}{:value/%03d/%d}, {Lwc:color}{:color}\n' \
+ $1 $2 $3
+ NF=--not-first
+done
+
+${XO} --close top
\ No newline at end of file
Property changes on: vendor/Juniper/libxo/dist/tests/xo/xo_01.sh
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/xo/Makefile.am
===================================================================
--- vendor/Juniper/libxo/dist/xo/Makefile.am (nonexistent)
+++ vendor/Juniper/libxo/dist/xo/Makefile.am (revision 296962)
@@ -0,0 +1,43 @@
+#
+# Copyright 2014, Juniper Networks, Inc.
+# All rights reserved.
+# This SOFTWARE is licensed under the LICENSE provided in the
+# ../Copyright file. By downloading, installing, copying, or otherwise
+# using the SOFTWARE, you agree to be bound by the terms of that
+# LICENSE.
+
+if LIBXO_WARNINGS_HIGH
+LIBXO_WARNINGS = HIGH
+endif
+include ${top_srcdir}/warnings.mk
+
+AM_CFLAGS = \
+ -DLIBXO_XMLSOFT_NEED_PRIVATE \
+ -I${top_builddir} \
+ -I${top_srcdir} \
+ -I${top_srcdir}/libxo \
+ ${WARNINGS}
+
+LIBS = \
+ ${LIBXO_LIBS}
+
+bin_PROGRAMS = xo
+
+xo_SOURCES = xo.c
+#xo_LDADD = ../libxo/libxo.la
+#xo_LDFLAGS = -static
+
+LDADD = \
+ ${top_builddir}/libxo/libxo.la
+
+if HAVE_HUMANIZE_NUMBER
+LDADD += -lutil
+endif
+
+man_MANS = xo.1
+
+EXTRA_DIST = xo.1
+
+install-data-hook:
+ for file in ${man_MANS}; do \
+ cat ../libxo/add.man >> ${DESTDIR}${man1dir}/$$file ; done
Property changes on: vendor/Juniper/libxo/dist/xo/Makefile.am
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/Juniper/libxo/dist/xo/xo.1
===================================================================
--- vendor/Juniper/libxo/dist/xo/xo.1 (nonexistent)
+++ vendor/Juniper/libxo/dist/xo/xo.1 (revision 296962)
@@ -0,0 +1,173 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt XO 1
+.Os
+.Sh NAME
+.Nm xo
+.Nd emit formatted output based on format string and arguments
+.Sh SYNOPSIS
+.Nm
+.Op Fl options
+.Op Ar argument...
+.Sh DESCRIPTION
+The
+.Nm
+utility allows command line access to the functionality of
+the
+.Nm libxo
+library.
+Using
+.Nm ,
+shell scripts can emit
+.Em XML ,
+.Em JSON ,
+or
+.Em HTML
+using the same commands that emit text output.
+.Pp
+.Bl -tag -width "12345678901234567"
+.It Fl "-close "
+Close tags for the given path
+.It Fl "-depth "
+Set the depth for pretty printing
+.It Fl "-help"
+Display this help text
+.It Fl "-html OR -H"
+Generate HTML output
+.It Fl "-json OR -J"
+Generate JSON output
+.It Fl "-leading-xpath "
+Add a prefix to generated XPaths (HTML)
+.It Fl "-open "
+Open tags for the given path
+.It Fl "-pretty OR -p"
+Make 'pretty' output (add indent, newlines)
+.It Fl "-style