xref: /freebsd/contrib/libxo/doc/field-formatting.rst (revision 13ea0450a9c8742119d36f3bf8f47accdce46e54)
1
2.. index:: Field Formatting
3
4Field Formatting
5----------------
6
7The field format is similar to the format string for printf(3).  Its
8use varies based on the role of the field, but generally is used to
9format the field's contents.
10
11If the format string is not provided for a value field, it defaults to
12"%s".
13
14Note a field definition can contain zero or more printf-style
15'directives', which are sequences that start with a '%' and end with
16one of following characters: "diouxXDOUeEfFgGaAcCsSp".  Each directive
17is matched by one of more arguments to the xo_emit function.
18
19The format string has the form::
20
21  '%' format-modifier * format-character
22
23The format-modifier can be:
24
25- a '#' character, indicating the output value should be prefixed
26  with '0x', typically to indicate a base 16 (hex) value.
27- a minus sign ('-'), indicating the output value should be padded on
28  the right instead of the left.
29- a leading zero ('0') indicating the output value should be padded on the
30  left with zeroes instead of spaces (' ').
31- one or more digits ('0' - '9') indicating the minimum width of the
32  argument.  If the width in columns of the output value is less than
33  the minimum width, the value will be padded to reach the minimum.
34- a period followed by one or more digits indicating the maximum
35  number of bytes which will be examined for a string argument, or the maximum
36  width for a non-string argument.  When handling ASCII strings this
37  functions as the field width but for multi-byte characters, a single
38  character may be composed of multiple bytes.
39  xo_emit will never dereference memory beyond the given number of bytes.
40- a second period followed by one or more digits indicating the maximum
41  width for a string argument.  This modifier cannot be given for non-string
42  arguments.
43- one or more 'h' characters, indicating shorter input data.
44- one or more 'l' characters, indicating longer input data.
45- a 'z' character, indicating a 'size_t' argument.
46- a 't' character, indicating a 'ptrdiff_t' argument.
47- a ' ' character, indicating a space should be emitted before
48  positive numbers.
49- a '+' character, indicating sign should emitted before any number.
50
51Note that 'q', 'D', 'O', and 'U' are considered deprecated and will be
52removed eventually.
53
54The format character is described in the following table:
55
56===== ================= ======================
57 Ltr   Argument Type     Format
58===== ================= ======================
59 d     int               base 10 (decimal)
60 i     int               base 10 (decimal)
61 o     int               base 8 (octal)
62 u     unsigned          base 10 (decimal)
63 x     unsigned          base 16 (hex)
64 X     unsigned long     base 16 (hex)
65 D     long              base 10 (decimal)
66 O     unsigned long     base 8 (octal)
67 U     unsigned long     base 10 (decimal)
68 e     double            [-]d.ddde+-dd
69 E     double            [-]d.dddE+-dd
70 f     double            [-]ddd.ddd
71 F     double            [-]ddd.ddd
72 g     double            as 'e' or 'f'
73 G     double            as 'E' or 'F'
74 a     double            [-]0xh.hhhp[+-]d
75 A     double            [-]0Xh.hhhp[+-]d
76 c     unsigned char     a character
77 C     wint_t            a character
78 s     char \*           a UTF-8 string
79 S     wchar_t \*        a unicode/WCS string
80 p     void \*           '%#lx'
81===== ================= ======================
82
83The 'h' and 'l' modifiers affect the size and treatment of the
84argument:
85
86===== ============= ====================
87 Mod   d, i          o, u, x, X
88===== ============= ====================
89 hh    signed char   unsigned char
90 h     short         unsigned short
91 l     long          unsigned long
92 ll    long long     unsigned long long
93 j     intmax_t      uintmax_t
94 t     ptrdiff_t     ptrdiff_t
95 z     size_t        size_t
96 q     quad_t        u_quad_t
97===== ============= ====================
98
99.. index:: UTF-8
100.. index:: Locale
101
102.. _utf-8:
103
104UTF-8 and Locale Strings
105~~~~~~~~~~~~~~~~~~~~~~~~
106
107For strings, the 'h' and 'l' modifiers affect the interpretation of
108the bytes pointed to argument.  The default '%s' string is a 'char \*'
109pointer to a string encoded as UTF-8.  Since UTF-8 is compatible with
110ASCII data, a normal 7-bit ASCII string can be used.  '%ls' expects a
111'wchar_t \*' pointer to a wide-character string, encoded as a 32-bit
112Unicode values.  '%hs' expects a 'char \*' pointer to a multi-byte
113string encoded with the current locale, as given by the LC_CTYPE,
114LANG, or LC_ALL environment varibles.  The first of this list of
115variables is used and if none of the variables are set, the locale
116defaults to "UTF-8".
117
118libxo will convert these arguments as needed to either UTF-8 (for XML,
119JSON, and HTML styles) or locale-based strings for display in text
120style::
121
122   xo_emit("All strings are utf-8 content {:tag/%ls}",
123           L"except for wide strings");
124
125======== ================== ===============================
126 Format   Argument Type      Argument Contents
127======== ================== ===============================
128 %s       const char \*      UTF-8 string
129 %S       const char \*      UTF-8 string (alias for '%ls')
130 %ls      const wchar_t \*   Wide character UNICODE string
131 %hs      const char *       locale-based string
132======== ================== ===============================
133
134.. admonition:: "Long", not "locale"
135
136  The "*l*" in "%ls" is for "*long*", following the convention of "%ld".
137  It is not "*locale*", a common mis-mnemonic.  "%S" is equivalent to
138  "%ls".
139
140For example, the following function is passed a locale-base name, a
141hat size, and a time value.  The hat size is formatted in a UTF-8
142(ASCII) string, and the time value is formatted into a wchar_t
143string::
144
145    void print_order (const char *name, int size,
146                      struct tm *timep) {
147        char buf[32];
148        const char *size_val = "unknown";
149
150	if (size > 0)
151            snprintf(buf, sizeof(buf), "%d", size);
152            size_val = buf;
153        }
154
155        wchar_t when[32];
156        wcsftime(when, sizeof(when), L"%d%b%y", timep);
157
158        xo_emit("The hat for {:name/%hs} is {:size/%s}.\n",
159                name, size_val);
160        xo_emit("It was ordered on {:order-time/%ls}.\n",
161                when);
162    }
163
164It is important to note that xo_emit will perform the conversion
165required to make appropriate output.  Text style output uses the
166current locale (as described above), while XML, JSON, and HTML use
167UTF-8.
168
169UTF-8 and locale-encoded strings can use multiple bytes to encode one
170column of data.  The traditional "precision'" (aka "max-width") value
171for "%s" printf formatting becomes overloaded since it specifies both
172the number of bytes that can be safely referenced and the maximum
173number of columns to emit.  xo_emit uses the precision as the former,
174and adds a third value for specifying the maximum number of columns.
175
176In this example, the name field is printed with a minimum of 3 columns
177and a maximum of 6.  Up to ten bytes of data at the location given by
178'name' are in used in filling those columns::
179
180    xo_emit("{:name/%3.10.6s}", name);
181
182Characters Outside of Field Definitions
183~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
184
185Characters in the format string that are not part of a field
186definition are copied to the output for the TEXT style, and are
187ignored for the JSON and XML styles.  For HTML, these characters are
188placed in a <div> with class "text"::
189
190  EXAMPLE:
191      xo_emit("The hat is {:size/%s}.\n", size_val);
192  TEXT:
193      The hat is extra small.
194  XML:
195      <size>extra small</size>
196  JSON:
197      "size": "extra small"
198  HTML:
199      <div class="text">The hat is </div>
200      <div class="data" data-tag="size">extra small</div>
201      <div class="text">.</div>
202
203.. index:: errno
204
205"%m" Is Supported
206~~~~~~~~~~~~~~~~~
207
208libxo supports the '%m' directive, which formats the error message
209associated with the current value of "errno".  It is the equivalent
210of "%s" with the argument strerror(errno)::
211
212    xo_emit("{:filename} cannot be opened: {:error/%m}", filename);
213    xo_emit("{:filename} cannot be opened: {:error/%s}",
214            filename, strerror(errno));
215
216"%n" Is Not Supported
217~~~~~~~~~~~~~~~~~~~~~
218
219libxo does not support the '%n' directive.  It's a bad idea and we
220just don't do it.
221
222The Encoding Format (eformat)
223~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
224
225The "eformat" string is the format string used when encoding the field
226for JSON and XML.  If not provided, it defaults to the primary format
227with any minimum width removed.  If the primary is not given, both
228default to "%s".
229
230Content Strings
231~~~~~~~~~~~~~~~
232
233For padding and labels, the content string is considered the content,
234unless a format is given.
235
236.. index:: printf-like
237
238Argument Validation
239~~~~~~~~~~~~~~~~~~~
240
241Many compilers and tool chains support validation of printf-like
242arguments.  When the format string fails to match the argument list,
243a warning is generated.  This is a valuable feature and while the
244formatting strings for libxo differ considerably from printf, many of
245these checks can still provide build-time protection against bugs.
246
247libxo provide variants of functions that provide this ability, if the
248"--enable-printflike" option is passed to the "configure" script.
249These functions use the "_p" suffix, like "xo_emit_p()",
250xo_emit_hp()", etc.
251
252The following are features of libxo formatting strings that are
253incompatible with printf-like testing:
254
255- implicit formats, where "{:tag}" has an implicit "%s";
256- the "max" parameter for strings, where "{:tag/%4.10.6s}" means up to
257  ten bytes of data can be inspected to fill a minimum of 4 columns and
258  a maximum of 6;
259- percent signs in strings, where "{:filled}%" makes a single,
260  trailing percent sign;
261- the "l" and "h" modifiers for strings, where "{:tag/%hs}" means
262  locale-based string and "{:tag/%ls}" means a wide character string;
263- distinct encoding formats, where "{:tag/#%s/%s}" means the display
264  styles (text and HTML) will use "#%s" where other styles use "%s";
265
266If none of these features are in use by your code, then using the "_p"
267variants might be wise:
268
269================== ========================
270 Function           printf-like Equivalent
271================== ========================
272 xo_emit_hv         xo_emit_hvp
273 xo_emit_h          xo_emit_hp
274 xo_emit            xo_emit_p
275 xo_emit_warn_hcv   xo_emit_warn_hcvp
276 xo_emit_warn_hc    xo_emit_warn_hcp
277 xo_emit_warn_c     xo_emit_warn_cp
278 xo_emit_warn       xo_emit_warn_p
279 xo_emit_warnx      xo_emit_warnx_p
280 xo_emit_err        xo_emit_err_p
281 xo_emit_errx       xo_emit_errx_p
282 xo_emit_errc       xo_emit_errc_p
283================== ========================
284
285.. index:: performance
286.. index:: XOEF_RETAIN
287
288.. _retain:
289
290Retaining Parsed Format Information
291~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
292
293libxo can retain the parsed internal information related to the given
294format string, allowing subsequent xo_emit calls, the retained
295information is used, avoiding repetitive parsing of the format string::
296
297    SYNTAX:
298      int xo_emit_f(xo_emit_flags_t flags, const char fmt, ...);
299    EXAMPLE:
300      xo_emit_f(XOEF_RETAIN, "{:some/%02d}{:thing/%-6s}{:fancy}\n",
301                     some, thing, fancy);
302
303To retain parsed format information, use the XOEF_RETAIN flag to the
304xo_emit_f() function.  A complete set of xo_emit_f functions exist to
305match all the xo_emit function signatures (with handles, varadic
306argument, and printf-like flags):
307
308================== ========================
309 Function           Flags Equivalent
310================== ========================
311 xo_emit_hv         xo_emit_hvf
312 xo_emit_h          xo_emit_hf
313 xo_emit            xo_emit_f
314 xo_emit_hvp        xo_emit_hvfp
315 xo_emit_hp         xo_emit_hfp
316 xo_emit_p          xo_emit_fp
317================== ========================
318
319The format string must be immutable across multiple calls to xo_emit_f(),
320since the library retains the string.  Typically this is done by using
321static constant strings, such as string literals. If the string is not
322immutable, the XOEF_RETAIN flag must not be used.
323
324The functions xo_retain_clear() and xo_retain_clear_all() release
325internal information on either a single format string or all format
326strings, respectively.  Neither is required, but the library will
327retain this information until it is cleared or the process exits::
328
329    const char *fmt = "{:name}  {:count/%d}\n";
330    for (i = 0; i < 1000; i++) {
331        xo_open_instance("item");
332        xo_emit_f(XOEF_RETAIN, fmt, name[i], count[i]);
333    }
334    xo_retain_clear(fmt);
335
336The retained information is kept as thread-specific data.
337
338Example
339~~~~~~~
340
341In this example, the value for the number of items in stock is emitted::
342
343        xo_emit("{P:   }{Lwc:In stock}{:in-stock/%u}\n",
344                instock);
345
346This call will generate the following output::
347
348  TEXT:
349       In stock: 144
350  XML:
351      <in-stock>144</in-stock>
352  JSON:
353      "in-stock": 144,
354  HTML:
355      <div class="line">
356        <div class="padding">   </div>
357        <div class="label">In stock</div>
358        <div class="decoration">:</div>
359        <div class="padding"> </div>
360        <div class="data" data-tag="in-stock">144</div>
361      </div>
362
363Clearly HTML wins the verbosity award, and this output does
364not include XOF_XPATH or XOF_INFO data, which would expand the
365penultimate line to::
366
367       <div class="data" data-tag="in-stock"
368          data-xpath="/top/data/item/in-stock"
369          data-type="number"
370          data-help="Number of items in stock">144</div>
371