mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-18 15:30:21 +00:00
Vendor import of Juniper libxo at 1.6.0
This commit is contained in:
parent
b1cbac9ff4
commit
7087c8de43
12
.travis.yml
Normal file
12
.travis.yml
Normal file
@ -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
|
23
LICENSE
Normal file
23
LICENSE
Normal file
@ -0,0 +1,23 @@
|
||||
Copyright (c) 2014, Juniper Networks
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* 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.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
|
@ -16,7 +16,7 @@ xo_emit call:
|
||||
```
|
||||
xo_emit(" {:lines/%7ju/%ju} {:words/%7ju/%ju} "
|
||||
"{:characters/%7ju/%ju}{d:filename/%s}\n",
|
||||
line_count, word_count, char_count, file);
|
||||
linect, wordct, charct, file);
|
||||
```
|
||||
|
||||
Output can then be generated in various style, using the "--libxo"
|
||||
|
23
configure.ac
23
configure.ac
@ -82,8 +82,7 @@ AC_CHECK_LIB([util], [humanize_number],
|
||||
[HAVE_HUMANIZE_NUMBER=$ac_cv_header_libutil_h],
|
||||
[HAVE_HUMANIZE_NUMBER=no])
|
||||
|
||||
AC_MSG_CHECKING([humanize_number results])
|
||||
AC_MSG_RESULT(:${HAVE_HUMANIZE_NUMBER}:${ac_cv_header_libutil_h}:)
|
||||
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)])
|
||||
@ -177,25 +176,6 @@ AC_SUBST(GETTEXT_BINDIR)
|
||||
|
||||
AM_CONDITIONAL([HAVE_GETTEXT], [test "$HAVE_GETTEXT" = "yes"])
|
||||
|
||||
dnl on macosx, strings are not in the .text segment, making the call
|
||||
dnl to get_etext pointless
|
||||
AC_MSG_CHECKING([style of etext])
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([
|
||||
[#include <stdio.h>]
|
||||
[extern char etext;]
|
||||
[int main() { const char *p = &etext; printf("%p\n", p); return 0; }]])],
|
||||
[HAVE_ETEXT=1 ; HAVE_ETEXT_STYLE="symbol"],
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([
|
||||
[#include <stdio.h>]
|
||||
[#include <mach-o/getsect.h>]
|
||||
[int main() { const char *p = (const char *) get_etext(); printf("%p\n", p); return 0; }]])],
|
||||
[HAVE_ETEXT=2 ; HAVE_ETEXT_STYLE="function"],
|
||||
[HAVE_ETEXT=0 ; HAVE_ETEXT_STYLE="none"]
|
||||
)
|
||||
)
|
||||
AC_MSG_RESULT(${HAVE_ETEXT_STYLE})
|
||||
AC_DEFINE_UNQUOTED([HAVE_ETEXT], [$HAVE_ETEXT], [Style of etext])
|
||||
|
||||
dnl Looking for how to do thread-local variables
|
||||
AC_ARG_WITH(threads,
|
||||
[ --with-threads=[STYLE] Specify style of thread-local support (none)],
|
||||
@ -517,5 +497,4 @@ AC_MSG_NOTICE([summary of build options:
|
||||
thread-local: ${THREAD_LOCAL:-no}
|
||||
local wcwidth: ${LIBXO_WCWIDTH:-no}
|
||||
retain size: ${XO_RETAIN_SIZE:-no}
|
||||
have etext: ${HAVE_ETEXT:-no} (${HAVE_ETEXT_STYLE})
|
||||
])
|
||||
|
657
doc/_static/basic.css_t
vendored
Normal file
657
doc/_static/basic.css_t
vendored
Normal file
@ -0,0 +1,657 @@
|
||||
/*
|
||||
* basic.css
|
||||
* ~~~~~~~~~
|
||||
*
|
||||
* Sphinx stylesheet -- basic theme.
|
||||
*
|
||||
* :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
/* -- main layout ----------------------------------------------------------- */
|
||||
|
||||
div.clearer {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* -- relbar ---------------------------------------------------------------- */
|
||||
|
||||
div.related {
|
||||
width: 100%;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
div.related h3 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div.related ul {
|
||||
margin: 0;
|
||||
padding: 0 0 0 10px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
div.related li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.related li.right {
|
||||
float: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
/* -- sidebar --------------------------------------------------------------- */
|
||||
|
||||
div.sphinxsidebarwrapper {
|
||||
padding: 10px 5px 0 10px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar {
|
||||
float: left;
|
||||
width: {{ theme_sidebarwidth|toint }}px;
|
||||
margin-left: -100%;
|
||||
font-size: 90%;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap : break-word;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul ul,
|
||||
div.sphinxsidebar ul.want-points {
|
||||
margin-left: 20px;
|
||||
list-style: square;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar form {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input {
|
||||
border: 1px solid #98dbcc;
|
||||
font-family: sans-serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
div.sphinxsidebar #searchbox input[type="text"] {
|
||||
width: 170px;
|
||||
}
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* -- search page ----------------------------------------------------------- */
|
||||
|
||||
ul.search {
|
||||
margin: 10px 0 0 20px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul.search li {
|
||||
padding: 5px 0 5px 20px;
|
||||
background-image: url(file.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 7px;
|
||||
}
|
||||
|
||||
ul.search li a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ul.search li div.context {
|
||||
color: #888;
|
||||
margin: 2px 0 0 30px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
ul.keywordmatches li.goodmatch a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* -- index page ------------------------------------------------------------ */
|
||||
|
||||
table.contentstable {
|
||||
width: 90%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
table.contentstable p.biglink {
|
||||
line-height: 150%;
|
||||
}
|
||||
|
||||
a.biglink {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
span.linkdescr {
|
||||
font-style: italic;
|
||||
padding-top: 5px;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
/* -- general index --------------------------------------------------------- */
|
||||
|
||||
table.indextable {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table.indextable td {
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table.indextable ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
table.indextable > tbody > tr > td > ul {
|
||||
padding-left: 0em;
|
||||
}
|
||||
|
||||
table.indextable tr.pcap {
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
table.indextable tr.cap {
|
||||
margin-top: 10px;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
img.toggler {
|
||||
margin-right: 3px;
|
||||
margin-top: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.modindex-jumpbox {
|
||||
border-top: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
margin: 1em 0 1em 0;
|
||||
padding: 0.4em;
|
||||
}
|
||||
|
||||
div.genindex-jumpbox {
|
||||
border-top: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
margin: 1em 0 1em 0;
|
||||
padding: 0.4em;
|
||||
}
|
||||
|
||||
/* -- domain module index --------------------------------------------------- */
|
||||
|
||||
table.modindextable td {
|
||||
padding: 2px;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
/* -- general body styles --------------------------------------------------- */
|
||||
|
||||
div.body p, div.body dd, div.body li, div.body blockquote {
|
||||
-moz-hyphens: auto;
|
||||
-ms-hyphens: auto;
|
||||
-webkit-hyphens: auto;
|
||||
hyphens: auto;
|
||||
}
|
||||
|
||||
a.headerlink {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
h1:hover > a.headerlink,
|
||||
h2:hover > a.headerlink,
|
||||
h3:hover > a.headerlink,
|
||||
h4:hover > a.headerlink,
|
||||
h5:hover > a.headerlink,
|
||||
h6:hover > a.headerlink,
|
||||
dt:hover > a.headerlink,
|
||||
caption:hover > a.headerlink,
|
||||
p.caption:hover > a.headerlink,
|
||||
div.code-block-caption:hover > a.headerlink {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
div.body p.caption {
|
||||
text-align: inherit;
|
||||
}
|
||||
|
||||
div.body td {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
blockquote.epigraph p.attribution {
|
||||
margin-left: 50%;
|
||||
}
|
||||
|
||||
blockquote.epigraph {
|
||||
background-color: #eee;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.first {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
p.rubric {
|
||||
margin-top: 30px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
img.align-left, .figure.align-left, object.align-left {
|
||||
clear: left;
|
||||
float: left;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
img.align-right, .figure.align-right, object.align-right {
|
||||
/* clear: right; */
|
||||
float: right;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
img.align-center, .figure.align-center, object.align-center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.align-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.align-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* -- sidebars -------------------------------------------------------------- */
|
||||
|
||||
div.sidebar {
|
||||
margin: 1em 1em 1em 1em;
|
||||
border: 1px solid #ddb;
|
||||
padding: 7px 7px 0 7px;
|
||||
background-color: #ffe;
|
||||
width: 40%;
|
||||
float: right;
|
||||
}
|
||||
|
||||
p.sidebar-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* -- topics ---------------------------------------------------------------- */
|
||||
|
||||
div.topic {
|
||||
border: 1px solid #ccc;
|
||||
padding: 7px 7px 0 7px;
|
||||
margin: 10px 0 10px 0;
|
||||
}
|
||||
|
||||
p.topic-title {
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* -- admonitions ----------------------------------------------------------- */
|
||||
|
||||
div.admonition {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
div.admonition dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.admonition dl {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
p.admonition-title {
|
||||
margin: 0px 10px 5px 0px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.body p.centered {
|
||||
text-align: center;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
/* -- tables ---------------------------------------------------------------- */
|
||||
|
||||
table.docutils {
|
||||
border: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table caption span.caption-number {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
table caption span.caption-text {
|
||||
}
|
||||
|
||||
dl.function table.docutils th.field-name {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
table.docutils td, table.docutils th {
|
||||
padding: 1px 8px 1px 5px;
|
||||
border-top: 1px solid #aaa;
|
||||
border-left: 1px solid #aaa;
|
||||
border-right: 1px solid #aaa;
|
||||
border-bottom: 1px solid #aaa;
|
||||
}
|
||||
|
||||
table.docutils th {
|
||||
border-bottom: 2px solid #aaa;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
table.footnote td, table.footnote th {
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
table.citation {
|
||||
border-left: solid 1px gray;
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
table.citation td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* -- figures --------------------------------------------------------------- */
|
||||
|
||||
div.figure {
|
||||
margin: 0.5em;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
div.figure p.caption {
|
||||
padding: 0.3em;
|
||||
}
|
||||
|
||||
div.figure p.caption span.caption-number {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
div.figure p.caption span.caption-text {
|
||||
}
|
||||
|
||||
/* -- field list styles ----------------------------------------------------- */
|
||||
|
||||
table.field-list td, table.field-list th {
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
.field-list ul {
|
||||
margin: 0;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.field-list p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.field-name {
|
||||
-moz-hyphens: manual;
|
||||
-ms-hyphens: manual;
|
||||
-webkit-hyphens: manual;
|
||||
hyphens: manual;
|
||||
}
|
||||
|
||||
/* -- other body styles ----------------------------------------------------- */
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha;
|
||||
}
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha;
|
||||
}
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman;
|
||||
}
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
dd p {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
dd ul, dd table {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-top: 3px;
|
||||
margin-bottom: 10px;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
dt:target, .highlighted {
|
||||
background-color: #fbe54e;
|
||||
}
|
||||
|
||||
dl.glossary dt {
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.optional {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
.sig-paren {
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
.versionmodified {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.system-message {
|
||||
background-color: #fda;
|
||||
padding: 5px;
|
||||
border: 3px solid red;
|
||||
}
|
||||
|
||||
.footnote:target {
|
||||
background-color: #ffa;
|
||||
}
|
||||
|
||||
.line-block {
|
||||
display: block;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.line-block .line-block {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
margin-left: 1.5em;
|
||||
}
|
||||
|
||||
.guilabel, .menuselection {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.accelerator {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.classifier {
|
||||
font-style: oblique;
|
||||
}
|
||||
|
||||
abbr, acronym {
|
||||
border-bottom: dotted 1px;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
/* -- code displays --------------------------------------------------------- */
|
||||
|
||||
pre {
|
||||
overflow: auto;
|
||||
overflow-y: hidden; /* fixes display issues on Chrome browsers */
|
||||
}
|
||||
|
||||
span.pre {
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
-webkit-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
td.linenos pre {
|
||||
padding: 5px 0px;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
table.highlighttable {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
table.highlighttable td {
|
||||
padding: 0 0.5em 0 0.5em;
|
||||
}
|
||||
|
||||
div.code-block-caption {
|
||||
padding: 2px 5px;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
div.code-block-caption code {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
div.code-block-caption + div > div.highlight > pre {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
div.code-block-caption span.caption-number {
|
||||
padding: 0.1em 0.3em;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
div.code-block-caption span.caption-text {
|
||||
}
|
||||
|
||||
div.literal-block-wrapper {
|
||||
padding: 1em 1em 0;
|
||||
}
|
||||
|
||||
div.literal-block-wrapper div.highlight {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
code.descname {
|
||||
background-color: transparent;
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
code.descclassname {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
code.xref, a code {
|
||||
background-color: transparent;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.viewcode-link {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.viewcode-back {
|
||||
float: right;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
div.viewcode-block:target {
|
||||
margin: -1px -10px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
/* -- math display ---------------------------------------------------------- */
|
||||
|
||||
img.math {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.body div.math p {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
span.eqno {
|
||||
float: right;
|
||||
}
|
||||
|
||||
span.eqno a.headerlink {
|
||||
position: relative;
|
||||
left: 0px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
div.math:hover a.headerlink {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/* -- printout stylesheet --------------------------------------------------- */
|
||||
|
||||
@media print {
|
||||
div.document,
|
||||
div.documentwrapper,
|
||||
div.bodywrapper {
|
||||
margin: 0 !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.sphinxsidebar,
|
||||
div.related,
|
||||
div.footer,
|
||||
#top-link {
|
||||
display: none;
|
||||
}
|
||||
}
|
14
doc/_templates/localtoc.html
vendored
Normal file
14
doc/_templates/localtoc.html
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
{#
|
||||
basic/localtoc.html
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sphinx sidebar template: local table of contents.
|
||||
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
#}
|
||||
{%- if display_toc %}
|
||||
<h3><a href="{{ pathto(master_doc) }}">{{ _('On This Page') }}</a></h3>
|
||||
{{ toc }}
|
||||
<h3><a href="{{ pathto(master_doc) }}">{{ _('Full Documentation') }}</a></h3>
|
||||
{%- endif %}
|
1702
doc/api.rst
Normal file
1702
doc/api.rst
Normal file
File diff suppressed because it is too large
Load Diff
186
doc/conf.py
Normal file
186
doc/conf.py
Normal file
@ -0,0 +1,186 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# JuniperStory documentation build configuration file, created by
|
||||
# sphinx-quickstart on Tue Oct 10 10:18:55 2017.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
import subprocess
|
||||
|
||||
#
|
||||
# Instead of hardcoding the version number here, we read it from the
|
||||
# project's configure script
|
||||
#
|
||||
vers_cmd = "grep AC_INIT ../configure.ac | awk '{ print substr($2, 2, length($2) - 3);}'"
|
||||
version = subprocess.check_output(vers_cmd, shell=True).decode("utf-8")
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = []
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'libxo'
|
||||
copyright = '2017-2019, Juniper Networks Inc'
|
||||
author = 'Phil Shafer'
|
||||
default_role = 'code'
|
||||
primary_domain = 'c'
|
||||
smart_quotes = False
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
#version = 'develop'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = version
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = []
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'sphinxdoc'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
html_theme_options = {
|
||||
"sidebarwidth": 320,
|
||||
}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
#
|
||||
# This is required for the alabaster theme
|
||||
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
|
||||
alabaster_html_sidebars = {
|
||||
'**': [
|
||||
'about.html',
|
||||
'navigation.html',
|
||||
'relations.html', # needs 'show_related': True theme option to display
|
||||
'searchbox.html',
|
||||
'donate.html',
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'libxo-manual'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'libxo.tex', 'libxo Documentation',
|
||||
'Phil Shafer', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'libxo', 'libxo Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'libxo', 'libxo Documentation',
|
||||
author, 'libxo', 'A Library for Generating Text, XML, JSON, and HTML Output',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
|
274
doc/encoders.rst
Normal file
274
doc/encoders.rst
Normal file
@ -0,0 +1,274 @@
|
||||
.. index:: encoder
|
||||
|
||||
Encoders
|
||||
========
|
||||
|
||||
This section gives an overview of encoders, details on the encoders
|
||||
that ship with libxo, and documentation for developers of future
|
||||
encoders.
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The libxo library contains software to generate four "built-in"
|
||||
formats: text, XML, JSON, and HTML. These formats are common and
|
||||
useful, but there are other common and useful formats that users will
|
||||
want, and including them all in the libxo software would be difficult
|
||||
and cumbersome.
|
||||
|
||||
To allow support for additional encodings, libxo includes a
|
||||
"pluggable" extension mechanism for dynamically loading new encoders.
|
||||
libxo-based applications can automatically use any installed encoder.
|
||||
|
||||
Use the "encoder=XXX" option to access encoders. The following
|
||||
example uses the "cbor" encoder, saving the output into a file::
|
||||
|
||||
df --libxo encoder=cbor > df-output.cbor
|
||||
|
||||
Encoders can support specific options that can be accessed by
|
||||
following the encoder name with a colon (':') or a plus sign ('+') and
|
||||
one of more options, separated by the same character::
|
||||
|
||||
df --libxo encoder=csv+path=filesystem+leaf=name+no-header
|
||||
df --libxo encoder=csv:path=filesystem:leaf=name:no-header
|
||||
|
||||
These examples instructs libxo to load the "csv" encoder and pass the
|
||||
following options::
|
||||
|
||||
path=filesystem
|
||||
leaf=name
|
||||
no-header
|
||||
|
||||
Each of these option is interpreted by the encoder, and all such
|
||||
options names and semantics are specific to the particular encoder.
|
||||
Refer to the intended encoder for documentation on its options.
|
||||
|
||||
The string "@" can be used in place of the string "encoder=".
|
||||
|
||||
df --libxo @csv:no-header
|
||||
|
||||
.. _csv_encoder:
|
||||
|
||||
CSV - Comma Separated Values
|
||||
----------------------------
|
||||
|
||||
libxo ships with a custom encoder for "CSV" files, a common format for
|
||||
comma separated values. The output of the CSV encoder can be loaded
|
||||
directly into spreadsheets or similar applications.
|
||||
|
||||
A standard for CSV files is provided in :RFC:`4180`, but since the
|
||||
format predates that standard by decades, there are many minor
|
||||
differences in CSV file consumers and their expectations. The CSV
|
||||
encoder has a number of options to tailor output to those
|
||||
expectations.
|
||||
|
||||
Consider the following XML::
|
||||
|
||||
% list-items --libxo xml,pretty
|
||||
<top>
|
||||
<data test="value">
|
||||
<item test2="value2">
|
||||
<sku test3="value3" key="key">GRO-000-415</sku>
|
||||
<name key="key">gum</name>
|
||||
<sold>1412</sold>
|
||||
<in-stock>54</in-stock>
|
||||
<on-order>10</on-order>
|
||||
</item>
|
||||
<item>
|
||||
<sku test3="value3" key="key">HRD-000-212</sku>
|
||||
<name key="key">rope</name>
|
||||
<sold>85</sold>
|
||||
<in-stock>4</in-stock>
|
||||
<on-order>2</on-order>
|
||||
</item>
|
||||
<item>
|
||||
<sku test3="value3" key="key">HRD-000-517</sku>
|
||||
<name key="key">ladder</name>
|
||||
<sold>0</sold>
|
||||
<in-stock>2</in-stock>
|
||||
<on-order>1</on-order>
|
||||
</item>
|
||||
</data>
|
||||
</top>
|
||||
|
||||
This output is a list of `instances` (named "item"), each containing a
|
||||
set of `leafs` ("sku", "name", etc).
|
||||
|
||||
The CSV encoder will emit the leaf values in this output as `fields`
|
||||
inside a CSV `record`, which is a line containing a set of
|
||||
comma-separated values::
|
||||
|
||||
% list-items --libxo encoder=csv
|
||||
sku,name,sold,in-stock,on-order
|
||||
GRO-000-415,gum,1412,54,10
|
||||
HRD-000-212,rope,85,4,2
|
||||
HRD-000-517,ladder,0,2,1
|
||||
|
||||
Be aware that since the CSV encoder looks for data instances, when
|
||||
used with :ref:`xo`, the `--instance` option will be needed::
|
||||
|
||||
% xo --libxo encoder=csv --instance foo 'The {:product} is {:status}\n' stereo "in route"
|
||||
product,status
|
||||
stereo,in route
|
||||
|
||||
.. _csv_path:
|
||||
|
||||
The `path` Option
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
By default, the CSV encoder will attempt to emit any list instance
|
||||
generated by the application. In some cases, this may be
|
||||
unacceptable, and a specific list may be desired.
|
||||
|
||||
Use the "path" option to limit the processing of output to a specific
|
||||
hierarchy. The path should be one or more names of containers or
|
||||
lists.
|
||||
|
||||
For example, if the "list-items" application generates other lists,
|
||||
the user can give "path=top/data/item" as a path::
|
||||
|
||||
% list-items --libxo encoder=csv:path=top/data/item
|
||||
sku,name,sold,in-stock,on-order
|
||||
GRO-000-415,gum,1412,54,10
|
||||
HRD-000-212,rope,85,4,2
|
||||
HRD-000-517,ladder,0,2,1
|
||||
|
||||
Paths are "relative", meaning they need not be a complete set
|
||||
of names to the list. This means that "path=item" may be sufficient
|
||||
for the above example.
|
||||
|
||||
.. _csv_leafs:
|
||||
|
||||
The `leafs` Option
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The CSV encoding requires that all lines of output have the same
|
||||
number of fields with the same order. In contrast, XML and JSON allow
|
||||
any order (though libxo forces key leafs to appear before other
|
||||
leafs).
|
||||
|
||||
To maintain a consistent set of fields inside the CSV file, the same
|
||||
set of leafs must be selected from each list item. By default, the
|
||||
CSV encoder records the set of leafs that appear in the first list
|
||||
instance it processes, and extract only those leafs from future
|
||||
instances. If the first instance is missing a leaf that is desired by
|
||||
the consumer, the "leaf" option can be used to ensure that an empty
|
||||
value is recorded for instances that lack a particular leaf.
|
||||
|
||||
The "leafs" option can also be used to exclude leafs, limiting the
|
||||
output to only those leafs provided.
|
||||
|
||||
In addition, the order of the output fields follows the order in which
|
||||
the leafs are listed. "leafs=one.two" and "leafs=two.one" give
|
||||
distinct output.
|
||||
|
||||
So the "leafs" option can be used to expand, limit, and order the set
|
||||
of leafs.
|
||||
|
||||
The value of the leafs option should be one or more leaf names,
|
||||
separated by a period (".")::
|
||||
|
||||
% list-items --libxo encoder=csv:leafs=sku.on-order
|
||||
sku,on-order
|
||||
GRO-000-415,10
|
||||
HRD-000-212,2
|
||||
HRD-000-517,1
|
||||
% list-items -libxo encoder=csv:leafs=on-order.sku
|
||||
on-order,sku
|
||||
10,GRO-000-415
|
||||
2,HRD-000-212
|
||||
1,HRD-000-517
|
||||
|
||||
Note that since libxo uses terminology from YANG (:RFC:`7950`), the
|
||||
data modeling language for NETCONF (:RFC:`6241`), which uses "leafs"
|
||||
as the plural form of "leaf". libxo follows that convention.
|
||||
|
||||
.. _csv_no_header:
|
||||
|
||||
The `no-header` Option
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
CSV files typical begin with a line that defines the fields included
|
||||
in that file, in an attempt to make the contents self-defining::
|
||||
|
||||
sku,name,sold,in-stock,on-order
|
||||
GRO-000-415,gum,1412,54,10
|
||||
HRD-000-212,rope,85,4,2
|
||||
HRD-000-517,ladder,0,2,1
|
||||
|
||||
There is no reliable mechanism for determining whether this header
|
||||
line is included, so the consumer must make an assumption.
|
||||
|
||||
The csv encoder defaults to producing the header line, but the
|
||||
"no-header" option can be included to avoid the header line.
|
||||
|
||||
.. _csv_no_quotes:
|
||||
|
||||
The `no-quotes` Option
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:RFC:`4180` specifies that fields containing spaces should be quoted, but
|
||||
many CSV consumers do not handle quotes. The "no-quotes" option
|
||||
instruct the CSV encoder to avoid the use of quotes.
|
||||
|
||||
.. _csv_dos:
|
||||
|
||||
The `dos` Option
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
:RFC:`4180` defines the end-of-line marker as a carriage return
|
||||
followed by a newline. This `CRLF` convention dates from the distant
|
||||
past, but its use was anchored in the 1980s by the `DOS` operating
|
||||
system.
|
||||
|
||||
The CSV encoder defaults to using the standard Unix end-of-line
|
||||
marker, a simple newline. Use the "dos" option to use the `CRLF`
|
||||
convention.
|
||||
|
||||
The Encoder API
|
||||
---------------
|
||||
|
||||
The encoder API consists of three distinct phases:
|
||||
|
||||
- loading the encoder
|
||||
- initializing the encoder
|
||||
- feeding operations to the encoder
|
||||
|
||||
To load the encoder, libxo will open a shared library named:
|
||||
|
||||
${prefix}/lib/libxo/encoder/${name}.enc
|
||||
|
||||
This file is typically a symbolic link to a dynamic library, suitable
|
||||
for `dlopen`(). libxo looks for a symbol called
|
||||
`xo_encoder_library_init` inside that library and calls it with the
|
||||
arguments defined in the header file "xo_encoder.h". This function
|
||||
should look as follows::
|
||||
|
||||
int
|
||||
xo_encoder_library_init (XO_ENCODER_INIT_ARGS)
|
||||
{
|
||||
arg->xei_version = XO_ENCODER_VERSION;
|
||||
arg->xei_handler = test_handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Several features here allow for future compatibility: the macro
|
||||
XO_ENCODER_INIT_ARGS allows the arguments to this function change over
|
||||
time, and the XO_ENCODER_VERSION allows the library to tell libxo
|
||||
which version of the API it was compiled with.
|
||||
|
||||
The function places in xei_handler should be have the signature::
|
||||
|
||||
static int
|
||||
test_handler (XO_ENCODER_HANDLER_ARGS)
|
||||
{
|
||||
...
|
||||
|
||||
This function will be called with the "op" codes defined in
|
||||
"xo_encoder.h". Each op code represents a distinct event in the libxo
|
||||
processing model. For example OP_OPEN_CONTAINER tells the encoder
|
||||
that a new container has been opened, and the encoder can behave in an
|
||||
appropriate manner.
|
||||
|
||||
|
694
doc/example.rst
Normal file
694
doc/example.rst
Normal file
@ -0,0 +1,694 @@
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
Unit Test
|
||||
---------
|
||||
|
||||
Here is one of the unit tests as an example::
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
static char base_grocery[] = "GRO";
|
||||
static char base_hardware[] = "HRD";
|
||||
struct item {
|
||||
const char *i_title;
|
||||
int i_sold;
|
||||
int i_instock;
|
||||
int i_onorder;
|
||||
const char *i_sku_base;
|
||||
int i_sku_num;
|
||||
};
|
||||
struct item list[] = {
|
||||
{ "gum", 1412, 54, 10, base_grocery, 415 },
|
||||
{ "rope", 85, 4, 2, base_hardware, 212 },
|
||||
{ "ladder", 0, 2, 1, base_hardware, 517 },
|
||||
{ "bolt", 4123, 144, 42, base_hardware, 632 },
|
||||
{ "water", 17, 14, 2, base_grocery, 2331 },
|
||||
{ NULL, 0, 0, 0, NULL, 0 }
|
||||
};
|
||||
struct item list2[] = {
|
||||
{ "fish", 1321, 45, 1, base_grocery, 533 },
|
||||
};
|
||||
struct item *ip;
|
||||
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" },
|
||||
{ NULL, NULL, NULL },
|
||||
};
|
||||
int info_count = (sizeof(info) / sizeof(info[0])) - 1;
|
||||
|
||||
argc = xo_parse_args(argc, argv);
|
||||
if (argc < 0)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
xo_set_info(NULL, info, info_count);
|
||||
|
||||
xo_open_container_h(NULL, "top");
|
||||
|
||||
xo_open_container("data");
|
||||
xo_open_list("item");
|
||||
|
||||
for (ip = list; ip->i_title; ip++) {
|
||||
xo_open_instance("item");
|
||||
|
||||
xo_emit("{L:Item} '{k:name/%s}':\n", ip->i_title);
|
||||
xo_emit("{P: }{L:Total sold}: {n:sold/%u%s}\n",
|
||||
ip->i_sold, ip->i_sold ? ".0" : "");
|
||||
xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\n",
|
||||
ip->i_instock);
|
||||
xo_emit("{P: }{Lwc:On order}{:on-order/%u}\n",
|
||||
ip->i_onorder);
|
||||
xo_emit("{P: }{L:SKU}: {q:sku/%s-000-%u}\n",
|
||||
ip->i_sku_base, ip->i_sku_num);
|
||||
|
||||
xo_close_instance("item");
|
||||
}
|
||||
|
||||
xo_close_list("item");
|
||||
xo_close_container("data");
|
||||
|
||||
xo_open_container("data");
|
||||
xo_open_list("item");
|
||||
|
||||
for (ip = list2; ip->i_title; ip++) {
|
||||
xo_open_instance("item");
|
||||
|
||||
xo_emit("{L:Item} '{:name/%s}':\n", ip->i_title);
|
||||
xo_emit("{P: }{L:Total sold}: {n:sold/%u%s}\n",
|
||||
ip->i_sold, ip->i_sold ? ".0" : "");
|
||||
xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\n",
|
||||
ip->i_instock);
|
||||
xo_emit("{P: }{Lwc:On order}{:on-order/%u}\n",
|
||||
ip->i_onorder);
|
||||
xo_emit("{P: }{L:SKU}: {q:sku/%s-000-%u}\n",
|
||||
ip->i_sku_base, ip->i_sku_num);
|
||||
|
||||
xo_close_instance("item");
|
||||
}
|
||||
|
||||
xo_close_list("item");
|
||||
xo_close_container("data");
|
||||
|
||||
xo_close_container_h(NULL, "top");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Text output::
|
||||
|
||||
% ./testxo --libxo text
|
||||
Item 'gum':
|
||||
Total sold: 1412.0
|
||||
In stock: 54
|
||||
On order: 10
|
||||
SKU: GRO-000-415
|
||||
Item 'rope':
|
||||
Total sold: 85.0
|
||||
In stock: 4
|
||||
On order: 2
|
||||
SKU: HRD-000-212
|
||||
Item 'ladder':
|
||||
Total sold: 0
|
||||
In stock: 2
|
||||
On order: 1
|
||||
SKU: HRD-000-517
|
||||
Item 'bolt':
|
||||
Total sold: 4123.0
|
||||
In stock: 144
|
||||
On order: 42
|
||||
SKU: HRD-000-632
|
||||
Item 'water':
|
||||
Total sold: 17.0
|
||||
In stock: 14
|
||||
On order: 2
|
||||
SKU: GRO-000-2331
|
||||
Item 'fish':
|
||||
Total sold: 1321.0
|
||||
In stock: 45
|
||||
On order: 1
|
||||
SKU: GRO-000-533
|
||||
|
||||
JSON output::
|
||||
|
||||
% ./testxo --libxo json,pretty
|
||||
"top": {
|
||||
"data": {
|
||||
"item": [
|
||||
{
|
||||
"name": "gum",
|
||||
"sold": 1412.0,
|
||||
"in-stock": 54,
|
||||
"on-order": 10,
|
||||
"sku": "GRO-000-415"
|
||||
},
|
||||
{
|
||||
"name": "rope",
|
||||
"sold": 85.0,
|
||||
"in-stock": 4,
|
||||
"on-order": 2,
|
||||
"sku": "HRD-000-212"
|
||||
},
|
||||
{
|
||||
"name": "ladder",
|
||||
"sold": 0,
|
||||
"in-stock": 2,
|
||||
"on-order": 1,
|
||||
"sku": "HRD-000-517"
|
||||
},
|
||||
{
|
||||
"name": "bolt",
|
||||
"sold": 4123.0,
|
||||
"in-stock": 144,
|
||||
"on-order": 42,
|
||||
"sku": "HRD-000-632"
|
||||
},
|
||||
{
|
||||
"name": "water",
|
||||
"sold": 17.0,
|
||||
"in-stock": 14,
|
||||
"on-order": 2,
|
||||
"sku": "GRO-000-2331"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"item": [
|
||||
{
|
||||
"name": "fish",
|
||||
"sold": 1321.0,
|
||||
"in-stock": 45,
|
||||
"on-order": 1,
|
||||
"sku": "GRO-000-533"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
XML output::
|
||||
|
||||
% ./testxo --libxo pretty,xml
|
||||
<top>
|
||||
<data>
|
||||
<item>
|
||||
<name>gum</name>
|
||||
<sold>1412.0</sold>
|
||||
<in-stock>54</in-stock>
|
||||
<on-order>10</on-order>
|
||||
<sku>GRO-000-415</sku>
|
||||
</item>
|
||||
<item>
|
||||
<name>rope</name>
|
||||
<sold>85.0</sold>
|
||||
<in-stock>4</in-stock>
|
||||
<on-order>2</on-order>
|
||||
<sku>HRD-000-212</sku>
|
||||
</item>
|
||||
<item>
|
||||
<name>ladder</name>
|
||||
<sold>0</sold>
|
||||
<in-stock>2</in-stock>
|
||||
<on-order>1</on-order>
|
||||
<sku>HRD-000-517</sku>
|
||||
</item>
|
||||
<item>
|
||||
<name>bolt</name>
|
||||
<sold>4123.0</sold>
|
||||
<in-stock>144</in-stock>
|
||||
<on-order>42</on-order>
|
||||
<sku>HRD-000-632</sku>
|
||||
</item>
|
||||
<item>
|
||||
<name>water</name>
|
||||
<sold>17.0</sold>
|
||||
<in-stock>14</in-stock>
|
||||
<on-order>2</on-order>
|
||||
<sku>GRO-000-2331</sku>
|
||||
</item>
|
||||
</data>
|
||||
<data>
|
||||
<item>
|
||||
<name>fish</name>
|
||||
<sold>1321.0</sold>
|
||||
<in-stock>45</in-stock>
|
||||
<on-order>1</on-order>
|
||||
<sku>GRO-000-533</sku>
|
||||
</item>
|
||||
</data>
|
||||
</top>
|
||||
|
||||
HMTL output::
|
||||
|
||||
% ./testxo --libxo pretty,html
|
||||
<div class="line">
|
||||
<div class="label">Item</div>
|
||||
<div class="text"> '</div>
|
||||
<div class="data" data-tag="name">gum</div>
|
||||
<div class="text">':</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">Total sold</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sold">1412.0</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">In stock</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="in-stock">54</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">On order</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="on-order">10</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">SKU</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sku">GRO-000-415</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="label">Item</div>
|
||||
<div class="text"> '</div>
|
||||
<div class="data" data-tag="name">rope</div>
|
||||
<div class="text">':</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">Total sold</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sold">85.0</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">In stock</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="in-stock">4</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">On order</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="on-order">2</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">SKU</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sku">HRD-000-212</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="label">Item</div>
|
||||
<div class="text"> '</div>
|
||||
<div class="data" data-tag="name">ladder</div>
|
||||
<div class="text">':</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">Total sold</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sold">0</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">In stock</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="in-stock">2</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">On order</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="on-order">1</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">SKU</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sku">HRD-000-517</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="label">Item</div>
|
||||
<div class="text"> '</div>
|
||||
<div class="data" data-tag="name">bolt</div>
|
||||
<div class="text">':</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">Total sold</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sold">4123.0</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">In stock</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="in-stock">144</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">On order</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="on-order">42</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">SKU</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sku">HRD-000-632</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="label">Item</div>
|
||||
<div class="text"> '</div>
|
||||
<div class="data" data-tag="name">water</div>
|
||||
<div class="text">':</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">Total sold</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sold">17.0</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">In stock</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="in-stock">14</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">On order</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="on-order">2</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">SKU</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sku">GRO-000-2331</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="label">Item</div>
|
||||
<div class="text"> '</div>
|
||||
<div class="data" data-tag="name">fish</div>
|
||||
<div class="text">':</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">Total sold</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sold">1321.0</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">In stock</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="in-stock">45</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">On order</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="on-order">1</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">SKU</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sku">GRO-000-533</div>
|
||||
</div>
|
||||
|
||||
HTML output with xpath and info flags::
|
||||
|
||||
% ./testxo --libxo pretty,html,xpath,info
|
||||
<div class="line">
|
||||
<div class="label">Item</div>
|
||||
<div class="text"> '</div>
|
||||
<div class="data" data-tag="name"
|
||||
data-xpath="/top/data/item/name" data-type="string"
|
||||
data-help="Name of the item">gum</div>
|
||||
<div class="text">':</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">Total sold</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sold"
|
||||
data-xpath="/top/data/item/sold" data-type="number"
|
||||
data-help="Number of items sold">1412.0</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">In stock</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="in-stock"
|
||||
data-xpath="/top/data/item/in-stock" data-type="number"
|
||||
data-help="Number of items in stock">54</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">On order</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="on-order"
|
||||
data-xpath="/top/data/item/on-order" data-type="number"
|
||||
data-help="Number of items on order">10</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">SKU</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sku"
|
||||
data-xpath="/top/data/item/sku" data-type="string"
|
||||
data-help="Stock Keeping Unit">GRO-000-415</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="label">Item</div>
|
||||
<div class="text"> '</div>
|
||||
<div class="data" data-tag="name"
|
||||
data-xpath="/top/data/item/name" data-type="string"
|
||||
data-help="Name of the item">rope</div>
|
||||
<div class="text">':</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">Total sold</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sold"
|
||||
data-xpath="/top/data/item/sold" data-type="number"
|
||||
data-help="Number of items sold">85.0</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">In stock</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="in-stock"
|
||||
data-xpath="/top/data/item/in-stock" data-type="number"
|
||||
data-help="Number of items in stock">4</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">On order</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="on-order"
|
||||
data-xpath="/top/data/item/on-order" data-type="number"
|
||||
data-help="Number of items on order">2</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">SKU</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sku"
|
||||
data-xpath="/top/data/item/sku" data-type="string"
|
||||
data-help="Stock Keeping Unit">HRD-000-212</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="label">Item</div>
|
||||
<div class="text"> '</div>
|
||||
<div class="data" data-tag="name"
|
||||
data-xpath="/top/data/item/name" data-type="string"
|
||||
data-help="Name of the item">ladder</div>
|
||||
<div class="text">':</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">Total sold</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sold"
|
||||
data-xpath="/top/data/item/sold" data-type="number"
|
||||
data-help="Number of items sold">0</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">In stock</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="in-stock"
|
||||
data-xpath="/top/data/item/in-stock" data-type="number"
|
||||
data-help="Number of items in stock">2</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">On order</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="on-order"
|
||||
data-xpath="/top/data/item/on-order" data-type="number"
|
||||
data-help="Number of items on order">1</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">SKU</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sku"
|
||||
data-xpath="/top/data/item/sku" data-type="string"
|
||||
data-help="Stock Keeping Unit">HRD-000-517</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="label">Item</div>
|
||||
<div class="text"> '</div>
|
||||
<div class="data" data-tag="name"
|
||||
data-xpath="/top/data/item/name" data-type="string"
|
||||
data-help="Name of the item">bolt</div>
|
||||
<div class="text">':</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">Total sold</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sold"
|
||||
data-xpath="/top/data/item/sold" data-type="number"
|
||||
data-help="Number of items sold">4123.0</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">In stock</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="in-stock"
|
||||
data-xpath="/top/data/item/in-stock" data-type="number"
|
||||
data-help="Number of items in stock">144</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">On order</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="on-order"
|
||||
data-xpath="/top/data/item/on-order" data-type="number"
|
||||
data-help="Number of items on order">42</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">SKU</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sku"
|
||||
data-xpath="/top/data/item/sku" data-type="string"
|
||||
data-help="Stock Keeping Unit">HRD-000-632</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="label">Item</div>
|
||||
<div class="text"> '</div>
|
||||
<div class="data" data-tag="name"
|
||||
data-xpath="/top/data/item/name" data-type="string"
|
||||
data-help="Name of the item">water</div>
|
||||
<div class="text">':</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">Total sold</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sold"
|
||||
data-xpath="/top/data/item/sold" data-type="number"
|
||||
data-help="Number of items sold">17.0</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">In stock</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="in-stock"
|
||||
data-xpath="/top/data/item/in-stock" data-type="number"
|
||||
data-help="Number of items in stock">14</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">On order</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="on-order"
|
||||
data-xpath="/top/data/item/on-order" data-type="number"
|
||||
data-help="Number of items on order">2</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">SKU</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sku"
|
||||
data-xpath="/top/data/item/sku" data-type="string"
|
||||
data-help="Stock Keeping Unit">GRO-000-2331</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="label">Item</div>
|
||||
<div class="text"> '</div>
|
||||
<div class="data" data-tag="name"
|
||||
data-xpath="/top/data/item/name" data-type="string"
|
||||
data-help="Name of the item">fish</div>
|
||||
<div class="text">':</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">Total sold</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sold"
|
||||
data-xpath="/top/data/item/sold" data-type="number"
|
||||
data-help="Number of items sold">1321.0</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">In stock</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="in-stock"
|
||||
data-xpath="/top/data/item/in-stock" data-type="number"
|
||||
data-help="Number of items in stock">45</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">On order</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="on-order"
|
||||
data-xpath="/top/data/item/on-order" data-type="number"
|
||||
data-help="Number of items on order">1</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">SKU</div>
|
||||
<div class="text">: </div>
|
||||
<div class="data" data-tag="sku"
|
||||
data-xpath="/top/data/item/sku" data-type="string"
|
||||
data-help="Stock Keeping Unit">GRO-000-533</div>
|
||||
</div>
|
211
doc/faq.rst
Normal file
211
doc/faq.rst
Normal file
@ -0,0 +1,211 @@
|
||||
|
||||
FAQs
|
||||
====
|
||||
|
||||
This section contains the set of questions that users typically ask,
|
||||
along with answers that might be helpful.
|
||||
|
||||
General
|
||||
-------
|
||||
|
||||
Can you share the history of libxo?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In 2001, we added an XML API to the JUNOS operating system, which is
|
||||
built on top of FreeBSD_. Eventually this API became standardized as
|
||||
the NETCONF API (:RFC:`6241`). As part of this effort, we modified many
|
||||
FreeBSD utilities to emit XML, typically via a "-X" switch. The
|
||||
results were mixed. The cost of maintaining this code, updating it,
|
||||
and carrying it were non-trivial, and contributed to our expense (and
|
||||
the associated delay) with upgrading the version of FreeBSD on which
|
||||
each release of JUNOS is based.
|
||||
|
||||
.. _FreeBSD: https://www.freebsd.org
|
||||
|
||||
A recent (2014) effort within JUNOS aims at removing our modifications
|
||||
to the underlying FreeBSD code as a means of reducing the expense and
|
||||
delay in tracking HEAD. JUNOS is structured to have system components
|
||||
generate XML that is rendered by the CLI (think: login shell) into
|
||||
human-readable text. This allows the API to use the same plumbing as
|
||||
the CLI, and ensures that all components emit XML, and that it is
|
||||
emitted with knowledge of the consumer of that XML, yielding an API
|
||||
that have no incremental cost or feature delay.
|
||||
|
||||
libxo is an effort to mix the best aspects of the JUNOS strategy into
|
||||
FreeBSD in a seemless way, allowing commands to make printf-like
|
||||
output calls with a single code path.
|
||||
|
||||
Did the complex semantics of format strings evolve over time?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The history is both long and short: libxo's functionality is based
|
||||
on what JUNOS does in a data modeling language called ODL (output
|
||||
definition language). In JUNOS, all subcomponents generate XML,
|
||||
which is feed to the CLI, where data from the ODL files tell is
|
||||
how to render that XML into text. ODL might had a set of tags
|
||||
like::
|
||||
|
||||
tag docsis-state {
|
||||
help "State of the DOCSIS interface";
|
||||
type string;
|
||||
}
|
||||
|
||||
tag docsis-mode {
|
||||
help "DOCSIS mode (2.0/3.0) of the DOCSIS interface";
|
||||
type string;
|
||||
}
|
||||
|
||||
tag docsis-upstream-speed {
|
||||
help "Operational upstream speed of the interface";
|
||||
type string;
|
||||
}
|
||||
|
||||
tag downstream-scanning {
|
||||
help "Result of scanning in downstream direction";
|
||||
type string;
|
||||
}
|
||||
|
||||
tag ranging {
|
||||
help "Result of ranging action";
|
||||
type string;
|
||||
}
|
||||
|
||||
tag signal-to-noise-ratio {
|
||||
help "Signal to noise ratio for all channels";
|
||||
type string;
|
||||
}
|
||||
|
||||
tag power {
|
||||
help "Operational power of the signal on all channels";
|
||||
type string;
|
||||
}
|
||||
|
||||
format docsis-status-format {
|
||||
picture "
|
||||
State : @, Mode: @, Upstream speed: @
|
||||
Downstream scanning: @, Ranging: @
|
||||
Signal to noise ratio: @
|
||||
Power: @
|
||||
";
|
||||
line {
|
||||
field docsis-state;
|
||||
field docsis-mode;
|
||||
field docsis-upstream-speed;
|
||||
field downstream-scanning;
|
||||
field ranging;
|
||||
field signal-to-noise-ratio;
|
||||
field power;
|
||||
}
|
||||
}
|
||||
|
||||
These tag definitions are compiled into field definitions
|
||||
that are triggered when matching XML elements are seen. ODL
|
||||
also supports other means of defining output.
|
||||
|
||||
The roles and modifiers describe these details.
|
||||
|
||||
In moving these ideas to bsd, two things had to happen: the
|
||||
formatting had to happen at the source since BSD won't have
|
||||
a JUNOS-like CLI to do the rendering, and we can't depend on
|
||||
external data models like ODL, which was seen as too hard a
|
||||
sell to the BSD community.
|
||||
|
||||
The results were that the xo_emit strings are used to encode the
|
||||
roles, modifiers, names, and formats. They are dense and a bit
|
||||
cryptic, but not so unlike printf format strings that developers will
|
||||
be lost.
|
||||
|
||||
libxo is a new implementation of these ideas and is distinct from
|
||||
the previous implementation in JUNOS.
|
||||
|
||||
.. index:: XOF_UNDERSCORES
|
||||
|
||||
.. _good-field-names:
|
||||
|
||||
What makes a good field name?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To make useful, consistent field names, follow these guidelines:
|
||||
|
||||
Use lower case, even for TLAs
|
||||
Lower case is more civilized. Even TLAs should be lower case
|
||||
to avoid scenarios where the differences between "XPath" and
|
||||
"Xpath" drive your users crazy. Using "xpath" is simpler and better.
|
||||
|
||||
Use hyphens, not underscores
|
||||
Use of hyphens is traditional in XML, and the XOF_UNDERSCORES
|
||||
flag can be used to generate underscores in JSON, if desired.
|
||||
But the raw field name should use hyphens.
|
||||
|
||||
Use full words
|
||||
Don't abbreviate especially when the abbreviation is not obvious or
|
||||
not widely used. Use "data-size", not "dsz" or "dsize". Use
|
||||
"interface" instead of "ifname", "if-name", "iface", "if", or "intf".
|
||||
|
||||
Use <verb>-<units>
|
||||
Using the form <verb>-<units> or <verb>-<classifier>-<units> helps in
|
||||
making consistent, useful names, avoiding the situation where one app
|
||||
uses "sent-packet" and another "packets-sent" and another
|
||||
"packets-we-have-sent". The <units> can be dropped when it is
|
||||
obvious, as can obvious words in the classification.
|
||||
Use "receive-after-window-packets" instead of
|
||||
"received-packets-of-data-after-window".
|
||||
|
||||
Reuse existing field names
|
||||
Nothing's worse than writing expressions like::
|
||||
|
||||
if ($src1/process[pid == $pid]/name ==
|
||||
$src2/proc-table/proc-list
|
||||
/prc-entry[prcss-id == $pid]/proc-name) {
|
||||
...
|
||||
}
|
||||
|
||||
Find someone else who is expressing similar data and follow their
|
||||
fields and hierarchy. Remember the quote is not "Consistency is the
|
||||
hobgoblin of little minds", but "A *foolish* consistency is the
|
||||
hobgoblin of little minds". Consistency rocks!
|
||||
|
||||
Use containment as scoping
|
||||
In the previous example, all the names are prefixed with "proc-",
|
||||
which is redundant given that they are nested under the process table.
|
||||
|
||||
Think about your users
|
||||
Have empathy for your users, choosing clear and useful fields that
|
||||
contain clear and useful data. You may need to augment the display
|
||||
content with xo_attr() calls (:ref:`xo_attr`) or "{e:}"
|
||||
fields (:ref:`encoding-modifier`) to make the data useful.
|
||||
|
||||
Don't use an arbitrary number postfix
|
||||
What does "errors2" mean? No one will know. "errors-after-restart"
|
||||
would be a better choice. Think of your users, and think of the
|
||||
future. If you make "errors2", the next guy will happily make
|
||||
"errors3" and before you know it, someone will be asking what's the
|
||||
difference between errors37 and errors63.
|
||||
|
||||
Be consistent, uniform, unsurprising, and predictable
|
||||
Think of your field vocabulary as an API. You want it useful,
|
||||
expressive, meaningful, direct, and obvious. You want the client
|
||||
application's programmer to move between without the need to
|
||||
understand a variety of opinions on how fields are named. They
|
||||
should see the system as a single cohesive whole, not a sack of
|
||||
cats.
|
||||
|
||||
Field names constitute the means by which client programmers interact
|
||||
with our system. By choosing wise names now, you are making their
|
||||
lives better.
|
||||
|
||||
After using `xolint` to find errors in your field descriptors, use
|
||||
"`xolint -V`" to spell check your field names and to help you detect
|
||||
different names for the same data. "dropped-short" and
|
||||
"dropped-too-short" are both reasonable names, but using them both
|
||||
will lead users to ask the difference between the two fields. If
|
||||
there is no difference, use only one of the field names. If there is
|
||||
a difference, change the names to make that difference more obvious.
|
||||
|
||||
What does this message mean?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
xolint-errors.rst
|
371
doc/field-formatting.rst
Normal file
371
doc/field-formatting.rst
Normal file
@ -0,0 +1,371 @@
|
||||
|
||||
.. index:: Field Formatting
|
||||
.. _field-formatting:
|
||||
|
||||
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 than
|
||||
the minimum 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
|
||||
===== ============= ====================
|
||||
|
||||
.. index:: UTF-8
|
||||
.. index:: Locale
|
||||
|
||||
.. _utf-8:
|
||||
|
||||
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".
|
||||
|
||||
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("All strings are utf-8 content {:tag/%ls}",
|
||||
L"except for wide strings");
|
||||
|
||||
======== ================== ===============================
|
||||
Format Argument Type Argument Contents
|
||||
======== ================== ===============================
|
||||
%s const char \* UTF-8 string
|
||||
%S const char \* UTF-8 string (alias for '%ls')
|
||||
%ls const wchar_t \* Wide character UNICODE string
|
||||
%hs const char * locale-based string
|
||||
======== ================== ===============================
|
||||
|
||||
.. admonition:: "Long", not "locale"
|
||||
|
||||
The "*l*" in "%ls" is for "*long*", following the convention of "%ld".
|
||||
It is not "*locale*", a common mis-mnemonic. "%S" is equivalent to
|
||||
"%ls".
|
||||
|
||||
For example, the following 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 <div> with class "text"::
|
||||
|
||||
EXAMPLE:
|
||||
xo_emit("The hat is {:size/%s}.\n", size_val);
|
||||
TEXT:
|
||||
The hat is extra small.
|
||||
XML:
|
||||
<size>extra small</size>
|
||||
JSON:
|
||||
"size": "extra small"
|
||||
HTML:
|
||||
<div class="text">The hat is </div>
|
||||
<div class="data" data-tag="size">extra small</div>
|
||||
<div class="text">.</div>
|
||||
|
||||
.. index:: errno
|
||||
|
||||
"%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.
|
||||
|
||||
.. index:: printf-like
|
||||
|
||||
Argument Validation
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
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
|
||||
================== ========================
|
||||
|
||||
.. index:: performance
|
||||
.. index:: XOEF_RETAIN
|
||||
|
||||
.. _retain:
|
||||
|
||||
Retaining Parsed Format Information
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
libxo can retain the parsed internal information related to the given
|
||||
format string, allowing subsequent xo_emit calls, the retained
|
||||
information is used, avoiding repetitive parsing of the format string::
|
||||
|
||||
SYNTAX:
|
||||
int xo_emit_f(xo_emit_flags_t flags, const char fmt, ...);
|
||||
EXAMPLE:
|
||||
xo_emit_f(XOEF_RETAIN, "{:some/%02d}{:thing/%-6s}{:fancy}\n",
|
||||
some, thing, fancy);
|
||||
|
||||
To retain parsed format information, use the XOEF_RETAIN flag to the
|
||||
xo_emit_f() function. A complete set of xo_emit_f functions exist to
|
||||
match all the xo_emit function signatures (with handles, varadic
|
||||
argument, and printf-like flags):
|
||||
|
||||
================== ========================
|
||||
Function Flags Equivalent
|
||||
================== ========================
|
||||
xo_emit_hv xo_emit_hvf
|
||||
xo_emit_h xo_emit_hf
|
||||
xo_emit xo_emit_f
|
||||
xo_emit_hvp xo_emit_hvfp
|
||||
xo_emit_hp xo_emit_hfp
|
||||
xo_emit_p xo_emit_fp
|
||||
================== ========================
|
||||
|
||||
The format string must be immutable across multiple calls to xo_emit_f(),
|
||||
since the library retains the string. Typically this is done by using
|
||||
static constant strings, such as string literals. If the string is not
|
||||
immutable, the XOEF_RETAIN flag must not be used.
|
||||
|
||||
The functions xo_retain_clear() and xo_retain_clear_all() release
|
||||
internal information on either a single format string or all format
|
||||
strings, respectively. Neither is required, but the library will
|
||||
retain this information until it is cleared or the process exits::
|
||||
|
||||
const char *fmt = "{:name} {:count/%d}\n";
|
||||
for (i = 0; i < 1000; i++) {
|
||||
xo_open_instance("item");
|
||||
xo_emit_f(XOEF_RETAIN, fmt, name[i], count[i]);
|
||||
}
|
||||
xo_retain_clear(fmt);
|
||||
|
||||
The retained information is kept as thread-specific data.
|
||||
|
||||
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:
|
||||
<in-stock>144</in-stock>
|
||||
JSON:
|
||||
"in-stock": 144,
|
||||
HTML:
|
||||
<div class="line">
|
||||
<div class="padding"> </div>
|
||||
<div class="label">In stock</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="in-stock">144</div>
|
||||
</div>
|
||||
|
||||
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::
|
||||
|
||||
<div class="data" data-tag="in-stock"
|
||||
data-xpath="/top/data/item/in-stock"
|
||||
data-type="number"
|
||||
data-help="Number of items in stock">144</div>
|
353
doc/field-modifiers.rst
Normal file
353
doc/field-modifiers.rst
Normal file
@ -0,0 +1,353 @@
|
||||
|
||||
.. index:: Field Modifiers
|
||||
.. _field-modifiers:
|
||||
|
||||
Field Modifiers
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Field modifiers are flags which modify the way content emitted for
|
||||
particular output styles:
|
||||
|
||||
=== =============== ===================================================
|
||||
M Name Description
|
||||
=== =============== ===================================================
|
||||
a argument The content appears as a 'const char \*' argument
|
||||
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 preceded 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.
|
||||
|
||||
.. index:: Field Modifiers; Argument
|
||||
.. _argument-modifier:
|
||||
|
||||
The Argument Modifier ({a:})
|
||||
++++++++++++++++++++++++++++
|
||||
|
||||
.. index:: Field Modifiers; Argument
|
||||
|
||||
The argument modifier indicates that the content of the field
|
||||
descriptor will be placed as a UTF-8 string (const char \*) argument
|
||||
within the xo_emit parameters::
|
||||
|
||||
EXAMPLE:
|
||||
xo_emit("{La:} {a:}\n", "Label text", "label", "value");
|
||||
TEXT:
|
||||
Label text value
|
||||
JSON:
|
||||
"label": "value"
|
||||
XML:
|
||||
<label>value</label>
|
||||
|
||||
The argument modifier allows field names for value fields to be passed
|
||||
on the stack, avoiding the need to build a field descriptor using
|
||||
snprintf. For many field roles, the argument modifier is not needed,
|
||||
since those roles have specific mechanisms for arguments, such as
|
||||
"{C:fg-%s}".
|
||||
|
||||
.. index:: Field Modifiers; Colon
|
||||
.. _colon-modifier:
|
||||
|
||||
The Colon Modifier ({c:})
|
||||
+++++++++++++++++++++++++
|
||||
|
||||
.. index:: Field Modifiers; Colon
|
||||
|
||||
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.
|
||||
|
||||
.. index:: Field Modifiers; Display
|
||||
.. _display-modifier:
|
||||
|
||||
The Display Modifier ({d:})
|
||||
+++++++++++++++++++++++++++
|
||||
|
||||
.. index:: Field Modifiers; Display
|
||||
|
||||
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:
|
||||
<id>1</id>
|
||||
|
||||
The display modifier is the opposite of the encoding modifier, and
|
||||
they are often used to give to distinct views of the underlying data.
|
||||
|
||||
.. index:: Field Modifiers; Encoding
|
||||
.. _encoding-modifier:
|
||||
|
||||
The Encoding Modifier ({e:})
|
||||
++++++++++++++++++++++++++++
|
||||
|
||||
.. index:: Field Modifiers; Encoding
|
||||
|
||||
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:
|
||||
<name>phil</name><id>1</id>
|
||||
|
||||
The encoding modifier is the opposite of the display modifier, and
|
||||
they are often used to give to distinct views of the underlying data.
|
||||
|
||||
.. index:: Field Modifiers; Gettext
|
||||
.. _gettext-modifier:
|
||||
|
||||
The Gettext Modifier ({g:})
|
||||
+++++++++++++++++++++++++++
|
||||
|
||||
.. index:: Field Modifiers; Gettext
|
||||
.. index:: gettext
|
||||
|
||||
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 :ref:`gettext-role`, :ref:`plural-modifier`, and
|
||||
:ref:`i18n` for additional details.
|
||||
|
||||
.. index:: Field Modifiers; Humanize
|
||||
.. _humanize-modifier:
|
||||
|
||||
The Humanize Modifier ({h:})
|
||||
++++++++++++++++++++++++++++
|
||||
|
||||
.. index:: Field Modifiers; Humanize
|
||||
|
||||
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 :ref:`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 <div> element::
|
||||
|
||||
<div class="data" data-tag="errors"
|
||||
data-number="100663296">96M</div>
|
||||
|
||||
.. index:: Field Modifiers; Key
|
||||
.. _key-modifier:
|
||||
|
||||
The Key Modifier ({k:})
|
||||
+++++++++++++++++++++++
|
||||
|
||||
.. index:: Field Modifiers; Key
|
||||
|
||||
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");
|
||||
|
||||
.. index:: XOF_XPATH
|
||||
|
||||
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.
|
||||
|
||||
.. index:: Field Modifiers; Leaf-List
|
||||
.. _leaf-list:
|
||||
|
||||
The Leaf-List Modifier ({l:})
|
||||
+++++++++++++++++++++++++++++
|
||||
|
||||
.. index:: Field Modifiers; Leaf-List
|
||||
|
||||
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:
|
||||
<user>phil</user>
|
||||
<user>pallavi</user>
|
||||
JSON:
|
||||
"user": [ "phil", "pallavi" ]
|
||||
|
||||
The name of the field must match the name of the leaf list.
|
||||
|
||||
.. index:: Field Modifiers; No-Quotes
|
||||
.. _no-quotes-modifier:
|
||||
|
||||
The No-Quotes Modifier ({n:})
|
||||
+++++++++++++++++++++++++++++
|
||||
|
||||
.. index:: Field Modifiers; No-Quotes
|
||||
|
||||
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
|
||||
|
||||
.. index:: Field Modifiers; Plural
|
||||
.. _plural-modifier:
|
||||
|
||||
The Plural Modifier ({p:})
|
||||
++++++++++++++++++++++++++
|
||||
|
||||
.. index:: Field Modifiers; Plural
|
||||
.. index:: gettext
|
||||
|
||||
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 :ref:`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.
|
||||
|
||||
.. index:: Field Modifiers; Quotes
|
||||
.. _quotes-modifier:
|
||||
|
||||
The Quotes Modifier ({q:})
|
||||
++++++++++++++++++++++++++
|
||||
|
||||
.. index:: Field Modifiers; Quotes
|
||||
|
||||
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 heuristic is based on the format; if the format uses any of the
|
||||
following conversion specifiers, then no quotes are used::
|
||||
|
||||
d i o u x X D O U e E f F g G a A c C p
|
||||
|
||||
.. index:: Field Modifiers; Trim
|
||||
.. _trim-modifier:
|
||||
|
||||
The Trim Modifier ({t:})
|
||||
++++++++++++++++++++++++
|
||||
|
||||
.. index:: Field Modifiers; Trim
|
||||
|
||||
The trim modifier removes any leading or trailing whitespace from
|
||||
the value::
|
||||
|
||||
EXAMPLE:
|
||||
xo_emit("{t:description}", " some input ");
|
||||
JSON:
|
||||
"description": "some input"
|
||||
|
||||
.. index:: Field Modifiers; White Space
|
||||
.. _white-space-modifier:
|
||||
|
||||
The White Space Modifier ({w:})
|
||||
+++++++++++++++++++++++++++++++
|
||||
|
||||
.. index:: Field Modifiers; White Space
|
||||
|
||||
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.
|
317
doc/field-roles.rst
Normal file
317
doc/field-roles.rst
Normal file
@ -0,0 +1,317 @@
|
||||
|
||||
.. index:: Field Roles
|
||||
.. _field-roles:
|
||||
|
||||
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 preceded by
|
||||
a comma::
|
||||
|
||||
EXAMPLE:
|
||||
xo_emit("{,label:Free}{,decoration::}{,padding: }"
|
||||
"{,value:free/%u} {,units:Blocks}\n",
|
||||
free_blocks);
|
||||
|
||||
.. index:: Field Roles; Color
|
||||
.. _color-role:
|
||||
|
||||
The Color Role ({C:})
|
||||
+++++++++++++++++++++
|
||||
|
||||
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
|
||||
========= ============================================
|
||||
|
||||
When using colors, the developer should remember that users will
|
||||
change the foreground and background colors of terminal session
|
||||
according to their own tastes, so assuming that "blue" looks nice is
|
||||
never safe, and is a constant annoyance to your dear author. In
|
||||
addition, a significant percentage of users (1 in 12) will be color
|
||||
blind. Depending on color to convey critical information is not a
|
||||
good idea. Color should enhance output, but should not be used as the
|
||||
sole means of encoding information.
|
||||
|
||||
.. index:: Field Roles; Decoration
|
||||
.. _decoration-role:
|
||||
|
||||
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);
|
||||
|
||||
.. index:: Field Roles; Gettext
|
||||
.. _gettext-role:
|
||||
|
||||
The Gettext Role ({G:})
|
||||
+++++++++++++++++++++++
|
||||
|
||||
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 $text`" command, or an entire .pot can be translated using
|
||||
the "`xopo -f $input -o $output`" 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 :ref:`i18n` for additional details.
|
||||
|
||||
.. index:: Field Roles; Label
|
||||
.. _label-role:
|
||||
|
||||
The Label Role ({L:})
|
||||
+++++++++++++++++++++
|
||||
|
||||
Labels are text that appears before a value::
|
||||
|
||||
xo_emit("{Lwc:Cost}{:cost/%u}\n", cost);
|
||||
|
||||
If a label needs to include a slash, it must be escaped using two
|
||||
backslashes, one for the C compiler and one for libxo::
|
||||
|
||||
xo_emit("{Lc:Low\\/warn level}{:level/%s}\n", level);
|
||||
|
||||
.. index:: Field Roles; Note
|
||||
.. _note-role:
|
||||
|
||||
The Note Role ({N:})
|
||||
++++++++++++++++++++
|
||||
|
||||
Notes are text that appears after a value::
|
||||
|
||||
xo_emit("{:cost/%u} {N:per year}\n", cost);
|
||||
|
||||
.. index:: Field Roles; Padding
|
||||
.. _padding-role:
|
||||
|
||||
The Padding Role ({P:})
|
||||
+++++++++++++++++++++++
|
||||
|
||||
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);
|
||||
|
||||
.. index:: Field Roles; Title
|
||||
.. _title-role:
|
||||
|
||||
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.
|
||||
|
||||
.. index:: Field Roles; Units
|
||||
.. index:: XOF_UNITS
|
||||
.. _units-role:
|
||||
|
||||
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::
|
||||
|
||||
<distance units="miles">50</distance>
|
||||
|
||||
Units can also be rendered in HTML as the "data-units" attribute::
|
||||
|
||||
<div class="data" data-tag="distance" data-units="miles"
|
||||
data-xpath="/top/data/distance">50</div>
|
||||
|
||||
.. index:: Field Roles; Value
|
||||
.. _value-role:
|
||||
|
||||
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);
|
||||
|
||||
.. index:: Field Roles; Anchor
|
||||
.. _anchor-role:
|
||||
|
||||
The Anchor Roles ({[:} and {]:})
|
||||
++++++++++++++++++++++++++++++++
|
||||
|
||||
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.
|
||||
|
||||
.. index:: XOF_WARN
|
||||
|
||||
Widths over 8k are considered probable errors and not supported. If
|
||||
XOF_WARN is set, a warning will be generated.
|
47
doc/format-strings.rst
Normal file
47
doc/format-strings.rst
Normal file
@ -0,0 +1,47 @@
|
||||
|
||||
.. index:: Format Strings
|
||||
.. _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
|
||||
("<in-stock>65</in-stock>"), 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);
|
165
doc/formatting.rst
Normal file
165
doc/formatting.rst
Normal file
@ -0,0 +1,165 @@
|
||||
|
||||
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; "<div>" 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:
|
||||
<host>my-box</host>
|
||||
<domain>example.com</domain>
|
||||
JSON:
|
||||
"host": "my-box",
|
||||
"domain": "example.com"
|
||||
HTML:
|
||||
<div class="line">
|
||||
<div class="text">Connecting to </div>
|
||||
<div class="data" data-tag="host"
|
||||
data-xpath="/top/host">my-box</div>
|
||||
<div class="text">.</div>
|
||||
<div class="data" data-tag="domain"
|
||||
data-xpath="/top/domain">example.com</div>
|
||||
<div class="text">...</div>
|
||||
</div>
|
||||
|
||||
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 :ref:`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::
|
||||
|
||||
<item>
|
||||
<blocks>36</blocks>
|
||||
<path>./src</path>
|
||||
</item>
|
||||
<item>
|
||||
<blocks>40</blocks>
|
||||
<path>./bin</path>
|
||||
</item>
|
||||
<item>
|
||||
<blocks>90</blocks>
|
||||
<path>.</path>
|
||||
</item>
|
||||
|
||||
`XML`_ is the W3C standard for encoding data.
|
||||
|
||||
.. _XML: https://w3c.org/TR/xml
|
||||
|
||||
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 <div> 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::
|
||||
|
||||
<div class="line">
|
||||
<div class="data" data-tag="blocks">36</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="path">./src</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="blocks">40</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="path">./bin</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="blocks">90</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="path">./</div>
|
||||
</div>
|
185
doc/getting.rst
Normal file
185
doc/getting.rst
Normal file
@ -0,0 +1,185 @@
|
||||
|
||||
.. index:: Getting libxo
|
||||
|
||||
Getting libxo
|
||||
=============
|
||||
|
||||
libxo now ships as part of the FreeBSD Operating System (as of Release
|
||||
11).
|
||||
|
||||
libxo source code lives on github:
|
||||
|
||||
https://github.com/Juniper/libxo
|
||||
|
||||
The latest release of libxo is available at:
|
||||
|
||||
https://github.com/Juniper/libxo/releases
|
||||
|
||||
We're using `Semantic Versioning`_ to number our releases. libxo is
|
||||
open source, distributed under the BSD license. We follow the
|
||||
branching scheme from `A Successful Git Branching Model`_:
|
||||
we 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
|
||||
|
||||
.. _Semantic Versioning: http://semver.org/spec/v2.0.0.html
|
||||
.. _A Successful Git Branching Model:
|
||||
http://nvie.com/posts/a-successful-git-branching-model
|
||||
|
||||
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 the `release page`_ to see the list of
|
||||
releases. To download the latest, look for the release witeh the
|
||||
green "Latest release" button and the green "libxo-RELEASE.tar.gz"
|
||||
button under that section.
|
||||
|
||||
.. _release page: https://github.com/Juniper/libxo/releases
|
||||
|
||||
After downloading that release's distfile, untar it as follows::
|
||||
|
||||
tar -zxf libxo-RELEASE.tar.gz
|
||||
cd libxo-RELEASE
|
||||
|
||||
.. admonition:: Solaris Users
|
||||
|
||||
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
|
||||
|
||||
.. admonition:: 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:
|
||||
|
||||
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 through each of these steps with
|
||||
additional details and options, but the above directions should be all
|
||||
that's needed.
|
||||
|
||||
Setting up the build
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. admonition: Note
|
||||
|
||||
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
|
394
doc/howto.rst
Normal file
394
doc/howto.rst
Normal file
@ -0,0 +1,394 @@
|
||||
|
||||
Howtos: Focused Directions
|
||||
==========================
|
||||
|
||||
This section provides task-oriented instructions for selected tasks.
|
||||
If you have a task that needs instructions, please open a request as
|
||||
an enhancement issue on github.
|
||||
|
||||
Howto: Report bugs
|
||||
------------------
|
||||
|
||||
libxo uses github to track bugs or request enhancements. Please use
|
||||
the following URL:
|
||||
|
||||
https://github.com/Juniper/libxo/issues
|
||||
|
||||
Howto: Install libxo
|
||||
--------------------
|
||||
|
||||
libxo is open source, under a new BSD license. Source code is
|
||||
available on github, as are recent releases. To get the most
|
||||
current release, please visit:
|
||||
|
||||
https://github.com/Juniper/libxo/releases
|
||||
|
||||
After downloading and untarring the source code, building involves the
|
||||
following steps::
|
||||
|
||||
sh bin/setup.sh
|
||||
cd build
|
||||
../configure
|
||||
make
|
||||
make test
|
||||
sudo make install
|
||||
|
||||
libxo uses a distinct "*build*" directory to keep generated files
|
||||
separated from source files.
|
||||
|
||||
.. index:: configure
|
||||
|
||||
Use "`../configure --help`" to display available configuration
|
||||
options, which include the following::
|
||||
|
||||
--enable-warnings Turn on compiler warnings
|
||||
--enable-debug Turn on debugging
|
||||
--enable-text-only Turn on text-only rendering
|
||||
--enable-printflike Enable use of GCC __printflike attribute
|
||||
--disable-libxo-options Turn off support for LIBXO_OPTIONS
|
||||
--with-gettext=PFX Specify location of gettext installation
|
||||
--with-libslax-prefix=PFX Specify location of libslax config
|
||||
|
||||
Compiler warnings are a very good thing, but recent compiler version
|
||||
have added some very pedantic checks. While every attempt is made to
|
||||
keep libxo code warning-free, warnings are now optional. If you are
|
||||
doing development work on libxo, it is required that you
|
||||
use --enable-warnings to keep the code warning free, but most users
|
||||
need not use this option.
|
||||
|
||||
.. index:: --enable-text-only
|
||||
|
||||
libxo provides the `--enable-text-only` option to reduce the
|
||||
footprint of the library for smaller installations. XML, JSON, and
|
||||
HTML rendering logic is removed.
|
||||
|
||||
.. index:: --with-gettext
|
||||
|
||||
The gettext library does not provide a simple means of learning its
|
||||
location, but libxo will look for it in /usr and /opt/local. If
|
||||
installed elsewhere, the installer will need to provide this
|
||||
information using the "`--with-gettext=/dir/path`" option.
|
||||
|
||||
.. index:: libslax
|
||||
|
||||
libslax is not required by libxo; it contains the "oxtradoc" program
|
||||
used to format documentation.
|
||||
|
||||
For additional information, see :ref:`building`.
|
||||
|
||||
Howto: Convert command line applications
|
||||
----------------------------------------
|
||||
|
||||
Common question: How do I convert an existing command line application?
|
||||
|
||||
There are four basic steps for converting command line application to
|
||||
use libxo::
|
||||
|
||||
- Setting up the context
|
||||
- Converting printf calls
|
||||
- Creating hierarchy
|
||||
- Converting error functions
|
||||
|
||||
Setting up the context
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To use libxo, you'll need to include the "xo.h" header file in your
|
||||
source code files::
|
||||
|
||||
#include <libxo/xo.h>
|
||||
|
||||
In your main() function, you'll need to call xo_parse_args to handling
|
||||
argument parsing (:ref:`xo_parse_args`). This function removes
|
||||
libxo-specific arguments the program's argv and returns either the
|
||||
number of remaining arguments or -1 to indicate an error::
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
argc = xo_parse_args(argc, argv);
|
||||
if (argc < 0)
|
||||
return argc;
|
||||
....
|
||||
}
|
||||
|
||||
.. index:: atexit
|
||||
.. index:: xo_finish_atexit
|
||||
|
||||
At the bottom of your main(), you'll need to call xo_finish() to
|
||||
complete output processing for the default handle (:ref:`handles`). This
|
||||
is required to flush internal information buffers. libxo provides the
|
||||
xo_finish_atexit function that is suitable for use with the
|
||||
:manpage:`atexit(3)` function::
|
||||
|
||||
atexit(xo_finish_atexit);
|
||||
|
||||
Converting printf Calls
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The second task is inspecting code for :manpage:`printf(3)` calls and
|
||||
replacing them with xo_emit() calls. The format strings are similar
|
||||
in task, but libxo format strings wrap output fields in braces. The
|
||||
following two calls produce identical text output::
|
||||
|
||||
OLD::
|
||||
printf("There are %d %s events\n", count, etype);
|
||||
|
||||
NEW::
|
||||
xo_emit("There are {:count/%d} {:event} events\n", count, etype);
|
||||
|
||||
"count" and "event" are used as names for JSON and XML output. The
|
||||
"count" field uses the format "%d" and "event" uses the default "%s"
|
||||
format. Both are "value" roles, which is the default role.
|
||||
|
||||
Since text outside of output fields is passed verbatim, other roles
|
||||
are less important, but their proper use can help make output more
|
||||
useful. The "note" and "label" roles allow HTML output to recognize
|
||||
the relationship between text and the associated values, allowing
|
||||
appropriate "hover" and "onclick" behavior. Using the "units" role
|
||||
allows the presentation layer to perform conversions when needed. The
|
||||
"warning" and "error" roles allows use of color and font to draw
|
||||
attention to warnings. The "padding" role makes the use of vital
|
||||
whitespace more clear (:ref:`padding-role`).
|
||||
|
||||
The "*title*" role indicates the headings of table and sections. This
|
||||
allows HTML output to use CSS to make this relationship more obvious::
|
||||
|
||||
OLD::
|
||||
printf("Statistics:\n");
|
||||
|
||||
NEW::
|
||||
xo_emit("{T:Statistics}:\n");
|
||||
|
||||
The "*color*" roles controls foreground and background colors, as well
|
||||
as effects like bold and underline (see :ref:`color-role`)::
|
||||
|
||||
NEW::
|
||||
xo_emit("{C:bold}required{C:}\n");
|
||||
|
||||
Finally, the start- and stop-anchor roles allow justification and
|
||||
padding over multiple fields (see :ref:`anchor-role`)::
|
||||
|
||||
OLD::
|
||||
snprintf(buf, sizeof(buf), "(%u/%u/%u)", min, ave, max);
|
||||
printf("%30s", buf);
|
||||
|
||||
NEW::
|
||||
xo_emit("{[:30}({:minimum/%u}/{:average/%u}/{:maximum/%u}{]:}",
|
||||
min, ave, max);
|
||||
|
||||
Creating Hierarchy
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Text output doesn't have any sort of hierarchy, but XML and JSON
|
||||
require this. Typically applications use indentation to represent
|
||||
these relationship::
|
||||
|
||||
OLD::
|
||||
printf("table %d\n", tnum);
|
||||
for (i = 0; i < tmax; i++) {
|
||||
printf(" %s %d\n", table[i].name, table[i].size);
|
||||
}
|
||||
|
||||
NEW::
|
||||
xo_emit("{T:/table %d}\n", tnum);
|
||||
xo_open_list("table");
|
||||
for (i = 0; i < tmax; i++) {
|
||||
xo_open_instance("table");
|
||||
xo_emit("{P: }{k:name} {:size/%d}\n",
|
||||
table[i].name, table[i].size);
|
||||
xo_close_instance("table");
|
||||
}
|
||||
xo_close_list("table");
|
||||
|
||||
The open and close list functions are used before and after the list,
|
||||
and the open and close instance functions are used before and after
|
||||
each instance with in the list.
|
||||
|
||||
Typically these developer looks for a "for" loop as an indication of
|
||||
where to put these calls.
|
||||
|
||||
In addition, the open and close container functions allow for
|
||||
organization levels of hierarchy::
|
||||
|
||||
OLD::
|
||||
printf("Paging information:\n");
|
||||
printf(" Free: %lu\n", free);
|
||||
printf(" Active: %lu\n", active);
|
||||
printf(" Inactive: %lu\n", inactive);
|
||||
|
||||
NEW::
|
||||
xo_open_container("paging-information");
|
||||
xo_emit("{P: }{L:Free: }{:free/%lu}\n", free);
|
||||
xo_emit("{P: }{L:Active: }{:active/%lu}\n", active);
|
||||
xo_emit("{P: }{L:Inactive: }{:inactive/%lu}\n", inactive);
|
||||
xo_close_container("paging-information");
|
||||
|
||||
Converting Error Functions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
libxo provides variants of the standard error and warning functions,
|
||||
:manpage:`err(3)` and :manpage:`warn(3)`. There are two variants, one
|
||||
for putting the errors on standard error, and the other writes the
|
||||
errors and warnings to the handle using the appropriate encoding
|
||||
style::
|
||||
|
||||
OLD::
|
||||
err(1, "cannot open output file: %s", file);
|
||||
|
||||
NEW::
|
||||
xo_err(1, "cannot open output file: %s", file);
|
||||
xo_emit_err(1, "cannot open output file: {:filename}", file);
|
||||
|
||||
.. index:: xo_finish
|
||||
|
||||
Call xo_finish
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
One important item: call `xo_finish` at the end of your program so
|
||||
ensure that all buffered data is written out. You can call it
|
||||
explicitly call it, or use :manpage:`atexit(3)` to have
|
||||
`xo_finish_atexit` called implicitly on exit::
|
||||
|
||||
OLD::
|
||||
exit(0);
|
||||
|
||||
NEW::
|
||||
xo_finish();
|
||||
exit(0);
|
||||
|
||||
Howto: Use "xo" in Shell Scripts
|
||||
--------------------------------
|
||||
|
||||
.. admonition:: Needed
|
||||
|
||||
Documentation is needed for this area.
|
||||
|
||||
.. index:: Internationalization (i18n)
|
||||
.. index:: gettext
|
||||
.. index:: xopo
|
||||
|
||||
.. _i18n:
|
||||
|
||||
Howto: Internationalization (i18n)
|
||||
-----------------------------------------------
|
||||
|
||||
How do I use libxo to support internationalization?
|
||||
|
||||
libxo allows format and field strings to be used a keys into message
|
||||
catalogs to enable translation into a user's native language by
|
||||
invoking the standard :manpage:`gettext(3)` functions.
|
||||
|
||||
gettext setup is a bit complicated: text strings are extracted from
|
||||
source files into "*portable object template*" (.pot) files using the
|
||||
`xgettext` command. For each language, this template file is used as
|
||||
the source for a message catalog in the "*portable object*" (.po)
|
||||
format, which are translated by hand and compiled into "*machine
|
||||
object*" (.mo) files using the `msgfmt` command. The .mo files are
|
||||
then typically installed in the /usr/share/locale or
|
||||
/opt/local/share/locale directories. At run time, the user's language
|
||||
settings are used to select a .mo file which is searched for matching
|
||||
messages. Text strings in the source code are used as keys to look up
|
||||
the native language strings in the .mo file.
|
||||
|
||||
Since the xo_emit format string is used as the key into the message
|
||||
catalog, libxo removes unimportant field formatting and modifiers from
|
||||
the format string before use so that minor formatting changes will not
|
||||
impact the expensive translation process. We don't want a developer
|
||||
change such as changing "/%06d" to "/%08d" to force hand inspection of
|
||||
all .po files. The simplified version can be generated for a single
|
||||
message using the `xopo -s $text` command, or an entire .pot can be
|
||||
translated using the `xopo -f $input -o $output` command::
|
||||
|
||||
EXAMPLE:
|
||||
% xopo -s "There are {:count/%u} {:event/%.6s} events\n"
|
||||
There are {:count} {:event} events\n
|
||||
|
||||
Recommended workflow:
|
||||
# Extract text messages
|
||||
xgettext --default-domain=foo --no-wrap \
|
||||
--add-comments --keyword=xo_emit --keyword=xo_emit_h \
|
||||
--keyword=xo_emit_warn -C -E -n --foreign-user \
|
||||
-o foo.pot.raw foo.c
|
||||
|
||||
# Simplify format strings for libxo
|
||||
xopo -f foo.pot.raw -o foo.pot
|
||||
|
||||
# For a new language, just copy the file
|
||||
cp foo.pot po/LC/my_lang/foo.po
|
||||
|
||||
# For an existing language:
|
||||
msgmerge --no-wrap po/LC/my_lang/foo.po \
|
||||
foo.pot -o po/LC/my_lang/foo.po.new
|
||||
|
||||
# Now the hard part: translate foo.po using tools
|
||||
# like poedit or emacs' po-mode
|
||||
|
||||
# Compile the finished file; Use of msgfmt's "-v" option is
|
||||
# strongly encouraged, so that "fuzzy" entries are reported.
|
||||
msgfmt -v -o po/my_lang/LC_MESSAGES/foo.mo po/my_lang/foo.po
|
||||
|
||||
# Install the .mo file
|
||||
sudo cp po/my_lang/LC_MESSAGES/foo.mo \
|
||||
/opt/local/share/locale/my_lang/LC_MESSAGE/
|
||||
|
||||
Once these steps are complete, you can use the `gettext` command to
|
||||
test the message catalog::
|
||||
|
||||
gettext -d foo -e "some text"
|
||||
|
||||
i18n and xo_emit
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
There are three features used in libxo used to support i18n:
|
||||
|
||||
- The "{G:}" role looks for a translation of the format string.
|
||||
- The "{g:}" modifier looks for a translation of the field.
|
||||
- The "{p:}" modifier looks for a pluralized version of the field.
|
||||
|
||||
Together these three flags allows a single function call to give
|
||||
native language support, as well as libxo's normal XML, JSON, and HTML
|
||||
support::
|
||||
|
||||
printf(gettext("Received %zu %s from {g:server} server\n"),
|
||||
counter, ngettext("byte", "bytes", counter),
|
||||
gettext("web"));
|
||||
|
||||
xo_emit("{G:}Received {:received/%zu} {Ngp:byte,bytes} "
|
||||
"from {g:server} server\n", counter, "web");
|
||||
|
||||
libxo will see the "{G:}" role and will first simplify the format
|
||||
string, removing field formats and modifiers::
|
||||
|
||||
"Received {:received} {N:byte,bytes} from {:server} server\n"
|
||||
|
||||
libxo calls :manpage:`gettext(3)` with that string to get a localized
|
||||
version. If your language were *Pig Latin*, the result might look
|
||||
like::
|
||||
|
||||
"Eceivedray {:received} {N:byte,bytes} omfray "
|
||||
"{:server} erversay\n"
|
||||
|
||||
Note the field names do not change and they should not be translated.
|
||||
The contents of the note ("byte,bytes") should also not be translated,
|
||||
since the "g" modifier will need the untranslated value as the key for
|
||||
the message catalog.
|
||||
|
||||
The field "{g:server}" requests the rendered value of the field be
|
||||
translated using :manpage:`gettext(3)`. In this example, "web" would
|
||||
be used.
|
||||
|
||||
The field "{Ngp:byte,bytes}" shows an example of plural form using the
|
||||
"{p:}" modifier with the "{g:}" modifier. The base singular and plural
|
||||
forms appear inside the field, separated by a comma. At run time,
|
||||
libxo uses the previous field's numeric value to decide which form to
|
||||
use by calling :manpage:`ngettext(3)`.
|
||||
|
||||
If a domain name is needed, it can be supplied as the content of the
|
||||
{G:} role. Domain names remain in use throughout the format string
|
||||
until cleared with another domain name::
|
||||
|
||||
printf(dgettext("dns", "Host %s not found: %d(%s)\n"),
|
||||
name, errno, dgettext("strerror", strerror(errno)));
|
||||
|
||||
xo_emit("{G:dns}Host {:hostname} not found: "
|
||||
"%d({G:strerror}{g:%m})\n", name, errno);
|
54
doc/index.rst
Normal file
54
doc/index.rst
Normal file
@ -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
|
||||
#
|
||||
|
||||
.. default-role:: code
|
||||
|
||||
libxo - A Library for Generating Text, XML, JSON, and HTML Output
|
||||
===================================================================
|
||||
|
||||
The libxo library allows an application to generate text, XML, JSON,
|
||||
and HTML output, suitable for both command line use and for web
|
||||
applications. The application decides at run time which output style
|
||||
should be produced. By using libxo, a single source code path can
|
||||
emit multiple styles of output using command line options to select
|
||||
the style, along with optional behaviors. libxo includes support for
|
||||
multiple output streams, pluralization, color, syslog,
|
||||
:manpage:`humanized(3)` output, internationalization, and UTF-8. The
|
||||
library aims to minimize the cost of migrating code to libxo.
|
||||
|
||||
libxo ships as part of FreeBSD.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
:caption: Documentation Contents:
|
||||
|
||||
intro
|
||||
getting
|
||||
formatting
|
||||
options
|
||||
format-strings
|
||||
field-roles
|
||||
field-modifiers
|
||||
field-formatting
|
||||
api
|
||||
encoders
|
||||
xo
|
||||
xolint
|
||||
xohtml
|
||||
xopo
|
||||
faq
|
||||
howto
|
||||
example
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`search`
|
90
doc/intro.rst
Normal file
90
doc/intro.rst
Normal file
@ -0,0 +1,90 @@
|
||||
|
||||
Introducing libxo
|
||||
=================
|
||||
|
||||
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 printf-like :ref:`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 (see
|
||||
:ref:`field-roles` for details). Modifiers change how the field is
|
||||
rendered in different output styles (see :ref:`field-modifiers` for
|
||||
details. 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
|
||||
<wc>
|
||||
<file>
|
||||
<lines>25</lines>
|
||||
<words>165</words>
|
||||
<characters>1140</characters>
|
||||
<filename>/etc/motd</filename>
|
||||
</file>
|
||||
</wc>
|
||||
% 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
|
||||
<div class="line">
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="lines"> 25</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="words"> 165</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="characters"> 1140</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="filename">/etc/motd</div>
|
||||
</div>
|
||||
|
||||
Same code path, same format strings, same information, but it's
|
||||
rendered in distinct styles based on run-time flags.
|
||||
|
||||
.. admonition:: Tale of Two Code Paths
|
||||
|
||||
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 work done 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 */
|
||||
if (xml) {
|
||||
/* some code to make xml */
|
||||
} else {
|
||||
/* other code to make text */
|
||||
/* oops! forgot to add something on both clauses! */
|
||||
}
|
||||
|
||||
/* And ifdefs are right out. */
|
||||
#ifdef MAKE_XML
|
||||
/* icky */
|
||||
#else
|
||||
/* pooh */
|
||||
#endif
|
||||
|
||||
But you'd really, really like all the fancy features that modern
|
||||
encoding formats can provide. libxo can help.
|
184
doc/options.rst
Normal file
184
doc/options.rst
Normal file
@ -0,0 +1,184 @@
|
||||
|
||||
.. index:: --libxo
|
||||
.. index:: Options
|
||||
|
||||
.. _options:
|
||||
|
||||
Command-line Arguments
|
||||
======================
|
||||
|
||||
libxo uses command line options to trigger rendering behavior. There
|
||||
are multiple conventions for passing options, all using the
|
||||
"`--libxo`" option::
|
||||
|
||||
--libxo <options>
|
||||
--libxo=<options>
|
||||
--libxo:<brief-options>
|
||||
|
||||
The *brief-options* is a series of single letter abbrevations, where
|
||||
the *options* is a comma-separated list of words. Both provide access
|
||||
to identical functionality. The following invocations are all
|
||||
identical in outcome::
|
||||
|
||||
my-app --libxo warn,pretty arg1
|
||||
my-app --libxo=warn,pretty arg1
|
||||
my-app --libxo:WP arg1
|
||||
|
||||
Programs using libxo are expecting to call the xo_parse_args function
|
||||
to parse these arguments. See :ref:`xo_parse_args` for details.
|
||||
|
||||
Option Keywords
|
||||
---------------
|
||||
|
||||
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)
|
||||
colors=xxxx Adjust color output values
|
||||
dtrt Enable "Do The Right Thing" mode
|
||||
flush Flush after every libxo function call
|
||||
flush-line Flush after every line (line-buffered)
|
||||
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-retain Prevent retaining formatting information
|
||||
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
|
||||
retain Force retaining formatting information
|
||||
text Emit TEXT output
|
||||
underscores Replace XML-friendly "-"s with JSON friendly "_"s
|
||||
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)
|
||||
=============== =======================================================
|
||||
|
||||
Most of these option are simple and direct, but some require
|
||||
additional details:
|
||||
|
||||
- "colors" is described in :ref:`color-mapping`.
|
||||
- "flush-line" performs line buffering, even when the output is not
|
||||
directed to a TTY device.
|
||||
- "info" generates additional data for HTML, encoded in attributes
|
||||
using names that state with "data-".
|
||||
- "keys" adds a "key" attribute for XML output to indicate that a leaf
|
||||
is an identifier for the list member.
|
||||
- "no-humanize" avoids "humanizing" numeric output (see
|
||||
:ref:`humanize-modifier` for details).
|
||||
- "no-locale" instructs libxo to avoid translating output to the
|
||||
current locale.
|
||||
- "no-retain" disables the ability of libxo to internally retain
|
||||
"compiled" information about formatting strings (see :ref:`retain`
|
||||
for details).
|
||||
- "underscores" can be used with JSON output to change XML-friendly
|
||||
names with dashes into JSON-friendly name with underscores.
|
||||
- "warn" allows libxo to emit warnings on stderr when application code
|
||||
make incorrect calls.
|
||||
- "warn-xml" causes those warnings to be placed in XML inside the
|
||||
output.
|
||||
|
||||
Brief Options
|
||||
-------------
|
||||
|
||||
The brief options are simple single-letter aliases to the normal
|
||||
keywords, as detailed below:
|
||||
|
||||
======== =============================================
|
||||
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<num> Indent by <number>
|
||||
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)
|
||||
======== =============================================
|
||||
|
||||
.. index:: Colors
|
||||
|
||||
.. _color-mapping:
|
||||
|
||||
Color Mapping
|
||||
-------------
|
||||
|
||||
The "colors" option takes a value that is a set of mappings from the
|
||||
pre-defined set of colors to new foreground and background colors.
|
||||
The value is a series of "fg/bg" values, separated by a "+". Each
|
||||
pair of "fg/bg" values gives the colors to which a basic color is
|
||||
mapped when used as a foreground or background color. The order is
|
||||
the mappings is:
|
||||
|
||||
- black
|
||||
- red
|
||||
- green
|
||||
- yellow
|
||||
- blue
|
||||
- magenta
|
||||
- cyan
|
||||
- white
|
||||
|
||||
Pairs may be skipped, leaving them mapped as normal, as are missing
|
||||
pairs or single colors.
|
||||
|
||||
For example consider the following xo_emit call::
|
||||
|
||||
xo_emit("{C:fg-red,bg-green}Merry XMas!!{C:}\n");
|
||||
|
||||
To turn all colored output to red-on-blue, use eight pairs of
|
||||
"red/blue" mappings separated by plus signs ("+")::
|
||||
|
||||
--libxo colors=red/blue+red/blue+red/blue+red/blue+\
|
||||
red/blue+red/blue+red/blue+red/blue
|
||||
|
||||
To turn the red-on-green text to magenta-on-cyan, give a "magenta"
|
||||
foreground value for red (the second mapping) and a "cyan" background
|
||||
to green (the third mapping)::
|
||||
|
||||
--libxo colors=+magenta+/cyan
|
||||
|
||||
Consider the common situation where blue output looks unreadable on a
|
||||
terminal session with a black background. To turn both "blue"
|
||||
foreground and background output to "yellow", give only the fifth
|
||||
mapping, skipping the first four mappings with bare plus signs ("+")::
|
||||
|
||||
--libxo colors=++++yellow/yellow
|
||||
|
||||
Encoders
|
||||
--------
|
||||
|
||||
In addition to the four "built-in" formats, libxo supports an
|
||||
extensible mechanism for adding encoders. These are activated
|
||||
using the "encoder" keyword::
|
||||
|
||||
--libxo encoder=cbor
|
||||
|
||||
The encoder can include encoder-specific options, separated by either
|
||||
colons (":") or plus signs ("+"):
|
||||
|
||||
--libxo encoder=csv+path=filesystem+leaf=name+no-header
|
||||
--libxo encoder=csv:path=filesystem:leaf=name:no-header
|
||||
|
||||
For brevity, the string "@" can be used in place of the string
|
||||
"encoder=".
|
||||
|
||||
df --libxo @csv:no-header
|
234
doc/xo.rst
Normal file
234
doc/xo.rst
Normal file
@ -0,0 +1,234 @@
|
||||
.. index:: --libxo, xo
|
||||
.. _xo:
|
||||
|
||||
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 <style>" option can also be used. The standard
|
||||
set of "--libxo" options are available (see :ref:`options`), as well
|
||||
as the :ref:`LIBXO_OPTIONS <libxo-options>` environment variable.
|
||||
|
||||
The `xo` utility accepts a format string suitable for `xo_emit` and
|
||||
a set of zero or more arguments used to supply data for that string::
|
||||
|
||||
xo "The {k:name} weighs {:weight/%d} pounds.\n" fish 6
|
||||
|
||||
TEXT:
|
||||
The fish weighs 6 pounds.
|
||||
|
||||
XML:
|
||||
<name>fish</name>
|
||||
<weight>6</weight>
|
||||
|
||||
JSON:
|
||||
"name": "fish",
|
||||
"weight": 6
|
||||
|
||||
HTML:
|
||||
<div class="line">
|
||||
<div class="text">The </div>
|
||||
<div class="data" data-tag="name">fish</div>
|
||||
<div class="text"> weighs </div>
|
||||
<div class="data" data-tag="weight">6</div>
|
||||
<div class="text"> pounds.</div>
|
||||
</div>
|
||||
|
||||
The `--wrap $path` option can be used to wrap emitted content in a
|
||||
specific hierarchy. The path is a set of hierarchical names separated
|
||||
by the '/' character::
|
||||
|
||||
xo --wrap top/a/b/c '{:tag}' value
|
||||
|
||||
XML:
|
||||
<top>
|
||||
<a>
|
||||
<b>
|
||||
<c>
|
||||
<tag>value</tag>
|
||||
</c>
|
||||
</b>
|
||||
</a>
|
||||
</top>
|
||||
|
||||
JSON:
|
||||
"top": {
|
||||
"a": {
|
||||
"b": {
|
||||
"c": {
|
||||
"tag": "value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
The `--open $path` and `--close $path` can be used to emit
|
||||
hierarchical information without the matching close and open
|
||||
tag. This allows a shell script to emit open tags, data, and
|
||||
then close tags. The `--depth` option may be used to set the
|
||||
depth for indentation. The `--leading-xpath` may be used to
|
||||
prepend data to the XPath values used for HTML output style::
|
||||
|
||||
EXAMPLE:
|
||||
#!/bin/sh
|
||||
xo --open top/data
|
||||
xo --depth 2 '{:tag}' value
|
||||
xo --close top/data
|
||||
|
||||
XML:
|
||||
<top>
|
||||
<data>
|
||||
<tag>value</tag>
|
||||
</data>
|
||||
</top>
|
||||
|
||||
JSON:
|
||||
"top": {
|
||||
"data": {
|
||||
"tag": "value"
|
||||
}
|
||||
}
|
||||
|
||||
When making partial lines of output (where the format string does not
|
||||
include a newline), use the `--continuation` option to let secondary
|
||||
invocations know they are adding data to an existing line.
|
||||
|
||||
When emitting a series of objects, use the `--not-first` option to
|
||||
ensure that any details from the previous object (e.g. commas in JSON)
|
||||
are handled correctly.
|
||||
|
||||
Use the `--top-wrap` option to ensure any top-level object details are
|
||||
handled correctly, e.g. wrap the entire output in a top-level set of
|
||||
braces for JSON output.
|
||||
|
||||
::
|
||||
|
||||
EXAMPLE:
|
||||
#!/bin/sh
|
||||
xo --top-wrap --open top/data
|
||||
xo --depth 2 'First {:tag} ' value1
|
||||
xo --depth 2 --continuation 'and then {:tag}\n' value2
|
||||
xo --top-wrap --close top/data
|
||||
|
||||
TEXT:
|
||||
First value1 and then value2
|
||||
|
||||
HTML:
|
||||
<div class="line">
|
||||
<div class="text">First </div>
|
||||
<div class="data" data-tag="tag">value1</div>
|
||||
<div class="text"> </div>
|
||||
<div class="text">and then </div>
|
||||
<div class="data" data-tag="tag">value2</div>
|
||||
</div>
|
||||
|
||||
XML:
|
||||
<top>
|
||||
<data>
|
||||
<tag>value1</tag>
|
||||
<tag>value2</tag>
|
||||
</data>
|
||||
</top>
|
||||
|
||||
JSON:
|
||||
{
|
||||
"top": {
|
||||
"data": {
|
||||
"tag": "value1",
|
||||
"tag": "value2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
Use the `--open-list` and `--open-instances` to open lists and
|
||||
instances. Use the `--close-list` and `--close-instances` to close
|
||||
them. Each of these options take a `name` parameter, providing the
|
||||
name of the list and instance.
|
||||
|
||||
In the following example, a list named "machine" is created with three
|
||||
instances::
|
||||
|
||||
opts="--json"
|
||||
xo $opts --open-list machine
|
||||
NF=
|
||||
for name in red green blue; do
|
||||
xo $opts --depth 1 $NF --open-instance machine
|
||||
xo $opts --depth 2 "Machine {k:name} has {:memory}\n" $name 55
|
||||
xo $opts --depth 1 --close-instance machine
|
||||
NF=--not-first
|
||||
done
|
||||
xo $opts $NF --close-list machine
|
||||
|
||||
The normal `libxo` functions use a state machine to help these
|
||||
transitions, but since each `xo` command is invoked independent of the
|
||||
previous calls, the state must be passed in explicitly via these
|
||||
command line options.
|
||||
|
||||
The `--instance` option can be used to treat a single `xo` invocation
|
||||
as an instance with the given set of fields::
|
||||
|
||||
% xo --libxo:XP --instance foo 'The {:product} is {:status}\n' stereo "in route"
|
||||
<foo>
|
||||
<product>stereo</product>
|
||||
<status>in route</status>
|
||||
</foo>
|
||||
|
||||
Command Line Options
|
||||
--------------------
|
||||
|
||||
::
|
||||
|
||||
Usage: xo [options] format [fields]
|
||||
--close <path> Close tags for the given path
|
||||
--close-instance <name> Close an open instance name
|
||||
--close-list <name> Close an open list name
|
||||
--continuation OR -C Output belongs on same line as previous output
|
||||
--depth <num> Set the depth for pretty printing
|
||||
--help Display this help text
|
||||
--html OR -H Generate HTML output
|
||||
--instance OR -I <name> Wrap in an instance of the given name
|
||||
--json OR -J Generate JSON output
|
||||
--leading-xpath <path> Add a prefix to generated XPaths (HTML)
|
||||
--not-first Indicate this object is not the first (JSON)
|
||||
--open <path> Open tags for the given path
|
||||
--open-instance <name> Open an instance given by name
|
||||
--open-list <name> Open a list given by name
|
||||
--option <opts> -or -O <opts> Give formatting options
|
||||
--pretty OR -p Make 'pretty' output (add indent, newlines)
|
||||
--style <style> Generate given style (xml, json, text, html)
|
||||
--text OR -T Generate text output (the default style)
|
||||
--top-wrap Generate a top-level object wrapper (JSON)
|
||||
--version Display version information
|
||||
--warn OR -W Display warnings in text on stderr
|
||||
--warn-xml Display warnings in xml on stdout
|
||||
--wrap <path> Wrap output in a set of containers
|
||||
--xml OR -X Generate XML output
|
||||
--xpath Add XPath data to HTML output)
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
::
|
||||
|
||||
% xo 'The {:product} is {:status}\n' stereo "in route"
|
||||
The stereo is in route
|
||||
% xo -p -X 'The {:product} is {:status}\n' stereo "in route"
|
||||
<product>stereo</product>
|
||||
<status>in route</status>
|
||||
% xo --libxo xml,pretty 'The {:product} is {:status}\n' stereo "in route"
|
||||
<product>stereo</product>
|
||||
<status>in route</status>
|
30
doc/xohtml.rst
Normal file
30
doc/xohtml.rst
Normal file
@ -0,0 +1,30 @@
|
||||
.. index:: xohtml
|
||||
|
||||
.. _xohtml:
|
||||
|
||||
xohtml
|
||||
======
|
||||
|
||||
`xohtml` is a tool for turning the output of libxo-enabled commands into
|
||||
html files suitable for display in modern HTML web browsers. It can
|
||||
be used to test and debug HTML output, as well as to make the user
|
||||
ache to escape the world of '70s terminal devices.
|
||||
|
||||
`xohtml` is given a command, either on the command line or via the "-c"
|
||||
option. If not command is given, standard input is used. The
|
||||
command's output is wrapped in HTML tags, with references to
|
||||
supporting CSS and Javascript files, and written to standard output or
|
||||
the file given in the "-f" option. The "-b" option can be used to
|
||||
provide an alternative base path for the support files:
|
||||
|
||||
============== ===================================================
|
||||
Option Meaning
|
||||
============== ===================================================
|
||||
-b <base> Base path for finding css/javascript files
|
||||
-c <command> Command to execute
|
||||
-f <file> Output file name
|
||||
============== ===================================================
|
||||
|
||||
The "-c" option takes a full command with arguments, including
|
||||
any libxo options needed to generate html (`--libxo=html`). This
|
||||
value must be quoted if it consists of multiple tokens.
|
444
doc/xolint-errors.rst
Normal file
444
doc/xolint-errors.rst
Normal file
@ -0,0 +1,444 @@
|
||||
'A percent sign appearing in text is a literal'
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "A percent sign appearing in text is a literal" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("cost: %d", cost);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{L:cost}: {:cost/%d}", cost);
|
||||
|
||||
This can be a bit surprising and could be a field that was not
|
||||
properly converted to a libxo-style format string.
|
||||
|
||||
|
||||
'Unknown long name for role/modifier'
|
||||
+++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Unknown long name for role/modifier" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{,humanization:value}", value);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{,humanize:value}", value);
|
||||
|
||||
The hn-* modifiers (hn-decimal, hn-space, hn-1000)
|
||||
are only valid for fields with the {h:} modifier.
|
||||
|
||||
|
||||
'Last character before field definition is a field type'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Last character before field definition is a field type" can be caused by code like:
|
||||
A common typo:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{T:Min} T{:Max}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{T:Min} {T:Max}");
|
||||
|
||||
Twiddling the "{" and the field role is a common typo.
|
||||
|
||||
|
||||
'Encoding format uses different number of arguments'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Encoding format uses different number of arguments" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:name/%6.6s %%04d/%s}", name, number);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:name/%6.6s %04d/%s-%d}", name, number);
|
||||
|
||||
Both format should consume the same number of arguments off the stack
|
||||
|
||||
|
||||
'Only one field role can be used'
|
||||
+++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Only one field role can be used" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{LT:Max}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{T:Max}");
|
||||
|
||||
'Potential missing slash after C, D, N, L, or T with format'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Potential missing slash after C, D, N, L, or T with format" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{T:%6.6s}\n", "Max");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{T:/%6.6s}\n", "Max");
|
||||
|
||||
The "%6.6s" will be a literal, not a field format. While
|
||||
it's possibly valid, it's likely a missing "/".
|
||||
|
||||
|
||||
'An encoding format cannot be given (roles: DNLT)'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "An encoding format cannot be given (roles: DNLT)" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{T:Max//%s}", "Max");
|
||||
|
||||
Fields with the C, D, N, L, and T roles are not emitted in
|
||||
the 'encoding' style (JSON, XML), so an encoding format
|
||||
would make no sense.
|
||||
|
||||
|
||||
'Format cannot be given when content is present (roles: CDLN)'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Format cannot be given when content is present (roles: CDLN)" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{N:Max/%6.6s}", "Max");
|
||||
|
||||
Fields with the C, D, L, or N roles can't have both
|
||||
static literal content ("{L:Label}") and a
|
||||
format ("{L:/%s}").
|
||||
This error will also occur when the content has a backslash
|
||||
in it, like "{N:Type of I/O}"; backslashes should be escaped,
|
||||
like "{N:Type of I\\/O}". Note the double backslash, one for
|
||||
handling 'C' strings, and one for libxo.
|
||||
|
||||
|
||||
'Field has color without fg- or bg- (role: C)'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Field has color without fg- or bg- (role: C)" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{C:green}{:foo}{C:}", x);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{C:fg-green}{:foo}{C:}", x);
|
||||
|
||||
Colors must be prefixed by either "fg-" or "bg-".
|
||||
|
||||
|
||||
'Field has invalid color or effect (role: C)'
|
||||
+++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Field has invalid color or effect (role: C)" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{C:fg-purple,bold}{:foo}{C:gween}", x);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{C:fg-red,bold}{:foo}{C:fg-green}", x);
|
||||
|
||||
The list of colors and effects are limited. The
|
||||
set of colors includes default, black, red, green,
|
||||
yellow, blue, magenta, cyan, and white, which must
|
||||
be prefixed by either "fg-" or "bg-". Effects are
|
||||
limited to bold, no-bold, underline, no-underline,
|
||||
inverse, no-inverse, normal, and reset. Values must
|
||||
be separated by commas.
|
||||
|
||||
|
||||
'Field has humanize modifier but no format string'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Field has humanize modifier but no format string" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{h:value}", value);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{h:value/%d}", value);
|
||||
|
||||
Humanization is only value for numbers, which are not
|
||||
likely to use the default format ("%s").
|
||||
|
||||
|
||||
'Field has hn-* modifier but not 'h' modifier'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Field has hn-* modifier but not 'h' modifier" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{,hn-1000:value}", value);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{h,hn-1000:value}", value);
|
||||
|
||||
The hn-* modifiers (hn-decimal, hn-space, hn-1000)
|
||||
are only valid for fields with the {h:} modifier.
|
||||
|
||||
|
||||
'Value field must have a name (as content)")'
|
||||
+++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Value field must have a name (as content)")" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:/%s}", "value");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:tag-name/%s}", "value");
|
||||
|
||||
The field name is used for XML and JSON encodings. These
|
||||
tags names are static and must appear directly in the
|
||||
field descriptor.
|
||||
|
||||
|
||||
'Use hyphens, not underscores, for value field name'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Use hyphens, not underscores, for value field name" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:no_under_scores}", "bad");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:no-under-scores}", "bad");
|
||||
|
||||
Use of hyphens is traditional in XML, and the XOF_UNDERSCORES
|
||||
flag can be used to generate underscores in JSON, if desired.
|
||||
But the raw field name should use hyphens.
|
||||
|
||||
|
||||
'Value field name cannot start with digit'
|
||||
++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Value field name cannot start with digit" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:10-gig/}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:ten-gig/}");
|
||||
|
||||
XML element names cannot start with a digit.
|
||||
|
||||
|
||||
'Value field name should be lower case'
|
||||
+++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Value field name should be lower case" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:WHY-ARE-YOU-SHOUTING}", "NO REASON");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:why-are-you-shouting}", "no reason");
|
||||
|
||||
Lower case is more civilized. Even TLAs should be lower case
|
||||
to avoid scenarios where the differences between "XPath" and
|
||||
"Xpath" drive your users crazy. Lower case rules the seas.
|
||||
|
||||
|
||||
'Value field name should be longer than two characters'
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Value field name should be longer than two characters" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:x}", "mumble");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:something-meaningful}", "mumble");
|
||||
|
||||
Field names should be descriptive, and it's hard to
|
||||
be descriptive in less than two characters. Consider
|
||||
your users and try to make something more useful.
|
||||
Note that this error often occurs when the field type
|
||||
is placed after the colon ("{:T/%20s}"), instead of before
|
||||
it ("{T:/20s}").
|
||||
|
||||
|
||||
'Value field name contains invalid character'
|
||||
+++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Value field name contains invalid character" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:cost-in-$$/%u}", 15);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:cost-in-dollars/%u}", 15);
|
||||
|
||||
An invalid character is often a sign of a typo, like "{:]}"
|
||||
instead of "{]:}". Field names are restricted to lower-case
|
||||
characters, digits, and hyphens.
|
||||
|
||||
|
||||
'decoration field contains invalid character'
|
||||
+++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "decoration field contains invalid character" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{D:not good}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{D:((}{:good}{D:))}", "yes");
|
||||
|
||||
This is minor, but fields should use proper roles. Decoration
|
||||
fields are meant to hold punctuation and other characters used
|
||||
to decorate the content, typically to make it more readable
|
||||
to human readers.
|
||||
|
||||
|
||||
'Anchor content should be decimal width'
|
||||
++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Anchor content should be decimal width" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{[:mumble}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{[:32}");
|
||||
|
||||
Anchors need an integer value to specify the width of
|
||||
the set of anchored fields. The value can be positive
|
||||
(for left padding/right justification) or negative (for
|
||||
right padding/left justification) and can appear in
|
||||
either the start or stop anchor field descriptor.
|
||||
|
||||
|
||||
'Anchor format should be "%d"'
|
||||
++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Anchor format should be "%d"" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{[:/%s}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{[:/%d}");
|
||||
|
||||
Anchors only grok integer values, and if the value is not static,
|
||||
if must be in an 'int' argument, represented by the "%d" format.
|
||||
Anything else is an error.
|
||||
|
||||
|
||||
'Anchor cannot have both format and encoding format")'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Anchor cannot have both format and encoding format")" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{[:32/%d}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{[:32}");
|
||||
|
||||
Anchors can have a static value or argument for the width,
|
||||
but cannot have both.
|
||||
|
||||
|
||||
'Max width only valid for strings'
|
||||
++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Max width only valid for strings" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:tag/%2.4.6d}", 55);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:tag/%2.6d}", 55);
|
||||
|
||||
libxo allows a true 'max width' in addition to the traditional
|
||||
printf-style 'max number of bytes to use for input'. But this
|
||||
is supported only for string values, since it makes no sense
|
||||
for non-strings. This error may occur from a typo,
|
||||
like "{:tag/%6..6d}" where only one period should be used.
|
40
doc/xolint.rst
Normal file
40
doc/xolint.rst
Normal file
@ -0,0 +1,40 @@
|
||||
======
|
||||
xolint
|
||||
======
|
||||
|
||||
`xolint` is a tool for reporting common mistakes in format strings
|
||||
in source code that invokes `xo_emit`. It allows these errors
|
||||
to be diagnosed at build time, rather than waiting until runtime.
|
||||
|
||||
`xolint` takes the one or more C files as arguments, and reports
|
||||
and errors, warning, or informational messages as needed:
|
||||
|
||||
============ ===================================================
|
||||
Option Meaning
|
||||
============ ===================================================
|
||||
-c Invoke 'cpp' against the input file
|
||||
-C <flags> Flags that are passed to 'cpp
|
||||
-d Enable debug output
|
||||
-D Generate documentation for all xolint messages
|
||||
-I Generate info table code
|
||||
-p Print the offending lines after the message
|
||||
-V Print vocabulary of all field names
|
||||
-X Extract samples from xolint, suitable for testing
|
||||
============ ===================================================
|
||||
|
||||
The output message will contain the source filename and line number, the
|
||||
class of the message, the message, and, if -p is given, the
|
||||
line that contains the error::
|
||||
|
||||
% xolint.pl -t xolint.c
|
||||
xolint.c: 16: error: anchor format should be "%d"
|
||||
16 xo_emit("{[:/%s}");
|
||||
|
||||
The "-I" option will generate a table of `xo_info_t`_ structures,
|
||||
suitable for inclusion in source code.
|
||||
|
||||
.. _xo_info_t: :ref:`field-information`
|
||||
|
||||
The "-V" option does not report errors, but prints a complete list of
|
||||
all field names, sorted alphabetically. The output can help spot
|
||||
inconsistencies and spelling errors.
|
45
doc/xopo.rst
Normal file
45
doc/xopo.rst
Normal file
@ -0,0 +1,45 @@
|
||||
|
||||
xopo
|
||||
====
|
||||
|
||||
The `xopo` utility filters ".pot" files generated by the
|
||||
:manpage:`xgettext(1)` utility to remove formatting information
|
||||
suitable for use with the "{G:}" modifier. This means that when the
|
||||
developer changes the formatting portion of the field definitions, or
|
||||
the fields modifiers, the string passed to :manpage:`gettext(3)` is
|
||||
unchanged, avoiding the expense of updating any existing translation
|
||||
files (".po" files).
|
||||
|
||||
The syntax for the xopo command is one of two forms; it can be used as
|
||||
a filter for processing a .po or .pot file, rewriting the "*msgid*"
|
||||
strings with a simplified message string. In this mode, the input is
|
||||
either standard input or a file given by the "-f" option, and the
|
||||
output is either standard output or a file given by the "-o" option.
|
||||
|
||||
In the second mode, a simple message given using the "-s" option on
|
||||
the command, and the simplified version of that message is printed on
|
||||
stdout:
|
||||
|
||||
=========== =================================
|
||||
Option Meaning
|
||||
=========== =================================
|
||||
-o <file> Output file name
|
||||
-f <file> Use the given .po file as input
|
||||
-s <text> Simplify a format string
|
||||
=========== =================================
|
||||
|
||||
::
|
||||
|
||||
EXAMPLE:
|
||||
% xopo -s "There are {:count/%u} {:event/%.6s} events\n"
|
||||
There are {:count} {:event} events\n
|
||||
|
||||
% xgettext --default-domain=foo --no-wrap \
|
||||
--add-comments --keyword=xo_emit --keyword=xo_emit_h \
|
||||
--keyword=xo_emit_warn -C -E -n --foreign-user \
|
||||
-o foo.pot.raw foo.c
|
||||
% xopo -f foo.pot.raw -o foo.pot
|
||||
|
||||
Use of the `--no-wrap` option for `xgettext` is required to
|
||||
ensure that incoming msgid strings are not wrapped across multiple
|
||||
lines.
|
@ -14,8 +14,6 @@
|
||||
static int
|
||||
test_handler (XO_ENCODER_HANDLER_ARGS)
|
||||
{
|
||||
flags &= ~XOF_UTF8; /* Skip this flag, since it depends on terminal */
|
||||
|
||||
printf("op %s: [%s] [%s] [%#llx]\n", xo_encoder_op_name(op),
|
||||
name ?: "", value ?: "", (unsigned long long) flags);
|
||||
|
||||
|
@ -22,8 +22,7 @@ AM_CFLAGS = \
|
||||
${GETTEXT_CFLAGS}
|
||||
|
||||
AM_CFLAGS += \
|
||||
-DXO_ENCODERDIR=\"${XO_ENCODERDIR}\" \
|
||||
-DXO_SHAREDIR=\"${XO_SHAREDIR}\"
|
||||
-DXO_ENCODERDIR=\"${XO_ENCODERDIR}\"
|
||||
|
||||
lib_LTLIBRARIES = libxo.la
|
||||
|
||||
|
76
libxo/gen-wide.sh
Normal file
76
libxo/gen-wide.sh
Normal file
@ -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
|
||||
"
|
@ -139,8 +139,7 @@ used with
|
||||
.Nm xo ,
|
||||
the `--instance` option will be needed:
|
||||
.Bd -literal -offset indent
|
||||
% xo --libxo encoder=csv --instance foo \\
|
||||
'The {:product} is {:status}\\n' stereo "in route"
|
||||
% xo --libxo encoder=csv --instance foo 'The {:product} is {:status}\n' stereo "in route"
|
||||
product,status
|
||||
stereo,in route
|
||||
.Ed
|
||||
|
514
libxo/libxo.c
514
libxo/libxo.c
@ -42,7 +42,6 @@
|
||||
#include <ctype.h>
|
||||
#include <wctype.h>
|
||||
#include <getopt.h>
|
||||
#include <langinfo.h>
|
||||
|
||||
#include "xo_config.h"
|
||||
#include "xo.h"
|
||||
@ -97,10 +96,6 @@
|
||||
#include <libintl.h>
|
||||
#endif /* HAVE_GETTEXT */
|
||||
|
||||
#if HAVE_ETEXT == 1 /* Symbol */
|
||||
extern char etext;
|
||||
#endif /* HAVE_ETEXT */
|
||||
|
||||
/* Rather lame that we can't count on these... */
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
@ -141,17 +136,6 @@ static const char xo_default_format[] = "%s";
|
||||
#define UNUSED __attribute__ ((__unused__))
|
||||
#endif /* UNUSED */
|
||||
|
||||
#ifndef LIBXO_TEXT_ONLY
|
||||
/* We don't want the overhead of tag maps when in text-only mode */
|
||||
#define LIBXO_NEED_MAP
|
||||
|
||||
#define XO_MAP_INCR 128 /* Must be even */
|
||||
|
||||
#ifndef XO_MAPDIR
|
||||
#define XO_MAPDIR XO_SHAREDIR "/map"
|
||||
#endif /* XO_MAPDIR */
|
||||
#endif /* LIBXO_TEXT_ONLY */
|
||||
|
||||
#define XO_INDENT_BY 2 /* Amount to indent when pretty printing */
|
||||
#define XO_DEPTH 128 /* Default stack depth */
|
||||
#define XO_MAX_ANCHOR_WIDTH (8*1024) /* Anything wider is just silly */
|
||||
@ -284,12 +268,6 @@ struct xo_handle_s {
|
||||
char *xo_gt_domain; /* Gettext domain, suitable for dgettext(3) */
|
||||
xo_encoder_func_t xo_encoder; /* Encoding function */
|
||||
void *xo_private; /* Private data for external encoders */
|
||||
#ifdef LIBXO_NEED_MAP
|
||||
char **xo_map; /* Name mapping array */
|
||||
int xo_map_size; /* Size (count) of xo_map[] */
|
||||
int xo_map_len; /* Current length (count) of xo_map[] */
|
||||
xo_buffer_t xo_map_data; /* Data values for name mapping */
|
||||
#endif /* LIBXO_NEED_MAP */
|
||||
};
|
||||
|
||||
/* Flag operations */
|
||||
@ -415,7 +393,6 @@ static THREAD_LOCAL(xo_handle_t) xo_default_handle;
|
||||
static THREAD_LOCAL(int) xo_default_inited;
|
||||
static int xo_locale_inited;
|
||||
static const char *xo_program;
|
||||
static int xo_codeset_is_utf8; /* Is stdout UTF-8? */
|
||||
|
||||
/*
|
||||
* To allow libxo to be used in diverse environment, we allow the
|
||||
@ -445,9 +422,6 @@ xo_buf_append_div (xo_handle_t *xop, const char *class, xo_xff_flags_t flags,
|
||||
static void
|
||||
xo_anchor_clear (xo_handle_t *xop);
|
||||
|
||||
static int
|
||||
xo_map_option (xo_handle_t *xop, const char *opts);
|
||||
|
||||
/*
|
||||
* xo_style is used to retrieve the current style. When we're built
|
||||
* for "text only" mode, we use this function to drive the removal
|
||||
@ -551,18 +525,6 @@ xo_printable (const char *str)
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xo_str_is_const (const char *str UNUSED)
|
||||
{
|
||||
#if HAVE_ETEXT == 1
|
||||
const char *xo_etext = (const char *) &etext;
|
||||
|
||||
return (str < xo_etext);
|
||||
#else /* HAVE_ETEXT */
|
||||
return FALSE;
|
||||
#endif /* HAVE_ETEXT */
|
||||
}
|
||||
|
||||
static int
|
||||
xo_depth_check (xo_handle_t *xop, int depth)
|
||||
{
|
||||
@ -602,7 +564,7 @@ xo_no_setlocale (void)
|
||||
static const char *
|
||||
xo_xml_leader_len (xo_handle_t *xop, const char *name, xo_ssize_t nlen)
|
||||
{
|
||||
if (name == NULL || name[0] == '\0' || isalpha(name[0]) || name[0] == '_')
|
||||
if (name == NULL || isalpha(name[0]) || name[0] == '_')
|
||||
return "";
|
||||
|
||||
xo_failure(xop, "invalid XML tag name: '%.*s'", nlen, name);
|
||||
@ -675,13 +637,6 @@ xo_init_handle (xo_handle_t *xop)
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
(void) setlocale(LC_CTYPE, cp);
|
||||
|
||||
#ifdef CODESET
|
||||
/* Now that locale is set, determine if our stdout output is UTF-8 */
|
||||
const char *codeset = nl_langinfo(CODESET);
|
||||
if (codeset && xo_streq(codeset, "UTF-8"))
|
||||
xo_codeset_is_utf8 = TRUE;
|
||||
#endif /* CODESET */
|
||||
}
|
||||
|
||||
/*
|
||||
@ -711,9 +666,6 @@ xo_default_init (void)
|
||||
|
||||
xo_init_handle(xop);
|
||||
|
||||
if (xo_codeset_is_utf8)
|
||||
XOF_SET(xop, XOF_UTF8);
|
||||
|
||||
#if !defined(NO_LIBXO_OPTIONS)
|
||||
if (!XOF_ISSET(xop, XOF_NO_ENV)) {
|
||||
char *env = getenv("LIBXO_OPTIONS");
|
||||
@ -727,20 +679,6 @@ xo_default_init (void)
|
||||
xo_default_inited = 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Is the output for this handle UTF-8?
|
||||
*/
|
||||
static int
|
||||
xo_is_text_utf8 (xo_handle_t *xop)
|
||||
{
|
||||
if (xo_style(xop) == XO_STYLE_TEXT)
|
||||
return XOF_ISSET(xop, XOF_UTF8);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Cheap convenience function to return either the argument, or
|
||||
* the internal handle, after it has been initialized. The usage
|
||||
@ -1381,12 +1319,6 @@ xo_retain_find (const char *fmt UNUSED, xo_field_info_t **valp UNUSED,
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
xo_retain_get_hits (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !LIBXO_NO_RETAIN */
|
||||
/*
|
||||
* Retain: We retain parsed field definitions to enhance performance,
|
||||
@ -1422,7 +1354,6 @@ typedef struct xo_retain_s {
|
||||
|
||||
static THREAD_LOCAL(xo_retain_t) xo_retain;
|
||||
static THREAD_LOCAL(unsigned) xo_retain_count;
|
||||
static THREAD_LOCAL(unsigned long) xo_retain_hits;
|
||||
|
||||
/*
|
||||
* Simple hash function based on Thomas Wang's paper. The original is
|
||||
@ -1472,7 +1403,6 @@ xo_retain_clear_all (void)
|
||||
xo_retain.xr_bucket[i] = NULL;
|
||||
}
|
||||
xo_retain_count = 0;
|
||||
xo_retain_hits = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1512,7 +1442,6 @@ xo_retain_find (const char *fmt, xo_field_info_t **valp, unsigned *nump)
|
||||
*valp = xrep->xre_fields;
|
||||
*nump = xrep->xre_num_fields;
|
||||
xrep->xre_hits += 1;
|
||||
xo_retain_hits += 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -1547,12 +1476,6 @@ xo_retain_add (const char *fmt, xo_field_info_t *fields, unsigned num_fields)
|
||||
xo_retain_count += 1;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
xo_retain_get_hits (void)
|
||||
{
|
||||
return xo_retain_hits;
|
||||
}
|
||||
|
||||
#endif /* !LIBXO_NO_RETAIN */
|
||||
|
||||
/*
|
||||
@ -2118,14 +2041,14 @@ xo_style_is_encoding (xo_handle_t *xop)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Simple name->value mapping */
|
||||
typedef struct xo_flag_mapping_s {
|
||||
/* Simple name-value mapping */
|
||||
typedef struct xo_mapping_s {
|
||||
xo_xff_flags_t xm_value; /* Flag value */
|
||||
const char *xm_name; /* String name */
|
||||
} xo_flag_mapping_t;
|
||||
} xo_mapping_t;
|
||||
|
||||
static xo_xff_flags_t
|
||||
xo_name_lookup (xo_flag_mapping_t *map, const char *value, ssize_t len)
|
||||
xo_name_lookup (xo_mapping_t *map, const char *value, ssize_t len)
|
||||
{
|
||||
if (len == 0)
|
||||
return 0;
|
||||
@ -2153,7 +2076,7 @@ xo_name_lookup (xo_flag_mapping_t *map, const char *value, ssize_t len)
|
||||
|
||||
#ifdef NOT_NEEDED_YET
|
||||
static const char *
|
||||
xo_value_lookup (xo_flag_mapping_t *map, xo_xff_flags_t value)
|
||||
xo_value_lookup (xo_mapping_t *map, xo_xff_flags_t value)
|
||||
{
|
||||
if (value == 0)
|
||||
return NULL;
|
||||
@ -2166,7 +2089,7 @@ xo_value_lookup (xo_flag_mapping_t *map, xo_xff_flags_t value)
|
||||
}
|
||||
#endif /* NOT_NEEDED_YET */
|
||||
|
||||
static xo_flag_mapping_t xo_xof_names[] = {
|
||||
static xo_mapping_t xo_xof_names[] = {
|
||||
{ XOF_COLOR_ALLOWED, "color" },
|
||||
{ XOF_COLOR, "color-force" },
|
||||
{ XOF_COLUMNS, "columns" },
|
||||
@ -2187,7 +2110,6 @@ static xo_flag_mapping_t xo_xof_names[] = {
|
||||
{ XOF_RETAIN_ALL, "retain" },
|
||||
{ XOF_UNDERSCORES, "underscores" },
|
||||
{ XOF_UNITS, "units" },
|
||||
{ XOF_UTF8, "utf8" },
|
||||
{ XOF_WARN, "warn" },
|
||||
{ XOF_WARN_XML, "warn-xml" },
|
||||
{ XOF_XPATH, "xpath" },
|
||||
@ -2195,7 +2117,7 @@ static xo_flag_mapping_t xo_xof_names[] = {
|
||||
};
|
||||
|
||||
/* Options available via the environment variable ($LIBXO_OPTIONS) */
|
||||
static xo_flag_mapping_t xo_xof_simple_names[] = {
|
||||
static xo_mapping_t xo_xof_simple_names[] = {
|
||||
{ XOF_COLOR_ALLOWED, "color" },
|
||||
{ XOF_FLUSH, "flush" },
|
||||
{ XOF_FLUSH_LINE, "flush-line" },
|
||||
@ -2339,7 +2261,7 @@ xo_set_options_simple (xo_handle_t *xop, const char *input)
|
||||
int
|
||||
xo_set_options (xo_handle_t *xop, const char *input)
|
||||
{
|
||||
char *cp, *ep, *vp, *np, *bp, *zp;
|
||||
char *cp, *ep, *vp, *np, *bp;
|
||||
int style = -1, new_style, rc = 0;
|
||||
ssize_t len;
|
||||
xo_xof_flags_t new_flag;
|
||||
@ -2468,11 +2390,7 @@ xo_set_options (xo_handle_t *xop, const char *input)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We allow either '=' or ':' to separate the keyword from the value */
|
||||
vp = strchr(cp, '=');
|
||||
zp = strchr(cp, ':');
|
||||
if (zp != NULL && (vp == NULL || zp < vp))
|
||||
vp = zp;
|
||||
if (vp)
|
||||
*vp++ = '\0';
|
||||
|
||||
@ -2511,24 +2429,6 @@ xo_set_options (xo_handle_t *xop, const char *input)
|
||||
xo_warnx("error initializing encoder: %s", vp);
|
||||
}
|
||||
|
||||
} else if (xo_streq(cp, "map")) {
|
||||
if (vp == NULL)
|
||||
xo_failure(xop, "missing value for map option");
|
||||
else {
|
||||
rc = xo_map_option(xop, vp);
|
||||
if (rc)
|
||||
xo_warnx("error initializing map: '%s'", vp);
|
||||
}
|
||||
|
||||
} else if (xo_streq(cp, "map-file")) {
|
||||
if (vp == NULL)
|
||||
xo_failure(xop, "missing value for map-file option");
|
||||
else {
|
||||
rc = xo_map_add_file(xop, vp);
|
||||
if (rc)
|
||||
xo_warnx("error initializing map-file: '%s'", vp);
|
||||
}
|
||||
|
||||
} else {
|
||||
xo_warnx("unknown libxo option value: '%s'", cp);
|
||||
rc = -1;
|
||||
@ -2807,30 +2707,6 @@ xo_format_string_direct (xo_handle_t *xop, xo_buffer_t *xbp,
|
||||
if (len > 0 && !xo_buf_has_room(xbp, len))
|
||||
return 0;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* If we have the "right" encoding for text, then our job is
|
||||
* simpler. We can skim over the string and process it quickly.
|
||||
*/
|
||||
if (cp && xo_is_text_utf8(xop) && need_enc == have_enc) {
|
||||
const char *np, *ep;
|
||||
for (np = cp, ep = cp + len; np < ep; np++)
|
||||
if (xo_is_utf8(*np) || *np == '\\' || *np == '%'
|
||||
|| *np == '{' || *np == '}')
|
||||
break;
|
||||
|
||||
/* If we found no non-ascii characters, we're golden */
|
||||
if (np == ep) {
|
||||
if (!xo_buf_has_room(xbp, len))
|
||||
return -1;
|
||||
|
||||
memcpy(xbp->xb_curp, cp, len);
|
||||
xbp->xb_curp += len;
|
||||
return len; /* Len is the number of columns */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
if (len == 0)
|
||||
break;
|
||||
@ -2858,13 +2734,6 @@ xo_format_string_direct (xo_handle_t *xop, xo_buffer_t *xbp,
|
||||
break;
|
||||
|
||||
case XF_ENC_UTF8: /* UTF-8 */
|
||||
/* Optimize the simple case: this is a traditional ASCII c */
|
||||
if (0 < *cp && *cp <= 0x7F) {
|
||||
wc = (wchar_t) *cp++;
|
||||
ilen = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
ilen = xo_utf8_to_wc_len(cp);
|
||||
if (ilen < 0) {
|
||||
xo_failure(xop, "invalid UTF-8 character: %02hhx", *cp);
|
||||
@ -2912,7 +2781,8 @@ xo_format_string_direct (xo_handle_t *xop, xo_buffer_t *xbp,
|
||||
|
||||
/*
|
||||
* Find the width-in-columns of this character, which must be done
|
||||
* in wide characters, since we lack a mbswidth() function.
|
||||
* in wide characters, since we lack a mbswidth() function. If
|
||||
* it doesn't fit
|
||||
*/
|
||||
width = xo_wcwidth(wc);
|
||||
if (width < 0)
|
||||
@ -3020,7 +2890,7 @@ xo_needed_encoding (xo_handle_t *xop)
|
||||
if (XOF_ISSET(xop, XOF_UTF8)) /* Check the override flag */
|
||||
return XF_ENC_UTF8;
|
||||
|
||||
if (xo_style(xop) == XO_STYLE_TEXT) /* Text defaults to locale */
|
||||
if (xo_style(xop) == XO_STYLE_TEXT) /* Text means locale */
|
||||
return XF_ENC_LOCALE;
|
||||
|
||||
return XF_ENC_UTF8; /* Otherwise, we love UTF-8 */
|
||||
@ -3511,7 +3381,7 @@ xo_do_format_field (xo_handle_t *xop, xo_buffer_t *xbp,
|
||||
* we want to ignore
|
||||
*/
|
||||
if (!XOF_ISSET(xop, XOF_NO_VA_ARG))
|
||||
(void) va_arg(xop->xo_vap, int);
|
||||
va_arg(xop->xo_vap, int);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4408,226 +4278,6 @@ xo_arg (xo_handle_t *xop)
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
/*
|
||||
* We want to allow mapping from one "name" to another replacement
|
||||
* name, like "df --libxo mapfile=df.map", so we can change the
|
||||
* vocabulary as needed. This means maintaining an array of old and
|
||||
* new names, along with the memory for the strings themselves. We
|
||||
* want this to be specific to the handle, so when the user requests a
|
||||
* map, we don't break other users of libxo. We'll need two fields in
|
||||
* the handle, one for the array, and one for the string buffer.
|
||||
*/
|
||||
#ifdef LIBXO_NEED_MAP
|
||||
static int
|
||||
xo_map_find (xo_handle_t *xop, const char *name, size_t len)
|
||||
{
|
||||
for (int i = 0; i < xop->xo_map_len; i += 2) {
|
||||
if (strncmp(xop->xo_map[i], name, len) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is the path something we can find in $XO_MAPDIR? The current test
|
||||
* is simple: lack of '/'.
|
||||
*/
|
||||
static int
|
||||
xo_is_shareable_filename (const char *path)
|
||||
{
|
||||
return strchr(path, '/') == NULL;
|
||||
}
|
||||
|
||||
#endif /* LIBXO_NEED_MAP */
|
||||
|
||||
/*
|
||||
* Find the replacement string for a tag, or return the tag itself
|
||||
*/
|
||||
static inline const char *
|
||||
xo_map_name (xo_handle_t *xop UNUSED, const char *name)
|
||||
{
|
||||
#ifdef LIBXO_NEED_MAP
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
|
||||
size_t len = strlen(name);
|
||||
for (int i = 0; i < xop->xo_map_len; i += 2) {
|
||||
if (strncmp(xop->xo_map[i], name, len) == 0)
|
||||
return xop->xo_map[i + 1];
|
||||
}
|
||||
#endif /* LIBXO_NEED_MAP */
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a mapping from one tag name to another. Both "from" and "to" are
|
||||
* UTF-8 strings.
|
||||
*/
|
||||
int
|
||||
xo_map_add (xo_handle_t *xop UNUSED, const char *from UNUSED,
|
||||
size_t flen UNUSED, const char *to UNUSED, size_t tlen UNUSED)
|
||||
{
|
||||
#ifdef LIBXO_NEED_MAP
|
||||
xop = xo_default(xop);
|
||||
|
||||
int val = xo_map_find(xop, from, flen);
|
||||
if (val >= 0) {
|
||||
/* We hit a "from" value that's already there; replace the "to" */
|
||||
char *newp = xo_buf_append_val(&xop->xo_map_data, to, tlen);
|
||||
if (newp == NULL)
|
||||
return -1;
|
||||
|
||||
/* NUL terminate the string */
|
||||
if (!xo_buf_append_val(&xop->xo_map_data, "", 1))
|
||||
return -1;
|
||||
|
||||
xop->xo_map[val + 1] = newp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (xop->xo_map_len >= xop->xo_map_size) {
|
||||
char **newp = xo_realloc(xop->xo_map, xop->xo_map_size + XO_MAP_INCR);
|
||||
if (newp == NULL)
|
||||
return -1;
|
||||
xop->xo_map = newp;
|
||||
xop->xo_map_size += XO_MAP_INCR;
|
||||
}
|
||||
|
||||
char *new_from = xo_buf_append_val(&xop->xo_map_data, from, flen);
|
||||
if (new_from == NULL)
|
||||
return -1;
|
||||
|
||||
/* NUL terminate the new string */
|
||||
if (!xo_buf_append_val(&xop->xo_map_data, "", 1))
|
||||
return -1;
|
||||
|
||||
char *new_to = xo_buf_append_val(&xop->xo_map_data, to, tlen);
|
||||
if (new_to == NULL)
|
||||
return -1;
|
||||
|
||||
/* NUL terminate the new string */
|
||||
if (!xo_buf_append_val(&xop->xo_map_data, "", 1))
|
||||
return -1;
|
||||
|
||||
val = xop->xo_map_len; /* Use next slot */
|
||||
|
||||
xop->xo_map[val] = new_from;
|
||||
xop->xo_map[val + 1] = new_to;
|
||||
|
||||
xop->xo_map_len += 2; /* Consume the slot */
|
||||
#endif /* LIBXO_NEED_MAP */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
xo_map_option (xo_handle_t *xop, const char *opts)
|
||||
{
|
||||
const char *cp, *np, *vp, *ep;
|
||||
size_t nlen, vlen;
|
||||
|
||||
for (np = opts; *np; np = ep) {
|
||||
cp = strchr(np, '=');
|
||||
if (cp == NULL)
|
||||
break;
|
||||
|
||||
nlen = cp - np;
|
||||
|
||||
vp = cp + 1; /* Skip '=' */
|
||||
ep = strchr(vp, ':');
|
||||
vlen = ep ? ep - vp : strlen(vp);
|
||||
|
||||
if (xo_map_add(xop, np, nlen, vp, vlen))
|
||||
return -1;
|
||||
|
||||
if (ep == NULL)
|
||||
break;
|
||||
ep += 1; /* Skip ':' */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a file of tag maps, with the format:
|
||||
* # example comment
|
||||
* old-tag=new-tag
|
||||
* ancient=new-hotness
|
||||
* The file should be UTF-8.
|
||||
*/
|
||||
int
|
||||
xo_map_add_file (xo_handle_t *xop UNUSED, const char *fname UNUSED)
|
||||
{
|
||||
#ifdef LIBXO_NEED_MAP
|
||||
const char bom0 = 0xEF, bom1 = 0xBB, bom2 = 0xBF;
|
||||
|
||||
char buf[BUFSIZ], *np, *cp, *ep, *vp;
|
||||
int first = TRUE;
|
||||
|
||||
xop = xo_default(xop);
|
||||
|
||||
FILE *fp = fopen(fname, "r");
|
||||
if (fp == NULL) {
|
||||
if (!xo_is_shareable_filename(fname))
|
||||
return -1;
|
||||
|
||||
static const char dir[] = XO_MAPDIR;
|
||||
size_t dlen = sizeof(dir) - 1;
|
||||
size_t flen = strlen(fname);
|
||||
char *new_path = alloca(dlen + 1 + flen + 1);
|
||||
memcpy(new_path, dir, dlen);
|
||||
new_path[dlen] = '/';
|
||||
memcpy(new_path + dlen + 1, fname, flen);
|
||||
new_path[dlen + 1 + flen] = '\0';
|
||||
|
||||
fp = fopen(new_path, "r");
|
||||
if (fp == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (fgets(buf, sizeof(buf), fp) == NULL)
|
||||
break;
|
||||
|
||||
/*
|
||||
* The UTF-8 file can start with a "BOM":
|
||||
* https://en.wikipedia.org/wiki/Byte_order_mark
|
||||
* So if we see this at the start of the file, we need to skip
|
||||
* over it.
|
||||
*/
|
||||
cp = buf;
|
||||
if (first && buf[0] == bom0 && buf[1] == bom1 && buf[2] == bom2)
|
||||
cp += 3;
|
||||
first = FALSE;
|
||||
|
||||
/* Skip to the start of the name (the "from") */
|
||||
np = cp + strspn(cp, " \t\r\n");
|
||||
if (*np == '#')
|
||||
continue;
|
||||
|
||||
/* Skip to the "=" */
|
||||
cp = np + strcspn(np, " \t\r\n=");
|
||||
if (cp == np)
|
||||
continue;
|
||||
|
||||
/* Find the start and the end of the value (the "to") */
|
||||
vp = cp + 1 + strspn(cp + 1, " \t\r\n=");
|
||||
ep = vp + strcspn(vp, " \t\r\n;");
|
||||
if (ep == vp)
|
||||
continue;
|
||||
|
||||
(void) xo_map_add(xop, np, cp - np, vp, ep - vp);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
#endif /* LIBXO_NEED_MAP */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
xo_format_value (xo_handle_t *xop, const char *name, ssize_t nlen,
|
||||
const char *value, ssize_t vlen,
|
||||
@ -4709,20 +4359,6 @@ xo_format_value (xo_handle_t *xop, const char *name, ssize_t nlen,
|
||||
xo_buffer_t *xbp = &xop->xo_data;
|
||||
xo_humanize_save_t save; /* Save values for humanizing logic */
|
||||
|
||||
if (name) {
|
||||
/*
|
||||
* We have a name, but need to see if it's been remapped
|
||||
* to a different name. To look up the tag name, we need
|
||||
* to make a local copy and NUL terminate it.
|
||||
*/
|
||||
char *new_name = alloca(nlen + 1);
|
||||
memcpy(new_name, name, nlen);
|
||||
new_name[nlen] = '\0';
|
||||
|
||||
name = xo_map_name(xop, new_name);
|
||||
nlen = strlen(name); /* Need new length for new name */
|
||||
}
|
||||
|
||||
const char *leader = xo_xml_leader_len(xop, name, nlen);
|
||||
|
||||
switch (xo_style(xop)) {
|
||||
@ -5715,7 +5351,7 @@ xo_role_wants_default_format (int ftype)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static xo_flag_mapping_t xo_role_names[] = {
|
||||
static xo_mapping_t xo_role_names[] = {
|
||||
{ 'C', "color" },
|
||||
{ 'D', "decoration" },
|
||||
{ 'E', "error" },
|
||||
@ -5735,7 +5371,7 @@ static xo_flag_mapping_t xo_role_names[] = {
|
||||
#define XO_ROLE_TEXT '+'
|
||||
#define XO_ROLE_NEWLINE '\n'
|
||||
|
||||
static xo_flag_mapping_t xo_modifier_names[] = {
|
||||
static xo_mapping_t xo_modifier_names[] = {
|
||||
{ XFF_ARGUMENT, "argument" },
|
||||
{ XFF_COLON, "colon" },
|
||||
{ XFF_COMMA, "comma" },
|
||||
@ -5761,7 +5397,7 @@ static xo_flag_mapping_t xo_modifier_names[] = {
|
||||
};
|
||||
|
||||
#ifdef NOT_NEEDED_YET
|
||||
static xo_flag_mapping_t xo_modifier_short_names[] = {
|
||||
static xo_mapping_t xo_modifier_short_names[] = {
|
||||
{ XFF_COLON, "c" },
|
||||
{ XFF_DISPLAY_ONLY, "d" },
|
||||
{ XFF_ENCODE_ONLY, "e" },
|
||||
@ -5778,10 +5414,6 @@ static xo_flag_mapping_t xo_modifier_short_names[] = {
|
||||
};
|
||||
#endif /* NOT_NEEDED_YET */
|
||||
|
||||
/*
|
||||
* This is not really a count, more like a quick-but-pessimisstic number,
|
||||
* rounded up to an even more pessimisstic number, plus one.
|
||||
*/
|
||||
static int
|
||||
xo_count_fields (xo_handle_t *xop UNUSED, const char *fmt)
|
||||
{
|
||||
@ -6888,32 +6520,15 @@ xo_do_emit (xo_handle_t *xop, xo_emit_flags_t flags, const char *fmt)
|
||||
xo_field_info_t *fields = NULL;
|
||||
|
||||
/* Adjust XOEF_RETAIN based on global flags */
|
||||
if (flags & XOEF_NO_RETAIN) {
|
||||
/* If the "don't retain flag is on, remove the retain, just in case */
|
||||
flags &= ~XOEF_RETAIN;
|
||||
|
||||
} else if (flags & XOEF_RETAIN) {
|
||||
/* If the user doesn't want to retain, even if the caller does */
|
||||
if (XOF_ISSET(xop, XOF_RETAIN_NONE))
|
||||
flags &= ~XOEF_RETAIN;
|
||||
} else if (!xo_str_is_const(fmt)) {
|
||||
/*
|
||||
* Unless the caller explicitly tells us otherwise, we can
|
||||
* only retain (cache) const strings, since dynamic strings
|
||||
* aren't cachable due to changing content.
|
||||
*/
|
||||
/* Do nothing */
|
||||
} else if (XOF_ISSET(xop, XOF_RETAIN_ALL)) {
|
||||
/* If the user wants to retain allow it */
|
||||
if (XOF_ISSET(xop, XOF_RETAIN_ALL))
|
||||
flags |= XOEF_RETAIN;
|
||||
}
|
||||
if (XOF_ISSET(xop, XOF_RETAIN_NONE))
|
||||
flags &= ~XOEF_RETAIN;
|
||||
|
||||
/*
|
||||
* Check for 'retain' flag, telling us to retain the field
|
||||
* information. If we've already saved it, then we can avoid
|
||||
* re-parsing the format string.
|
||||
* Dynamically build formats must tell us that the format is
|
||||
* dynamic using the XOEF_NO_RETAIN flag.
|
||||
*/
|
||||
if (!(flags & XOEF_RETAIN)
|
||||
|| xo_retain_find(fmt, &fields, &max_fields) != 0
|
||||
@ -7011,20 +6626,6 @@ xo_emit (const char *fmt, ...)
|
||||
return rc;
|
||||
}
|
||||
|
||||
xo_ssize_t
|
||||
xo_emitr (const char *fmt, ...)
|
||||
{
|
||||
xo_handle_t *xop = xo_default(NULL);
|
||||
ssize_t rc;
|
||||
|
||||
va_start(xop->xo_vap, fmt);
|
||||
rc = xo_do_emit(xop, XOEF_RETAIN, fmt);
|
||||
va_end(xop->xo_vap);
|
||||
bzero(&xop->xo_vap, sizeof(xop->xo_vap));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
xo_ssize_t
|
||||
xo_emit_hvf (xo_handle_t *xop, xo_emit_flags_t flags,
|
||||
const char *fmt, va_list vap)
|
||||
@ -7075,10 +6676,9 @@ xo_emit_f (xo_emit_flags_t flags, const char *fmt, ...)
|
||||
* descriptions.
|
||||
*/
|
||||
xo_ssize_t
|
||||
xo_emit_field_hvf (xo_handle_t *xop, xo_emit_flags_t flags UNUSED,
|
||||
const char *rolmod, const char *contents,
|
||||
const char *fmt, const char *efmt,
|
||||
va_list vap)
|
||||
xo_emit_field_hv (xo_handle_t *xop, const char *rolmod, const char *contents,
|
||||
const char *fmt, const char *efmt,
|
||||
va_list vap)
|
||||
{
|
||||
ssize_t rc;
|
||||
|
||||
@ -7120,14 +6720,6 @@ xo_emit_field_hvf (xo_handle_t *xop, xo_emit_flags_t flags UNUSED,
|
||||
return rc;
|
||||
}
|
||||
|
||||
xo_ssize_t
|
||||
xo_emit_field_hv (xo_handle_t *xop, const char *rolmod, const char *contents,
|
||||
const char *fmt, const char *efmt,
|
||||
va_list vap)
|
||||
{
|
||||
return xo_emit_field_hvf(xop, 0, rolmod, contents, fmt, efmt, vap);
|
||||
}
|
||||
|
||||
xo_ssize_t
|
||||
xo_emit_field_h (xo_handle_t *xop, const char *rolmod, const char *contents,
|
||||
const char *fmt, const char *efmt, ...)
|
||||
@ -7136,24 +6728,7 @@ xo_emit_field_h (xo_handle_t *xop, const char *rolmod, const char *contents,
|
||||
va_list vap;
|
||||
|
||||
va_start(vap, efmt);
|
||||
rc = xo_emit_field_hvf(xop, 0, rolmod, contents, fmt, efmt, vap);
|
||||
va_end(vap);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
xo_ssize_t
|
||||
xo_emit_field_f (xo_emit_flags_t flags, const char *rolmod,
|
||||
const char *contents,
|
||||
const char *fmt, const char *efmt, ...)
|
||||
{
|
||||
xo_handle_t *xop = xo_default(NULL);
|
||||
|
||||
ssize_t rc;
|
||||
va_list vap;
|
||||
|
||||
va_start(vap, efmt);
|
||||
rc = xo_emit_field_hvf(xop, flags, rolmod, contents, fmt, efmt, vap);
|
||||
rc = xo_emit_field_hv(xop, rolmod, contents, fmt, efmt, vap);
|
||||
va_end(vap);
|
||||
|
||||
return rc;
|
||||
@ -7167,7 +6742,7 @@ xo_emit_field (const char *rolmod, const char *contents,
|
||||
va_list vap;
|
||||
|
||||
va_start(vap, efmt);
|
||||
rc = xo_emit_field_hvf(NULL, 0, rolmod, contents, fmt, efmt, vap);
|
||||
rc = xo_emit_field_hv(NULL, rolmod, contents, fmt, efmt, vap);
|
||||
va_end(vap);
|
||||
|
||||
return rc;
|
||||
@ -7376,8 +6951,6 @@ xo_do_open_container (xo_handle_t *xop, xo_xof_flags_t flags, const char *name)
|
||||
name = XO_FAILURE_NAME;
|
||||
}
|
||||
|
||||
name = xo_map_name(xop, name); /* Find mapped name, if any */
|
||||
|
||||
const char *leader = xo_xml_leader(xop, name);
|
||||
flags |= xop->xo_flags; /* Pick up handle flags */
|
||||
|
||||
@ -7486,22 +7059,18 @@ xo_do_close_container (xo_handle_t *xop, const char *name)
|
||||
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");
|
||||
} else if (!(xsp->xs_flags & XSF_DTRT)) {
|
||||
xo_failure(xop, "missing name without 'dtrt' mode");
|
||||
name = XO_FAILURE_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
name = xo_map_name(xop, name); /* Find mapped name, if any */
|
||||
|
||||
const char *leader = xo_xml_leader(xop, 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>%s", xo_indent(xop),
|
||||
"", leader, name, ppn);
|
||||
rc = xo_printf(xop, "%*s</%s%s>%s", xo_indent(xop), "", leader, name, ppn);
|
||||
break;
|
||||
|
||||
case XO_STYLE_JSON:
|
||||
@ -7567,8 +7136,6 @@ xo_do_open_list (xo_handle_t *xop, xo_xof_flags_t flags, const char *name)
|
||||
const char *ppn = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : "";
|
||||
const char *pre_nl = "";
|
||||
|
||||
name = xo_map_name(xop, name); /* Find mapped name, if any */
|
||||
|
||||
switch (xo_style(xop)) {
|
||||
case XO_STYLE_JSON:
|
||||
|
||||
@ -7662,15 +7229,12 @@ xo_do_close_list (xo_handle_t *xop, const char *name)
|
||||
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");
|
||||
} else if (!(xsp->xs_flags & XSF_DTRT)) {
|
||||
xo_failure(xop, "missing name without 'dtrt' mode");
|
||||
name = XO_FAILURE_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
name = xo_map_name(xop, name); /* Find mapped name, if any */
|
||||
|
||||
switch (xo_style(xop)) {
|
||||
case XO_STYLE_JSON:
|
||||
if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST)
|
||||
@ -7731,8 +7295,6 @@ xo_do_open_leaf_list (xo_handle_t *xop, xo_xof_flags_t flags, const char *name)
|
||||
const char *ppn = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : "";
|
||||
const char *pre_nl = "";
|
||||
|
||||
name = xo_map_name(xop, name); /* Find mapped name, if any */
|
||||
|
||||
switch (xo_style(xop)) {
|
||||
case XO_STYLE_JSON:
|
||||
indent = 1;
|
||||
@ -7786,15 +7348,12 @@ xo_do_close_leaf_list (xo_handle_t *xop, const char *name)
|
||||
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");
|
||||
} else if (!(xsp->xs_flags & XSF_DTRT)) {
|
||||
xo_failure(xop, "missing name without 'dtrt' mode");
|
||||
name = XO_FAILURE_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
name = xo_map_name(xop, name); /* Find mapped name, if any */
|
||||
|
||||
switch (xo_style(xop)) {
|
||||
case XO_STYLE_JSON:
|
||||
if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST)
|
||||
@ -7833,8 +7392,6 @@ xo_do_open_instance (xo_handle_t *xop, xo_xof_flags_t flags, const char *name)
|
||||
name = XO_FAILURE_NAME;
|
||||
}
|
||||
|
||||
name = xo_map_name(xop, name); /* Find mapped name, if any */
|
||||
|
||||
const char *leader = xo_xml_leader(xop, name);
|
||||
flags |= xop->xo_flags;
|
||||
|
||||
@ -7925,15 +7482,12 @@ xo_do_close_instance (xo_handle_t *xop, const char *name)
|
||||
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");
|
||||
} else if (!(xsp->xs_flags & XSF_DTRT)) {
|
||||
xo_failure(xop, "missing name without 'dtrt' mode");
|
||||
name = XO_FAILURE_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
name = xo_map_name(xop, name); /* Find mapped name, if any */
|
||||
|
||||
const char *leader = xo_xml_leader(xop, name);
|
||||
|
||||
switch (xo_style(xop)) {
|
||||
@ -8060,8 +7614,6 @@ xo_do_close (xo_handle_t *xop, const char *name, xo_state_t new_state)
|
||||
else
|
||||
return 0; /* Unknown or useless new states are ignored */
|
||||
|
||||
name = xo_map_name(xop, name);
|
||||
|
||||
for (xsp = &xop->xo_stack[xop->xo_depth]; xsp > xop->xo_stack; xsp--) {
|
||||
/*
|
||||
* Marker's normally stop us from going any further, unless
|
||||
|
25
libxo/xo.h
25
libxo/xo.h
@ -106,7 +106,6 @@ typedef unsigned long long xo_xof_flags_t;
|
||||
|
||||
typedef unsigned xo_emit_flags_t; /* Flags to xo_emit() and friends */
|
||||
#define XOEF_RETAIN (1<<0) /* Retain parsed formatting information */
|
||||
#define XOEF_NO_RETAIN (1<<1) /* Format must not be retained (dynamic) */
|
||||
|
||||
/*
|
||||
* The xo_info_t structure provides a mapping between names and
|
||||
@ -210,9 +209,6 @@ xo_emit_h (xo_handle_t *xop, const char *fmt, ...);
|
||||
xo_ssize_t
|
||||
xo_emit (const char *fmt, ...);
|
||||
|
||||
xo_ssize_t
|
||||
xo_emitr (const char *fmt, ...);
|
||||
|
||||
xo_ssize_t
|
||||
xo_emit_hvf (xo_handle_t *xop, xo_emit_flags_t flags,
|
||||
const char *fmt, va_list vap);
|
||||
@ -684,12 +680,6 @@ char *
|
||||
xo_simplify_format (xo_handle_t *xop, const char *fmt, int with_numbers,
|
||||
xo_simplify_field_func_t field_cb);
|
||||
|
||||
xo_ssize_t
|
||||
xo_emit_field_hvf (xo_handle_t *xop, xo_emit_flags_t flags,
|
||||
const char *rolmod, const char *contents,
|
||||
const char *fmt, const char *efmt,
|
||||
va_list vap);
|
||||
|
||||
xo_ssize_t
|
||||
xo_emit_field_hv (xo_handle_t *xop, const char *rolmod, const char *contents,
|
||||
const char *fmt, const char *efmt,
|
||||
@ -699,11 +689,6 @@ xo_ssize_t
|
||||
xo_emit_field_h (xo_handle_t *xop, const char *rolmod, const char *contents,
|
||||
const char *fmt, const char *efmt, ...);
|
||||
|
||||
xo_ssize_t
|
||||
xo_emit_field_f (xo_emit_flags_t flags, const char *rolmod,
|
||||
const char *contents,
|
||||
const char *fmt, const char *efmt, ...);
|
||||
|
||||
xo_ssize_t
|
||||
xo_emit_field (const char *rolmod, const char *contents,
|
||||
const char *fmt, const char *efmt, ...);
|
||||
@ -714,14 +699,4 @@ xo_retain_clear_all (void);
|
||||
void
|
||||
xo_retain_clear (const char *fmt);
|
||||
|
||||
unsigned long
|
||||
xo_retain_get_hits (void);
|
||||
|
||||
int
|
||||
xo_map_add (xo_handle_t *xop, const char *from, size_t flen,
|
||||
const char *to, size_t tlen);
|
||||
|
||||
int
|
||||
xo_map_add_file (xo_handle_t *xop, const char *fname);
|
||||
|
||||
#endif /* INCLUDE_XO_H */
|
||||
|
@ -135,49 +135,29 @@ xo_buf_has_room (xo_buffer_t *xbp, ssize_t len)
|
||||
/*
|
||||
* Append the given string to the given buffer
|
||||
*/
|
||||
static inline char *
|
||||
xo_buf_append_val (xo_buffer_t *xbp, const char *str, ssize_t len)
|
||||
{
|
||||
if (str == NULL || len == 0 || !xo_buf_has_room(xbp, len))
|
||||
return NULL;
|
||||
|
||||
char *val = xbp->xb_curp; /* The "new" value */
|
||||
|
||||
memcpy(xbp->xb_curp, str, len);
|
||||
xbp->xb_curp += len;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xo_buf_append (xo_buffer_t *xbp, const char *str, ssize_t len)
|
||||
{
|
||||
(void) xo_buf_append_val(xbp, str, len);
|
||||
if (str == NULL || len == 0 || !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 char *
|
||||
xo_buf_append_str_val (xo_buffer_t *xbp, const char *str)
|
||||
static inline void
|
||||
xo_buf_append_str (xo_buffer_t *xbp, const char *str)
|
||||
{
|
||||
ssize_t len = strlen(str);
|
||||
|
||||
if (!xo_buf_has_room(xbp, len))
|
||||
return NULL;
|
||||
|
||||
char *val = xbp->xb_curp; /* The "new" value */
|
||||
return;
|
||||
|
||||
memcpy(xbp->xb_curp, str, len);
|
||||
xbp->xb_curp += len;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xo_buf_append_str (xo_buffer_t *xbp, const char *str)
|
||||
{
|
||||
(void) xo_buf_append_str_val(xbp, str);
|
||||
}
|
||||
|
||||
#endif /* XO_BUF_H */
|
||||
|
@ -1,254 +0,0 @@
|
||||
/* libxo/xo_config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to 1 if using 'alloca.c'. */
|
||||
#undef C_ALLOCA
|
||||
|
||||
/* Define to 1 if you have 'alloca', as a function or macro. */
|
||||
#undef HAVE_ALLOCA
|
||||
|
||||
/* Define to 1 if <alloca.h> works. */
|
||||
#undef HAVE_ALLOCA_H
|
||||
|
||||
/* Define to 1 if you have the `asprintf' function. */
|
||||
#undef HAVE_ASPRINTF
|
||||
|
||||
/* Define to 1 if you have the `bzero' function. */
|
||||
#undef HAVE_BZERO
|
||||
|
||||
/* Define to 1 if you have the `ctime' function. */
|
||||
#undef HAVE_CTIME
|
||||
|
||||
/* Define to 1 if you have the <ctype.h> header file. */
|
||||
#undef HAVE_CTYPE_H
|
||||
|
||||
/* Define to 1 if you have the declaration of `__isthreaded', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL___ISTHREADED
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the `dlfunc' function. */
|
||||
#undef HAVE_DLFUNC
|
||||
|
||||
/* Define to 1 if you have the <errno.h> header file. */
|
||||
#undef HAVE_ERRNO_H
|
||||
|
||||
/* Style of etext */
|
||||
#undef HAVE_ETEXT
|
||||
|
||||
/* Define to 1 if you have the `fdopen' function. */
|
||||
#undef HAVE_FDOPEN
|
||||
|
||||
/* Define to 1 if you have the `flock' function. */
|
||||
#undef HAVE_FLOCK
|
||||
|
||||
/* Using real gcc */
|
||||
#undef HAVE_GCC
|
||||
|
||||
/* Define to 1 if you have the `getpass' function. */
|
||||
#undef HAVE_GETPASS
|
||||
|
||||
/* Define to 1 if you have the `getprogname' function. */
|
||||
#undef HAVE_GETPROGNAME
|
||||
|
||||
/* Define to 1 if you have the `getrusage' function. */
|
||||
#undef HAVE_GETRUSAGE
|
||||
|
||||
/* gettext(3) */
|
||||
#undef HAVE_GETTEXT
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#undef HAVE_GETTIMEOFDAY
|
||||
|
||||
/* humanize_number(3) */
|
||||
#undef HAVE_HUMANIZE_NUMBER
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the `crypto' library (-lcrypto). */
|
||||
#undef HAVE_LIBCRYPTO
|
||||
|
||||
/* Define to 1 if you have the `m' library (-lm). */
|
||||
#undef HAVE_LIBM
|
||||
|
||||
/* Define to 1 if you have the <libutil.h> header file. */
|
||||
#undef HAVE_LIBUTIL_H
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
|
||||
to 0 otherwise. */
|
||||
#undef HAVE_MALLOC
|
||||
|
||||
/* Define to 1 if you have the `memmove' function. */
|
||||
#undef HAVE_MEMMOVE
|
||||
|
||||
/* Define to 1 if you have the <monitor.h> header file. */
|
||||
#undef HAVE_MONITOR_H
|
||||
|
||||
/* Support printflike */
|
||||
#undef HAVE_PRINTFLIKE
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `realloc' function,
|
||||
and to 0 otherwise. */
|
||||
#undef HAVE_REALLOC
|
||||
|
||||
/* Define to 1 if you have the `srand' function. */
|
||||
#undef HAVE_SRAND
|
||||
|
||||
/* Define to 1 if you have the `sranddev' function. */
|
||||
#undef HAVE_SRANDDEV
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdio_ext.h> header file. */
|
||||
#undef HAVE_STDIO_EXT_H
|
||||
|
||||
/* Define to 1 if you have the <stdio.h> header file. */
|
||||
#undef HAVE_STDIO_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <stdtime/tzfile.h> header file. */
|
||||
#undef HAVE_STDTIME_TZFILE_H
|
||||
|
||||
/* Define to 1 if you have the `strchr' function. */
|
||||
#undef HAVE_STRCHR
|
||||
|
||||
/* Define to 1 if you have the `strcspn' function. */
|
||||
#undef HAVE_STRCSPN
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the `strlcpy' function. */
|
||||
#undef HAVE_STRLCPY
|
||||
|
||||
/* Define to 1 if you have the `strspn' function. */
|
||||
#undef HAVE_STRSPN
|
||||
|
||||
/* Have struct sockaddr_un.sun_len */
|
||||
#undef HAVE_SUN_LEN
|
||||
|
||||
/* Define to 1 if you have the `sysctlbyname' function. */
|
||||
#undef HAVE_SYSCTLBYNAME
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/sysctl.h> header file. */
|
||||
#undef HAVE_SYS_SYSCTL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <threads.h> header file. */
|
||||
#undef HAVE_THREADS_H
|
||||
|
||||
/* thread-local setting */
|
||||
#undef HAVE_THREAD_LOCAL
|
||||
|
||||
/* Define to 1 if you have the <tzfile.h> header file. */
|
||||
#undef HAVE_TZFILE_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* 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 */
|
||||
#undef LIBXO_VERSION
|
||||
|
||||
/* Version number extra information */
|
||||
#undef LIBXO_VERSION_EXTRA
|
||||
|
||||
/* Version number as a number */
|
||||
#undef LIBXO_VERSION_NUMBER
|
||||
|
||||
/* Version number as string */
|
||||
#undef LIBXO_VERSION_STRING
|
||||
|
||||
/* Enable local wcwidth implementation */
|
||||
#undef LIBXO_WCWIDTH
|
||||
|
||||
/* Define to the sub-directory where libtool stores uninstalled libraries. */
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* 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 all of the C90 standard headers exist (not just the ones
|
||||
required in a freestanding environment). This macro is provided for
|
||||
backward compatibility; new code need not use it. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Use int return codes */
|
||||
#undef USE_INT_RETURN_CODES
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Retain hash bucket size */
|
||||
#undef XO_RETAIN_SIZE
|
||||
|
||||
/* 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 <sys/types.h> does not define. */
|
||||
#undef size_t
|
@ -23,8 +23,6 @@
|
||||
.Fn xo_emit_h "xo_handle_t *xop" "const char *fmt" "..."
|
||||
.Ft xo_ssize_t
|
||||
.Fn xo_emit_hv "xo_handle_t *xop" "const char *fmt" "va_list vap"
|
||||
.Ft xo_ssize_t
|
||||
.Fn xo_emitr "const char *fmt" "..."
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Fn xo_emit
|
||||
@ -92,33 +90,6 @@ the "--libxo" option:
|
||||
<div class="data" data-tag="filename">/etc/motd</div>
|
||||
</div>
|
||||
.Ed
|
||||
.Sh Retaining Formatting Information for Constant Strings
|
||||
.Pp
|
||||
The
|
||||
.Nm libxo
|
||||
library can cache the compiled internal version of the format for
|
||||
circumstances when the format will be used repeatedly, such as a loop.
|
||||
This cannot be used when the format string is in a dynamic buffer,
|
||||
since the cache retains a reference to the static format string,
|
||||
typically a static compile-time constant value.
|
||||
.Pp
|
||||
Typically static strings are placed in an executable's ".text" segment,
|
||||
so
|
||||
.Nm libxo
|
||||
knows that the formatting information in such static strings can be
|
||||
cached (retained), but shared libraries will have their own ".text"
|
||||
segment, so without the XOEF_RETAIN flag,
|
||||
.Nm libxo
|
||||
cannot presume to retain formatting information.
|
||||
If a caller in shared library code want their formats retained, they
|
||||
need to pass the XOEF_RETAIN flag.
|
||||
.Pp
|
||||
The
|
||||
.Fn xo_emitr
|
||||
function is a convenience function that passes the XOEF_RETAIN
|
||||
flag to
|
||||
.Fn xo_emit_hvf ,
|
||||
and can be used in shared libraries when the format string is static.
|
||||
.Sh RETURN CODE
|
||||
.Nm
|
||||
returns a negative value on error. If the
|
||||
|
121
libxo/xo_emit_f.3
Normal file
121
libxo/xo_emit_f.3
Normal file
@ -0,0 +1,121 @@
|
||||
.\" #
|
||||
.\" # Copyright (c) 2016, 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, April 2016
|
||||
.\"
|
||||
.Dd April 15, 2016
|
||||
.Dt LIBXO 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm xo_emit_f , xo_emit_hf , xo_emit_hvf
|
||||
.Nd emit formatted output based on format string and arguments
|
||||
.Sh LIBRARY
|
||||
.Lb libxo
|
||||
.Sh SYNOPSIS
|
||||
.In libxo/xo.h
|
||||
.Ft xo_ssize_t
|
||||
.Fn xo_emit_f "xo_emit_flags_t flags" "const char *fmt" "..."
|
||||
.Ft xo_ssize_t
|
||||
.Fn xo_emit_hf "xo_handle_t *xop" "xo_emit_flags_t flags" "const char *fmt" "..."
|
||||
.Ft xo_ssize_t
|
||||
.Fn xo_emit_hvf "xo_handle_t *xop" "xo_emit_flags_t flags" "const char *fmt" "va_list vap"
|
||||
.Ft void
|
||||
.Fn xo_retain_clear_all "void"
|
||||
.Ft void
|
||||
.Fn xo_retain_clear "const char *fmt"
|
||||
.Sh DESCRIPTION
|
||||
These functions allow callers to pass a set of flags to
|
||||
.Nm
|
||||
emitting functions. These processing of arguments, except for
|
||||
.Fa flags ,
|
||||
is identical to the base functions.
|
||||
See
|
||||
.Xr xo_emit 3
|
||||
for additional information.
|
||||
.Pp
|
||||
The only currently defined flag is
|
||||
.Dv XOEF_RETAIN .
|
||||
.Nm
|
||||
can retain the parsed internal information related to the given
|
||||
format string, allowing subsequent
|
||||
.Xr xo_emit 3
|
||||
calls, the retained
|
||||
information is used, avoiding repetitive parsing of the format string.
|
||||
To retain parsed format information, use the
|
||||
.Dv XOEF_RETAIN
|
||||
flag to the
|
||||
.Fn xo_emit_f
|
||||
function.
|
||||
.Pp
|
||||
The format string must be immutable across multiple calls to
|
||||
.Xn xo_emit_f ,
|
||||
since the library retains the string.
|
||||
Typically this is done by using
|
||||
static constant strings, such as string literals. If the string is not
|
||||
immutable, the
|
||||
.Dv XOEF_RETAIN
|
||||
flag must not be used.
|
||||
.Pp
|
||||
The functions
|
||||
.Fn xo_retain_clear
|
||||
and
|
||||
.Fn xo_retain_clear_all
|
||||
release internal information on either a single format string or all
|
||||
format strings, respectively.
|
||||
Neither is required, but the library will
|
||||
retain this information until it is cleared or the process exits.
|
||||
.Pp
|
||||
The retained information is kept as thread-specific data.
|
||||
.Pp
|
||||
Use
|
||||
.Fn xo_retain_clear
|
||||
and
|
||||
.Fn xo_retain_clear_all
|
||||
to clear the retained information, clearing the retained information
|
||||
for either a specific format string or all format strings, respectively.
|
||||
These functions are only needed when the calling application wants to
|
||||
clear this information; they are not generally needed.
|
||||
.Sh EXAMPLES
|
||||
.Pp
|
||||
.Bd -literal -offset indent
|
||||
for (i = 0; i < 1000; i++) {
|
||||
xo_open_instance("item");
|
||||
xo_emit_f(XOEF_RETAIN, "{:name} {:count/%d}\\n",
|
||||
name[i], count[i]);
|
||||
}
|
||||
.Ed
|
||||
.Pp
|
||||
In this example, the caller desires to clear the retained information.
|
||||
.Bd -literal -offset indent
|
||||
const char *fmt = "{:name} {:count/%d}\\n";
|
||||
for (i = 0; i < 1000; i++) {
|
||||
xo_open_instance("item");
|
||||
xo_emit_f(XOEF_RETAIN, fmt, name[i], count[i]);
|
||||
}
|
||||
xo_retain_clear(fmt);
|
||||
.Ed
|
||||
.Sh RETURN CODE
|
||||
The return values for these functions is identical to those of their
|
||||
traditional counterparts. See
|
||||
.Xr xo_emit 3
|
||||
for details.
|
||||
.Sh SEE ALSO
|
||||
.Xr xo_emit 3 ,
|
||||
.Xr xo_open_container 3 ,
|
||||
.Xr xo_open_list 3 ,
|
||||
.Xr xo_format 5 ,
|
||||
.Xr libxo 3
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm libxo
|
||||
library first appeared in
|
||||
.Fx 11.0 .
|
||||
.Sh AUTHORS
|
||||
.Nm libxo
|
||||
was written by
|
||||
.An Phil Shafer Aq Mt phil@freebsd.org .
|
||||
|
113
libxo/xo_emit_field.3
Normal file
113
libxo/xo_emit_field.3
Normal file
@ -0,0 +1,113 @@
|
||||
.\" #
|
||||
.\" # Copyright (c) 2021, 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_field
|
||||
.Nd emit formatted output based on format string and arguments
|
||||
.Sh LIBRARY
|
||||
.Lb libxo
|
||||
.Sh SYNOPSIS
|
||||
.In libxo/xo.h
|
||||
.Ft xo_ssize_t
|
||||
.Fn xo_emit_field "const char *rolmod" "const char *content" "const char *fmt" "const char *efmt" "..."
|
||||
.Ft xo_ssize_t
|
||||
.Fn xo_emit_field_h "xo_handle_t *xop" "const char *rolmod" "const char *content" "const char *fmt" const char *efmt" "..."
|
||||
.Ft xo_ssize_t
|
||||
.Fn xo_emit_field_hv "xo_handle_t *xop" "const char *rolmod" "const char *content" "const char *fmt" "const char *efmt" "va_list vap"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Fn xo_emit_field
|
||||
function emits formatted output similar to
|
||||
.Xr xo_emit 3
|
||||
but where
|
||||
.Fn xo_emit
|
||||
uses a single string argument containing the description
|
||||
for multiple fields,
|
||||
.Fn xo_emit_field
|
||||
emits a single field using multiple arguments to contain the
|
||||
field description.
|
||||
.Fn xo_emit_field_h
|
||||
adds an explicit handle to use instead of the default
|
||||
handle, while
|
||||
.Fn xo_emit_field_hv
|
||||
accepts a
|
||||
.Fa va_list
|
||||
for additional flexibility.
|
||||
.Pp
|
||||
The arguments
|
||||
.Fa rolmod ,
|
||||
.Fa content ,
|
||||
.Fa fmt ,
|
||||
and
|
||||
.Fa efmt
|
||||
are detailed in
|
||||
.Xr xo_format 5 .
|
||||
Using distinct arguments allows callers to pass the field description
|
||||
in pieces, rather than having to use something like
|
||||
.Xr snprintf 3
|
||||
to build the format string required by
|
||||
.Fn xo_emit .
|
||||
The arguments are each NUL-terminated strings. The
|
||||
.Fa rolmod
|
||||
argument contains the "role" and "modifier" portions of
|
||||
the field description, the
|
||||
.Fa content
|
||||
argument contains the "content" portion, and the
|
||||
.Fa fmt
|
||||
and
|
||||
.Fa efmt
|
||||
contain the "field-format" and "encoding-format" portions, respectively.
|
||||
.Pp
|
||||
As with xo_emit, the
|
||||
.Fa fmt
|
||||
and
|
||||
.Fa efmt
|
||||
values are both optional, since the field-format string
|
||||
defaults to "%s", and the encoding-format's default value is
|
||||
derived from the field-format
|
||||
per
|
||||
.Xr xo_format 5 .
|
||||
However, care must be taken to avoid using a value directly as the
|
||||
format, since characters like '{', '%', and '}' will be interpreted
|
||||
as formatting directives, and may cause
|
||||
.Nm
|
||||
to dereference arbitrary values off the stack, leading to bugs,
|
||||
core files, and gnashing of teeth.
|
||||
.Sh EXAMPLES
|
||||
In this example, a set of four values is emitted using the following
|
||||
source code:
|
||||
.Bd -literal -offset indent
|
||||
xo_emit_field("T", title, NULL, NULL, NULL);
|
||||
xo_emit_field("Vt", "max-chaos", NULL, NULL, " very ");
|
||||
xo_emit_field("V", "min-chaos", "%02d", "%d", 42);
|
||||
xo_emit_field_h(NULL, ",leaf-list,quotes", "sku", "%s-%u", "%s-000-%u",
|
||||
"gum", 1412);
|
||||
.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_format 5 ,
|
||||
.Xr libxo 3
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm libxo
|
||||
library first appeared in
|
||||
.Fx 11.0 .
|
||||
.Sh AUTHORS
|
||||
.Nm libxo
|
||||
was written by
|
||||
.An Phil Shafer Aq Mt phil@freebsd.org .
|
@ -37,6 +37,8 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
@ -50,8 +50,6 @@ The triggered functionality is identical.
|
||||
.It "keys " "Emit the key attribute for keys (XML)"
|
||||
.It "log\-gettext" "Log (via stderr) each gettext(3) string lookup"
|
||||
.It "log\-syslog " "Log (via stderr) each syslog message (via xo_syslog)"
|
||||
.It "map " "Map between tag names"
|
||||
.It "map\-file " "Use a file to specify mapping between tag names"
|
||||
.It "no\-humanize" "Ignore the {h:} modifier (TEXT, HTML)"
|
||||
.It "no\-locale " "Do not initialize the locale setting"
|
||||
.It "no\-retain " "Prevent retaining formatting information"
|
||||
@ -103,11 +101,6 @@ names that state with "data\-".
|
||||
adds a "key" attribute for XML output to indicate that a leaf is
|
||||
an identifier for the list member.
|
||||
.Pp
|
||||
.Fa map
|
||||
and
|
||||
.Fa map\-file
|
||||
are described below.
|
||||
.Pp
|
||||
.Fa no\-humanize
|
||||
avoids "humanizing" numeric output (see
|
||||
.Xr humanize_number 3
|
||||
@ -139,176 +132,6 @@ to emit warnings on stderr when application code make incorrect calls.
|
||||
.Fa warn\-xml causes those warnings to be placed in
|
||||
.Em XML
|
||||
inside the output.
|
||||
.Sh Color Mapping
|
||||
The
|
||||
.Fa colors
|
||||
option takes a value that is a set of mappings from the
|
||||
pre-defined set of colors to new foreground and background colors.
|
||||
The value is a series of "fg/bg" values, separated by a "+".
|
||||
Each pair of "fg/bg" values gives the colors to which a basic color is
|
||||
mapped when used as a foreground or background color.
|
||||
The order is the mappings is:
|
||||
.Bd -literal -offset indent
|
||||
- black
|
||||
- red
|
||||
- green
|
||||
- yellow
|
||||
- blue
|
||||
- magenta
|
||||
- cyan
|
||||
- white
|
||||
.Ed
|
||||
.Pp
|
||||
Pairs may be skipped, leaving them mapped as normal, as are missing
|
||||
pairs or single colors.
|
||||
.Pp
|
||||
For example consider the following xo_emit call:
|
||||
.Bd -literal -offset indent
|
||||
xo_emit("{C:fg-red,bg-green}Merry XMas!!{C:}\n");
|
||||
.Ed
|
||||
.Pp
|
||||
To turn all colored output to red-on-blue, use eight pairs of
|
||||
"red/blue" mappings separated by plus signs ("+"):
|
||||
.Bd -literal -offset indent
|
||||
--libxo colors=red/blue+red/blue+red/blue+red/blue+\
|
||||
red/blue+red/blue+red/blue+red/blue
|
||||
.Ed
|
||||
.Pp
|
||||
To turn the red-on-green text to magenta-on-cyan, give a "magenta"
|
||||
foreground value for red (the second mapping) and a "cyan" background
|
||||
to green (the third mapping):
|
||||
.Bd -literal -offset indent
|
||||
--libxo colors=+magenta+/cyan
|
||||
.Ed
|
||||
.Pp
|
||||
Consider the common situation where blue output looks unreadable on a
|
||||
terminal session with a black background.
|
||||
To turn both "blue" foreground and background output to "yellow",
|
||||
give only the fifth mapping, skipping the first four mappings
|
||||
with bare plus signs ("+"):
|
||||
.Bd -literal -offset indent
|
||||
--libxo colors=++++yellow/yellow
|
||||
.Ed
|
||||
.Pp
|
||||
.Sh Tag Mapping
|
||||
.Nm libxo
|
||||
supports mapping between tag names, for scenarios where the tags
|
||||
need to make specific values.
|
||||
For example, the "user" tag might be
|
||||
needed as the "owner" tag.
|
||||
.Nm libxo
|
||||
can perform this one-to-one tag
|
||||
replacement.
|
||||
.Pp
|
||||
Note that
|
||||
.Nm libxo
|
||||
does not perform more complex transformations;
|
||||
languages such as XSLT or SLAX should be used when something more than
|
||||
simple one-to-one replacement is required.
|
||||
.Pp
|
||||
Mapping can be specified using the
|
||||
.Fa map
|
||||
and
|
||||
.Fa map-file options.
|
||||
The
|
||||
.Fa map
|
||||
option accepts one or more mapping, in the format "old=new",
|
||||
separated by colons:
|
||||
.Bd -literal -offset indent
|
||||
--libxo map:one=red,map:two=blue
|
||||
.Ed
|
||||
.Pp
|
||||
This example would turn:
|
||||
.Bd -literal -offset indent
|
||||
<one>fish</one>
|
||||
<two>fish</two>
|
||||
.Ed
|
||||
.Pp
|
||||
into:
|
||||
.Bd -literal -offset indent
|
||||
<red>fish</red>
|
||||
<blue>fish</blue>
|
||||
.Ed
|
||||
.Pp
|
||||
In another example, the command-line options:
|
||||
.Bd -literal -offset indent
|
||||
--libxo map:user=owner:name=file:size=bytes:modify-time=time
|
||||
.Ed
|
||||
.Pp
|
||||
would turn:
|
||||
.Bd -literal -offset indent
|
||||
<entry>
|
||||
<name>xx-00000009</name>
|
||||
<user>phil</user>
|
||||
<size>12345</size>
|
||||
<modify-time value="1644355825">1644355825</modify-time>
|
||||
</entry>
|
||||
.Ed
|
||||
.Pp
|
||||
into:
|
||||
.Bd -literal -offset indent
|
||||
<entry>
|
||||
<file>xx-00000009</file>
|
||||
<owner>phil</owner>
|
||||
<bytes>12345</bytes>
|
||||
<time value="1644355825">1644355825</time>
|
||||
</entry>
|
||||
.Ed
|
||||
.Pp
|
||||
The
|
||||
.Fa map-file
|
||||
option allows the mappings to be placed into a file,
|
||||
one per line:
|
||||
.Bd -literal -offset indent
|
||||
--libxo map-file=foo.map
|
||||
.Ed
|
||||
.Pp
|
||||
where "foo.map" might contain:
|
||||
.Bd -literal -offset indent
|
||||
# comments are supported, white space is ignored
|
||||
user = owner
|
||||
name=file
|
||||
# blank lines are allowed
|
||||
|
||||
size = bytes
|
||||
modify-time= time
|
||||
.Ed
|
||||
.Pp
|
||||
This untidy example demonstrates the flexibility in the
|
||||
.Nm libxo
|
||||
mapping files.
|
||||
.Pp
|
||||
If the filename given with the
|
||||
.Fa map-file
|
||||
option contains no slashes ("/") and such a file does not
|
||||
exist in the current working directory,
|
||||
.Nm libxo
|
||||
will look for the file in the "map" subdirectory of the system
|
||||
"share" directory, typically /usr/share/libxo/map/.
|
||||
.Sh Encoders
|
||||
In addition to the four "built-in" formats,
|
||||
.Nm libxo
|
||||
supports an extensible mechanism for adding encoders.
|
||||
These are activated using the
|
||||
.Fa encoder
|
||||
keyword::
|
||||
.Bd -literal -offset indent
|
||||
--libxo encoder=cbor
|
||||
.Ed
|
||||
.Pp
|
||||
The encoder can include encoder-specific options, separated by either
|
||||
colons (":") or plus signs ("+"):
|
||||
.Bd -literal -offset indent
|
||||
--libxo encoder=csv+path=filesystem+leaf=name+no-header
|
||||
--libxo encoder=csv:path=filesystem:leaf=name:no-header
|
||||
.Ed
|
||||
.Pp
|
||||
For brevity, the string "@" can be used in place of the string
|
||||
"encoder=".
|
||||
.Bd -literal -offset indent
|
||||
df --libxo @csv:no-header
|
||||
.Ed
|
||||
.Pp
|
||||
.Sh EXAMPLES
|
||||
The following are three example invocations of
|
||||
.Xr ps 1 :
|
||||
|
@ -38,6 +38,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/syslog.h>
|
||||
@ -57,13 +58,9 @@
|
||||
#include <stdarg.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include "xo_config.h"
|
||||
|
||||
#ifdef HAVE_SYSCTLBYNAME
|
||||
#include <sys/sysctl.h>
|
||||
#endif /* HAVE_SYSCTLBYNAME */
|
||||
|
||||
#include "xo.h"
|
||||
#include "xo_encoder.h" /* For xo_realloc */
|
||||
#include "xo_buf.h"
|
||||
@ -92,18 +89,18 @@
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#define XO_DEFAULT_EID 2238
|
||||
#elif defined(__APPLE__)
|
||||
#elif defined(__macosx__)
|
||||
#define XO_DEFAULT_EID 63
|
||||
#else
|
||||
#define XO_DEFAULT_EID 32473 /* Fallback to the "example" number */
|
||||
#endif
|
||||
|
||||
#ifndef HOST_NAME_MAX
|
||||
#ifdef _POSIX_HOST_NAME_MAX
|
||||
#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
|
||||
#ifdef _SC_HOST_NAME_MAX
|
||||
#define HOST_NAME_MAX _SC_HOST_NAME_MAX
|
||||
#else
|
||||
#define HOST_NAME_MAX 255
|
||||
#endif /* _POSIX_HOST_NAME_MAX */
|
||||
#endif /* _SC_HOST_NAME_MAX */
|
||||
#endif /* HOST_NAME_MAX */
|
||||
|
||||
#ifndef UNUSED
|
||||
@ -587,13 +584,12 @@ xo_vsyslog (int pri, const char *name, const char *fmt, va_list vap)
|
||||
* Add HOSTNAME; we rely on gethostname and don't fluff with
|
||||
* ip addresses. Might need to revisit.....
|
||||
*/
|
||||
char hostname[HOST_NAME_MAX + 1];
|
||||
char hostname[HOST_NAME_MAX];
|
||||
hostname[0] = '\0';
|
||||
if (xo_unit_test)
|
||||
strcpy(hostname, "worker-host");
|
||||
else
|
||||
(void) gethostname(hostname, sizeof(hostname) - 1);
|
||||
hostname[HOST_NAME_MAX] = '\0'; /* Ensure NUL-terminated */
|
||||
(void) gethostname(hostname, sizeof(hostname));
|
||||
|
||||
xb.xb_curp += xo_snprintf(xb.xb_curp, xo_buf_left(&xb), "%s ",
|
||||
hostname[0] ? hostname : "-");
|
||||
|
@ -1,44 +0,0 @@
|
||||
Name: libxo
|
||||
Version: 1.6.0
|
||||
Release: 1%{?dist}
|
||||
Summary: The libxo library
|
||||
|
||||
Prefix: /usr
|
||||
|
||||
Vendor: Juniper Networks, Inc.
|
||||
Packager: Phil Shafer <phil@juniper.net>
|
||||
License: BSD
|
||||
|
||||
Group: Development/Libraries
|
||||
URL: https://github.com/Juniper/libxo
|
||||
Source0: https://github.com/Juniper/libxo/releases/1.6.0/libxo-1.6.0.tar.gz
|
||||
|
||||
|
||||
%description
|
||||
Welcome to libxo, a library that generates text, XML, JSON, and HTML
|
||||
from a single source code path.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
%configure
|
||||
make %{?_smp_mflags}
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
%make_install
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%post -p /sbin/ldconfig
|
||||
|
||||
%files
|
||||
%{_bindir}/*
|
||||
%{_includedir}/libxo/*
|
||||
%{_libdir}/*
|
||||
%{_datadir}/doc/libxo/*
|
||||
%docdir %{_datadir}/doc/libxo/*
|
||||
%{_mandir}/*/*
|
||||
%docdir %{_mandir}/*/*
|
@ -23,8 +23,7 @@ test_08.c \
|
||||
test_09.c \
|
||||
test_10.c \
|
||||
test_11.c \
|
||||
test_12.c \
|
||||
test_13.c
|
||||
test_12.c
|
||||
|
||||
test_01_test_SOURCES = test_01.c
|
||||
test_02_test_SOURCES = test_02.c
|
||||
@ -38,7 +37,6 @@ test_09_test_SOURCES = test_09.c
|
||||
test_10_test_SOURCES = test_10.c
|
||||
test_11_test_SOURCES = test_11.c
|
||||
test_12_test_SOURCES = test_12.c
|
||||
test_13_test_SOURCES = test_13.c
|
||||
|
||||
# TEST_CASES := $(shell cd ${srcdir} ; echo *.c )
|
||||
|
||||
@ -98,7 +96,7 @@ TEST_JIG = \
|
||||
|
||||
TEST_JIG2 = \
|
||||
echo "... $$test ... $$fmt ..."; \
|
||||
xoopts==warn,$$extra ; \
|
||||
xoopts==warn,$$csv ; \
|
||||
${TEST_JIG}; true;
|
||||
|
||||
TEST_FORMATS = T XP JP JPu HP X J H HIPx
|
||||
@ -121,20 +119,15 @@ test tests: ${bin_PROGRAMS}
|
||||
done) \
|
||||
done)
|
||||
-@ (${TEST_TRACE} test=test_01.c; base=test_01; \
|
||||
( fmt=Ecsv1; extra=encoder=csv ; \
|
||||
( fmt=Ecsv1; csv=encoder=csv ; \
|
||||
${TEST_JIG2} ); \
|
||||
( fmt=Ecsv2; extra=encoder=csv:path=top-level/data/item:no-header ; \
|
||||
( fmt=Ecsv2; csv=encoder=csv:path=top-level/data/item:no-header ; \
|
||||
${TEST_JIG2} ); \
|
||||
( fmt=Ecsv3; extra=@csv:path=item:leafs=sku.sold:no-quotes ; \
|
||||
${TEST_JIG2} ); \
|
||||
)
|
||||
-@ (${TEST_TRACE} test=test_12.c; base=test_12; \
|
||||
( fmt=XPmap; extra=xml,pretty,map-file=${srcdir}/test_12.map ; \
|
||||
${TEST_JIG2} ); \
|
||||
( fmt=JPmap; extra=json,pretty,map-file=${srcdir}/test_12.map ; \
|
||||
( fmt=Ecsv3; csv=@csv:path=item:leafs=sku.sold:no-quotes ; \
|
||||
${TEST_JIG2} ); \
|
||||
)
|
||||
|
||||
|
||||
one:
|
||||
-@(test=${TEST_CASE}; data=${TEST_DATA}; ${TEST_ONE} ; true)
|
||||
|
||||
@ -152,11 +145,6 @@ accept:
|
||||
${CP} out/$$base.$$fmt.out ${srcdir}/saved/$$base.$$fmt.out ; \
|
||||
${CP} out/$$base.$$fmt.err ${srcdir}/saved/$$base.$$fmt.err ; \
|
||||
done)
|
||||
-@(test=test_01.c; base=test_12; for fmt in XPmap JPmap ; 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)
|
||||
|
||||
.c.test:
|
||||
$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -o $@ $<
|
||||
|
@ -24,7 +24,6 @@ op string: [some-chaos] [[42]] [0]
|
||||
op attr: [test-attr] [attr-value] [0]
|
||||
op open_leaf_list: [sku] [] [0]
|
||||
op string: [sku] [gum-000-1412] [0x2010]
|
||||
op string: [sku] [sum-000-4121] [0x2010]
|
||||
op close_leaf_list: [sku] [] [0]
|
||||
op string: [host] [my-box] [0]
|
||||
op string: [domain] [example.com] [0]
|
||||
@ -202,15 +201,6 @@ op content: [mode_octal] [640] [0x8]
|
||||
op content: [links] [1] [0x1000]
|
||||
op string: [user] [user] [0x1000]
|
||||
op string: [group] [group] [0x1000]
|
||||
op content: [one] [1] [0]
|
||||
op content: [two] [2] [0]
|
||||
op content: [three] [3] [0]
|
||||
op content: [one] [1] [0]
|
||||
op content: [two] [2] [0]
|
||||
op content: [three] [3] [0]
|
||||
op content: [one] [1] [0]
|
||||
op content: [two] [2] [0]
|
||||
op content: [three] [3] [0]
|
||||
op close_container: [top-level] [] [0]
|
||||
op finish: [] [] [0]
|
||||
op flush: [] [] [0]
|
||||
|
File diff suppressed because one or more lines are too long
@ -58,7 +58,6 @@
|
||||
<div class="data" data-tag="some-chaos" data-xpath="/top-level/some-chaos">42
|
||||
</div>
|
||||
<div class="data" data-tag="sku" data-xpath="/top-level/sku" data-type="string" data-help="Stock Keeping Unit">gum-1412</div>
|
||||
<div class="data" data-tag="sku" data-xpath="/top-level/sku" data-type="string" data-help="Stock Keeping Unit">sum-4121</div>
|
||||
<div class="text">Connecting to </div>
|
||||
<div class="data" data-tag="host" data-xpath="/top-level/host">my-box</div>
|
||||
<div class="text">.</div>
|
||||
@ -436,27 +435,3 @@
|
||||
<div class="data" data-tag="group" data-xpath="/top-level/group">group </div>
|
||||
<div class="text"> </div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="text">Testing...</div>
|
||||
<div class="data" data-tag="one" data-xpath="/top-level/one">1</div>
|
||||
<div class="text">...</div>
|
||||
<div class="data" data-tag="two" data-xpath="/top-level/two">2</div>
|
||||
<div class="text">...</div>
|
||||
<div class="data" data-tag="three" data-xpath="/top-level/three">3</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="text">Testing...</div>
|
||||
<div class="data" data-tag="one" data-xpath="/top-level/one">1</div>
|
||||
<div class="text">...</div>
|
||||
<div class="data" data-tag="two" data-xpath="/top-level/two">2</div>
|
||||
<div class="text">...</div>
|
||||
<div class="data" data-tag="three" data-xpath="/top-level/three">3</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="text">Xesting...</div>
|
||||
<div class="data" data-tag="one" data-xpath="/top-level/one">1</div>
|
||||
<div class="text">...</div>
|
||||
<div class="data" data-tag="two" data-xpath="/top-level/two">2</div>
|
||||
<div class="text">...</div>
|
||||
<div class="data" data-tag="three" data-xpath="/top-level/three">3</div>
|
||||
</div>
|
||||
|
@ -58,7 +58,6 @@
|
||||
<div class="data" data-tag="some-chaos">42
|
||||
</div>
|
||||
<div class="data" data-tag="sku">gum-1412</div>
|
||||
<div class="data" data-tag="sku">sum-4121</div>
|
||||
<div class="text">Connecting to </div>
|
||||
<div class="data" data-tag="host">my-box</div>
|
||||
<div class="text">.</div>
|
||||
@ -436,27 +435,3 @@
|
||||
<div class="data" data-tag="group">group </div>
|
||||
<div class="text"> </div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="text">Testing...</div>
|
||||
<div class="data" data-tag="one">1</div>
|
||||
<div class="text">...</div>
|
||||
<div class="data" data-tag="two">2</div>
|
||||
<div class="text">...</div>
|
||||
<div class="data" data-tag="three">3</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="text">Testing...</div>
|
||||
<div class="data" data-tag="one">1</div>
|
||||
<div class="text">...</div>
|
||||
<div class="data" data-tag="two">2</div>
|
||||
<div class="text">...</div>
|
||||
<div class="data" data-tag="three">3</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="text">Xesting...</div>
|
||||
<div class="data" data-tag="one">1</div>
|
||||
<div class="text">...</div>
|
||||
<div class="data" data-tag="two">2</div>
|
||||
<div class="text">...</div>
|
||||
<div class="data" data-tag="three">3</div>
|
||||
</div>
|
||||
|
@ -1 +1 @@
|
||||
{"top-level": {"type":"ethernet","type":"bridge","type":"18u","type":24,"address":"0x0","port":1,"address":"0x0","port":1,"address":"0x0","port":1,"used-percent":12,"kve_start":"0xdeadbeef","kve_end":"0xcabb1e","host":"my-box","domain":"example.com","host":"my-box","domain":"example.com","label":"value","max-chaos":"very","min-chaos":42,"some-chaos":"[42]", "sku": ["gum-000-1412","sum-000-4121"],"host":"my-box","domain":"example.com", "data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17,"in-stock":14,"on-order":2}]}, "data2": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412.0,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85.0,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123.0,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17.0,"in-stock":14,"on-order":2}]}, "data3": {"item": [{"sku":"GRO-000-533","name":"fish","sold":1321.0,"in-stock":45,"on-order":1}]}, "data4": {"item": ["gum","rope","ladder","bolt","water"]}, "data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412,"on-order":10,"in-stock":54}, {"sku":"HRD-000-212","name":"rope","sold":85,"extra":"special","on-order":2,"in-stock":4}, {"sku":"HRD-000-517","name":"ladder","sold":0,"extra":"special","on-order":1,"in-stock":2}, {"sku":"HRD-000-632","name":"bolt","sold":4123,"on-order":42,"in-stock":144}, {"sku":"GRO-000-2331","name":"water","sold":17,"extra":"special","on-order":2,"in-stock":14}]},"cost":425,"cost":455,"mode":"mode","mode_octal":"octal","links":"links","user":"user","group":"group","pre":"that","links":3,"post":"this","mode":"/some/file","mode_octal":640,"links":1,"user":"user","group":"group","one":1,"two":2,"three":3,"one":1,"two":2,"three":3,"one":1,"two":2,"three":3}}
|
||||
{"top-level": {"type":"ethernet","type":"bridge","type":"18u","type":24,"address":"0x0","port":1,"address":"0x0","port":1,"address":"0x0","port":1,"used-percent":12,"kve_start":"0xdeadbeef","kve_end":"0xcabb1e","host":"my-box","domain":"example.com","host":"my-box","domain":"example.com","label":"value","max-chaos":"very","min-chaos":42,"some-chaos":"[42]", "sku": ["gum-000-1412"],"host":"my-box","domain":"example.com", "data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17,"in-stock":14,"on-order":2}]}, "data2": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412.0,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85.0,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123.0,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17.0,"in-stock":14,"on-order":2}]}, "data3": {"item": [{"sku":"GRO-000-533","name":"fish","sold":1321.0,"in-stock":45,"on-order":1}]}, "data4": {"item": ["gum","rope","ladder","bolt","water"]}, "data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412,"on-order":10,"in-stock":54}, {"sku":"HRD-000-212","name":"rope","sold":85,"extra":"special","on-order":2,"in-stock":4}, {"sku":"HRD-000-517","name":"ladder","sold":0,"extra":"special","on-order":1,"in-stock":2}, {"sku":"HRD-000-632","name":"bolt","sold":4123,"on-order":42,"in-stock":144}, {"sku":"GRO-000-2331","name":"water","sold":17,"extra":"special","on-order":2,"in-stock":14}]},"cost":425,"cost":455,"mode":"mode","mode_octal":"octal","links":"links","user":"user","group":"group","pre":"that","links":3,"post":"this","mode":"/some/file","mode_octal":640,"links":1,"user":"user","group":"group"}}
|
||||
|
@ -22,8 +22,7 @@
|
||||
"min-chaos": 42,
|
||||
"some-chaos": "[42]",
|
||||
"sku": [
|
||||
"gum-000-1412",
|
||||
"sum-000-4121"
|
||||
"gum-000-1412"
|
||||
],
|
||||
"host": "my-box",
|
||||
"domain": "example.com",
|
||||
@ -181,15 +180,6 @@
|
||||
"mode_octal": 640,
|
||||
"links": 1,
|
||||
"user": "user",
|
||||
"group": "group",
|
||||
"one": 1,
|
||||
"two": 2,
|
||||
"three": 3,
|
||||
"one": 1,
|
||||
"two": 2,
|
||||
"three": 3,
|
||||
"one": 1,
|
||||
"two": 2,
|
||||
"three": 3
|
||||
"group": "group"
|
||||
}
|
||||
}
|
||||
|
@ -22,8 +22,7 @@
|
||||
"min_chaos": 42,
|
||||
"some_chaos": "[42]",
|
||||
"sku": [
|
||||
"gum-000-1412",
|
||||
"sum-000-4121"
|
||||
"gum-000-1412"
|
||||
],
|
||||
"host": "my-box",
|
||||
"domain": "example.com",
|
||||
@ -181,15 +180,6 @@
|
||||
"mode_octal": 640,
|
||||
"links": 1,
|
||||
"user": "user",
|
||||
"group": "group",
|
||||
"one": 1,
|
||||
"two": 2,
|
||||
"three": 3,
|
||||
"one": 1,
|
||||
"two": 2,
|
||||
"three": 3,
|
||||
"one": 1,
|
||||
"two": 2,
|
||||
"three": 3
|
||||
"group": "group"
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ testing argument modifier with encoding to .example.com...
|
||||
Label text value
|
||||
My Title
|
||||
very 4242
|
||||
gum-1412sum-4121Connecting to my-box.example.com...
|
||||
gum-1412Connecting to my-box.example.com...
|
||||
Item Total Sold In Stock On Order SKU
|
||||
gum 1412 54 10 GRO-000-415
|
||||
rope 85 4 2 HRD-000-212
|
||||
@ -65,6 +65,3 @@ X XCost: 455
|
||||
links user group
|
||||
3 this
|
||||
/some/file 1 user group
|
||||
Testing...1...2...3
|
||||
Testing...1...2...3
|
||||
Xesting...1...2...3
|
||||
|
@ -1 +1 @@
|
||||
<top-level><type>ethernet</type><type>bridge</type><type>18u</type><type>24</type><address>0x0</address><port>1</port><address>0x0</address><port>1</port><address>0x0</address><port>1</port><used-percent>12</used-percent><kve_start>0xdeadbeef</kve_start><kve_end>0xcabb1e</kve_end><host>my-box</host><domain>example.com</domain><host>my-box</host><domain>example.com</domain><label>value</label><max-chaos>very</max-chaos><min-chaos>42</min-chaos><some-chaos>[42]</some-chaos><sku test-attr="attr-value">gum-000-1412</sku><sku>sum-000-4121</sku><host>my-box</host><domain>example.com</domain><data test="value"><item test2="value2"><sku test3="value3" key="key">GRO-000-415</sku><name key="key">gum</name><sold>1412</sold><in-stock>54</in-stock><on-order>10</on-order></item><item><sku test3="value3" key="key">HRD-000-212</sku><name key="key">rope</name><sold>85</sold><in-stock>4</in-stock><on-order>2</on-order></item><item><sku test3="value3" key="key">HRD-000-517</sku><name key="key">ladder</name><sold>0</sold><in-stock>2</in-stock><on-order>1</on-order></item><item><sku test3="value3" key="key">HRD-000-632</sku><name key="key">bolt</name><sold>4123</sold><in-stock>144</in-stock><on-order>42</on-order></item><item><sku test3="value3" key="key">GRO-000-2331</sku><name key="key">water</name><sold>17</sold><in-stock>14</in-stock><on-order>2</on-order></item></data><data2><item><sku key="key">GRO-000-415</sku><name key="key">gum</name><sold>1412.0</sold><in-stock>54</in-stock><on-order>10</on-order></item><item><sku key="key">HRD-000-212</sku><name key="key">rope</name><sold>85.0</sold><in-stock>4</in-stock><on-order>2</on-order></item><item><sku key="key">HRD-000-517</sku><name key="key">ladder</name><sold>0</sold><in-stock>2</in-stock><on-order>1</on-order></item><item><sku key="key">HRD-000-632</sku><name key="key">bolt</name><sold>4123.0</sold><in-stock>144</in-stock><on-order>42</on-order></item><item><sku key="key">GRO-000-2331</sku><name key="key">water</name><sold>17.0</sold><in-stock>14</in-stock><on-order>2</on-order></item></data2><data3><item><sku key="key">GRO-000-533</sku><name key="key">fish</name><sold>1321.0</sold><in-stock>45</in-stock><on-order>1</on-order></item></data3><data4><item test4="value4">gum</item><item test4="value4">rope</item><item test4="value4">ladder</item><item test4="value4">bolt</item><item test4="value4">water</item></data4><data test="value"><item test2="value2"><sku test3="value3" key="key">GRO-000-415</sku><name key="key">gum</name><sold>1412</sold><on-order>10</on-order><in-stock>54</in-stock></item><item><sku test3="value3" key="key">HRD-000-212</sku><name key="key">rope</name><sold>85</sold><extra>special</extra><on-order>2</on-order><in-stock>4</in-stock></item><item><sku test3="value3" key="key">HRD-000-517</sku><name key="key">ladder</name><sold>0</sold><extra>special</extra><on-order>1</on-order><in-stock>2</in-stock></item><item><sku test3="value3" key="key">HRD-000-632</sku><name key="key">bolt</name><sold>4123</sold><on-order>42</on-order><in-stock>144</in-stock></item><item><sku test3="value3" key="key">GRO-000-2331</sku><name key="key">water</name><sold>17</sold><extra>special</extra><on-order>2</on-order><in-stock>14</in-stock></item></data><cost>425</cost><cost>455</cost><mode>mode</mode><mode_octal>octal</mode_octal><links>links</links><user>user</user><group>group</group><pre>that</pre><links>3</links><post>this</post><mode>/some/file</mode><mode_octal>640</mode_octal><links>1</links><user>user</user><group>group</group><one>1</one><two>2</two><three>3</three><one>1</one><two>2</two><three>3</three><one>1</one><two>2</two><three>3</three></top-level>
|
||||
<top-level><type>ethernet</type><type>bridge</type><type>18u</type><type>24</type><address>0x0</address><port>1</port><address>0x0</address><port>1</port><address>0x0</address><port>1</port><used-percent>12</used-percent><kve_start>0xdeadbeef</kve_start><kve_end>0xcabb1e</kve_end><host>my-box</host><domain>example.com</domain><host>my-box</host><domain>example.com</domain><label>value</label><max-chaos>very</max-chaos><min-chaos>42</min-chaos><some-chaos>[42]</some-chaos><sku test-attr="attr-value">gum-000-1412</sku><host>my-box</host><domain>example.com</domain><data test="value"><item test2="value2"><sku test3="value3" key="key">GRO-000-415</sku><name key="key">gum</name><sold>1412</sold><in-stock>54</in-stock><on-order>10</on-order></item><item><sku test3="value3" key="key">HRD-000-212</sku><name key="key">rope</name><sold>85</sold><in-stock>4</in-stock><on-order>2</on-order></item><item><sku test3="value3" key="key">HRD-000-517</sku><name key="key">ladder</name><sold>0</sold><in-stock>2</in-stock><on-order>1</on-order></item><item><sku test3="value3" key="key">HRD-000-632</sku><name key="key">bolt</name><sold>4123</sold><in-stock>144</in-stock><on-order>42</on-order></item><item><sku test3="value3" key="key">GRO-000-2331</sku><name key="key">water</name><sold>17</sold><in-stock>14</in-stock><on-order>2</on-order></item></data><data2><item><sku key="key">GRO-000-415</sku><name key="key">gum</name><sold>1412.0</sold><in-stock>54</in-stock><on-order>10</on-order></item><item><sku key="key">HRD-000-212</sku><name key="key">rope</name><sold>85.0</sold><in-stock>4</in-stock><on-order>2</on-order></item><item><sku key="key">HRD-000-517</sku><name key="key">ladder</name><sold>0</sold><in-stock>2</in-stock><on-order>1</on-order></item><item><sku key="key">HRD-000-632</sku><name key="key">bolt</name><sold>4123.0</sold><in-stock>144</in-stock><on-order>42</on-order></item><item><sku key="key">GRO-000-2331</sku><name key="key">water</name><sold>17.0</sold><in-stock>14</in-stock><on-order>2</on-order></item></data2><data3><item><sku key="key">GRO-000-533</sku><name key="key">fish</name><sold>1321.0</sold><in-stock>45</in-stock><on-order>1</on-order></item></data3><data4><item test4="value4">gum</item><item test4="value4">rope</item><item test4="value4">ladder</item><item test4="value4">bolt</item><item test4="value4">water</item></data4><data test="value"><item test2="value2"><sku test3="value3" key="key">GRO-000-415</sku><name key="key">gum</name><sold>1412</sold><on-order>10</on-order><in-stock>54</in-stock></item><item><sku test3="value3" key="key">HRD-000-212</sku><name key="key">rope</name><sold>85</sold><extra>special</extra><on-order>2</on-order><in-stock>4</in-stock></item><item><sku test3="value3" key="key">HRD-000-517</sku><name key="key">ladder</name><sold>0</sold><extra>special</extra><on-order>1</on-order><in-stock>2</in-stock></item><item><sku test3="value3" key="key">HRD-000-632</sku><name key="key">bolt</name><sold>4123</sold><on-order>42</on-order><in-stock>144</in-stock></item><item><sku test3="value3" key="key">GRO-000-2331</sku><name key="key">water</name><sold>17</sold><extra>special</extra><on-order>2</on-order><in-stock>14</in-stock></item></data><cost>425</cost><cost>455</cost><mode>mode</mode><mode_octal>octal</mode_octal><links>links</links><user>user</user><group>group</group><pre>that</pre><links>3</links><post>this</post><mode>/some/file</mode><mode_octal>640</mode_octal><links>1</links><user>user</user><group>group</group></top-level>
|
@ -21,7 +21,6 @@
|
||||
<min-chaos>42</min-chaos>
|
||||
<some-chaos>[42]</some-chaos>
|
||||
<sku test-attr="attr-value">gum-000-1412</sku>
|
||||
<sku>sum-000-4121</sku>
|
||||
<host>my-box</host>
|
||||
<domain>example.com</domain>
|
||||
<data test="value">
|
||||
@ -169,13 +168,4 @@
|
||||
<links>1</links>
|
||||
<user>user</user>
|
||||
<group>group</group>
|
||||
<one>1</one>
|
||||
<two>2</two>
|
||||
<three>3</three>
|
||||
<one>1</one>
|
||||
<two>2</two>
|
||||
<three>3</three>
|
||||
<one>1</one>
|
||||
<two>2</two>
|
||||
<three>3</three>
|
||||
</top-level>
|
||||
|
38
tests/core/saved/test_01.out
Normal file
38
tests/core/saved/test_01.out
Normal file
@ -0,0 +1,38 @@
|
||||
Item Total Sold In Stock On Order SKU
|
||||
gum 1412 54 10 GRO-000-415
|
||||
rope 85 4 2 HRD-000-212
|
||||
ladder 0 2 1 HRD-000-517
|
||||
bolt 4123 144 42 HRD-000-632
|
||||
water 17 14 2 GRO-000-2331
|
||||
|
||||
|
||||
Item 'gum':
|
||||
Total sold: 1412.0
|
||||
In stock: 54
|
||||
On order: 10
|
||||
SKU: GRO-000-415
|
||||
Item 'rope':
|
||||
Total sold: 85.0
|
||||
In stock: 4
|
||||
On order: 2
|
||||
SKU: HRD-000-212
|
||||
Item 'ladder':
|
||||
Total sold: 0
|
||||
In stock: 2
|
||||
On order: 1
|
||||
SKU: HRD-000-517
|
||||
Item 'bolt':
|
||||
Total sold: 4123.0
|
||||
In stock: 144
|
||||
On order: 42
|
||||
SKU: HRD-000-632
|
||||
Item 'water':
|
||||
Total sold: 17.0
|
||||
In stock: 14
|
||||
On order: 2
|
||||
SKU: GRO-000-2331
|
||||
Item 'fish':
|
||||
Total sold: 1321.0
|
||||
In stock: 45
|
||||
On order: 1
|
||||
SKU: GRO-000-533
|
38
tests/core/saved/test_02.out
Normal file
38
tests/core/saved/test_02.out
Normal file
@ -0,0 +1,38 @@
|
||||
Item Total Sold In Stock On Order SKU
|
||||
gum 1412 54 10 GRO-000-415
|
||||
rope 85 4 2 HRD-000-212
|
||||
ladder 0 2 1 HRD-000-517
|
||||
bolt 4123 144 42 HRD-000-632
|
||||
water 17 14 2 GRO-000-2331
|
||||
|
||||
|
||||
Item 'gum':
|
||||
Total sold: 1412.0
|
||||
In stock: 54
|
||||
On order: 10
|
||||
SKU: GRO-000-415
|
||||
Item 'rope':
|
||||
Total sold: 85.0
|
||||
In stock: 4
|
||||
On order: 2
|
||||
SKU: HRD-000-212
|
||||
Item 'ladder':
|
||||
Total sold: 0
|
||||
In stock: 2
|
||||
On order: 1
|
||||
SKU: HRD-000-517
|
||||
Item 'bolt':
|
||||
Total sold: 4123.0
|
||||
In stock: 144
|
||||
On order: 42
|
||||
SKU: HRD-000-632
|
||||
Item 'water':
|
||||
Total sold: 17.0
|
||||
In stock: 14
|
||||
On order: 2
|
||||
SKU: GRO-000-2331
|
||||
Item 'fish':
|
||||
Total sold: 1321.0
|
||||
In stock: 45
|
||||
On order: 1
|
||||
SKU: GRO-000-533
|
3
tests/core/saved/test_03.out
Normal file
3
tests/core/saved/test_03.out
Normal file
@ -0,0 +1,3 @@
|
||||
Terry Jones works in dept #660
|
||||
Leslie Patterson works in dept #341
|
||||
Ashley Smith works in dept #1440
|
38
tests/core/saved/test_10.out
Normal file
38
tests/core/saved/test_10.out
Normal file
@ -0,0 +1,38 @@
|
||||
Item Total Sold In Stock On Order SKU
|
||||
gum 1412 54 10 GRO-000-415
|
||||
rope 85 4 2 HRD-000-212
|
||||
ladder 0 2 1 HRD-000-517
|
||||
bolt 4123 144 42 HRD-000-632
|
||||
water 17 14 2 GRO-000-2331
|
||||
|
||||
|
||||
Item 'gum':
|
||||
Total sold: 1412.0
|
||||
In stock: 54
|
||||
On order: 10
|
||||
SKU: GRO-000-415
|
||||
Item 'rope':
|
||||
Total sold: 85.0
|
||||
In stock: 4
|
||||
On order: 2
|
||||
SKU: HRD-000-212
|
||||
Item 'ladder':
|
||||
Total sold: 0
|
||||
In stock: 2
|
||||
On order: 1
|
||||
SKU: HRD-000-517
|
||||
Item 'bolt':
|
||||
Total sold: 4123.0
|
||||
In stock: 144
|
||||
On order: 42
|
||||
SKU: HRD-000-632
|
||||
Item 'water':
|
||||
Total sold: 17.0
|
||||
In stock: 14
|
||||
On order: 2
|
||||
SKU: GRO-000-2331
|
||||
Item 'fish':
|
||||
Total sold: 1321.0
|
||||
In stock: 45
|
||||
On order: 1
|
||||
SKU: GRO-000-533
|
@ -83,16 +83,12 @@ op content: [time] [2:15] [0]
|
||||
op string: [hand] [left] [0]
|
||||
op string: [color] [blue] [0]
|
||||
op content: [time] [3:45] [0]
|
||||
op close_instance: [thing] [] [0]
|
||||
op close_list: [thing] [] [0]
|
||||
op open_container: [2by4] [] [0x4040010]
|
||||
op string: [4x4] [truck] [0]
|
||||
op string: [2morrow] [tomorrow] [0]
|
||||
op close_container: [2by4] [] [0]
|
||||
op open_container: [tagÜÖÄ] [] [0x4040010]
|
||||
op string: [cölor] [blue] [0]
|
||||
op string: [säfe] [yes] [0]
|
||||
op close_container: [tagÜÖÄ] [] [0]
|
||||
op close_instance: [thing] [] [0]
|
||||
op close_list: [thing] [] [0]
|
||||
op close_container: [data] [] [0]
|
||||
op close_container: [top] [] [0]
|
||||
op finish: [] [] [0]
|
||||
|
File diff suppressed because one or more lines are too long
@ -169,13 +169,7 @@
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="text">There is </div>
|
||||
<div class="data" data-tag="4x4" data-xpath="/top/data/2by4/4x4">truck</div>
|
||||
<div class="data" data-tag="4x4" data-xpath="/top/data/thing[name = 'thing']/2by4/4x4">truck</div>
|
||||
<div class="text"> in </div>
|
||||
<div class="data" data-tag="2morrow" data-xpath="/top/data/2by4/2morrow">tomorrow</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="text">The </div>
|
||||
<div class="data" data-tag="cölor" data-xpath="/top/data/tagÜÖÄ/cölor">blue</div>
|
||||
<div class="text"> is </div>
|
||||
<div class="data" data-tag="säfe" data-xpath="/top/data/tagÜÖÄ/säfe">yes</div>
|
||||
<div class="data" data-tag="2morrow" data-xpath="/top/data/thing[name = 'thing']/2by4/2morrow">tomorrow</div>
|
||||
</div>
|
||||
|
@ -173,9 +173,3 @@
|
||||
<div class="text"> in </div>
|
||||
<div class="data" data-tag="2morrow">tomorrow</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="text">The </div>
|
||||
<div class="data" data-tag="cölor">blue</div>
|
||||
<div class="text"> is </div>
|
||||
<div class="data" data-tag="säfe">yes</div>
|
||||
</div>
|
||||
|
@ -1 +1 @@
|
||||
{"top": {"data": {"animal":"fish","animal":"fish", "thing": [{"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}], "2by4": {"4x4":"truck","2morrow":"tomorrow"}, "tagÜÖÄ": {"cölor":"blue","säfe":"yes"}}}}
|
||||
{"top": {"data": {"animal":"fish","animal":"fish", "thing": [{"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45", "2by4": {"4x4":"truck","2morrow":"tomorrow"}}]}}}
|
||||
|
@ -82,17 +82,13 @@
|
||||
"time": "2:15",
|
||||
"hand": "left",
|
||||
"color": "blue",
|
||||
"time": "3:45"
|
||||
"time": "3:45",
|
||||
"2by4": {
|
||||
"4x4": "truck",
|
||||
"2morrow": "tomorrow"
|
||||
}
|
||||
}
|
||||
],
|
||||
"2by4": {
|
||||
"4x4": "truck",
|
||||
"2morrow": "tomorrow"
|
||||
},
|
||||
"tagÜÖÄ": {
|
||||
"cölor": "blue",
|
||||
"säfe": "yes"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -82,17 +82,13 @@
|
||||
"time": "2:15",
|
||||
"hand": "left",
|
||||
"color": "blue",
|
||||
"time": "3:45"
|
||||
"time": "3:45",
|
||||
"2by4": {
|
||||
"4x4": "truck",
|
||||
"2morrow": "tomorrow"
|
||||
}
|
||||
}
|
||||
],
|
||||
"2by4": {
|
||||
"4x4": "truck",
|
||||
"2morrow": "tomorrow"
|
||||
},
|
||||
"tagÜÖÄ": {
|
||||
"cölor": "blue",
|
||||
"säfe": "yes"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,4 +21,3 @@ My [31mleft[0m hand is [34mblue[0m til 03:45
|
||||
The [31mthing[0m is [32mgreen[0m til 02:15
|
||||
My [31mleft[0m hand is [34mblue[0m til 03:45
|
||||
There is truck in tomorrow
|
||||
The blue is yes
|
||||
|
@ -1 +1 @@
|
||||
<top><data><animal>fish</animal><animal>fish</animal><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><_2by4><_4x4>truck</_4x4><_2morrow>tomorrow</_2morrow></_2by4><tagÜÖÄ><cölor>blue</cölor><säfe>yes</säfe></tagÜÖÄ></data></top>
|
||||
<top><data><animal>fish</animal><animal>fish</animal><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time><_2by4><_4x4>truck</_4x4><_2morrow>tomorrow</_2morrow></_2by4></thing></data></top>
|
@ -81,14 +81,10 @@
|
||||
<hand>left</hand>
|
||||
<color>blue</color>
|
||||
<time>3:45</time>
|
||||
<_2by4>
|
||||
<_4x4>truck</_4x4>
|
||||
<_2morrow>tomorrow</_2morrow>
|
||||
</_2by4>
|
||||
</thing>
|
||||
<_2by4>
|
||||
<_4x4>truck</_4x4>
|
||||
<_2morrow>tomorrow</_2morrow>
|
||||
</_2by4>
|
||||
<tagÜÖÄ>
|
||||
<cölor>blue</cölor>
|
||||
<säfe>yes</säfe>
|
||||
</tagÜÖÄ>
|
||||
</data>
|
||||
</top>
|
||||
|
@ -1,170 +0,0 @@
|
||||
op create: [test] [] [0]
|
||||
op open_container: [top] [] [0x4040010]
|
||||
op open_container: [data] [] [0x4040010]
|
||||
op open_list: [entry] [] [0]
|
||||
op open_instance: [entry] [] [0x44040010]
|
||||
op string: [name] [xx-00000000] [0x88]
|
||||
op content: [inode] [12] [0x1000]
|
||||
op content: [blocks] [1234] [0x1000]
|
||||
op string: [mode] [mode] [0x1000]
|
||||
op content: [mode_octal] [660] [0x8]
|
||||
op content: [links] [12] [0x1000]
|
||||
op string: [user] [phil] [0x1000]
|
||||
op string: [group] [phil] [0x1000]
|
||||
op string: [type] [regular] [0x8]
|
||||
op string: [flags] [123] [0]
|
||||
op string: [label] [1234] [0x1000]
|
||||
op content: [size] [12345] [0]
|
||||
op attr: [value] [1644355825] [0]
|
||||
op content: [modify-time] [1644355825] [0x28]
|
||||
op close_instance: [entry] [] [0]
|
||||
op open_instance: [entry] [] [0x44040010]
|
||||
op string: [name] [xx-00000001] [0x88]
|
||||
op content: [inode] [12] [0x1000]
|
||||
op content: [blocks] [1234] [0x1000]
|
||||
op string: [mode] [mode] [0x1000]
|
||||
op content: [mode_octal] [660] [0x8]
|
||||
op content: [links] [12] [0x1000]
|
||||
op string: [user] [phil] [0x1000]
|
||||
op string: [group] [phil] [0x1000]
|
||||
op string: [type] [regular] [0x8]
|
||||
op string: [flags] [123] [0]
|
||||
op string: [label] [1234] [0x1000]
|
||||
op content: [size] [12345] [0]
|
||||
op attr: [value] [1644355825] [0]
|
||||
op content: [modify-time] [1644355825] [0x28]
|
||||
op close_instance: [entry] [] [0]
|
||||
op open_instance: [entry] [] [0x44040010]
|
||||
op string: [name] [xx-00000002] [0x88]
|
||||
op content: [inode] [12] [0x1000]
|
||||
op content: [blocks] [1234] [0x1000]
|
||||
op string: [mode] [mode] [0x1000]
|
||||
op content: [mode_octal] [660] [0x8]
|
||||
op content: [links] [12] [0x1000]
|
||||
op string: [user] [phil] [0x1000]
|
||||
op string: [group] [phil] [0x1000]
|
||||
op string: [type] [regular] [0x8]
|
||||
op string: [flags] [123] [0]
|
||||
op string: [label] [1234] [0x1000]
|
||||
op content: [size] [12345] [0]
|
||||
op attr: [value] [1644355825] [0]
|
||||
op content: [modify-time] [1644355825] [0x28]
|
||||
op close_instance: [entry] [] [0]
|
||||
op open_instance: [entry] [] [0x44040010]
|
||||
op string: [name] [xx-00000003] [0x88]
|
||||
op content: [inode] [12] [0x1000]
|
||||
op content: [blocks] [1234] [0x1000]
|
||||
op string: [mode] [mode] [0x1000]
|
||||
op content: [mode_octal] [660] [0x8]
|
||||
op content: [links] [12] [0x1000]
|
||||
op string: [user] [phil] [0x1000]
|
||||
op string: [group] [phil] [0x1000]
|
||||
op string: [type] [regular] [0x8]
|
||||
op string: [flags] [123] [0]
|
||||
op string: [label] [1234] [0x1000]
|
||||
op content: [size] [12345] [0]
|
||||
op attr: [value] [1644355825] [0]
|
||||
op content: [modify-time] [1644355825] [0x28]
|
||||
op close_instance: [entry] [] [0]
|
||||
op open_instance: [entry] [] [0x44040010]
|
||||
op string: [name] [xx-00000004] [0x88]
|
||||
op content: [inode] [12] [0x1000]
|
||||
op content: [blocks] [1234] [0x1000]
|
||||
op string: [mode] [mode] [0x1000]
|
||||
op content: [mode_octal] [660] [0x8]
|
||||
op content: [links] [12] [0x1000]
|
||||
op string: [user] [phil] [0x1000]
|
||||
op string: [group] [phil] [0x1000]
|
||||
op string: [type] [regular] [0x8]
|
||||
op string: [flags] [123] [0]
|
||||
op string: [label] [1234] [0x1000]
|
||||
op content: [size] [12345] [0]
|
||||
op attr: [value] [1644355825] [0]
|
||||
op content: [modify-time] [1644355825] [0x28]
|
||||
op close_instance: [entry] [] [0]
|
||||
op open_instance: [entry] [] [0x44040010]
|
||||
op string: [name] [xx-00000005] [0x88]
|
||||
op content: [inode] [12] [0x1000]
|
||||
op content: [blocks] [1234] [0x1000]
|
||||
op string: [mode] [mode] [0x1000]
|
||||
op content: [mode_octal] [660] [0x8]
|
||||
op content: [links] [12] [0x1000]
|
||||
op string: [user] [phil] [0x1000]
|
||||
op string: [group] [phil] [0x1000]
|
||||
op string: [type] [regular] [0x8]
|
||||
op string: [flags] [123] [0]
|
||||
op string: [label] [1234] [0x1000]
|
||||
op content: [size] [12345] [0]
|
||||
op attr: [value] [1644355825] [0]
|
||||
op content: [modify-time] [1644355825] [0x28]
|
||||
op close_instance: [entry] [] [0]
|
||||
op open_instance: [entry] [] [0x44040010]
|
||||
op string: [name] [xx-00000006] [0x88]
|
||||
op content: [inode] [12] [0x1000]
|
||||
op content: [blocks] [1234] [0x1000]
|
||||
op string: [mode] [mode] [0x1000]
|
||||
op content: [mode_octal] [660] [0x8]
|
||||
op content: [links] [12] [0x1000]
|
||||
op string: [user] [phil] [0x1000]
|
||||
op string: [group] [phil] [0x1000]
|
||||
op string: [type] [regular] [0x8]
|
||||
op string: [flags] [123] [0]
|
||||
op string: [label] [1234] [0x1000]
|
||||
op content: [size] [12345] [0]
|
||||
op attr: [value] [1644355825] [0]
|
||||
op content: [modify-time] [1644355825] [0x28]
|
||||
op close_instance: [entry] [] [0]
|
||||
op open_instance: [entry] [] [0x44040010]
|
||||
op string: [name] [xx-00000007] [0x88]
|
||||
op content: [inode] [12] [0x1000]
|
||||
op content: [blocks] [1234] [0x1000]
|
||||
op string: [mode] [mode] [0x1000]
|
||||
op content: [mode_octal] [660] [0x8]
|
||||
op content: [links] [12] [0x1000]
|
||||
op string: [user] [phil] [0x1000]
|
||||
op string: [group] [phil] [0x1000]
|
||||
op string: [type] [regular] [0x8]
|
||||
op string: [flags] [123] [0]
|
||||
op string: [label] [1234] [0x1000]
|
||||
op content: [size] [12345] [0]
|
||||
op attr: [value] [1644355825] [0]
|
||||
op content: [modify-time] [1644355825] [0x28]
|
||||
op close_instance: [entry] [] [0]
|
||||
op open_instance: [entry] [] [0x44040010]
|
||||
op string: [name] [xx-00000008] [0x88]
|
||||
op content: [inode] [12] [0x1000]
|
||||
op content: [blocks] [1234] [0x1000]
|
||||
op string: [mode] [mode] [0x1000]
|
||||
op content: [mode_octal] [660] [0x8]
|
||||
op content: [links] [12] [0x1000]
|
||||
op string: [user] [phil] [0x1000]
|
||||
op string: [group] [phil] [0x1000]
|
||||
op string: [type] [regular] [0x8]
|
||||
op string: [flags] [123] [0]
|
||||
op string: [label] [1234] [0x1000]
|
||||
op content: [size] [12345] [0]
|
||||
op attr: [value] [1644355825] [0]
|
||||
op content: [modify-time] [1644355825] [0x28]
|
||||
op close_instance: [entry] [] [0]
|
||||
op open_instance: [entry] [] [0x44040010]
|
||||
op string: [name] [xx-00000009] [0x88]
|
||||
op content: [inode] [12] [0x1000]
|
||||
op content: [blocks] [1234] [0x1000]
|
||||
op string: [mode] [mode] [0x1000]
|
||||
op content: [mode_octal] [660] [0x8]
|
||||
op content: [links] [12] [0x1000]
|
||||
op string: [user] [phil] [0x1000]
|
||||
op string: [group] [phil] [0x1000]
|
||||
op string: [type] [regular] [0x8]
|
||||
op string: [flags] [123] [0]
|
||||
op string: [label] [1234] [0x1000]
|
||||
op content: [size] [12345] [0]
|
||||
op attr: [value] [1644355825] [0]
|
||||
op content: [modify-time] [1644355825] [0x28]
|
||||
op close_instance: [entry] [] [0]
|
||||
op close_list: [entry] [] [0]
|
||||
op content: [hits] [72] [0]
|
||||
op close_container: [data] [] [0]
|
||||
op close_container: [top] [] [0]
|
||||
op finish: [] [] [0]
|
||||
op flush: [] [] [0]
|
File diff suppressed because one or more lines are too long
@ -1,236 +0,0 @@
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000000']/inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000000']/blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000000']/mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000000']/links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000000']/user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000000']/group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000000']/flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000000']/label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000000']/size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000000']/modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000000</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000001']/inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000001']/blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000001']/mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000001']/links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000001']/user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000001']/group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000001']/flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000001']/label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000001']/size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000001']/modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000001</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000002']/inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000002']/blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000002']/mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000002']/links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000002']/user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000002']/group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000002']/flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000002']/label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000002']/size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000002']/modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000002</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000003']/inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000003']/blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000003']/mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000003']/links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000003']/user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000003']/group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000003']/flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000003']/label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000003']/size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000003']/modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000003</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000004']/inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000004']/blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000004']/mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000004']/links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000004']/user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000004']/group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000004']/flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000004']/label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000004']/size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000004']/modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000004</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000005']/inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000005']/blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000005']/mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000005']/links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000005']/user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000005']/group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000005']/flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000005']/label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000005']/size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000005']/modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000005</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000006']/inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000006']/blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000006']/mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000006']/links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000006']/user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000006']/group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000006']/flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000006']/label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000006']/size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000006']/modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000006</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000007']/inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000007']/blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000007']/mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000007']/links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000007']/user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000007']/group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000007']/flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000007']/label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000007']/size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000007']/modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000007</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000008']/inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000008']/blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000008']/mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000008']/links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000008']/user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000008']/group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000008']/flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000008']/label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000008']/size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000008']/modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000008</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000009']/inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000009']/blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000009']/mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000009']/links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000009']/user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000009']/group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000009']/flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000009']/label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000009']/size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000009']/modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000009</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="label">hits</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="hits" data-xpath="/top/data/hits">72</div>
|
||||
</div>
|
@ -1,236 +0,0 @@
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name">xx-00000000</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name">xx-00000001</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name">xx-00000002</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name">xx-00000003</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name">xx-00000004</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name">xx-00000005</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name">xx-00000006</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name">xx-00000007</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name">xx-00000008</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="data" data-tag="inode"> 12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="blocks">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="mode">mode</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="links">12</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="user">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="group">phil</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="flags">123</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="label">1234</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="size">12345</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
|
||||
<div class="text"> </div>
|
||||
<div class="data" data-tag="name">xx-00000009</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="label">hits</div>
|
||||
<div class="decoration">:</div>
|
||||
<div class="padding"> </div>
|
||||
<div class="data" data-tag="hits">72</div>
|
||||
</div>
|
@ -1 +0,0 @@
|
||||
{"top": {"data": {"entry": [{"name":"xx-00000000","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}, {"name":"xx-00000001","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}, {"name":"xx-00000002","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}, {"name":"xx-00000003","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}, {"name":"xx-00000004","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}, {"name":"xx-00000005","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}, {"name":"xx-00000006","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}, {"name":"xx-00000007","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}, {"name":"xx-00000008","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}, {"name":"xx-00000009","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}],"hits":72}}}
|
@ -1,159 +0,0 @@
|
||||
{
|
||||
"top": {
|
||||
"data": {
|
||||
"entry": [
|
||||
{
|
||||
"name": "xx-00000000",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify-time": 1644355825
|
||||
},
|
||||
{
|
||||
"name": "xx-00000001",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify-time": 1644355825
|
||||
},
|
||||
{
|
||||
"name": "xx-00000002",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify-time": 1644355825
|
||||
},
|
||||
{
|
||||
"name": "xx-00000003",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify-time": 1644355825
|
||||
},
|
||||
{
|
||||
"name": "xx-00000004",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify-time": 1644355825
|
||||
},
|
||||
{
|
||||
"name": "xx-00000005",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify-time": 1644355825
|
||||
},
|
||||
{
|
||||
"name": "xx-00000006",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify-time": 1644355825
|
||||
},
|
||||
{
|
||||
"name": "xx-00000007",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify-time": 1644355825
|
||||
},
|
||||
{
|
||||
"name": "xx-00000008",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify-time": 1644355825
|
||||
},
|
||||
{
|
||||
"name": "xx-00000009",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify-time": 1644355825
|
||||
}
|
||||
],
|
||||
"hits": 72
|
||||
}
|
||||
}
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
{
|
||||
"top": {
|
||||
"data": {
|
||||
"entry": [
|
||||
{
|
||||
"name": "xx-00000000",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify_time": 1644355825
|
||||
},
|
||||
{
|
||||
"name": "xx-00000001",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify_time": 1644355825
|
||||
},
|
||||
{
|
||||
"name": "xx-00000002",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify_time": 1644355825
|
||||
},
|
||||
{
|
||||
"name": "xx-00000003",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify_time": 1644355825
|
||||
},
|
||||
{
|
||||
"name": "xx-00000004",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify_time": 1644355825
|
||||
},
|
||||
{
|
||||
"name": "xx-00000005",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify_time": 1644355825
|
||||
},
|
||||
{
|
||||
"name": "xx-00000006",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify_time": 1644355825
|
||||
},
|
||||
{
|
||||
"name": "xx-00000007",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify_time": 1644355825
|
||||
},
|
||||
{
|
||||
"name": "xx-00000008",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify_time": 1644355825
|
||||
},
|
||||
{
|
||||
"name": "xx-00000009",
|
||||
"inode": 12,
|
||||
"blocks": 1234,
|
||||
"mode": "mode",
|
||||
"mode_octal": 660,
|
||||
"links": 12,
|
||||
"user": "phil",
|
||||
"group": "phil",
|
||||
"type": "regular",
|
||||
"flags": "123",
|
||||
"label": "1234",
|
||||
"size": 12345,
|
||||
"modify_time": 1644355825
|
||||
}
|
||||
],
|
||||
"hits": 72
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000000
|
||||
12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000001
|
||||
12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000002
|
||||
12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000003
|
||||
12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000004
|
||||
12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000005
|
||||
12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000006
|
||||
12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000007
|
||||
12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000008
|
||||
12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000009
|
||||
hits: 72
|
@ -1 +0,0 @@
|
||||
<top><data><entry><name>xx-00000000</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><entry><name>xx-00000001</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><entry><name>xx-00000002</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><entry><name>xx-00000003</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><entry><name>xx-00000004</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><entry><name>xx-00000005</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><entry><name>xx-00000006</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><entry><name>xx-00000007</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><entry><name>xx-00000008</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><entry><name>xx-00000009</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><hits>72</hits></data></top>
|
@ -1,155 +0,0 @@
|
||||
<top>
|
||||
<data>
|
||||
<entry>
|
||||
<name>xx-00000000</name>
|
||||
<inode>12</inode>
|
||||
<blocks>1234</blocks>
|
||||
<mode>mode</mode>
|
||||
<mode_octal>660</mode_octal>
|
||||
<links>12</links>
|
||||
<user>phil</user>
|
||||
<group>phil</group>
|
||||
<type>regular</type>
|
||||
<flags>123</flags>
|
||||
<label>1234</label>
|
||||
<size>12345</size>
|
||||
<modify-time value="1644355825">1644355825</modify-time>
|
||||
</entry>
|
||||
<entry>
|
||||
<name>xx-00000001</name>
|
||||
<inode>12</inode>
|
||||
<blocks>1234</blocks>
|
||||
<mode>mode</mode>
|
||||
<mode_octal>660</mode_octal>
|
||||
<links>12</links>
|
||||
<user>phil</user>
|
||||
<group>phil</group>
|
||||
<type>regular</type>
|
||||
<flags>123</flags>
|
||||
<label>1234</label>
|
||||
<size>12345</size>
|
||||
<modify-time value="1644355825">1644355825</modify-time>
|
||||
</entry>
|
||||
<entry>
|
||||
<name>xx-00000002</name>
|
||||
<inode>12</inode>
|
||||
<blocks>1234</blocks>
|
||||
<mode>mode</mode>
|
||||
<mode_octal>660</mode_octal>
|
||||
<links>12</links>
|
||||
<user>phil</user>
|
||||
<group>phil</group>
|
||||
<type>regular</type>
|
||||
<flags>123</flags>
|
||||
<label>1234</label>
|
||||
<size>12345</size>
|
||||
<modify-time value="1644355825">1644355825</modify-time>
|
||||
</entry>
|
||||
<entry>
|
||||
<name>xx-00000003</name>
|
||||
<inode>12</inode>
|
||||
<blocks>1234</blocks>
|
||||
<mode>mode</mode>
|
||||
<mode_octal>660</mode_octal>
|
||||
<links>12</links>
|
||||
<user>phil</user>
|
||||
<group>phil</group>
|
||||
<type>regular</type>
|
||||
<flags>123</flags>
|
||||
<label>1234</label>
|
||||
<size>12345</size>
|
||||
<modify-time value="1644355825">1644355825</modify-time>
|
||||
</entry>
|
||||
<entry>
|
||||
<name>xx-00000004</name>
|
||||
<inode>12</inode>
|
||||
<blocks>1234</blocks>
|
||||
<mode>mode</mode>
|
||||
<mode_octal>660</mode_octal>
|
||||
<links>12</links>
|
||||
<user>phil</user>
|
||||
<group>phil</group>
|
||||
<type>regular</type>
|
||||
<flags>123</flags>
|
||||
<label>1234</label>
|
||||
<size>12345</size>
|
||||
<modify-time value="1644355825">1644355825</modify-time>
|
||||
</entry>
|
||||
<entry>
|
||||
<name>xx-00000005</name>
|
||||
<inode>12</inode>
|
||||
<blocks>1234</blocks>
|
||||
<mode>mode</mode>
|
||||
<mode_octal>660</mode_octal>
|
||||
<links>12</links>
|
||||
<user>phil</user>
|
||||
<group>phil</group>
|
||||
<type>regular</type>
|
||||
<flags>123</flags>
|
||||
<label>1234</label>
|
||||
<size>12345</size>
|
||||
<modify-time value="1644355825">1644355825</modify-time>
|
||||
</entry>
|
||||
<entry>
|
||||
<name>xx-00000006</name>
|
||||
<inode>12</inode>
|
||||
<blocks>1234</blocks>
|
||||
<mode>mode</mode>
|
||||
<mode_octal>660</mode_octal>
|
||||
<links>12</links>
|
||||
<user>phil</user>
|
||||
<group>phil</group>
|
||||
<type>regular</type>
|
||||
<flags>123</flags>
|
||||
<label>1234</label>
|
||||
<size>12345</size>
|
||||
<modify-time value="1644355825">1644355825</modify-time>
|
||||
</entry>
|
||||
<entry>
|
||||
<name>xx-00000007</name>
|
||||
<inode>12</inode>
|
||||
<blocks>1234</blocks>
|
||||
<mode>mode</mode>
|
||||
<mode_octal>660</mode_octal>
|
||||
<links>12</links>
|
||||
<user>phil</user>
|
||||
<group>phil</group>
|
||||
<type>regular</type>
|
||||
<flags>123</flags>
|
||||
<label>1234</label>
|
||||
<size>12345</size>
|
||||
<modify-time value="1644355825">1644355825</modify-time>
|
||||
</entry>
|
||||
<entry>
|
||||
<name>xx-00000008</name>
|
||||
<inode>12</inode>
|
||||
<blocks>1234</blocks>
|
||||
<mode>mode</mode>
|
||||
<mode_octal>660</mode_octal>
|
||||
<links>12</links>
|
||||
<user>phil</user>
|
||||
<group>phil</group>
|
||||
<type>regular</type>
|
||||
<flags>123</flags>
|
||||
<label>1234</label>
|
||||
<size>12345</size>
|
||||
<modify-time value="1644355825">1644355825</modify-time>
|
||||
</entry>
|
||||
<entry>
|
||||
<name>xx-00000009</name>
|
||||
<inode>12</inode>
|
||||
<blocks>1234</blocks>
|
||||
<mode>mode</mode>
|
||||
<mode_octal>660</mode_octal>
|
||||
<links>12</links>
|
||||
<user>phil</user>
|
||||
<group>phil</group>
|
||||
<type>regular</type>
|
||||
<flags>123</flags>
|
||||
<label>1234</label>
|
||||
<size>12345</size>
|
||||
<modify-time value="1644355825">1644355825</modify-time>
|
||||
</entry>
|
||||
<hits>72</hits>
|
||||
</data>
|
||||
</top>
|
@ -114,8 +114,6 @@ main (int argc, char **argv)
|
||||
xo_attr("test-attr", "attr-value");
|
||||
xo_emit_field_h(NULL, ",leaf-list,quotes", "sku", "%s-%u", "%s-000-%u",
|
||||
"gum", 1412);
|
||||
xo_emit_field_h(NULL, ",leaf-list,quotes", "sku", "%s-%u", "%s-000-%u",
|
||||
"sum", 4121);
|
||||
|
||||
xo_emit("Connecting to {:host}.{:domain}...\n", "my-box", "example.com");
|
||||
|
||||
@ -257,14 +255,6 @@ main (int argc, char **argv)
|
||||
"/some/file", (int) 0640, 8, 1,
|
||||
10, "user", 12, "group");
|
||||
|
||||
/* Test retain flag for dynamic data */
|
||||
xo_set_flags(NULL, XOF_RETAIN_ALL);
|
||||
char buf[] = "Testing...{:one/%d}...{:two/%d}...{:three/%d}\n";
|
||||
xo_emit(buf, 1, 2, 3);
|
||||
xo_emit(buf, 1, 2, 3);
|
||||
buf[0] = 'X';
|
||||
xo_emit(buf, 1, 2, 3);
|
||||
|
||||
xo_close_container_h(NULL, "top-level");
|
||||
|
||||
xo_finish();
|
||||
|
@ -24,7 +24,6 @@ main (int argc, char **argv)
|
||||
int mon = 0;
|
||||
xo_emit_flags_t flags = XOEF_RETAIN;
|
||||
int opt_color = 1;
|
||||
const char *map = NULL;
|
||||
|
||||
xo_set_program("test_12");
|
||||
|
||||
@ -51,18 +50,12 @@ main (int argc, char **argv)
|
||||
xo_set_flags(NULL, XOF_INFO);
|
||||
else if (xo_streq(argv[argc], "no-retain"))
|
||||
flags &= ~XOEF_RETAIN;
|
||||
else if (xo_streq(argv[argc], "map")) {
|
||||
if (argv[argc + 1])
|
||||
map = argv[++argc];
|
||||
} else if (xo_streq(argv[argc], "big")) {
|
||||
else if (xo_streq(argv[argc], "big")) {
|
||||
if (argv[argc + 1])
|
||||
count = atoi(argv[++argc]);
|
||||
}
|
||||
}
|
||||
|
||||
if (map)
|
||||
xo_map_add_file(NULL, map);
|
||||
|
||||
xo_set_flags(NULL, XOF_UNITS); /* Always test w/ this */
|
||||
if (opt_color)
|
||||
xo_set_flags(NULL, XOF_COLOR); /* Force color output */
|
||||
@ -88,17 +81,11 @@ main (int argc, char **argv)
|
||||
xo_emit_f(flags, fmt2, "left", "blue", "blue", 3, 45);
|
||||
}
|
||||
|
||||
xo_close_list("thing");
|
||||
|
||||
xo_open_container("2by4");
|
||||
xo_emit("There is {:4x4} in {:2morrow}\n", "truck", "tomorrow");
|
||||
xo_close_container("2by4");
|
||||
|
||||
|
||||
xo_open_container("tagÜÖÄ");
|
||||
xo_emit("The {:cölor} is {:säfe}\n", "blue", "yes");
|
||||
xo_close_container("tagÜÖÄ");
|
||||
|
||||
xo_close_container("data");
|
||||
xo_close_container_h(NULL, "top");
|
||||
|
||||
|
@ -1,248 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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, Feb 2022
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <langinfo.h>
|
||||
#include <unistd.h>
|
||||
#include <wchar.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "xo_config.h"
|
||||
#include "xo.h"
|
||||
#include "xo_encoder.h"
|
||||
|
||||
static size_t padding_for_month[12];
|
||||
static size_t month_max_size = 0;
|
||||
|
||||
static const char *
|
||||
get_abmon(int mon)
|
||||
{
|
||||
|
||||
switch (mon) {
|
||||
case 0: return (nl_langinfo(ABMON_1));
|
||||
case 1: return (nl_langinfo(ABMON_2));
|
||||
case 2: return (nl_langinfo(ABMON_3));
|
||||
case 3: return (nl_langinfo(ABMON_4));
|
||||
case 4: return (nl_langinfo(ABMON_5));
|
||||
case 5: return (nl_langinfo(ABMON_6));
|
||||
case 6: return (nl_langinfo(ABMON_7));
|
||||
case 7: return (nl_langinfo(ABMON_8));
|
||||
case 8: return (nl_langinfo(ABMON_9));
|
||||
case 9: return (nl_langinfo(ABMON_10));
|
||||
case 10: return (nl_langinfo(ABMON_11));
|
||||
case 11: return (nl_langinfo(ABMON_12));
|
||||
}
|
||||
|
||||
/* should never happen */
|
||||
abort();
|
||||
}
|
||||
|
||||
static void
|
||||
compute_abbreviated_month_size(void)
|
||||
{
|
||||
int i;
|
||||
size_t width;
|
||||
size_t months_width[12];
|
||||
|
||||
for (i = 0; i < 12; i++) {
|
||||
width = strlen(get_abmon(i));
|
||||
if (width == (size_t)-1) {
|
||||
month_max_size = -1;
|
||||
return;
|
||||
}
|
||||
months_width[i] = width;
|
||||
if (width > month_max_size)
|
||||
month_max_size = width;
|
||||
}
|
||||
|
||||
for (i = 0; i < 12; i++)
|
||||
padding_for_month[i] = month_max_size - months_width[i];
|
||||
}
|
||||
|
||||
static void
|
||||
printsize(const char *field, size_t width, off_t bytes)
|
||||
{
|
||||
char fmt[BUFSIZ];
|
||||
|
||||
/* This format assignment needed to work round gcc bug. */
|
||||
snprintf(fmt, sizeof(fmt), "{:%s/%%%dj%sd} ",
|
||||
field, (int) width, "");
|
||||
xo_emit_f(XOEF_NO_RETAIN, fmt, (intmax_t) bytes);
|
||||
}
|
||||
|
||||
static size_t
|
||||
ls_strftime(char *str, size_t len, const char *fmt, const struct tm *tm)
|
||||
{
|
||||
char *posb, nfmt[BUFSIZ];
|
||||
const char *format = fmt;
|
||||
size_t ret;
|
||||
|
||||
if ((posb = strstr(fmt, "%b")) != NULL) {
|
||||
if (month_max_size > 0) {
|
||||
snprintf(nfmt, sizeof(nfmt), "%.*s%s%*s%s",
|
||||
(int)(posb - fmt), fmt,
|
||||
get_abmon(tm->tm_mon),
|
||||
(int)padding_for_month[tm->tm_mon],
|
||||
"",
|
||||
posb + 2);
|
||||
format = nfmt;
|
||||
}
|
||||
}
|
||||
ret = strftime(str, len, format, tm);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static void
|
||||
printtime(const char *field, time_t ftime)
|
||||
{
|
||||
char longstring[80];
|
||||
char fmt[BUFSIZ];
|
||||
static time_t now = 0;
|
||||
const char *format;
|
||||
static int d_first = -1;
|
||||
|
||||
if (d_first < 0)
|
||||
d_first = 1;
|
||||
if (now == 0)
|
||||
now = time(NULL);
|
||||
|
||||
#define SIXMONTHS ((365 / 2) * 86400)
|
||||
if (1)
|
||||
/* mmm dd hh:mm || dd mmm hh:mm */
|
||||
format = d_first ? "%e %b %R" : "%b %e %R";
|
||||
else
|
||||
/* mmm dd yyyy || dd mmm yyyy */
|
||||
format = d_first ? "%e %b %Y" : "%b %e %Y";
|
||||
ls_strftime(longstring, sizeof(longstring), format, localtime(&ftime));
|
||||
|
||||
snprintf(fmt, sizeof(fmt), "{d:%s/%%hs} ", field);
|
||||
xo_attr("value", "%ld", (long) ftime);
|
||||
xo_emit_f(XOEF_NO_RETAIN, fmt, longstring);
|
||||
snprintf(fmt, sizeof(fmt), "{en:%s/%%ld}", field);
|
||||
xo_emit_f(XOEF_NO_RETAIN, fmt, (long) ftime);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int i, count = 10;
|
||||
int mon = 0;
|
||||
xo_emit_flags_t flags = XOF_RETAIN_ALL;
|
||||
int opt_color = 1;
|
||||
|
||||
xo_set_program("test_13");
|
||||
|
||||
argc = xo_parse_args(argc, argv);
|
||||
if (argc < 0)
|
||||
return 1;
|
||||
|
||||
compute_abbreviated_month_size();
|
||||
|
||||
for (argc = 1; argv[argc]; argc++) {
|
||||
if (xo_streq(argv[argc], "xml"))
|
||||
xo_set_style(NULL, XO_STYLE_XML);
|
||||
else if (xo_streq(argv[argc], "json"))
|
||||
xo_set_style(NULL, XO_STYLE_JSON);
|
||||
else if (xo_streq(argv[argc], "text"))
|
||||
xo_set_style(NULL, XO_STYLE_TEXT);
|
||||
else if (xo_streq(argv[argc], "html"))
|
||||
xo_set_style(NULL, XO_STYLE_HTML);
|
||||
else if (xo_streq(argv[argc], "no-color"))
|
||||
opt_color = 0;
|
||||
else if (xo_streq(argv[argc], "pretty"))
|
||||
xo_set_flags(NULL, XOF_PRETTY);
|
||||
else if (xo_streq(argv[argc], "xpath"))
|
||||
xo_set_flags(NULL, XOF_XPATH);
|
||||
else if (xo_streq(argv[argc], "info"))
|
||||
xo_set_flags(NULL, XOF_INFO);
|
||||
else if (xo_streq(argv[argc], "no-retain"))
|
||||
flags &= ~XOF_RETAIN_ALL;
|
||||
else if (xo_streq(argv[argc], "big")) {
|
||||
if (argv[argc + 1]) {
|
||||
const char *cp = argv[++argc];
|
||||
char *ep;
|
||||
count = strtoul(cp, &ep, 0);
|
||||
if (ep && *ep) {
|
||||
const char suff[] = "kmgt";
|
||||
unsigned long mult[]
|
||||
= { 1000, 1000000, 1000000000, 1000000000000 };
|
||||
char *sp = strchr(suff, *ep);
|
||||
if (sp) {
|
||||
count *= mult[sp - suff];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (xo_streq(argv[argc], "null")) {
|
||||
int fd = open("/dev/null", O_WRONLY);
|
||||
if (fd >= 0) {
|
||||
close(1);
|
||||
dup2(fd, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xo_set_flags(NULL, XOF_UNITS); /* Always test w/ this */
|
||||
if (opt_color)
|
||||
xo_set_flags(NULL, XOF_COLOR); /* Force color output */
|
||||
xo_set_file(stdout);
|
||||
|
||||
xo_open_container("top");
|
||||
xo_open_container("data");
|
||||
|
||||
if (flags != 0)
|
||||
xo_set_flags(NULL, flags);
|
||||
|
||||
xo_open_list("entry");
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
xo_open_instance("entry");
|
||||
|
||||
char name[80];
|
||||
snprintf(name, sizeof(name), "xx-%08u", i);
|
||||
|
||||
xo_emitr("{ke:name/%hs}", name);
|
||||
|
||||
xo_emitr("{t:inode/%*ju} ", 3, 12);
|
||||
xo_emitr("{t:blocks/%*jd} ", 4, 1234);
|
||||
|
||||
xo_emitr("{t:mode/%s}{e:mode_octal/%03o} {t:links/%*ju} {t:user/%-*s} {t:group/%-*s} ",
|
||||
"mode", 0660, 2, (uintmax_t) 12,
|
||||
4, "phil", 4, "phil");
|
||||
|
||||
|
||||
xo_emitr("{e:type/%s}", "regular");
|
||||
|
||||
xo_emitr("{:flags/%-*s} ", 3, "123");
|
||||
xo_emitr("{t:label/%-*s} ", 4, "1234");
|
||||
printsize("size", 5, 12345);
|
||||
printtime("modify-time", 1644355825);
|
||||
|
||||
xo_emitr("{dk:name/%hs}", name);
|
||||
|
||||
xo_close_instance("entry");
|
||||
xo_emit("\n");
|
||||
}
|
||||
|
||||
xo_close_list("entry");
|
||||
|
||||
xo_emit("{Lwc:hits}{:hits/%ld}\n", xo_retain_get_hits());
|
||||
|
||||
xo_close_container("data");
|
||||
xo_close_container_h(NULL, "top");
|
||||
|
||||
xo_finish();
|
||||
|
||||
return 0;
|
||||
}
|
7
xo/xo.c
7
xo/xo.c
@ -95,10 +95,9 @@ static xo_ssize_t
|
||||
formatter (xo_handle_t *xop, char *buf, xo_ssize_t bufsiz,
|
||||
const char *fmt, va_list vap UNUSED)
|
||||
{
|
||||
/* printf-style formatting flags, currently ignored */
|
||||
int lflag UNUSED = 0, hflag UNUSED = 0, jflag UNUSED = 0,
|
||||
tflag UNUSED = 0, zflag UNUSED = 0, qflag UNUSED = 0;
|
||||
int star1 = 0, star2 = 0;
|
||||
int lflag UNUSED = 0; /* Parse long flag, though currently ignored */
|
||||
int hflag = 0, jflag = 0, tflag = 0,
|
||||
zflag = 0, qflag = 0, star1 = 0, star2 = 0;
|
||||
int rc = 0;
|
||||
int w1 = 0, w2 = 0;
|
||||
const char *cp;
|
||||
|
Loading…
Reference in New Issue
Block a user