diff options
author | marcel <marcel@FreeBSD.org> | 2015-08-24 16:26:20 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 2015-08-24 16:26:20 +0000 |
commit | 02ffac2cca7d10e6d7dd08bf0312f623bf082268 (patch) | |
tree | 2b06534b5d1c1378ec99094a62eff13dfd2e48fc /contrib/libxo/doc | |
parent | db61d1271ad0bc51e60afe181a45a7318591dad6 (diff) | |
download | FreeBSD-src-02ffac2cca7d10e6d7dd08bf0312f623bf082268.zip FreeBSD-src-02ffac2cca7d10e6d7dd08bf0312f623bf082268.tar.gz |
Upgrade libxo to 0.4.5.
Local changes incorporated by 0.4.5: r284340
Local changes retained: r276260, r282117
Obtained from: https://github.com/Juniper/libxo
Diffstat (limited to 'contrib/libxo/doc')
-rw-r--r-- | contrib/libxo/doc/Makefile.am | 23 | ||||
-rw-r--r-- | contrib/libxo/doc/libxo.txt | 1359 |
2 files changed, 1231 insertions, 151 deletions
diff --git a/contrib/libxo/doc/Makefile.am b/contrib/libxo/doc/Makefile.am index c0c3271..16d6ba5 100644 --- a/contrib/libxo/doc/Makefile.am +++ b/contrib/libxo/doc/Makefile.am @@ -8,6 +8,7 @@ # using the SOFTWARE, you agree to be bound by the terms of that # LICENSE. +if HAVE_OXTRADOC OXTRADOC_DIR = ${SLAX_OXTRADOCDIR} OXTRADOC_PREFIX = ${OXTRADOC_DIR} OXTRADOC = ${OXTRADOC_DIR}/oxtradoc @@ -38,28 +39,32 @@ OX_ARGS += -S ${SLAXPROC} -p doc OX_CMD = ${PERL} ${PERLOPTS} ${OXTRADOC} ${OX_ARGS} OXTRADOC_CMD = ${OX_CMD} - OUTPUT = libxo-manual -INPUT = libxo.txt +INPUT = libxo EXTRA_DIST = \ - ${INPUT} \ + ${INPUT}.txt \ ${OUTPUT}.html \ ${OUTPUT}.txt doc docs: ${OUTPUT}.txt ${OUTPUT}.html -${OUTPUT}.txt: ${INPUT} ${OXTRADOC} xolint.txt +${OUTPUT}.txt: ${INPUT}.txt ${OXTRADOC} xolint.txt ${OXTRADOC_CMD} -m text -o $@ $< -${OUTPUT}.html: ${INPUT} ${OXTRADOC} ${XML2HTMLBIN} xolint.txt +${OUTPUT}.html: ${INPUT}.txt ${OXTRADOC} ${XML2HTMLBIN} xolint.txt ${OXTRADOC_CMD} -m html -o $@ $< xolint.txt: ${top_srcdir}/xolint/xolint.pl perl ${top_srcdir}/xolint/xolint.pl -D > xolint.txt CLEANFILES = \ -${OUTPUT}.xml \ -${OUTPUT}.txt \ -${OUTPUT}.fxml \ -${OUTPUT}.html +xolint.txt \ +${INPUT}.xml \ +${INPUT}.txt \ +${INPUT}.fxml \ +${INPUT}.html +else +doc docs: + @${ECHO} "The 'oxtradoc' tool is not installed; see libslax.org" +endif diff --git a/contrib/libxo/doc/libxo.txt b/contrib/libxo/doc/libxo.txt index 81a40b6..1e7acc7 100644 --- a/contrib/libxo/doc/libxo.txt +++ b/contrib/libxo/doc/libxo.txt @@ -8,7 +8,7 @@ # Phil Shafer, July 2014 # -* libxo +* Overview libxo - A Library for Generating Text, XML, JSON, and HTML Output @@ -28,10 +28,10 @@ decides at run time which output style should be produced. The application calls a function "xo_emit" to product output that is described in a format string. A "field descriptor" tells libxo what the field is and what it means. Each field descriptor is placed in -braces with a printf-like format string: +braces with a printf-like format string (^format-strings^): xo_emit(" {:lines/%7ju} {:words/%7ju} " - "{:characters/%7ju}{d:filename/%s}\n", + "{:characters/%7ju} {d:filename/%s}\n", linect, wordct, charct, file); Each field can have a role, with the 'value' role being the default, @@ -43,10 +43,10 @@ can then be generated in various style, using the "--libxo" option: % wc --libxo xml,pretty,warn /etc/motd <wc> <file> - <filename>/etc/motd</filename> <lines>25</lines> <words>165</words> <characters>1140</characters> + <filename>/etc/motd</filename> </file> </wc> % wc --libxo json,pretty,warn /etc/motd @@ -54,10 +54,10 @@ can then be generated in various style, using the "--libxo" option: "wc": { "file": [ { - "filename": "/etc/motd", "lines": 25, "words": 165, - "characters": 1140 + "characters": 1140, + "filename": "/etc/motd" } ] } @@ -95,10 +95,151 @@ command: We're using semantic release numbering, as defined in ^http://semver.org/spec/v2.0.0.html^. -libxo is open source, distributed under the BSD license. It -is shipped as part of FreeBSD 11.0. +libxo is open source, distributed under the BSD license. It shipped +as part of the FreeBSD operating system starting with release 11.0. -* Overview +Issues, problems, and bugs should be directly to the issues page on +our github site. + +*** Downloading libxo Source Code + +You can retrieve the source for libxo in two ways: + +A) Use a "distfile" for a specific release. We use +github to maintain our releases. Visit +github release page (^https://github.com/Juniper/libxo/releases^) +to see the list of releases. To download the latest, look for the +release with the green "Latest release" button and the green +"libxo-RELEASE.tar.gz" button under that section. + +After downloading that release's distfile, untar it as follows: + + tar -zxf libxo-RELEASE.tar.gz + cd libxo-RELEASE + +[Note: for Solaris users, your "tar" command lacks the "-z" flag, +so you'll need to substitute "gzip -dc "file" | tar xf -" instead of +"tar -zxf "file"".] + +B) Use the current build from github. This gives you the most recent +source code, which might be less stable than a specific release. To +build libxo from the git repo: + + git clone https://github.com/Juniper/libxo.git + cd libxo + +_BE AWARE_: The github repository does _not_ contain the files +generated by "autoreconf", with the notable exception of the "m4" +directory. Since these files (depcomp, configure, missing, +install-sh, etc) are generated files, we keep them out of the source +code repository. + +This means that if you download the a release distfile, these files +will be ready and you'll just need to run "configure", but if you +download the source code from svn, then you'll need to run +"autoreconf" by hand. This step is done for you by the "setup.sh" +script, described in the next section. + +*** Building libxo + +To build libxo, you'll need to set up the build, run the "configure" +script, run the "make" command, and run the regression tests. + +The following is a summary of the commands needed. These commands are +explained in detail in the rest of this section. + + sh bin/setup.sh + cd build + ../configure + make + make test + sudo make install + +The following sections will walk thru each of these steps with +additional details and options, but the above directions should be all +that's needed. + +**** Setting up the build + +[If you downloaded a distfile, you can skip this step.] + +Run the "setup.sh" script to set up the build. This script runs the +"autoreconf" command to generate the "configure" script and other +generated files. + + sh bin/setup.sh + +Note: We're are currently using autoreconf version 2.69. + +**** Running the "configure" Script + +Configure (and autoconf in general) provides a means of building +software in diverse environments. Our configure script supports +a set of options that can be used to adjust to your operating +environment. Use "configure --help" to view these options. + +We use the "build" directory to keep object files and generated files +away from the source tree. + +To run the configure script, change into the "build" directory, and +run the "configure" script. Add any required options to the +"../configure" command line. + + cd build + ../configure + +Expect to see the "configure" script generate the following error: + + /usr/bin/rm: cannot remove `libtoolT': No such file or directory + +This error is harmless and can be safely ignored. + +By default, libxo installs architecture-independent files, including +extension library files, in the /usr/local directories. To specify an +installation prefix other than /usr/local for all installation files, +include the --prefix=prefix option and specify an alternate +location. To install just the extension library files in a different, +user-defined location, include the --with-extensions-dir=dir option +and specify the location where the extension libraries will live. + + cd build + ../configure [OPTION]... [VAR=VALUE]... + +**** Running the "make" command + +Once the "configure" script is run, build the images using the "make" +command: + + make + +**** Running the Regression Tests + +libxo includes a set of regression tests that can be run to ensure +the software is working properly. These test are optional, but will +help determine if there are any issues running libxo on your +machine. To run the regression tests: + + make test + +**** Installing libxo + +Once the software is built, you'll need to install libxo using the +"make install" command. If you are the root user, or the owner of the +installation directory, simply issue the command: + + make install + +If you are not the "root" user and are using the "sudo" package, use: + + sudo make install + +Verify the installation by viewing the output of "xo --version": + + % xo --version + libxo version 0.3.5-git-develop + xo version 0.3.5-git-develop + +* Formatting with libxo Most unix commands emit text output aimed at humans. It is designed to be parsed and understood by a user. Humans are gifted at @@ -128,26 +269,41 @@ A single libxo function call in source code is all that's required: xo_emit("Connecting to {:host}.{:domain}...\n", host, domain); - Text: - Connection to my-box.example.com... + TEXT: + Connecting to my-box.example.com... XML: <host>my-box</host> <domain>example.com</domain> JSON: "host": "my-box", "domain": "example.com" - -For brevity, the HTML output is emitted. + 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, HTML, JSON, -and XML. JSON and XML are suitable for encoding data, while TEXT and -HTML are suited for display to the user. TEXT output can be display -on a terminal session, allowing compatibility with traditional usage. -HTML can be matched with a small CSS file to permit rendering in any -HTML5 browser. XML output is suitable for tools like XPath and -protocols like NETCONF. JSON output can be used for RESTful APIs. +There are four encoding styles supported by libxo: + +- TEXT output can be display on a terminal session, allowing +compatibility with traditional command line usage. +- XML output is suitable for tools like XPath and protocols like +NETCONF. +- JSON output can be used for RESTful APIs and integration with +languages like Javascript and Python. +- HTML can be matched with a small CSS file to permit rendering in any +HTML5 browser. + +In general, XML and JSON are suitable for encoding data, while TEXT is +suited for terminal output and HTML is suited for display in a web +browser (see ^xohtml^). *** Text Output @@ -164,7 +320,7 @@ 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 +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 @@ -257,7 +413,7 @@ field descriptions within the format string. The field description is given as follows: - '{' [ role | modifier ]* ':' [ content ] + '{' [ role | modifier ]* [',' long-names ]* ':' [ content ] [ '/' field-format [ '/' encoding-format ]] '}' The role describes the function of the field, while the modifiers @@ -271,23 +427,31 @@ 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); + 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). -*** Modifier Roles +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); -Modifiers are optional, and indicate the role and formatting of the +*** 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: |---+--------------+-------------------------------------------------| -| M | Name | Description | +| R | Name | Description | |---+--------------+-------------------------------------------------| -| C | color/effect | Field has color and effect controls | +| 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 | @@ -295,25 +459,59 @@ content. The roles are listed below; only one role is permitted: | 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 | +| [ | start-anchor | Begin a section of anchored variable-width text | +| ] | stop-anchor | End a section of anchored variable-width text | |---+--------------+-------------------------------------------------| -**** The Color Role ({C:}) + EXAMPLE: + xo_emit("{L:Free}{D::}{P: }{:free/%u} {U:Blocks}\n", + free_blocks); + +When a role is not provided, the "value" role is used as the default. + +Roles and modifiers can also use more verbose names, when preceeded by +a comma: + + EXAMPLE: + xo_emit("{,label:Free}{,decoration::}{,padding: }" + "{,value:free/%u} {,units:Blocks}\n", + free_blocks); + +**** The Color Role ({C:}) @color-role@ Colors and effects control how text values are displayed; they are -used for display styles (TEXT and HTML). 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 ("/"): +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:bold}{Lwc:Cost}{:cost/%u}{C:reset}\n", cost); xo_emit("{C:/fg-%s,bg-%s}{Lwc:Cost}{:cost/%u}{C:reset}\n", fg_color, bg_color, cost); -The content should be a comma-separated list of zero or more colors or -display effects. Colors and effects remain in effect until -modified by other "C" roles. If the content is empty, the "reset" -action is performed. +The following table lists the supported effects: |---------------+-------------------------------------------------| | Name | Description | @@ -332,22 +530,19 @@ action is performed. The following color names are supported: -|---------------| -| Name | -|---------------| -| black | -| blue | -| cyan | -| default | -| green | -| magenta | -| red | -| white | -| yellow | -|---------------| - -Color names are prefixed with either "fg-" or "bg-" to change the -foreground and background colors, respectively. +|---------+--------------------------------------------| +| Name | Description | +|---------+--------------------------------------------| +| black | | +| blue | | +| cyan | | +| default | Default color for foreground or background | +| green | | +| magenta | | +| red | | +| white | | +| yellow | | +|---------+--------------------------------------------| **** The Decoration Role ({D:}) @@ -358,6 +553,37 @@ can use CSS to direct their display parameters. xo_emit("{D:((}{:name}{D:))}\n", name); +**** The Gettext Role ({G:}) @gettext-role@ + +libxo supports internationalization (i18n) through its use of +gettext(3). Use the "{G:}" role to request that the remaining part of +the format string, following the "{G:}" field, be handled using +gettext(). + +Since gettext() uses the string as the key into the message catalog, +libxo uses a simplified version of the format string that removes +unimportant field formatting and modifiers, stopping minor formatting +changes from impacting the expensive translation process. A developer +change such as changing "/%06d" to "/%08d" should not force hand +inspection of all .po files. + +The simplified version can be generated for a single message using the +"xopo -s <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 ^howto-i18n^ for additional details. + **** The Label Role ({L:}) Labels are text that appears before a value. @@ -370,7 +596,7 @@ Notes are text that appears after a value. xo_emit("{:cost/%u} {N:per year}\n", cost); -**** The Padding Role ({P:}) +**** The Padding Role ({P:}) @padding-role@ Padding represents whitespace used before and between fields. @@ -440,7 +666,7 @@ format descriptors default to "%s". xo_emit("{:author} wrote \"{:poem}\" in {:year/%4d}\n, author, poem, year); -**** The Anchor Modifiers ({[:} and {]:}) +**** The Anchor Roles ({[:} and {]:}) @anchor-role@ The anchor roles allow a set of strings by be padded as a group, but still be visible to xo_emit as distinct fields. Either the start @@ -468,29 +694,38 @@ than the absolute value of the given width, nothing happens. Widths over 8k are considered probable errors and not supported. If XOF_WARN is set, a warning will be generated. -*** Modifier Flags - -The modifiers can also include the following flags, which modify the -content emitted for some output styles: - -|---+--------------+-------------------------------------------------| -| M | Name | Description | -|---+--------------+-------------------------------------------------| -| c | colon | A colon (":") is appended after the label | -| d | display | Only emit field for display styles (text/HTML) | -| e | encoding | Only emit for encoding styles (XML/JSON) | -| 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 | -| q | quotes | Quote the field when using JSON style | -| w | white space | A blank (" ") is appended after the label | -|---+--------------+-------------------------------------------------| - -For example, the modifier string "Lwc" 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" means the -field has a value role, that it is a key for the current instance, and -that the value should be quoted when encoded for JSON. +*** Field Modifiers + +Field modifiers are flags which modify the way content emitted for +particular output styles: + +|---+---------------+-------------------------------------------------| +| M | Name | Description | +|---+---------------+-------------------------------------------------| +| c | colon | A colon (":") is appended after the label | +| d | display | Only emit field for display styles (text/HTML) | +| e | encoding | Only emit for encoding styles (XML/JSON) | +| g | gettext | Call gettext on field's render content | +| h | humanize (hn) | Format large numbers in human-readable style | +| | hn-space | Humanize: Place space between numeric and unit | +| | hn-decimal | Humanize: Add a decimal digit, if number < 10 | +| | hn-1000 | Humanize: Use 1000 as divisor instead of 1024 | +| k | key | Field is a key, suitable for XPath predicates | +| l | leaf-list | Field is a leaf-list | +| n | no-quotes | Do not quote the field when using JSON style | +| p | plural | Gettext: Use comma-separated plural form | +| q | quotes | Quote the field when using JSON style | +| t | trim | Trim leading and trailing whitespace | +| w | white | A blank (" ") is appended after the label | +|---+---------------+-------------------------------------------------| + +Roles and modifiers can also use more verbose names, when preceeded by +a comma. For example, the modifier string "Lwc" (or "L,white,colon") +means the field has a label role (text that describes the next field) +and should be followed by a colon ('c') and a space ('w'). The +modifier string "Vkq" (or ":key,quote") means the field has a value +role (the default role), that it is a key for the current instance, +and that the value should be quoted when encoded for JSON. **** The Colon Modifier ({c:}) @@ -535,6 +770,58 @@ the display output styles, TEXT and HTML. The encoding modifier is the opposite of the display modifier, and they are often used to give to distinct views of the underlying data. +**** The Gettext Modifier ({g:}) @gettext-modifier@ + +The gettext modifier is used to translate individual fields using the +gettext domain (typically set using the "{G:}" role) and current +language settings. Once libxo renders the field value, it is passed +to gettext(3), where it is used as a key to find the native language +translation. + +In the following example, the strings "State" and "full" are passed +to gettext() to find locale-based translated strings. + + xo_emit("{Lgwc:State}{g:state}\n", "full"); + +See ^gettext-role^, ^plural-modifier^, and ^howto-i18n^ for additional +details. + +**** The Humanize Modifier ({h:}) + +The humanize modifier is used to render large numbers as in a +human-readable format. While numbers like "44470272" are completely +readable to computers and savants, humans will generally find "44M" +more meaningful. + +"hn" can be used as an alias for "humanize". + +The humanize modifier only affects display styles (TEXT and HMTL). +The "no-humanize" option (See ^LIBXO_OPTIONS^) will block the function of +the humanize modifier. + +There are a number of modifiers that affect details of humanization. +These are only available in as full names, not single characters. The +"hn-space" modifier places a space between the number and any +multiplier symbol, such as "M" or "K" (ex: "44 K"). The "hn-decimal" +modifier will add a decimal point and a single tenths digit when the number is +less than 10 (ex: "4.4K"). The "hn-1000" modifier will use 1000 as divisor +instead of 1024, following the JEDEC-standard instead of the more +natural binary powers-of-two tradition. + + EXAMPLE: + xo_emit("{h:input/%u}, {h,hn-space:output/%u}, " + "{h,hn-decimal:errors/%u}, {h,hn-1000:capacity/%u}, " + "{h,hn-decimal:remaining/%u}\n", + input, output, errors, capacity, remaining); + TEXT: + 21, 57 K, 96M, 44M, 1.2G + +In the HTML style, the original numeric value is rendered in the +"data-number" attribute on the <div> element: + + <div class="data" data-tag="errors" + data-number="100663296">96M</div> + **** The Key Modifier ({k:}) The key modifier is used to indicate that a particular field helps @@ -586,6 +873,27 @@ needed, but often this needs to be controlled by the caller. JSON: "fancy": true +**** The Plural Modifier ({p:}) @plural-modifier@ + +The plural modifier selects the appropriate plural form of an +expression based on the most recent number emitted and the current +language settings. The contents of the field should be the singular +and plural English values, separated by a comma: + + xo_emit("{:bytes} {Ngp:byte,bytes}\n", bytes); + +The plural modifier is meant to work with the gettext modifier ({g:}) +but can work independently. See ^gettext-modifier^. + +When used without the gettext modifier or when the message does not +appear in the message catalog, the first token is chosen when the last +numeric value is equal to 1; otherwise the second value is used, +mimicking the simple pluralization rules of English. + +When used with the gettext modifier, the ngettext(3) function is +called to handle the heavy lifting, using the message catalog to +convert the singular and plural forms into the native language. + **** The Quotes Modifier ({q:}) The quotes modifier (and its twin, the 'no-quotes' modifier) affect @@ -757,8 +1065,8 @@ 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 are in used in filling those -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); @@ -782,7 +1090,17 @@ placed in a <div> with class "text". <div class="data" data-tag="size">extra small</div> <div class="text">.</div> -*** "%n" is Not Supported +*** "%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. @@ -799,6 +1117,52 @@ default to "%s". For padding and labels, the content string is considered the content, unless a format is given. +*** Argument Validation @printf-like@ + +Many compilers and tool chains support validation of printf-like +arguments. When the format string fails to match the argument list, +a warning is generated. This is a valuable feature and while the +formatting strings for libxo differ considerably from printf, many of +these checks can still provide build-time protection against bugs. + +libxo provide variants of functions that provide this ability, if the +"--enable-printflike" option is passed to the "configure" script. +These functions use the "_p" suffix, like "xo_emit_p()", +xo_emit_hp()", etc. + +The following are features of libxo formatting strings that are +incompatible with printf-like testing: + +- implicit formats, where "{:tag}" has an implicit "%s"; +- the "max" parameter for strings, where "{:tag/%4.10.6s}" means up to +ten bytes of data can be inspected to fill a minimum of 4 columns and +a maximum of 6; +- percent signs in strings, where "{:filled}%" makes a single, +trailing percent sign; +- the "l" and "h" modifiers for strings, where "{:tag/%hs}" means +locale-based string and "{:tag/%ls}" means a wide character string; +- distinct encoding formats, where "{:tag/#%s/%s}" means the display +styles (text and HTML) will use "#%s" where other styles use "%s"; + +If none of these features are in use by your code, then using the "_p" +variants might be wise. + +|------------------+------------------------| +| Function | printf-like Equivalent | +|------------------+------------------------| +| xo_emit_hv | xo_emit_hvp | +| xo_emit_h | xo_emit_hp | +| xo_emit | xo_emit_p | +| xo_emit_warn_hcv | xo_emit_warn_hcvp | +| xo_emit_warn_hc | xo_emit_warn_hcp | +| xo_emit_warn_c | xo_emit_warn_cp | +| xo_emit_warn | xo_emit_warn_p | +| xo_emit_warnx_ | xo_emit_warnx_p | +| xo_emit_err | xo_emit_err_p | +| xo_emit_errx | xo_emit_errx_p | +| xo_emit_errc | xo_emit_errc_p | +|------------------+------------------------| + *** Example In this example, the value for the number of items in stock is emitted: @@ -844,26 +1208,31 @@ following options are recognised: Options is a comma-separated list of tokens that correspond to output styles, flags, or features: -|-----------+-------------------------------------------------------| -| Token | Action | -|-----------+-------------------------------------------------------| -| dtrt | Enable "Do The Right Thing" mode | -| html | Emit HTML output | -| indent=xx | Set the indentation level | -| info | Add info attributes (HTML) | -| json | Emit JSON output | -| keys | Emit the key attribute for keys (XML) | -| no-locale | Do not initialize the locale setting | -| no-top | Do not emit a top set of braces (JSON) | -| not-first | Pretend the 1st output item was not 1st (JSON) | -| pretty | Emit pretty-printed output | -| text | Emit TEXT output | -| 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) | -|-----------+-------------------------------------------------------| +|-------------+-------------------------------------------------------| +| Token | Action | +|-------------+-------------------------------------------------------| +| color | Enable colors/effects for display styles (TEXT, HTML) | +| dtrt | Enable "Do The Right Thing" mode | +| html | Emit HTML output | +| indent=xx | Set the indentation level | +| info | Add info attributes (HTML) | +| json | Emit JSON output | +| keys | Emit the key attribute for keys (XML) | +| log-gettext | Log (via stderr) each gettext(3) string lookup | +| log-syslog | Log (via stderr) each syslog message (via xo_syslog) | +| no-humanize | Ignore the {h:} modifier (TEXT, HTML) | +| no-locale | Do not initialize the locale setting | +| no-top | Do not emit a top set of braces (JSON) | +| not-first | Pretend the 1st output item was not 1st (JSON) | +| pretty | Emit pretty-printed output | +| text | Emit TEXT output | +| underscores | Replace XML-friendly "-"s with JSON friendly "_"s e | +| units | Add the 'units' (XML) or 'data-units (HTML) attribute | +| warn | Emit warnings when libxo detects bad calls | +| warn-xml | Emit warnings in XML | +| xml | Emit XML output | +| xpath | Add XPath expressions (HTML) | +|-------------+-------------------------------------------------------| The brief options are detailed in ^LIBXO_OPTIONS^. @@ -1013,7 +1382,7 @@ properly. xo_close_marker("fish-guts"); } -** Handles +** Handles @handles@ libxo uses "handles" to control its rendering functionality. The handle contains state and buffered data, as well as callback functions @@ -1164,27 +1533,34 @@ To use the default handle, pass a NULL handle: The set of valid flags include: -|-----------------+---------------------------------------| -| Flag | Description | -|-----------------+---------------------------------------| -| XOF_CLOSE_FP | Close file pointer on xo_destroy() | -| XOF_DTRT | Enable "do the right thing" mode | -| XOF_INFO | Display info data attributes (HTML) | -| XOF_KEYS | Emit the key attribute (XML) | -| XOF_NO_ENV | Do not use the LIBXO_OPTIONS env var | -| XOF_PRETTY | Make 'pretty printed' output | -| XOF_UNDERSCORES | Replaces hyphens with underscores | -| XOF_UNITS | Display units (XML and HMTL) | -| XOF_WARN | Generate warnings for broken calls | -| XOF_WARN_XML | Generate warnings in XML on stdout | -| XOF_XPATH | Emit XPath expressions (HTML) | -| XOF_COLUMNS | Force xo_emit to return columns used | -| XOF_FLUSH | Flush output after each xo_emit call | -|-----------------+---------------------------------------| +|-------------------+----------------------------------------| +| Flag | Description | +|-------------------+----------------------------------------| +| XOF_CLOSE_FP | Close file pointer on xo_destroy() | +| XOF_COLOR | Enable color and effects in output | +| XOF_COLOR_ALLOWED | Allow color/effect for terminal output | +| XOF_DTRT | Enable "do the right thing" mode | +| XOF_INFO | Display info data attributes (HTML) | +| XOF_KEYS | Emit the key attribute (XML) | +| XOF_NO_ENV | Do not use the LIBXO_OPTIONS env var | +| XOF_NO_HUMANIZE | Display humanization (TEXT, HTML) | +| XOF_PRETTY | Make 'pretty printed' output | +| XOF_UNDERSCORES | Replaces hyphens with underscores | +| XOF_UNITS | Display units (XML, HMTL) | +| XOF_WARN | Generate warnings for broken calls | +| XOF_WARN_XML | Generate warnings in XML on stdout | +| XOF_XPATH | Emit XPath expressions (HTML) | +| XOF_COLUMNS | Force xo_emit to return columns used | +| XOF_FLUSH | Flush output after each xo_emit call | +|-------------------+----------------------------------------| The XOF_CLOSE_FP flag will trigger the call of the close_func (provided via xo_set_writer()) when the handle is destroyed. +The XOF_COLOR flag enables color and effects in output regardless of +output device, while the XOF_COLOR_ALLOWED flag allows color and +effects only if the output device is a terminal. + The XOF_PRETTY flag requests 'pretty printing', which will trigger the addition of indentation and newlines to enhance the readability of XML, JSON, and HTML output. Text output is not affected. @@ -1328,12 +1704,15 @@ When the program is ready to exit or close a handle, a call to xo_finish() is required. This flushes any buffered data, closes open libxo constructs, and completes any pending operations. - void xo_finish (void); - void xo_finish_h (xo_handle_t *xop); + int xo_finish (void); + int xo_finish_h (xo_handle_t *xop); + void xo_finish_atexit (void); Calling this function is vital to the proper operation of libxo, especially for the non-TEXT output styles. +xo_finish_atexit is suitable for use with atexit(3). + ** Emitting Hierarchy libxo represents to types of hierarchy: containers and lists. A @@ -1430,9 +1809,9 @@ style and usage expectations. } ] -** Additional Functionality +** Support Functions -*** Parsing Command-line Arguments (xo_parse_args) +*** Parsing Command-line Arguments (xo_parse_args) @xo_parse_args@ The xo_parse_args() function is used to process a program's arguments. libxo-specific options are processed and removed @@ -1442,7 +1821,7 @@ is returned. On failure, a message it emitted and -1 is returned. argc = xo_parse_args(argc, argv); if (argc < 0) - exit(1); + exit(EXIT_FAILURE); Following the call to xo_parse_args, the application can process the remaining arguments in a normal manner. See ^command-line-arguments^ @@ -1539,19 +1918,25 @@ By default, the standard realloc() and free() functions are used. The environment variable "LIBXO_OPTIONS" can be set to a string of options: -|--------+-------------------------------------------| -| Option | Action | -|--------+-------------------------------------------| -| 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) | -| P | Enable pretty-printed output (XOF_PRETTY) | -| T | Enable text output (XO_STYLE_TEXT) | -| W | Enable warnings (XOF_WARN) | -| X | Enable XML output (XO_STYLE_XML) | -| x | Enable XPath data (XOF_XPATH) | -|--------+-------------------------------------------| +|--------+---------------------------------------------| +| 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) | +|--------+---------------------------------------------| For example, warnings can be enabled by: @@ -1619,6 +2004,327 @@ can do so by calling the xo_no_setlocale() function. void xo_no_setlocale (void); +** Emitting syslog Messages + +syslog is the system logging facility used throughout the unix world. +Messages are sent from commands, applications, and daemons to a +hierarchy of servers, where they are filtered, saved, and forwarded +based on configuration behaviors. + +syslog is an older protocol, originally documented only in source +code. By the time RFC 3164 published, variation and mutation left the +leading "<pri>" string as only common content. RFC 5424 defines a new +version (version 1) of syslog and introduces structured data into the +messages. Structured data is a set of name/value pairs transmitted +distinctly alongside the traditional text message, allowing filtering +on precise values instead of regular expressions. + +These name/value pairs are scoped by a two-part identifier; an +enterprise identifier names the party responsible for the message +catalog and a name identifying that message. Enterprise IDs are +defined by IANA, the Internet Assigned Numbers Authority: + +https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers + +Use the ^xo_set_syslog_enterprise_id^() function to set the Enterprise +ID, as needed. + +The message name should follow the conventions in ^good-field-names^, +as should the fields within the message. + + /* Both of these calls are optional */ + xo_set_syslog_enterprise_id(32473); + xo_open_log("my-program", 0, LOG_DAEMON); + + /* Generate a syslog message */ + xo_syslog(LOG_ERR, "upload-failed", + "error <%d> uploading file '{:filename}' " + "as '{:target/%s:%s}'", + code, filename, protocol, remote); + + xo_syslog(LOG_INFO, "poofd-invalid-state", + "state {:current/%u} is invalid {:connection/%u}", + state, conn); + +The developer should be aware that the message name may be used in the +future to allow access to further information, including +documentation. Care should be taken to choose quality, descriptive +names. + +*** Priority, Facility, and Flags @priority@ + +The xo_syslog, xo_vsyslog, and xo_open_log functions accept a set of +flags which provide the priority of the message, the source facility, +and some additional features. These values are OR'd together to +create a single integer argument: + + xo_syslog(LOG_ERR | LOG_AUTH, "login-failed", + "Login failed; user '{:user}' from host '{:address}'", + user, addr); + +These values are defined in <syslog.h>. + +The priority value indicates the importance and potential impact of +each message. + +|-------------+-------------------------------------------------------| +| Priority | Description | +|-------------+-------------------------------------------------------| +| LOG_EMERG | A panic condition, normally broadcast to all users | +| LOG_ALERT | A condition that should be corrected immediately | +| LOG_CRIT | Critical conditions | +| LOG_ERR | Generic errors | +| LOG_WARNING | Warning messages | +| LOG_NOTICE | Non-error conditions that might need special handling | +| LOG_INFO | Informational messages | +| LOG_DEBUG | Developer-oriented messages | +|-------------+-------------------------------------------------------| + +The facility value indicates the source of message, in fairly generic +terms. + +|---------------+-------------------------------------------------| +| Facility | Description | +|---------------+-------------------------------------------------| +| LOG_AUTH | The authorization system (e.g. login(1)) | +| LOG_AUTHPRIV | As LOG_AUTH, but logged to a privileged file | +| LOG_CRON | The cron daemon: cron(8) | +| LOG_DAEMON | System daemons, not otherwise explicitly listed | +| LOG_FTP | The file transfer protocol daemons | +| LOG_KERN | Messages generated by the kernel | +| LOG_LPR | The line printer spooling system | +| LOG_MAIL | The mail system | +| LOG_NEWS | The network news system | +| LOG_SECURITY | Security subsystems, such as ipfw(4) | +| LOG_SYSLOG | Messages generated internally by syslogd(8) | +| LOG_USER | Messages generated by user processes (default) | +| LOG_UUCP | The uucp system | +| LOG_LOCAL0..7 | Reserved for local use | +|---------------+-------------------------------------------------| + +In addition to the values listed above, xo_open_log accepts a set of +addition flags requesting specific behaviors. + +|------------+----------------------------------------------------| +| Flag | Description | +|------------+----------------------------------------------------| +| LOG_CONS | If syslogd fails, attempt to write to /dev/console | +| LOG_NDELAY | Open the connection to syslogd(8) immediately | +| LOG_PERROR | Write the message also to standard error output | +| LOG_PID | Log the process id with each message | +|------------+----------------------------------------------------| + +*** xo_syslog + +Use the xo_syslog function to generate syslog messages by calling it +with a log priority and facility, a message name, a format string, and +a set of arguments. The priority/facility argument are discussed +above, as is the message name. + +The format string follows the same conventions as xo_emit's format +string, with each field being rendered as an SD-PARAM pair. + + xo_syslog(LOG_ERR, "poofd-missing-file", + "'{:filename}' not found: {:error/%m}", filename); + + ... [poofd-missing-file@32473 filename="/etc/poofd.conf" + error="Permission denied"] '/etc/poofd.conf' not + found: Permission denied + +*** Support functions + +**** xo_vsyslog + +xo_vsyslog is identical in function to xo_syslog, but takes the set of +arguments using a va_list. + + void my_log (const char *name, const char *fmt, ...) + { + va_list vap; + va_start(vap, fmt); + xo_vsyslog(LOG_ERR, name, fmt, vap); + va_end(vap); + } + +**** xo_open_log + +xo_open_log functions similar to openlog(3), allowing customization of +the program name, the log facility number, and the additional option +flags described in ^priority^. + + void + xo_open_log (const char *ident, int logopt, int facility); + +**** xo_close_log + +xo_close_log functions similar to closelog(3), closing the log file +and releasing any associated resources. + + void + xo_close_log (void); + +**** xo_set_logmask + +xo_set_logmask function similar to setlogmask(3), restricting the set +of generated log event to those whose associated bit is set in +maskpri. Use LOG_MASK(pri) to find the appropriate bit, or +LOG_UPTO(toppri) to create a mask for all priorities up to and +including toppri. + + int + xo_set_logmask (int maskpri); + + Example: + setlogmask(LOG_UPTO(LOG_WARN)); + +**** xo_set_syslog_enterprise_id + +Use the xo_set_syslog_enterprise_id to supply a platform- or +application-specific enterprise id. This value is used in any +future syslog messages. + +Ideally, the operating system should supply a default value via the +"kern.syslog.enterprise_id" sysctl value. Lacking that, the +application should provide a suitable value. + + void + xo_set_syslog_enterprise_id (unsigned short eid); + +Enterprise IDs are administered by IANA, the Internet Assigned Number +Authority. The complete list is EIDs on their web site: + + https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers + +New EIDs can be requested from IANA using the following page: + + http://pen.iana.org/pen/PenApplication.page + +Each software development organization that defines a set of syslog +messages should register their own EID and use that value in their +software to ensure that messages can be uniquely identified by the +combination of EID + message name. + +** Creating Custom Encoders + +The number of encoding schemes in current use is staggering, with new +and distinct schemes appearing daily. While libxo provide XML, JSON, +HMTL, and text natively, there are requirements for other encodings. + +Rather than bake support for all possible encoders into libxo, the API +allows them to be defined externally. libxo can then interfaces with +these encoding modules using a simplistic API. libxo processes all +functions calls, handles state transitions, performs all formatting, +and then passes the results as operations to a customized encoding +function, which implements specific encoding logic as required. This +means your encoder doesn't need to detect errors with unbalanced +open/close operations but can rely on libxo to pass correct data. + +By making a simple API, libxo internals are not exposed, insulating the +encoder and the library from future or internal changes. + +The three elements of the API are: +- loading +- initialization +- operations + +The following sections provide details about these topics. + +libxo source contain an encoder for Concise Binary Object +Representation, aka CBOR (RFC 7049) which can be used as used as an +example for the API. + +*** Loading Encoders + +Encoders can be registered statically or discovered dynamically. +Applications can choose to call the xo_encoder_register() +function to explicitly register encoders, but more typically they are +built as shared libraries, placed in the libxo/extensions directory, +and loaded based on name. libxo looks for a file with the name of the encoder +and an extension of ".enc". This can be a file or a symlink to the +shared library file that supports the encoder. + + % ls -1 lib/libxo/extensions/*.enc + lib/libxo/extensions/cbor.enc + lib/libxo/extensions/test.enc + +*** Encoder Initialization + +Each encoder must export a symbol used to access the library, which +must have the following signature: + + int xo_encoder_library_init (XO_ENCODER_INIT_ARGS); + +XO_ENCODER_INIT_ARGS is a macro defined in xo_encoder.h that defines +an argument called "arg", a pointer of the type +xo_encoder_init_args_t. This structure contains two fields: + +- xei_version is the version number of the API as implemented within +libxo. This version is currently as 1 using XO_ENCODER_VERSION. This +number can be checked to ensure compatibility. The working assumption +is that all versions should be backward compatible, but each side may +need to accurately know the version supported by the other side. +xo_encoder_library_init can optionally check this value, and must then +set it to the version number used by the encoder, allowing libxo to +detect version differences and react accordingly. For example, if +version 2 adds new operations, then libxo will know that an encoding +library that set xei_version to 1 cannot be expected to handle those +new operations. + +- xei_handler must be set to a pointer to a function of type +xo_encoder_func_t, as defined in xo_encoder.h. This function +takes a set of parameters: +-- xop is a pointer to the opaque xo_handle_t structure +-- op is an integer representing the current operation +-- name is a string whose meaning differs by operation +-- value is a string whose meaning differs by operation +-- private is an opaque structure provided by the encoder + +Additional arguments may be added in the future, so handler functions +should use the XO_ENCODER_HANDLER_ARGS macro. An appropriate +"extern" declaration is provided to help catch errors. + +Once the encoder initialization function has completed processing, it +should return zero to indicate that no error has occurred. A non-zero +return code will cause the handle initialization to fail. + +*** Operations + +The encoder API defines a set of operations representing the +processing model of libxo. Content is formatted within libxo, and +callbacks are made to the encoder's handler function when data is +ready to be processed. + +|-----------------------+---------------------------------------| +| Operation | Meaning (Base function) | +|-----------------------+---------------------------------------| +| XO_OP_CREATE | Called when the handle is created | +| XO_OP_OPEN_CONTAINER | Container opened (xo_open_container) | +| XO_OP_CLOSE_CONTAINER | Container closed (xo_close_container) | +| XO_OP_OPEN_LIST | List opened (xo_open_list) | +| XO_OP_CLOSE_LIST | List closed (xo_close_list) | +| XO_OP_OPEN_LEAF_LIST | Leaf list opened (xo_open_leaf_list) | +| XO_OP_CLOSE_LEAF_LIST | Leaf list closed (xo_close_leaf_list) | +| XO_OP_OPEN_INSTANCE | Instance opened (xo_open_instance) | +| XO_OP_CLOSE_INSTANCE | Instance closed (xo_close_instance) | +| XO_OP_STRING | Field with Quoted UTF-8 string | +| XO_OP_CONTENT | Field with content | +| XO_OP_FINISH | Finish any pending output | +| XO_OP_FLUSH | Flush any buffered output | +| XO_OP_DESTROY | Clean up resources | +| XO_OP_ATTRIBUTE | An attribute name/value pair | +| XO_OP_VERSION | A version string | +|-----------------------+---------------------------------------| + +For all the open and close operations, the name parameter holds the +name of the construct. For string, content, and attribute operations, +the name parameter is the name of the field and the value parameter is +the value. "string" are differentiated from "content" to allow differing +treatment of true, false, null, and numbers from real strings, though +content values are formatted as strings before the handler is called. +For version operations, the value parameter contains the version. + +All strings are encoded in UTF-8. + * The "xo" Utility The "xo" utility allows command line access to the functionality of @@ -1768,7 +2474,7 @@ 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. -* 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 @@ -1794,6 +2500,46 @@ 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. +* xopo + +The "xopo" utility filters ".pot" files generated by the "xgettext" +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 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. + * FAQs This section contains the set of questions that users typically ask, @@ -1909,7 +2655,7 @@ be lost. libxo is a new implementation of these ideas and is distinct from the previous implementation in JUNOS. -*** What makes a good field name? +*** What makes a good field name? @good-field-names@ To make useful, consistent field names, follow these guidelines: @@ -1937,7 +2683,8 @@ Use "receive-after-window-packets" instead of Nothing's worse than writing expressions like: if ($src1/process[pid == $pid]/name == - $src2/proc-table/proc/p[process-id == $pid]/proc-name) { + $src2/proc-table/proc-list + /proc-entry[process-id == $pid]/proc-name) { ... } @@ -1945,6 +2692,9 @@ 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". += 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 @@ -1979,6 +2729,331 @@ names to make that difference more obvious. !!include-file xolint.txt +* 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. + +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. + +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. + +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. + +libslax is not required by libxo; it contains the "oxtradoc" program +used to format documentation. + +For additional information, see ^building-libxo^. + +** Howto: Convert command line applications + + How do I convert an existing command line application? + +There are three 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 (^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; + .... + } + +At the bottom of your main(), you'll need to call xo_finish() to +complete output processing for the default handle (^handles^). libxo +provides the xo_finish_atexit function that is suitable for use with +the atexit(3) function. + + atexit(xo_finish_atexit); + +*** Converting printf Calls + +The second task is inspecting code for 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: + + printf("There are %d %s events\n", count, etype); + 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 (^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. + + printf("Statistics:\n"); + xo_emit("{T:Statistics}:\n"); + +The "color" roles controls foreground and background colors, as well +as effects like bold and underline (see ^color-role^). + + xo_emit("{C:bold}required{C:}\n"); + +Finally, the start- and stop-anchor roles allow justification and +padding over multiple fields (see ^anchor-role^). + + snprintf(buf, sizeof(buf), "(%u/%u/%u)", min, ave, max); + printf("%30s", buf); + + 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: + + printf("table %d\n", tnum); + for (i = 0; i < tmax; i++) { + printf(" %s %d\n", table[i].name, table[i].size); + } + + 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. + + printf("Paging information:\n"); + printf(" Free: %lu\n", free); + printf(" Active: %lu\n", active); + printf(" Inactive: %lu\n", inactive); + + 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, +err(3) and 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: + + err(1, "cannot open output file: %s", file); + + xo_err(1, "cannot open output file: %s", file); + xo_emit_err(1, "cannot open output file: {:filename}", file); + +** Howto: Use "xo" in Shell Scripts + +** Howto: Internationalization (i18n) @howto-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 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 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 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 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); + * Examples ** Unit Test @@ -2022,7 +3097,7 @@ Here is the unit test example: argc = xo_parse_args(argc, argv); if (argc < 0) - exit(1); + exit(EXIT_FAILURE); xo_set_info(NULL, info, info_count); |