1 2Howtos: Focused Directions 3========================== 4 5This section provides task-oriented instructions for selected tasks. 6If you have a task that needs instructions, please open a request as 7an enhancement issue on github. 8 9Howto: Report bugs 10------------------ 11 12libxo uses github to track bugs or request enhancements. Please use 13the following URL: 14 15 https://github.com/Juniper/libxo/issues 16 17Howto: Install libxo 18-------------------- 19 20libxo is open source, under a new BSD license. Source code is 21available on github, as are recent releases. To get the most 22current release, please visit: 23 24 https://github.com/Juniper/libxo/releases 25 26After downloading and untarring the source code, building involves the 27following steps:: 28 29 sh bin/setup.sh 30 cd build 31 ../configure 32 make 33 make test 34 sudo make install 35 36libxo uses a distinct "*build*" directory to keep generated files 37separated from source files. 38 39.. index:: configure 40 41Use "`../configure --help`" to display available configuration 42options, which include the following:: 43 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 51 52Compiler warnings are a very good thing, but recent compiler version 53have added some very pedantic checks. While every attempt is made to 54keep libxo code warning-free, warnings are now optional. If you are 55doing development work on libxo, it is required that you 56use --enable-warnings to keep the code warning free, but most users 57need not use this option. 58 59.. index:: --enable-text-only 60 61libxo provides the `--enable-text-only` option to reduce the 62footprint of the library for smaller installations. XML, JSON, and 63HTML rendering logic is removed. 64 65.. index:: --with-gettext 66 67The gettext library does not provide a simple means of learning its 68location, but libxo will look for it in /usr and /opt/local. If 69installed elsewhere, the installer will need to provide this 70information using the "`--with-gettext=/dir/path`" option. 71 72.. index:: libslax 73 74libslax is not required by libxo; it contains the "oxtradoc" program 75used to format documentation. 76 77For additional information, see :ref:`building`. 78 79Howto: Convert command line applications 80---------------------------------------- 81 82Common question: How do I convert an existing command line application? 83 84There are four basic steps for converting command line application to 85use libxo:: 86 87- Setting up the context 88- Converting printf calls 89- Creating hierarchy 90- Converting error functions 91 92Setting up the context 93~~~~~~~~~~~~~~~~~~~~~~ 94 95To use libxo, you'll need to include the "xo.h" header file in your 96source code files:: 97 98 #include <libxo/xo.h> 99 100In your main() function, you'll need to call xo_parse_args to handling 101argument parsing (:ref:`xo_parse_args`). This function removes 102libxo-specific arguments the program's argv and returns either the 103number of remaining arguments or -1 to indicate an error:: 104 105 int 106 main (int argc, char **argv) 107 { 108 argc = xo_parse_args(argc, argv); 109 if (argc < 0) 110 return argc; 111 .... 112 } 113 114.. index:: atexit 115.. index:: xo_finish_atexit 116 117At the bottom of your main(), you'll need to call xo_finish() to 118complete output processing for the default handle (:ref:`handles`). This 119is required to flush internal information buffers. libxo provides the 120xo_finish_atexit function that is suitable for use with the 121:manpage:`atexit(3)` function:: 122 123 atexit(xo_finish_atexit); 124 125Converting printf Calls 126~~~~~~~~~~~~~~~~~~~~~~~ 127 128The second task is inspecting code for :manpage:`printf(3)` calls and 129replacing them with xo_emit() calls. The format strings are similar 130in task, but libxo format strings wrap output fields in braces. The 131following two calls produce identical text output:: 132 133 OLD:: 134 printf("There are %d %s events\n", count, etype); 135 136 NEW:: 137 xo_emit("There are {:count/%d} {:event} events\n", count, etype); 138 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" 141format. Both are "value" roles, which is the default role. 142 143Since text outside of output fields is passed verbatim, other roles 144are less important, but their proper use can help make output more 145useful. The "note" and "label" roles allow HTML output to recognize 146the relationship between text and the associated values, allowing 147appropriate "hover" and "onclick" behavior. Using the "units" role 148allows the presentation layer to perform conversions when needed. The 149"warning" and "error" roles allows use of color and font to draw 150attention to warnings. The "padding" role makes the use of vital 151whitespace more clear (:ref:`padding-role`). 152 153The "*title*" role indicates the headings of table and sections. This 154allows HTML output to use CSS to make this relationship more obvious:: 155 156 OLD:: 157 printf("Statistics:\n"); 158 159 NEW:: 160 xo_emit("{T:Statistics}:\n"); 161 162The "*color*" roles controls foreground and background colors, as well 163as effects like bold and underline (see :ref:`color-role`):: 164 165 NEW:: 166 xo_emit("{C:bold}required{C:}\n"); 167 168Finally, the start- and stop-anchor roles allow justification and 169padding over multiple fields (see :ref:`anchor-role`):: 170 171 OLD:: 172 snprintf(buf, sizeof(buf), "(%u/%u/%u)", min, ave, max); 173 printf("%30s", buf); 174 175 NEW:: 176 xo_emit("{[:30}({:minimum/%u}/{:average/%u}/{:maximum/%u}{]:}", 177 min, ave, max); 178 179Creating Hierarchy 180~~~~~~~~~~~~~~~~~~ 181 182Text output doesn't have any sort of hierarchy, but XML and JSON 183require this. Typically applications use indentation to represent 184these relationship:: 185 186 OLD:: 187 printf("table %d\n", tnum); 188 for (i = 0; i < tmax; i++) { 189 printf(" %s %d\n", table[i].name, table[i].size); 190 } 191 192 NEW:: 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"); 200 } 201 xo_close_list("table"); 202 203The open and close list functions are used before and after the list, 204and the open and close instance functions are used before and after 205each instance with in the list. 206 207Typically these developer looks for a "for" loop as an indication of 208where to put these calls. 209 210In addition, the open and close container functions allow for 211organization levels of hierarchy:: 212 213 OLD:: 214 printf("Paging information:\n"); 215 printf(" Free: %lu\n", free); 216 printf(" Active: %lu\n", active); 217 printf(" Inactive: %lu\n", inactive); 218 219 NEW:: 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"); 225 226Converting Error Functions 227~~~~~~~~~~~~~~~~~~~~~~~~~~ 228 229libxo provides variants of the standard error and warning functions, 230:manpage:`err(3)` and :manpage:`warn(3)`. There are two variants, one 231for putting the errors on standard error, and the other writes the 232errors and warnings to the handle using the appropriate encoding 233style:: 234 235 OLD:: 236 err(1, "cannot open output file: %s", file); 237 238 NEW:: 239 xo_err(1, "cannot open output file: %s", file); 240 xo_emit_err(1, "cannot open output file: {:filename}", file); 241 242.. index:: xo_finish 243 244Call xo_finish 245~~~~~~~~~~~~~~ 246 247One important item: call `xo_finish` at the end of your program so 248ensure that all buffered data is written out. You can call it 249explicitly call it, or use :manpage:`atexit(3)` to have 250`xo_finish_atexit` called implicitly on exit:: 251 252 OLD:: 253 exit(0); 254 255 NEW:: 256 xo_finish(); 257 exit(0); 258 259Howto: Use "xo" in Shell Scripts 260-------------------------------- 261 262.. admonition:: Needed 263 264 Documentation is needed for this area. 265 266.. index:: Internationalization (i18n) 267.. index:: gettext 268.. index:: xopo 269 270.. _i18n: 271 272Howto: Internationalization (i18n) 273----------------------------------------------- 274 275 How do I use libxo to support internationalization? 276 277libxo allows format and field strings to be used a keys into message 278catalogs to enable translation into a user's native language by 279invoking the standard :manpage:`gettext(3)` functions. 280 281gettext setup is a bit complicated: text strings are extracted from 282source files into "*portable object template*" (.pot) files using the 283`xgettext` command. For each language, this template file is used as 284the source for a message catalog in the "*portable object*" (.po) 285format, which are translated by hand and compiled into "*machine 286object*" (.mo) files using the `msgfmt` command. The .mo files are 287then typically installed in the /usr/share/locale or 288/opt/local/share/locale directories. At run time, the user's language 289settings are used to select a .mo file which is searched for matching 290messages. Text strings in the source code are used as keys to look up 291the native language strings in the .mo file. 292 293Since the xo_emit format string is used as the key into the message 294catalog, libxo removes unimportant field formatting and modifiers from 295the format string before use so that minor formatting changes will not 296impact the expensive translation process. We don't want a developer 297change such as changing "/%06d" to "/%08d" to force hand inspection of 298all .po files. The simplified version can be generated for a single 299message using the `xopo -s $text` command, or an entire .pot can be 300translated using the `xopo -f $input -o $output` command:: 301 302 EXAMPLE: 303 % xopo -s "There are {:count/%u} {:event/%.6s} events\n" 304 There are {:count} {:event} events\n 305 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 \ 311 -o foo.pot.raw foo.c 312 313 # Simplify format strings for libxo 314 xopo -f foo.pot.raw -o foo.pot 315 316 # For a new language, just copy the file 317 cp foo.pot po/LC/my_lang/foo.po 318 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 322 323 # Now the hard part: translate foo.po using tools 324 # like poedit or emacs' po-mode 325 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 329 330 # Install the .mo file 331 sudo cp po/my_lang/LC_MESSAGES/foo.mo \ 332 /opt/local/share/locale/my_lang/LC_MESSAGE/ 333 334Once these steps are complete, you can use the `gettext` command to 335test the message catalog:: 336 337 gettext -d foo -e "some text" 338 339i18n and xo_emit 340~~~~~~~~~~~~~~~~ 341 342There are three features used in libxo used to support i18n: 343 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. 347 348Together these three flags allows a single function call to give 349native language support, as well as libxo's normal XML, JSON, and HTML 350support:: 351 352 printf(gettext("Received %zu %s from {g:server} server\n"), 353 counter, ngettext("byte", "bytes", counter), 354 gettext("web")); 355 356 xo_emit("{G:}Received {:received/%zu} {Ngp:byte,bytes} " 357 "from {g:server} server\n", counter, "web"); 358 359libxo will see the "{G:}" role and will first simplify the format 360string, removing field formats and modifiers:: 361 362 "Received {:received} {N:byte,bytes} from {:server} server\n" 363 364libxo calls :manpage:`gettext(3)` with that string to get a localized 365version. If your language were *Pig Latin*, the result might look 366like:: 367 368 "Eceivedray {:received} {N:byte,bytes} omfray " 369 "{:server} erversay\n" 370 371Note the field names do not change and they should not be translated. 372The contents of the note ("byte,bytes") should also not be translated, 373since the "g" modifier will need the untranslated value as the key for 374the message catalog. 375 376The field "{g:server}" requests the rendered value of the field be 377translated using :manpage:`gettext(3)`. In this example, "web" would 378be used. 379 380The field "{Ngp:byte,bytes}" shows an example of plural form using the 381"{p:}" modifier with the "{g:}" modifier. The base singular and plural 382forms appear inside the field, separated by a comma. At run time, 383libxo uses the previous field's numeric value to decide which form to 384use by calling :manpage:`ngettext(3)`. 385 386If 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 388until cleared with another domain name:: 389 390 printf(dgettext("dns", "Host %s not found: %d(%s)\n"), 391 name, errno, dgettext("strerror", strerror(errno))); 392 393 xo_emit("{G:dns}Host {:hostname} not found: " 394 "%d({G:strerror}{g:%m})\n", name, errno); 395