2 Howtos: Focused Directions
3 ==========================
5 This section provides task-oriented instructions for selected tasks.
6 If you have a task that needs instructions, please open a request as
7 an enhancement issue on github.
12 libxo uses github to track bugs or request enhancements. Please use
15 https://github.com/Juniper/libxo/issues
20 libxo is open source, under a new BSD license. Source code is
21 available on github, as are recent releases. To get the most
22 current release, please visit:
24 https://github.com/Juniper/libxo/releases
26 After downloading and untarring the source code, building involves the
36 libxo uses a distinct "*build*" directory to keep generated files
37 separated from source files.
41 Use "`../configure --help`" to display available configuration
42 options, which include the following::
44 --enable-warnings Turn on compiler warnings
45 --enable-debug Turn on debugging
46 --enable-text-only Turn on text-only rendering
47 --enable-printflike Enable use of GCC __printflike attribute
48 --disable-libxo-options Turn off support for LIBXO_OPTIONS
49 --with-gettext=PFX Specify location of gettext installation
50 --with-libslax-prefix=PFX Specify location of libslax config
52 Compiler warnings are a very good thing, but recent compiler version
53 have added some very pedantic checks. While every attempt is made to
54 keep libxo code warning-free, warnings are now optional. If you are
55 doing development work on libxo, it is required that you
56 use --enable-warnings to keep the code warning free, but most users
57 need not use this option.
59 .. index:: --enable-text-only
61 libxo provides the `--enable-text-only` option to reduce the
62 footprint of the library for smaller installations. XML, JSON, and
63 HTML rendering logic is removed.
65 .. index:: --with-gettext
67 The gettext library does not provide a simple means of learning its
68 location, but libxo will look for it in /usr and /opt/local. If
69 installed elsewhere, the installer will need to provide this
70 information using the "`--with-gettext=/dir/path`" option.
74 libslax is not required by libxo; it contains the "oxtradoc" program
75 used to format documentation.
77 For additional information, see :ref:`building`.
79 Howto: Convert command line applications
80 ----------------------------------------
82 Common question: How do I convert an existing command line application?
84 There are four basic steps for converting command line application to
87 - Setting up the context
88 - Converting printf calls
90 - Converting error functions
92 Setting up the context
93 ~~~~~~~~~~~~~~~~~~~~~~
95 To use libxo, you'll need to include the "xo.h" header file in your
100 In your main() function, you'll need to call xo_parse_args to handling
101 argument parsing (:ref:`xo_parse_args`). This function removes
102 libxo-specific arguments the program's argv and returns either the
103 number of remaining arguments or -1 to indicate an error::
106 main (int argc, char **argv)
108 argc = xo_parse_args(argc, argv);
115 .. index:: xo_finish_atexit
117 At the bottom of your main(), you'll need to call xo_finish() to
118 complete output processing for the default handle (:ref:`handles`). This
119 is required to flush internal information buffers. libxo provides the
120 xo_finish_atexit function that is suitable for use with the
121 :manpage:`atexit(3)` function::
123 atexit(xo_finish_atexit);
125 Converting printf Calls
126 ~~~~~~~~~~~~~~~~~~~~~~~
128 The second task is inspecting code for :manpage:`printf(3)` calls and
129 replacing them with xo_emit() calls. The format strings are similar
130 in task, but libxo format strings wrap output fields in braces. The
131 following two calls produce identical text output::
134 printf("There are %d %s events\n", count, etype);
137 xo_emit("There are {:count/%d} {:event} events\n", count, etype);
139 "count" and "event" are used as names for JSON and XML output. The
140 "count" field uses the format "%d" and "event" uses the default "%s"
141 format. Both are "value" roles, which is the default role.
143 Since text outside of output fields is passed verbatim, other roles
144 are less important, but their proper use can help make output more
145 useful. The "note" and "label" roles allow HTML output to recognize
146 the relationship between text and the associated values, allowing
147 appropriate "hover" and "onclick" behavior. Using the "units" role
148 allows the presentation layer to perform conversions when needed. The
149 "warning" and "error" roles allows use of color and font to draw
150 attention to warnings. The "padding" role makes the use of vital
151 whitespace more clear (:ref:`padding-role`).
153 The "*title*" role indicates the headings of table and sections. This
154 allows HTML output to use CSS to make this relationship more obvious::
157 printf("Statistics:\n");
160 xo_emit("{T:Statistics}:\n");
162 The "*color*" roles controls foreground and background colors, as well
163 as effects like bold and underline (see :ref:`color-role`)::
166 xo_emit("{C:bold}required{C:}\n");
168 Finally, the start- and stop-anchor roles allow justification and
169 padding over multiple fields (see :ref:`anchor-role`)::
172 snprintf(buf, sizeof(buf), "(%u/%u/%u)", min, ave, max);
176 xo_emit("{[:30}({:minimum/%u}/{:average/%u}/{:maximum/%u}{]:}",
182 Text output doesn't have any sort of hierarchy, but XML and JSON
183 require this. Typically applications use indentation to represent
187 printf("table %d\n", tnum);
188 for (i = 0; i < tmax; i++) {
189 printf(" %s %d\n", table[i].name, table[i].size);
193 xo_emit("{T:/table %d}\n", tnum);
194 xo_open_list("table");
195 for (i = 0; i < tmax; i++) {
196 xo_open_instance("table");
197 xo_emit("{P: }{k:name} {:size/%d}\n",
198 table[i].name, table[i].size);
199 xo_close_instance("table");
201 xo_close_list("table");
203 The open and close list functions are used before and after the list,
204 and the open and close instance functions are used before and after
205 each instance with in the list.
207 Typically these developer looks for a "for" loop as an indication of
208 where to put these calls.
210 In addition, the open and close container functions allow for
211 organization levels of hierarchy::
214 printf("Paging information:\n");
215 printf(" Free: %lu\n", free);
216 printf(" Active: %lu\n", active);
217 printf(" Inactive: %lu\n", inactive);
220 xo_open_container("paging-information");
221 xo_emit("{P: }{L:Free: }{:free/%lu}\n", free);
222 xo_emit("{P: }{L:Active: }{:active/%lu}\n", active);
223 xo_emit("{P: }{L:Inactive: }{:inactive/%lu}\n", inactive);
224 xo_close_container("paging-information");
226 Converting Error Functions
227 ~~~~~~~~~~~~~~~~~~~~~~~~~~
229 libxo provides variants of the standard error and warning functions,
230 :manpage:`err(3)` and :manpage:`warn(3)`. There are two variants, one
231 for putting the errors on standard error, and the other writes the
232 errors and warnings to the handle using the appropriate encoding
236 err(1, "cannot open output file: %s", file);
239 xo_err(1, "cannot open output file: %s", file);
240 xo_emit_err(1, "cannot open output file: {:filename}", file);
247 One important item: call `xo_finish` at the end of your program so
248 ensure that all buffered data is written out. You can call it
249 explicitly call it, or use :manpage:`atexit(3)` to have
250 `xo_finish_atexit` called implicitly on exit::
259 Howto: Use "xo" in Shell Scripts
260 --------------------------------
262 .. admonition:: Needed
264 Documentation is needed for this area.
266 .. index:: Internationalization (i18n)
272 Howto: Internationalization (i18n)
273 -----------------------------------------------
275 How do I use libxo to support internationalization?
277 libxo allows format and field strings to be used a keys into message
278 catalogs to enable translation into a user's native language by
279 invoking the standard :manpage:`gettext(3)` functions.
281 gettext setup is a bit complicated: text strings are extracted from
282 source files into "*portable object template*" (.pot) files using the
283 `xgettext` command. For each language, this template file is used as
284 the source for a message catalog in the "*portable object*" (.po)
285 format, which are translated by hand and compiled into "*machine
286 object*" (.mo) files using the `msgfmt` command. The .mo files are
287 then typically installed in the /usr/share/locale or
288 /opt/local/share/locale directories. At run time, the user's language
289 settings are used to select a .mo file which is searched for matching
290 messages. Text strings in the source code are used as keys to look up
291 the native language strings in the .mo file.
293 Since the xo_emit format string is used as the key into the message
294 catalog, libxo removes unimportant field formatting and modifiers from
295 the format string before use so that minor formatting changes will not
296 impact the expensive translation process. We don't want a developer
297 change such as changing "/%06d" to "/%08d" to force hand inspection of
298 all .po files. The simplified version can be generated for a single
299 message using the `xopo -s $text` command, or an entire .pot can be
300 translated using the `xopo -f $input -o $output` command::
303 % xopo -s "There are {:count/%u} {:event/%.6s} events\n"
304 There are {:count} {:event} events\n
306 Recommended workflow:
307 # Extract text messages
308 xgettext --default-domain=foo --no-wrap \
309 --add-comments --keyword=xo_emit --keyword=xo_emit_h \
310 --keyword=xo_emit_warn -C -E -n --foreign-user \
313 # Simplify format strings for libxo
314 xopo -f foo.pot.raw -o foo.pot
316 # For a new language, just copy the file
317 cp foo.pot po/LC/my_lang/foo.po
319 # For an existing language:
320 msgmerge --no-wrap po/LC/my_lang/foo.po \
321 foo.pot -o po/LC/my_lang/foo.po.new
323 # Now the hard part: translate foo.po using tools
324 # like poedit or emacs' po-mode
326 # Compile the finished file; Use of msgfmt's "-v" option is
327 # strongly encouraged, so that "fuzzy" entries are reported.
328 msgfmt -v -o po/my_lang/LC_MESSAGES/foo.mo po/my_lang/foo.po
330 # Install the .mo file
331 sudo cp po/my_lang/LC_MESSAGES/foo.mo \
332 /opt/local/share/locale/my_lang/LC_MESSAGE/
334 Once these steps are complete, you can use the `gettext` command to
335 test the message catalog::
337 gettext -d foo -e "some text"
342 There are three features used in libxo used to support i18n:
344 - The "{G:}" role looks for a translation of the format string.
345 - The "{g:}" modifier looks for a translation of the field.
346 - The "{p:}" modifier looks for a pluralized version of the field.
348 Together these three flags allows a single function call to give
349 native language support, as well as libxo's normal XML, JSON, and HTML
352 printf(gettext("Received %zu %s from {g:server} server\n"),
353 counter, ngettext("byte", "bytes", counter),
356 xo_emit("{G:}Received {:received/%zu} {Ngp:byte,bytes} "
357 "from {g:server} server\n", counter, "web");
359 libxo will see the "{G:}" role and will first simplify the format
360 string, removing field formats and modifiers::
362 "Received {:received} {N:byte,bytes} from {:server} server\n"
364 libxo calls :manpage:`gettext(3)` with that string to get a localized
365 version. If your language were *Pig Latin*, the result might look
368 "Eceivedray {:received} {N:byte,bytes} omfray "
369 "{:server} erversay\n"
371 Note the field names do not change and they should not be translated.
372 The contents of the note ("byte,bytes") should also not be translated,
373 since the "g" modifier will need the untranslated value as the key for
376 The field "{g:server}" requests the rendered value of the field be
377 translated using :manpage:`gettext(3)`. In this example, "web" would
380 The field "{Ngp:byte,bytes}" shows an example of plural form using the
381 "{p:}" modifier with the "{g:}" modifier. The base singular and plural
382 forms appear inside the field, separated by a comma. At run time,
383 libxo uses the previous field's numeric value to decide which form to
384 use by calling :manpage:`ngettext(3)`.
386 If a domain name is needed, it can be supplied as the content of the
387 {G:} role. Domain names remain in use throughout the format string
388 until cleared with another domain name::
390 printf(dgettext("dns", "Host %s not found: %d(%s)\n"),
391 name, errno, dgettext("strerror", strerror(errno)));
393 xo_emit("{G:dns}Host {:hostname} not found: "
394 "%d({G:strerror}{g:%m})\n", name, errno);