xref: /freebsd/contrib/libxo/libxo/xo_format.5 (revision 5b9c547c)
1.\" #
2.\" # Copyright (c) 2014, Juniper Networks, Inc.
3.\" # All rights reserved.
4.\" # This SOFTWARE is licensed under the LICENSE provided in the
5.\" # ../Copyright file. By downloading, installing, copying, or
6.\" # using the SOFTWARE, you agree to be bound by the terms of that
7.\" # LICENSE.
8.\" # Phil Shafer, July 2014
9.\"
10.Dd December 4, 2014
11.Dt LIBXO 3
12.Os
13.Sh NAME
14.Nm xo_format
15.Nd content of format descriptors for xo_emit
16.Sh DESCRIPTION
17.Pp
18.Nm libxo
19uses format strings to control the rendering of data into
20various output styles, including
21.Em text ,
22.Em XML ,
23.EM JSON ,
24and
25.Em HTML .
26Each format string contains a set of zero or more
27.Dq field descriptions ,
28which describe independent data fields.
29Each field description contains a set of
30.Dq modifiers ,
31a
32.Dq content string ,
33and zero, one, or two
34.Dq format descriptors .
35The modifiers tell
36.Nm libxo
37what the field is and how to treat it, while the format descriptors are
38formatting instructions using
39.Xr printf 3 Ns -style
40format strings, telling
41.Nm libxo
42how to format the field.
43The field description is placed inside
44a set of braces, with a colon
45.Ql ( \&: )
46after the modifiers and a slash
47.Ql ( \&/ )
48before each format descriptors.
49Text may be intermixed with
50field descriptions within the format string.
51.Pp
52The field description is given as follows:
53.Bd -literal -offset indent
54    '{' [ role | modifier ]* ':' [ content ]
55            [ '/' field-format [ '/' encoding-format ]] '}'
56.Ed
57.Pp
58The role describes the function of the field, while the modifiers
59enable optional behaviors.
60The contents, field-format, and
61encoding-format are used in varying ways, based on the role.
62These are described in the following sections.
63.Pp
64In the following example, three field descriptors appear.
65The first
66is a padding field containing three spaces of padding, the second is a
67label ("In stock"), and the third is a value field ("in-stock").
68The in-stock field has a "%u" format that will parse the next argument
69passed to the
70.Xr xo_emit 3 ,
71function as an unsigned integer.
72.Bd -literal -offset indent
73        xo_emit("{P:   }{Lwc:In stock}{:in-stock/%u}\\n", 65);
74.Ed
75.Pp
76This single line of code can generate text ("In stock: 65\\n"), XML
77("<in-stock>65</in-stock>"), JSON ('"in-stock": 6'), or HTML (too
78lengthy to be listed here).
79.Ss Modifier Roles
80Modifiers are optional, and indicate the role and formatting of the
81content.
82The roles are listed below; only one role is permitted:
83.Pp
84.Bl -column "M" "Name12341234"
85.It Sy "M  Name           Description"
86.It D "decoration  " "Field is non-text (e.g. colon, comma)"
87.It E "error       " "Field is an error message"
88.It L "label       " "Field is text that prefixes a value"
89.It N "note        " "Field is text that follows a value"
90.It P "padding     " "Field is spaces needed for vertical alignment"
91.It T "title       " "Field is a title value for headings"
92.It U "units       " "Field is the units for the previous value field"
93.It V "value       " "Field is the name of field (the default)"
94.It W "warning     " "Field is a warning message"
95.It \&[ "start anchor" "Begin a section of anchored variable-width text"
96.It \&] "stop anchor " "End a section of anchored variable-width text"
97.El
98.Pp
99.Ss The Decoration Role ({D:})
100Decorations are typically punctuation marks such as colons,
101semi-colons, and commas used to decorate the text and make it simpler
102for human readers.
103By marking these distinctly, HTML usage scenarios
104can use CSS to direct their display parameters.
105.Bd -literal -offset indent
106    xo_emit("{D:((}{:name}{D:))}\\n", name);
107.Ed
108.Ss The Label Role ({L:})
109Labels are text that appears before a value.
110.Bd -literal -offset indent
111    xo_emit("{Lwc:Cost}{:cost/%u}\\n", cost);
112.Ed
113.Ss The Note Role ({N:})
114Notes are text that appears after a value.
115.Bd -literal -offset indent
116    xo_emit("{:cost/%u} {N:per year}\\n", cost);
117.Ed
118.Ss The Padding Role ({P:})
119Padding represents whitespace used before and between fields.
120The padding content can be either static, when placed directly within
121the field descriptor, or a printf-style format descriptor can be used,
122if preceded by a slash ("/"):
123.Bd -literal -offset indent
124    xo_emit("{P:        }{Lwc:Cost}{:cost/%u}\\n", cost);
125    xo_emit("{P:/30s}{Lwc:Cost}{:cost/%u}\\n", "", cost);
126.Ed
127.Ss The Title Role ({T:})
128Titles are heading or column headers that are meant to be displayed to
129the user.
130The title can be either static, when placed directly within
131the field descriptor, or a printf-style format descriptor can be used,
132if preceded by a slash ("/"):
133.Bd -literal -offset indent
134    xo_emit("{T:Interface Statistics}\\n");
135    xo_emit("{T:/%20.20s}{T:/%6.6s}\\n", "Item Name", "Cost");
136.Ed
137.Ss The Units Role ({U:})
138Units are the dimension by which values are measured, such as degrees,
139miles, bytes, and decibels.
140The units field carries this information
141for the previous value field.
142.Bd -literal -offset indent
143    xo_emit("{Lwc:Distance}{:distance/%u}{Uw:miles}\\n", miles);
144.Ed
145.Pp
146Note that the sense of the 'w' modifier is reversed for units;
147a blank is added before the contents, rather than after it.
148.Pp
149When the
150.Dv XOF_UNITS
151flag is set, units are rendered in XML as the
152.Dq units
153attribute:
154.Bd -literal -offset indent
155    <distance units="miles">50</distance>
156.Ed
157.Pp
158Units can also be rendered in HTML as the "data-units" attribute:
159.Bd -literal -offset indent
160    <div class="data" data-tag="distance" data-units="miles"
161         data-xpath="/top/data/distance">50</div>
162.Ed
163.Ss The Value Role ({V:} and {:})
164The value role is used to represent the a data value that is
165interesting for the non-display output styles (XML and JSON).
166Value
167is the default role; if no other role designation is given, the field
168is a value.
169The field name must appear within the field descriptor,
170followed by one or two format descriptors.
171The first format
172descriptor is used for display styles (TEXT and HTML), while the
173second one is used for encoding styles (XML and JSON).
174If no second
175format is given, the encoding format defaults to the first format,
176with any minimum width removed.
177If no first format is given, both
178format descriptors default to "%s".
179.Bd -literal -offset indent
180    xo_emit("{:length/%02u}x{:width/%02u}x{:height/%02u}\\n",
181            length, width, height);
182    xo_emit("{:author} wrote \"{:poem}\" in {:year/%4d}\\n,
183            author, poem, year);
184.Ed
185.Ss The Anchor Modifiers ({[:} and {]:})
186The anchor roles allow a set of strings by be padded as a group,
187but still be visible to
188.Xr xo_emit 3
189as distinct fields.
190Either the start
191or stop anchor can give a field width and it can be either directly in
192the descriptor or passed as an argument.
193Any fields between the start
194and stop anchor are padded to meet the minimum width given.
195.Pp
196To give a width directly, encode it as the content of the anchor tag:
197.Bd -literal -offset indent
198    xo_emit("({[:10}{:min/%d}/{:max/%d}{]:})\\n", min, max);
199.Ed
200.Pp
201To pass a width as an argument, use "%d" as the format, which must
202appear after the "/".
203Note that only "%d" is supported for widths.
204Using any other value could ruin your day.
205.Bd -literal -offset indent
206    xo_emit("({[:/%d}{:min/%d}/{:max/%d}{]:})\\n", width, min, max);
207.Ed
208.Pp
209If the width is negative, padding will be added on the right, suitable
210for left justification.
211Otherwise the padding will be added to the
212left of the fields between the start and stop anchors, suitable for
213right justification.
214If the width is zero, nothing happens.
215If the
216number of columns of output between the start and stop anchors is less
217than the absolute value of the given width, nothing happens.
218.Pp
219Widths over 8k are considered probable errors and not supported.
220If
221.Dv XOF_WARN
222is set, a warning will be generated.
223.Ss Modifier Flags
224The modifiers can also include the following flags, which modify the
225content emitted for some output styles:
226.Pp
227.Bl -column M "Name12341234"
228.It Sy M "Name        Description"
229.It c "colon       " "A colon ("":"") is appended after the label"
230.It d "display     " "Only emit field for display styles (text/HTML)"
231.It e "encoding    " "Only emit for encoding styles (XML/JSON)"
232.It k "key         " "Field is a key, suitable for XPath predicates"
233.It n "no-quotes   " "Do not quote the field when using JSON style"
234.It q "quotes      " "Quote the field when using JSON style"
235.It w "white space " "A blank ("" "") is appended after the label"
236.El
237.Pp
238For example, the modifier string "Lwc" means the field has a label
239role (text that describes the next field) and should be followed by a
240colon ('c') and a space ('w').
241The modifier string "Vkq" means the
242field has a value role, that it is a key for the current instance, and
243that the value should be quoted when encoded for JSON.
244.Ss The Colon Modifier ({c:})
245The colon modifier appends a single colon to the data value:
246.Bd -literal -offset indent
247    EXAMPLE:
248      xo_emit("{Lc:Name}{:name}\\n", "phil");
249    TEXT:
250      Name:phil
251.Ed
252.Pp
253The colon modifier is only used for the TEXT and HTML output
254styles.
255It is commonly combined with the space modifier ('{w:}').
256It is purely a convenience feature.
257.Ss The Display Modifier ({d:})
258The display modifier indicated the field should only be generated for
259the display output styles, TEXT and HTML.
260.Bd -literal -offset indent
261    EXAMPLE:
262      xo_emit("{Lcw:Name}{d:name} {:id/%d}\\n", "phil", 1);
263    TEXT:
264      Name: phil 1
265    XML:
266      <id>1</id>
267.Ed
268.Pp
269The display modifier is the opposite of the encoding modifier, and
270they are often used to give to distinct views of the underlying data.
271.Ss The Encoding Modifier ({e:})
272The display modifier indicated the field should only be generated for
273the display output styles, TEXT and HTML.
274.Bd -literal -offset indent
275    EXAMPLE:
276      xo_emit("{Lcw:Name}{:name} {e:id/%d}\\n", "phil", 1);
277    TEXT:
278      Name: phil
279    XML:
280      <name>phil</name><id>1</id>
281.Ed
282.Pp
283The encoding modifier is the opposite of the display modifier, and
284they are often used to give to distinct views of the underlying data.
285.Ss The Key Modifier ({k:})
286The key modifier is used to indicate that a particular field helps
287uniquely identify an instance of list data.
288.Bd -literal -offset indent
289    EXAMPLE:
290        xo_open_list("user");
291        for (i = 0; i < num_users; i++) {
292	    xo_open_instance("user");
293            xo_emit("User {k:name} has {:count} tickets\\n",
294               user[i].u_name, user[i].u_tickets);
295            xo_close_instance("user");
296        }
297        xo_close_list("user");
298.Ed
299.Pp
300Currently the key modifier is only used when generating XPath values
301for the HTML output style when
302.Dv XOF_XPATH
303is set, but other uses are likely in the near future.
304.Ss The Leaf-List Modifier ({l:})
305The leaf-list modifier is used to distinguish lists where each
306instance consists of only a single value.  In XML, these are
307rendered as single elements, where JSON renders them as arrays.
308.Bd -literal -offset indent
309    EXAMPLE:
310        xo_open_list("user");
311        for (i = 0; i < num_users; i++) {
312            xo_emit("Member {l:name}\n", user[i].u_name);
313        }
314        xo_close_list("user");
315    XML:
316        <user>phil</user>
317        <user>pallavi</user>
318    JSON:
319        "user": [ "phil", "pallavi" ]
320.Ed
321.Ss The No-Quotes Modifier ({n:})
322The no-quotes modifier (and its twin, the 'quotes' modifier) affect
323the quoting of values in the JSON output style.
324JSON uses quotes for
325string values, but no quotes for numeric, boolean, and null data.
326.Xr xo_emit 3
327applies a simple heuristic to determine whether quotes are
328needed, but often this needs to be controlled by the caller.
329.Bd -literal -offset indent
330    EXAMPLE:
331      const char *bool = is_true ? "true" : "false";
332      xo_emit("{n:fancy/%s}", bool);
333    JSON:
334      "fancy": true
335.Ed
336.Ss The Quotes Modifier ({q:})
337The quotes modifier (and its twin, the 'no-quotes' modifier) affect
338the quoting of values in the JSON output style.
339JSON uses quotes for
340string values, but no quotes for numeric, boolean, and null data.
341.Xr xo_emit 3
342applies a simple heuristic to determine whether quotes are
343needed, but often this needs to be controlled by the caller.
344.Bd -literal -offset indent
345    EXAMPLE:
346      xo_emit("{q:time/%d}", 2014);
347    JSON:
348      "year": "2014"
349.Ed
350.Ss The White Space Modifier ({w:})
351The white space modifier appends a single space to the data value:
352.Bd -literal -offset indent
353    EXAMPLE:
354      xo_emit("{Lw:Name}{:name}\\n", "phil");
355    TEXT:
356      Name phil
357.Ed
358.Pp
359The white space modifier is only used for the TEXT and HTML output
360styles.
361It is commonly combined with the colon modifier ('{c:}').
362It is purely a convenience feature.
363.Pp
364Note that the sense of the 'w' modifier is reversed for the units role
365({Uw:}); a blank is added before the contents, rather than after it.
366.Ss Field Formatting
367The field format is similar to the format string for
368.Xr printf 3 .
369Its use varies based on the role of the field, but generally is used to
370format the field's contents.
371.Pp
372If the format string is not provided for a value field, it defaults
373to "%s".
374.Pp
375Note a field definition can contain zero or more printf-style
376.Dq directives ,
377which are sequences that start with a '%' and end with
378one of following characters: "diouxXDOUeEfFgGaAcCsSp".
379Each directive
380is matched by one of more arguments to the
381.Xr xo_emit 3
382function.
383.Pp
384The format string has the form:
385.Bd -literal -offset indent
386  '%' format-modifier * format-character
387.Ed
388.Pp
389The format- modifier can be:
390.Bl -bullet
391.It
392a '#' character, indicating the output value should be prefixed with
393'0x', typically to indicate a base 16 (hex) value.
394.It
395a minus sign ('-'), indicating the output value should be padded on
396the right instead of the left.
397.It
398a leading zero ('0') indicating the output value should be padded on the
399left with zeroes instead of spaces (' ').
400.It
401one or more digits ('0' - '9') indicating the minimum width of the
402argument.
403If the width in columns of the output value is less than
404the minimum width, the value will be padded to reach the minimum.
405.It
406a period followed by one or more digits indicating the maximum
407number of bytes which will be examined for a string argument, or the maximum
408width for a non-string argument.
409When handling ASCII strings this
410functions as the field width but for multi-byte characters, a single
411character may be composed of multiple bytes.
412.Xr xo_emit 3
413will never dereference memory beyond the given number of bytes.
414.It
415a second period followed by one or more digits indicating the maximum
416width for a string argument.
417This modifier cannot be given for non-string arguments.
418.It
419one or more 'h' characters, indicating shorter input data.
420.It
421one or more 'l' characters, indicating longer input data.
422.It
423a 'z' character, indicating a 'size_t' argument.
424.It
425a 't' character, indicating a 'ptrdiff_t' argument.
426.It
427a ' ' character, indicating a space should be emitted before
428positive numbers.
429.It
430a '+' character, indicating sign should emitted before any number.
431.El
432.Pp
433Note that 'q', 'D', 'O', and 'U' are considered deprecated and will be
434removed eventually.
435.Pp
436The format character is described in the following table:
437.Pp
438.Bl -column C "Argument Type12"
439.It Sy "C Argument Type   Format"
440.It d "int            " "base 10 (decimal)"
441.It i "int            " "base 10 (decimal)"
442.It o "int            " "base 8 (octal)"
443.It u "unsigned       " "base 10 (decimal)"
444.It x "unsigned       " "base 16 (hex)"
445.It X "unsigned long  " "base 16 (hex)"
446.It D "long           " "base 10 (decimal)"
447.It O "unsigned long  " "base 8 (octal)"
448.It U "unsigned long  " "base 10 (decimal)"
449.It e "double         " "[-]d.ddde+-dd"
450.It E "double         " "[-]d.dddE+-dd"
451.It f "double         " "[-]ddd.ddd"
452.It F "double         " "[-]ddd.ddd"
453.It g "double         " "as 'e' or 'f'"
454.It G "double         " "as 'E' or 'F'"
455.It a "double         " "[-]0xh.hhhp[+-]d"
456.It A "double         " "[-]0Xh.hhhp[+-]d"
457.It c "unsigned char  " "a character"
458.It C "wint_t         " "a character"
459.It s "char *         " "a UTF-8 string"
460.It S "wchar_t *      " "a unicode/WCS string"
461.It p "void *         " "'%#lx'"
462.El
463.Pp
464The 'h' and 'l' modifiers affect the size and treatment of the
465argument:
466.Bl -column "Mod" "d, i         " "o, u, x, X         "
467.It Sy "Mod" "d, i        " "o, u, x, X"
468.It "hh " "signed char " "unsigned char"
469.It "h  " "short       " "unsigned short"
470.It "l  " "long        " "unsigned long"
471.It "ll " "long long   " "unsigned long long"
472.It "j  " "intmax_t    " "uintmax_t"
473.It "t  " "ptrdiff_t   " "ptrdiff_t"
474.It "z  " "size_t      " "size_t"
475.It "q  " "quad_t      " "u_quad_t"
476.El
477.Pp
478.Ss UTF-8 and Locale Strings
479All strings for
480.Nm libxo
481must be UTF-8.
482.Nm libxo
483will handle turning them
484into locale-based strings for display to the user.
485.Pp
486For strings, the 'h' and 'l' modifiers affect the interpretation of
487the bytes pointed to argument.
488The default '%s' string is a 'char *'
489pointer to a string encoded as UTF-8.
490Since UTF-8 is compatible with
491.Em ASCII
492data, a normal 7-bit
493.Em ASCII
494string can be used.
495'%ls' expects a
496'wchar_t *' pointer to a wide-character string, encoded as 32-bit
497Unicode values.
498'%hs' expects a 'char *' pointer to a multi-byte
499string encoded with the current locale, as given by the
500.Ev LC_CTYPE ,
501.Ev LANG ,
502or
503.Ev LC_ALL
504environment variables.
505The first of this list of
506variables is used and if none of the variables are set, the locale defaults to
507.Em UTF-8 .
508.Pp
509.Nm libxo
510will
511convert these arguments as needed to either UTF-8 (for XML, JSON, and
512HTML styles) or locale-based strings for display in text style.
513.Bd -literal -offset indent
514   xo_emit("All strings are utf-8 content {:tag/%ls}",
515           L"except for wide strings");
516.Ed
517.Pp
518"%S" is equivalent to "%ls".
519.Pp
520For example, a function is passed a locale-base name, a hat size,
521and a time value.
522The hat size is formatted in a UTF-8 (ASCII)
523string, and the time value is formatted into a wchar_t string.
524.Bd -literal -offset indent
525    void print_order (const char *name, int size,
526                      struct tm *timep) {
527        char buf[32];
528        const char *size_val = "unknown";
529
530	if (size > 0)
531            snprintf(buf, sizeof(buf), "%d", size);
532            size_val = buf;
533        }
534
535        wchar_t when[32];
536        wcsftime(when, sizeof(when), L"%d%b%y", timep);
537
538        xo_emit("The hat for {:name/%hs} is {:size/%s}.\\n",
539                name, size_val);
540        xo_emit("It was ordered on {:order-time/%ls}.\\n",
541                when);
542    }
543.Ed
544.Pp
545It is important to note that
546.Xr xo_emit 3
547will perform the conversion
548required to make appropriate output.
549Text style output uses the
550current locale (as described above), while XML, JSON, and HTML use
551UTF-8.
552.Pp
553UTF-8 and locale-encoded strings can use multiple bytes to encode one
554column of data.
555The traditional "precision'" (aka "max-width") value
556for "%s" printf formatting becomes overloaded since it specifies both
557the number of bytes that can be safely referenced and the maximum
558number of columns to emit.
559.Xr xo_emit 3
560uses the precision as the former,
561and adds a third value for specifying the maximum number of columns.
562.Pp
563In this example, the name field is printed with a minimum of 3 columns
564and a maximum of 6.
565Up to ten bytes are in used in filling those columns.
566.Bd -literal -offset indent
567    xo_emit("{:name/%3.10.6s}", name);
568.Ed
569.Ss Characters Outside of Field Definitions
570Characters in the format string that are not part of a field definition are
571copied to the output for the TEXT style, and are ignored for the JSON
572and XML styles.
573For HTML, these characters are placed in a <div> with class "text".
574.Bd -literal -offset indent
575  EXAMPLE:
576      xo_emit("The hat is {:size/%s}.\\n", size_val);
577  TEXT:
578      The hat is extra small.
579  XML:
580      <size>extra small</size>
581  JSON:
582      "size": "extra small"
583  HTML:
584      <div class="text">The hat is </div>
585      <div class="data" data-tag="size">extra small</div>
586      <div class="text">.</div>
587.Ed
588.Ss "%n" is Not Supported
589.Nm libxo
590does not support the '%n' directive.
591It is a bad idea and we
592just do not do it.
593.Ss The Encoding Format (eformat)
594The "eformat" string is the format string used when encoding the field
595for JSON and XML.
596If not provided, it defaults to the primary format
597with any minimum width removed.
598If the primary is not given, both default to "%s".
599.Sh EXAMPLE
600In this example, the value for the number of items in stock is emitted:
601.Bd -literal -offset indent
602        xo_emit("{P:   }{Lwc:In stock}{:in-stock/%u}\\n",
603                instock);
604.Ed
605.Pp
606This call will generate the following output:
607.Bd -literal -offset indent
608  TEXT:
609       In stock: 144
610  XML:
611      <in-stock>144</in-stock>
612  JSON:
613      "in-stock": 144,
614  HTML:
615      <div class="line">
616        <div class="padding">   </div>
617        <div class="label">In stock</div>
618        <div class="decoration">:</div>
619        <div class="padding"> </div>
620        <div class="data" data-tag="in-stock">144</div>
621      </div>
622.Ed
623.Pp
624Clearly HTML wins the verbosity award, and this output does
625not include
626.Dv XOF_XPATH
627or
628.Dv XOF_INFO
629data, which would expand the penultimate line to:
630.Bd -literal -offset indent
631       <div class="data" data-tag="in-stock"
632          data-xpath="/top/data/item/in-stock"
633          data-type="number"
634          data-help="Number of items in stock">144</div>
635.Ed
636.Sh WHAT MAKES A GOOD FIELD NAME?
637To make useful, consistent field names, follow these guidelines:
638.Pp
639.Ss Use lower case, even for TLAs
640Lower case is more civilized.
641Even TLAs should be lower case
642to avoid scenarios where the differences between "XPath" and
643"Xpath" drive your users crazy.
644Using "xpath" is simpler and better.
645.Ss Use hyphens, not underscores
646Use of hyphens is traditional in XML, and the
647.Dv XOF_UNDERSCORES
648flag can be used to generate underscores in JSON, if desired.
649But the raw field name should use hyphens.
650.Ss Use full words
651Do not abbreviate especially when the abbreviation is not obvious or
652not widely used.
653Use "data-size", not "dsz" or "dsize".
654Use
655"interface" instead of "ifname", "if-name", "iface", "if", or "intf".
656.Ss Use <verb>-<units>
657Using the form <verb>-<units> or <verb>-<classifier>-<units> helps in
658making consistent, useful names, avoiding the situation where one app
659uses "sent-packet" and another "packets-sent" and another
660"packets-we-have-sent".
661The <units> can be dropped when it is
662obvious, as can obvious words in the classification.
663Use "receive-after-window-packets" instead of
664"received-packets-of-data-after-window".
665.Ss Reuse existing field names
666Nothing is worse than writing expressions like:
667.Bd -literal -offset indent
668    if ($src1/process[pid == $pid]/name ==
669        $src2/proc-table/proc/p[process-id == $pid]/proc-name) {
670        ...
671    }
672.Ed
673.Pp
674Find someone else who is expressing similar data and follow their
675fields and hierarchy.
676Remember the quote is not
677.Dq Consistency is the hobgoblin of little minds
678but
679.Dq A foolish consistency is the hobgoblin of little minds .
680.Ss Think about your users
681Have empathy for your users, choosing clear and useful fields that
682contain clear and useful data.
683You may need to augment the display content with
684.Xr xo_attr 3
685calls or "{e:}" fields to make the data useful.
686.Ss Do not use an arbitrary number postfix
687What does "errors2" mean?
688No one will know.
689"errors-after-restart" would be a better choice.
690Think of your users, and think of the future.
691If you make "errors2", the next guy will happily make
692"errors3" and before you know it, someone will be asking what is the
693difference between errors37 and errors63.
694.Ss Be consistent, uniform, unsurprising, and predictable
695Think of your field vocabulary as an API.
696You want it useful,
697expressive, meaningful, direct, and obvious.
698You want the client
699application's programmer to move between without the need to
700understand a variety of opinions on how fields are named.
701They should
702see the system as a single cohesive whole, not a sack of cats.
703.Pp
704Field names constitute the means by which client programmers interact
705with our system.
706By choosing wise names now, you are making their lives better.
707.Pp
708After using
709.Xr xolint 1
710to find errors in your field descriptors, use
711.Dq "xolint -V"
712to spell check your field names and to detect different
713names for the same data.
714.Dq dropped-short
715and
716.Dq dropped-too-short
717are both reasonable names, but using them both will lead users to ask the
718difference between the two fields.
719If there is no difference,
720use only one of the field names.
721If there is a difference, change the
722names to make that difference more obvious.
723.Sh ADDITIONAL DOCUMENTATION
724Complete documentation can be found on github:
725.Bd -literal -offset indent
726http://juniper.github.io/libxo/libxo-manual.html
727.Ed
728.Pp
729.Nm libxo
730lives on github as:
731.Bd -literal -offset indent
732https://github.com/Juniper/libxo
733.Ed
734.Pp
735The latest release of
736.Nm libxo
737is available at:
738.Bd -literal -offset indent
739https://github.com/Juniper/libxo/releases
740.Ed
741.Sh SEE ALSO
742.Xr xolint 1 ,
743.Xr xo_emit 3
744.Sh HISTORY
745The
746.Nm libxo
747library was added in
748.Fx 11.0 .
749.Sh AUTHOR
750Phil Shafer
751