diff --git a/doc/Makefile.am b/doc/Makefile.am index eb9ce364..dcd155e9 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -8,7 +8,7 @@ # using the SOFTWARE, you agree to be bound by the terms of that # LICENSE. -doc docs: xolint.rst html +doc docs: xolint-errors.rst html # # The contents of xolint.rst is generated based on xolint.pl, since we @@ -17,8 +17,8 @@ doc docs: xolint.rst html # the developer needs to commit any changes. # -xolint.rst: ${top_srcdir}/xolint/xolint.pl - perl ${top_srcdir}/xolint/xolint.pl -D > ${top_srcdir}/doc/xolint.rst +xolint-errors.rst: ${top_srcdir}/xolint/xolint.pl + perl ${top_srcdir}/xolint/xolint.pl -D > ${top_srcdir}/doc/xolint-errors.rst SPHINX = python3 -msphinx diff --git a/doc/api.rst b/doc/api.rst index 94358489..8a9b7bb5 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -386,19 +386,18 @@ xo_destroy Emitting Content (xo_emit) -------------------------- -The functions in this section are used to emit output. - -The "fmt" argument is a string containing field descriptors as -specified in :ref:`format-strings`. The use of a handle is optional and -`NULL` can be passed to access the internal "default" handle. See +The functions in this section are used to emit output. They use a +`format` string containing field descriptors as specified in +:ref:`format-strings`. The use of a handle is optional and `NULL` can +be passed to access the internal "default" handle. See :ref:`handles`. The remaining arguments to `xo_emit` and `xo_emit_h` are a set of arguments corresponding to the fields in the format string. Care must be taken to ensure the argument types match the fields in the format -string, since an inappropriate cast can ruin your day. The vap -argument to `xo_emit_hv` points to a variable argument list that can -be used to retrieve arguments via `va_arg`. +string, since an inappropriate or missing argument can ruin your day. +The `vap` argument to `xo_emit_hv` points to a variable argument list +that can be used to retrieve arguments via `va_arg`. .. c:function:: xo_ssize_t xo_emit (const char *fmt, ...) @@ -428,19 +427,40 @@ be used to retrieve arguments via `va_arg`. Single Field Emitting Functions (xo_emit_field) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The functions in this section can also make output, but only make a -single field at a time. These functions are intended to avoid the -scenario where one would otherwise need to compose a format -descriptors using `snprintf`. The individual parts of the format -descriptor are passed in distinctly. - -.. c:function:: xo_ssize_t xo_emit_field (const char *rolmod, const char *contents, const char *fmt, const char *efmt, ...) +The functions in this section emit formatted output similar to +`xo_emit` but where `xo_emit` uses a single string argument containing +the description for multiple fields, `xo_emit_field` emits a single +field using multiple ar- guments to contain the field description. +`xo_emit_field_h` adds an ex- plicit handle to use instead of the +default handle, while `xo_emit_field_hv` accepts a va_list for +additional flexibility. + +The arguments `rolmod`, `content`, `fmt`, and `efmt` are detailed in +:ref:`field-formatting`. Using distinct arguments allows callers to +pass the field description in pieces, rather than having to use +something like `snprintf` to build the format string required by +`xo_emit`. The arguments are each NUL-terminated strings. The `rolmod` +argument contains the `role` and `modifier` portions of the field +description, the `content` argument contains the `content` portion, and +the `fmt` and `efmt` contain the `field-format` and `encoding-format` por- +tions, respectively. + +As with `xo_emit`, the `fmt` and `efmt` values are both optional, +since the `field-format` string defaults to "%s", and the +`encoding-format`'s default value is derived from the `field-format` +per :ref:`field-formatting`. However, care must be taken to avoid +using a value directly as the format, since characters like '{', '%', +and '}' will be interpreted as formatting directives, and may cause +xo_emit_field to dereference arbitrary values off the stack, leading +to bugs, core files, and gnashing of teeth. + +.. c:function:: xo_ssize_t xo_emit_field (const char *rolmod, const char *content, const char *fmt, const char *efmt, ...) :param rolmod: A comma-separated list of field roles and field modifiers :type rolmod: const char * - :param contents: The "contents" portion of the field description string - :type contents: const char * - :param fmt: Content format string + :param content: The "content" portion of the field description string + :type content: const char * + :param fmt: Contents format string :type fmt: const char * :param efmt: Encoding format string, followed by additional arguments :type efmt: const char * @@ -450,8 +470,11 @@ descriptor are passed in distinctly. :: EXAMPLE:: + xo_emit_field("T", title, NULL, NULL, NULL); xo_emit_field("T", "Host name is ", NULL, NULL); xo_emit_field("V", "host-name", NULL, NULL, host-name); + xo_emit_field(",leaf-list,quotes", "sku", "%s-%u", "%s-000-%u", + "gum", 1412); .. c:function:: xo_ssize_t xo_emit_field_h (xo_handle_t *xop, const char *rolmod, const char *contents, const char *fmt, const char *efmt, ...) diff --git a/doc/faq.rst b/doc/faq.rst index 087ef710..5232a727 100644 --- a/doc/faq.rst +++ b/doc/faq.rst @@ -205,4 +205,7 @@ a difference, change the names to make that difference more obvious. What does this message mean? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. include:: xolint.rst +.. toctree:: + :maxdepth: 2 + + xolint-errors.rst diff --git a/doc/field-formatting.rst b/doc/field-formatting.rst index b182fcee..1a4a29af 100644 --- a/doc/field-formatting.rst +++ b/doc/field-formatting.rst @@ -1,5 +1,6 @@ .. index:: Field Formatting +.. _field-formatting: Field Formatting ---------------- diff --git a/doc/xolint-errors.rst b/doc/xolint-errors.rst new file mode 100644 index 00000000..c3e518b9 --- /dev/null +++ b/doc/xolint-errors.rst @@ -0,0 +1,444 @@ +'A percent sign appearing in text is a literal' ++++++++++++++++++++++++++++++++++++++++++++++++ + +The message "A percent sign appearing in text is a literal" can be caused by code like: + +:: + + xo_emit("cost: %d", cost); + +This code should be replaced with code like: + +:: + + xo_emit("{L:cost}: {:cost/%d}", cost); + +This can be a bit surprising and could be a field that was not +properly converted to a libxo-style format string. + + +'Unknown long name for role/modifier' ++++++++++++++++++++++++++++++++++++++ + +The message "Unknown long name for role/modifier" can be caused by code like: + +:: + + xo_emit("{,humanization:value}", value); + +This code should be replaced with code like: + +:: + + xo_emit("{,humanize:value}", value); + +The hn-* modifiers (hn-decimal, hn-space, hn-1000) +are only valid for fields with the {h:} modifier. + + +'Last character before field definition is a field type' +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +The message "Last character before field definition is a field type" can be caused by code like: +A common typo: + +:: + + xo_emit("{T:Min} T{:Max}"); + +This code should be replaced with code like: + +:: + + xo_emit("{T:Min} {T:Max}"); + +Twiddling the "{" and the field role is a common typo. + + +'Encoding format uses different number of arguments' +++++++++++++++++++++++++++++++++++++++++++++++++++++ + +The message "Encoding format uses different number of arguments" can be caused by code like: + +:: + + xo_emit("{:name/%6.6s %%04d/%s}", name, number); + +This code should be replaced with code like: + +:: + + xo_emit("{:name/%6.6s %04d/%s-%d}", name, number); + +Both format should consume the same number of arguments off the stack + + +'Only one field role can be used' ++++++++++++++++++++++++++++++++++ + +The message "Only one field role can be used" can be caused by code like: + +:: + + xo_emit("{LT:Max}"); + +This code should be replaced with code like: + +:: + + xo_emit("{T:Max}"); + +'Potential missing slash after C, D, N, L, or T with format' +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +The message "Potential missing slash after C, D, N, L, or T with format" can be caused by code like: + +:: + + xo_emit("{T:%6.6s}\n", "Max"); + +This code should be replaced with code like: + +:: + + xo_emit("{T:/%6.6s}\n", "Max"); + +The "%6.6s" will be a literal, not a field format. While +it's possibly valid, it's likely a missing "/". + + +'An encoding format cannot be given (roles: DNLT)' +++++++++++++++++++++++++++++++++++++++++++++++++++ + +The message "An encoding format cannot be given (roles: DNLT)" can be caused by code like: + +:: + + xo_emit("{T:Max//%s}", "Max"); + +Fields with the C, D, N, L, and T roles are not emitted in +the 'encoding' style (JSON, XML), so an encoding format +would make no sense. + + +'Format cannot be given when content is present (roles: CDLN)' +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +The message "Format cannot be given when content is present (roles: CDLN)" can be caused by code like: + +:: + + xo_emit("{N:Max/%6.6s}", "Max"); + +Fields with the C, D, L, or N roles can't have both +static literal content ("{L:Label}") and a +format ("{L:/%s}"). +This error will also occur when the content has a backslash +in it, like "{N:Type of I/O}"; backslashes should be escaped, +like "{N:Type of I\\/O}". Note the double backslash, one for +handling 'C' strings, and one for libxo. + + +'Field has color without fg- or bg- (role: C)' +++++++++++++++++++++++++++++++++++++++++++++++ + +The message "Field has color without fg- or bg- (role: C)" can be caused by code like: + +:: + + xo_emit("{C:green}{:foo}{C:}", x); + +This code should be replaced with code like: + +:: + + xo_emit("{C:fg-green}{:foo}{C:}", x); + +Colors must be prefixed by either "fg-" or "bg-". + + +'Field has invalid color or effect (role: C)' ++++++++++++++++++++++++++++++++++++++++++++++ + +The message "Field has invalid color or effect (role: C)" can be caused by code like: + +:: + + xo_emit("{C:fg-purple,bold}{:foo}{C:gween}", x); + +This code should be replaced with code like: + +:: + + xo_emit("{C:fg-red,bold}{:foo}{C:fg-green}", x); + +The list of colors and effects are limited. The +set of colors includes default, black, red, green, +yellow, blue, magenta, cyan, and white, which must +be prefixed by either "fg-" or "bg-". Effects are +limited to bold, no-bold, underline, no-underline, +inverse, no-inverse, normal, and reset. Values must +be separated by commas. + + +'Field has humanize modifier but no format string' +++++++++++++++++++++++++++++++++++++++++++++++++++ + +The message "Field has humanize modifier but no format string" can be caused by code like: + +:: + + xo_emit("{h:value}", value); + +This code should be replaced with code like: + +:: + + xo_emit("{h:value/%d}", value); + +Humanization is only value for numbers, which are not +likely to use the default format ("%s"). + + +'Field has hn-* modifier but not 'h' modifier' +++++++++++++++++++++++++++++++++++++++++++++++ + +The message "Field has hn-* modifier but not 'h' modifier" can be caused by code like: + +:: + + xo_emit("{,hn-1000:value}", value); + +This code should be replaced with code like: + +:: + + xo_emit("{h,hn-1000:value}", value); + +The hn-* modifiers (hn-decimal, hn-space, hn-1000) +are only valid for fields with the {h:} modifier. + + +'Value field must have a name (as content)")' ++++++++++++++++++++++++++++++++++++++++++++++ + +The message "Value field must have a name (as content)")" can be caused by code like: + +:: + + xo_emit("{:/%s}", "value"); + +This code should be replaced with code like: + +:: + + xo_emit("{:tag-name/%s}", "value"); + +The field name is used for XML and JSON encodings. These +tags names are static and must appear directly in the +field descriptor. + + +'Use hyphens, not underscores, for value field name' +++++++++++++++++++++++++++++++++++++++++++++++++++++ + +The message "Use hyphens, not underscores, for value field name" can be caused by code like: + +:: + + xo_emit("{:no_under_scores}", "bad"); + +This code should be replaced with code like: + +:: + + xo_emit("{:no-under-scores}", "bad"); + +Use of hyphens is traditional in XML, and the XOF_UNDERSCORES +flag can be used to generate underscores in JSON, if desired. +But the raw field name should use hyphens. + + +'Value field name cannot start with digit' +++++++++++++++++++++++++++++++++++++++++++ + +The message "Value field name cannot start with digit" can be caused by code like: + +:: + + xo_emit("{:10-gig/}"); + +This code should be replaced with code like: + +:: + + xo_emit("{:ten-gig/}"); + +XML element names cannot start with a digit. + + +'Value field name should be lower case' ++++++++++++++++++++++++++++++++++++++++ + +The message "Value field name should be lower case" can be caused by code like: + +:: + + xo_emit("{:WHY-ARE-YOU-SHOUTING}", "NO REASON"); + +This code should be replaced with code like: + +:: + + xo_emit("{:why-are-you-shouting}", "no reason"); + +Lower case is more civilized. Even TLAs should be lower case +to avoid scenarios where the differences between "XPath" and +"Xpath" drive your users crazy. Lower case rules the seas. + + +'Value field name should be longer than two characters' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +The message "Value field name should be longer than two characters" can be caused by code like: + +:: + + xo_emit("{:x}", "mumble"); + +This code should be replaced with code like: + +:: + + xo_emit("{:something-meaningful}", "mumble"); + +Field names should be descriptive, and it's hard to +be descriptive in less than two characters. Consider +your users and try to make something more useful. +Note that this error often occurs when the field type +is placed after the colon ("{:T/%20s}"), instead of before +it ("{T:/20s}"). + + +'Value field name contains invalid character' ++++++++++++++++++++++++++++++++++++++++++++++ + +The message "Value field name contains invalid character" can be caused by code like: + +:: + + xo_emit("{:cost-in-$$/%u}", 15); + +This code should be replaced with code like: + +:: + + xo_emit("{:cost-in-dollars/%u}", 15); + +An invalid character is often a sign of a typo, like "{:]}" +instead of "{]:}". Field names are restricted to lower-case +characters, digits, and hyphens. + + +'decoration field contains invalid character' ++++++++++++++++++++++++++++++++++++++++++++++ + +The message "decoration field contains invalid character" can be caused by code like: + +:: + + xo_emit("{D:not good}"); + +This code should be replaced with code like: + +:: + + xo_emit("{D:((}{:good}{D:))}", "yes"); + +This is minor, but fields should use proper roles. Decoration +fields are meant to hold punctuation and other characters used +to decorate the content, typically to make it more readable +to human readers. + + +'Anchor content should be decimal width' +++++++++++++++++++++++++++++++++++++++++ + +The message "Anchor content should be decimal width" can be caused by code like: + +:: + + xo_emit("{[:mumble}"); + +This code should be replaced with code like: + +:: + + xo_emit("{[:32}"); + +Anchors need an integer value to specify the width of +the set of anchored fields. The value can be positive +(for left padding/right justification) or negative (for +right padding/left justification) and can appear in +either the start or stop anchor field descriptor. + + +'Anchor format should be "%d"' +++++++++++++++++++++++++++++++ + +The message "Anchor format should be "%d"" can be caused by code like: + +:: + + xo_emit("{[:/%s}"); + +This code should be replaced with code like: + +:: + + xo_emit("{[:/%d}"); + +Anchors only grok integer values, and if the value is not static, +if must be in an 'int' argument, represented by the "%d" format. +Anything else is an error. + + +'Anchor cannot have both format and encoding format")' +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +The message "Anchor cannot have both format and encoding format")" can be caused by code like: + +:: + + xo_emit("{[:32/%d}"); + +This code should be replaced with code like: + +:: + + xo_emit("{[:32}"); + +Anchors can have a static value or argument for the width, +but cannot have both. + + +'Max width only valid for strings' +++++++++++++++++++++++++++++++++++ + +The message "Max width only valid for strings" can be caused by code like: + +:: + + xo_emit("{:tag/%2.4.6d}", 55); + +This code should be replaced with code like: + +:: + + xo_emit("{:tag/%2.6d}", 55); + +libxo allows a true 'max width' in addition to the traditional +printf-style 'max number of bytes to use for input'. But this +is supported only for string values, since it makes no sense +for non-strings. This error may occur from a typo, +like "{:tag/%6..6d}" where only one period should be used. diff --git a/doc/xolint.rst b/doc/xolint.rst index c3e518b9..739fa185 100644 --- a/doc/xolint.rst +++ b/doc/xolint.rst @@ -1,444 +1,40 @@ -'A percent sign appearing in text is a literal' -+++++++++++++++++++++++++++++++++++++++++++++++ - -The message "A percent sign appearing in text is a literal" can be caused by code like: - -:: - - xo_emit("cost: %d", cost); - -This code should be replaced with code like: - -:: - - xo_emit("{L:cost}: {:cost/%d}", cost); - -This can be a bit surprising and could be a field that was not -properly converted to a libxo-style format string. - - -'Unknown long name for role/modifier' -+++++++++++++++++++++++++++++++++++++ - -The message "Unknown long name for role/modifier" can be caused by code like: - -:: - - xo_emit("{,humanization:value}", value); - -This code should be replaced with code like: - -:: - - xo_emit("{,humanize:value}", value); - -The hn-* modifiers (hn-decimal, hn-space, hn-1000) -are only valid for fields with the {h:} modifier. - - -'Last character before field definition is a field type' -++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -The message "Last character before field definition is a field type" can be caused by code like: -A common typo: - -:: - - xo_emit("{T:Min} T{:Max}"); - -This code should be replaced with code like: - -:: - - xo_emit("{T:Min} {T:Max}"); - -Twiddling the "{" and the field role is a common typo. - - -'Encoding format uses different number of arguments' -++++++++++++++++++++++++++++++++++++++++++++++++++++ - -The message "Encoding format uses different number of arguments" can be caused by code like: - -:: - - xo_emit("{:name/%6.6s %%04d/%s}", name, number); - -This code should be replaced with code like: - -:: - - xo_emit("{:name/%6.6s %04d/%s-%d}", name, number); - -Both format should consume the same number of arguments off the stack - - -'Only one field role can be used' -+++++++++++++++++++++++++++++++++ - -The message "Only one field role can be used" can be caused by code like: - -:: - - xo_emit("{LT:Max}"); - -This code should be replaced with code like: - -:: - - xo_emit("{T:Max}"); - -'Potential missing slash after C, D, N, L, or T with format' -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -The message "Potential missing slash after C, D, N, L, or T with format" can be caused by code like: - -:: - - xo_emit("{T:%6.6s}\n", "Max"); - -This code should be replaced with code like: - -:: - - xo_emit("{T:/%6.6s}\n", "Max"); - -The "%6.6s" will be a literal, not a field format. While -it's possibly valid, it's likely a missing "/". - - -'An encoding format cannot be given (roles: DNLT)' -++++++++++++++++++++++++++++++++++++++++++++++++++ - -The message "An encoding format cannot be given (roles: DNLT)" can be caused by code like: - -:: - - xo_emit("{T:Max//%s}", "Max"); - -Fields with the C, D, N, L, and T roles are not emitted in -the 'encoding' style (JSON, XML), so an encoding format -would make no sense. - - -'Format cannot be given when content is present (roles: CDLN)' -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -The message "Format cannot be given when content is present (roles: CDLN)" can be caused by code like: - -:: - - xo_emit("{N:Max/%6.6s}", "Max"); - -Fields with the C, D, L, or N roles can't have both -static literal content ("{L:Label}") and a -format ("{L:/%s}"). -This error will also occur when the content has a backslash -in it, like "{N:Type of I/O}"; backslashes should be escaped, -like "{N:Type of I\\/O}". Note the double backslash, one for -handling 'C' strings, and one for libxo. - - -'Field has color without fg- or bg- (role: C)' -++++++++++++++++++++++++++++++++++++++++++++++ - -The message "Field has color without fg- or bg- (role: C)" can be caused by code like: - -:: - - xo_emit("{C:green}{:foo}{C:}", x); - -This code should be replaced with code like: - -:: - - xo_emit("{C:fg-green}{:foo}{C:}", x); - -Colors must be prefixed by either "fg-" or "bg-". - - -'Field has invalid color or effect (role: C)' -+++++++++++++++++++++++++++++++++++++++++++++ - -The message "Field has invalid color or effect (role: C)" can be caused by code like: - -:: - - xo_emit("{C:fg-purple,bold}{:foo}{C:gween}", x); - -This code should be replaced with code like: - -:: - - xo_emit("{C:fg-red,bold}{:foo}{C:fg-green}", x); - -The list of colors and effects are limited. The -set of colors includes default, black, red, green, -yellow, blue, magenta, cyan, and white, which must -be prefixed by either "fg-" or "bg-". Effects are -limited to bold, no-bold, underline, no-underline, -inverse, no-inverse, normal, and reset. Values must -be separated by commas. - - -'Field has humanize modifier but no format string' -++++++++++++++++++++++++++++++++++++++++++++++++++ - -The message "Field has humanize modifier but no format string" can be caused by code like: - -:: - - xo_emit("{h:value}", value); - -This code should be replaced with code like: - -:: - - xo_emit("{h:value/%d}", value); - -Humanization is only value for numbers, which are not -likely to use the default format ("%s"). - - -'Field has hn-* modifier but not 'h' modifier' -++++++++++++++++++++++++++++++++++++++++++++++ - -The message "Field has hn-* modifier but not 'h' modifier" can be caused by code like: - -:: - - xo_emit("{,hn-1000:value}", value); - -This code should be replaced with code like: - -:: - - xo_emit("{h,hn-1000:value}", value); - -The hn-* modifiers (hn-decimal, hn-space, hn-1000) -are only valid for fields with the {h:} modifier. - - -'Value field must have a name (as content)")' -+++++++++++++++++++++++++++++++++++++++++++++ - -The message "Value field must have a name (as content)")" can be caused by code like: - -:: - - xo_emit("{:/%s}", "value"); - -This code should be replaced with code like: - -:: - - xo_emit("{:tag-name/%s}", "value"); - -The field name is used for XML and JSON encodings. These -tags names are static and must appear directly in the -field descriptor. - - -'Use hyphens, not underscores, for value field name' -++++++++++++++++++++++++++++++++++++++++++++++++++++ - -The message "Use hyphens, not underscores, for value field name" can be caused by code like: - -:: - - xo_emit("{:no_under_scores}", "bad"); - -This code should be replaced with code like: - -:: - - xo_emit("{:no-under-scores}", "bad"); - -Use of hyphens is traditional in XML, and the XOF_UNDERSCORES -flag can be used to generate underscores in JSON, if desired. -But the raw field name should use hyphens. - - -'Value field name cannot start with digit' -++++++++++++++++++++++++++++++++++++++++++ - -The message "Value field name cannot start with digit" can be caused by code like: - -:: - - xo_emit("{:10-gig/}"); - -This code should be replaced with code like: - -:: - - xo_emit("{:ten-gig/}"); - -XML element names cannot start with a digit. - - -'Value field name should be lower case' -+++++++++++++++++++++++++++++++++++++++ - -The message "Value field name should be lower case" can be caused by code like: - -:: - - xo_emit("{:WHY-ARE-YOU-SHOUTING}", "NO REASON"); - -This code should be replaced with code like: - -:: - - xo_emit("{:why-are-you-shouting}", "no reason"); - -Lower case is more civilized. Even TLAs should be lower case -to avoid scenarios where the differences between "XPath" and -"Xpath" drive your users crazy. Lower case rules the seas. - - -'Value field name should be longer than two characters' -+++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -The message "Value field name should be longer than two characters" can be caused by code like: - -:: - - xo_emit("{:x}", "mumble"); - -This code should be replaced with code like: - -:: - - xo_emit("{:something-meaningful}", "mumble"); - -Field names should be descriptive, and it's hard to -be descriptive in less than two characters. Consider -your users and try to make something more useful. -Note that this error often occurs when the field type -is placed after the colon ("{:T/%20s}"), instead of before -it ("{T:/20s}"). - - -'Value field name contains invalid character' -+++++++++++++++++++++++++++++++++++++++++++++ - -The message "Value field name contains invalid character" can be caused by code like: - -:: - - xo_emit("{:cost-in-$$/%u}", 15); - -This code should be replaced with code like: - -:: - - xo_emit("{:cost-in-dollars/%u}", 15); - -An invalid character is often a sign of a typo, like "{:]}" -instead of "{]:}". Field names are restricted to lower-case -characters, digits, and hyphens. - - -'decoration field contains invalid character' -+++++++++++++++++++++++++++++++++++++++++++++ - -The message "decoration field contains invalid character" can be caused by code like: - -:: - - xo_emit("{D:not good}"); - -This code should be replaced with code like: - -:: - - xo_emit("{D:((}{:good}{D:))}", "yes"); - -This is minor, but fields should use proper roles. Decoration -fields are meant to hold punctuation and other characters used -to decorate the content, typically to make it more readable -to human readers. - - -'Anchor content should be decimal width' -++++++++++++++++++++++++++++++++++++++++ - -The message "Anchor content should be decimal width" can be caused by code like: - -:: - - xo_emit("{[:mumble}"); - -This code should be replaced with code like: - -:: - - xo_emit("{[:32}"); - -Anchors need an integer value to specify the width of -the set of anchored fields. The value can be positive -(for left padding/right justification) or negative (for -right padding/left justification) and can appear in -either the start or stop anchor field descriptor. - - -'Anchor format should be "%d"' -++++++++++++++++++++++++++++++ - -The message "Anchor format should be "%d"" can be caused by code like: - -:: - - xo_emit("{[:/%s}"); - -This code should be replaced with code like: - -:: - - xo_emit("{[:/%d}"); - -Anchors only grok integer values, and if the value is not static, -if must be in an 'int' argument, represented by the "%d" format. -Anything else is an error. - - -'Anchor cannot have both format and encoding format")' -++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -The message "Anchor cannot have both format and encoding format")" can be caused by code like: - -:: - - xo_emit("{[:32/%d}"); - -This code should be replaced with code like: - -:: - - xo_emit("{[:32}"); - -Anchors can have a static value or argument for the width, -but cannot have both. - - -'Max width only valid for strings' -++++++++++++++++++++++++++++++++++ - -The message "Max width only valid for strings" can be caused by code like: - -:: - - xo_emit("{:tag/%2.4.6d}", 55); - -This code should be replaced with code like: - -:: - - xo_emit("{:tag/%2.6d}", 55); - -libxo allows a true 'max width' in addition to the traditional -printf-style 'max number of bytes to use for input'. But this -is supported only for string values, since it makes no sense -for non-strings. This error may occur from a typo, -like "{:tag/%6..6d}" where only one period should be used. +====== +xolint +====== + +`xolint` is a tool for reporting common mistakes in format strings +in source code that invokes `xo_emit`. It allows these errors +to be diagnosed at build time, rather than waiting until runtime. + +`xolint` takes the one or more C files as arguments, and reports +and errors, warning, or informational messages as needed: + + ============ =================================================== + Option Meaning + ============ =================================================== + -c Invoke 'cpp' against the input file + -C Flags that are passed to 'cpp + -d Enable debug output + -D Generate documentation for all xolint messages + -I Generate info table code + -p Print the offending lines after the message + -V Print vocabulary of all field names + -X Extract samples from xolint, suitable for testing + ============ =================================================== + +The output message will contain the source filename and line number, the +class of the message, the message, and, if -p is given, the +line that contains the error:: + + % xolint.pl -t xolint.c + xolint.c: 16: error: anchor format should be "%d" + 16 xo_emit("{[:/%s}"); + +The "-I" option will generate a table of `xo_info_t`_ structures, +suitable for inclusion in source code. + +.. _xo_info_t: :ref:`field-information` + +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. diff --git a/libxo/libxo.c b/libxo/libxo.c index ea64feb8..916a111f 100644 --- a/libxo/libxo.c +++ b/libxo/libxo.c @@ -6979,8 +6979,21 @@ xo_do_open_container (xo_handle_t *xop, xo_xof_flags_t flags, const char *name) pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? ",\n" : ", "; xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + /* If we need underscores, make a local copy and doctor it */ + const char *new_name = name; + if (XOF_ISSET(xop, XOF_UNDERSCORES)) { + size_t len = strlen(name); + const char *old_name = name; + char *buf, *cp, *ep; + + buf = alloca(len + 1); + for (cp = buf, ep = buf + len + 1; cp < ep; cp++, old_name++) + *cp = (*old_name == '-') ? '_' : *old_name; + new_name = buf; + } + rc = xo_printf(xop, "%s%*s\"%s\": {%s", - pre_nl, xo_indent(xop), "", name, ppn); + pre_nl, xo_indent(xop), "", new_name, ppn); break; case XO_STYLE_SDPARAMS: @@ -7142,8 +7155,21 @@ xo_do_open_list (xo_handle_t *xop, xo_xof_flags_t flags, const char *name) pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? ",\n" : ", "; xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + /* If we need underscores, make a local copy and doctor it */ + const char *new_name = name; + if (XOF_ISSET(xop, XOF_UNDERSCORES)) { + size_t len = strlen(name); + const char *old_name = name; + char *buf, *cp, *ep; + + buf = alloca(len + 1); + for (cp = buf, ep = buf + len + 1; cp < ep; cp++, old_name++) + *cp = (*old_name == '-') ? '_' : *old_name; + new_name = buf; + } + rc = xo_printf(xop, "%s%*s\"%s\": [%s", - pre_nl, xo_indent(xop), "", name, ppn); + pre_nl, xo_indent(xop), "", new_name, ppn); break; case XO_STYLE_ENCODER: diff --git a/libxo/xo_create.3 b/libxo/xo_create.3 index 03d51764..ea811c27 100644 --- a/libxo/xo_create.3 +++ b/libxo/xo_create.3 @@ -33,7 +33,7 @@ function. Example: xo_handle_t *xop = xo_create(XO_STYLE_JSON, XOF_WARN); .... - xo_emit_h(xop, "testing\n"); + xo_emit_h(xop, "testing\\n"); .Ed .Pp By default, diff --git a/libxo/xo_emit.3 b/libxo/xo_emit.3 index 9e3ec85b..cbf9d2b1 100644 --- a/libxo/xo_emit.3 +++ b/libxo/xo_emit.3 @@ -48,7 +48,7 @@ In this example, a set of four values is emitted using the following source code: .Bd -literal -offset indent xo_emit(" {:lines/%7ju} {:words/%7ju} " - "{:characters/%7ju} {d:filename/%s}\n", + "{:characters/%7ju} {d:filename/%s}\\n", linect, wordct, charct, file); .Ed Output can then be generated in various style, using @@ -100,6 +100,8 @@ then the number of display columns consumed by the output will be returned. .Sh SEE ALSO .Xr xo_open_container 3 , .Xr xo_open_list 3 , +.Xr xo_emit_f 3 , +.Xo xo_emit_field 3 , .Xr xo_format 5 , .Xr libxo 3 .Sh HISTORY diff --git a/libxo/xo_emit_f.3 b/libxo/xo_emit_f.3 index 7c340175..f8ac0132 100644 --- a/libxo/xo_emit_f.3 +++ b/libxo/xo_emit_f.3 @@ -84,14 +84,14 @@ clear this information; they are not generally needed. .Bd -literal -offset indent for (i = 0; i < 1000; i++) { xo_open_instance("item"); - xo_emit_f(XOEF_RETAIN, "{:name} {:count/%d}\n", + xo_emit_f(XOEF_RETAIN, "{:name} {:count/%d}\\n", name[i], count[i]); } .Ed .Pp In this example, the caller desires to clear the retained information. .Bd -literal -offset indent - const char *fmt = "{:name} {:count/%d}\n"; + const char *fmt = "{:name} {:count/%d}\\n"; for (i = 0; i < 1000; i++) { xo_open_instance("item"); xo_emit_f(XOEF_RETAIN, fmt, name[i], count[i]); diff --git a/libxo/xo_emit_field.3 b/libxo/xo_emit_field.3 new file mode 100644 index 00000000..4f9636ce --- /dev/null +++ b/libxo/xo_emit_field.3 @@ -0,0 +1,113 @@ +.\" # +.\" # Copyright (c) 2021, Juniper Networks, Inc. +.\" # All rights reserved. +.\" # This SOFTWARE is licensed under the LICENSE provided in the +.\" # ../Copyright file. By downloading, installing, copying, or +.\" # using the SOFTWARE, you agree to be bound by the terms of that +.\" # LICENSE. +.\" # Phil Shafer, July 2014 +.\" +.Dd December 4, 2014 +.Dt LIBXO 3 +.Os +.Sh NAME +.Nm xo_emit_field +.Nd emit formatted output based on format string and arguments +.Sh LIBRARY +.Lb libxo +.Sh SYNOPSIS +.In libxo/xo.h +.Ft xo_ssize_t +.Fn xo_emit_field "const char *rolmod" "const char *content" "const char *fmt" "const char *efmt" "..." +.Ft xo_ssize_t +.Fn xo_emit_field_h "xo_handle_t *xop" "const char *rolmod" "const char *content" "const char *fmt" const char *efmt" "..." +.Ft xo_ssize_t +.Fn xo_emit_field_hv "xo_handle_t *xop" "const char *rolmod" "const char *content" "const char *fmt" "const char *efmt" "va_list vap" +.Sh DESCRIPTION +The +.Fn xo_emit_field +function emits formatted output similar to +.Xr xo_emit 3 +but where +.Fn xo_emit +uses a single string argument containing the description +for multiple fields, +.Fn xo_emit_field +emits a single field using multiple arguments to contain the +field description. +.Fn xo_emit_field_h +adds an explicit handle to use instead of the default +handle, while +.Fn xo_emit_field_hv +accepts a +.Fa va_list +for additional flexibility. +.Pp +The arguments +.Fa rolmod , +.Fa content , +.Fa fmt , +and +.Fa efmt +are detailed in +.Xr xo_format 5 . +Using distinct arguments allows callers to pass the field description +in pieces, rather than having to use something like +.Xr snprintf 3 +to build the format string required by +.Fn xo_emit . +The arguments are each NUL-terminated strings. The +.Fa rolmod +argument contains the "role" and "modifier" portions of +the field description, the +.Fa content +argument contains the "content" portion, and the +.Fa fmt +and +.Fa efmt +contain the "field-format" and "encoding-format" portions, respectively. +.Pp +As with xo_emit, the +.Fa fmt +and +.Fa efmt +values are both optional, since the field-format string +defaults to "%s", and the encoding-format's default value is +derived from the field-format +per +.Xr xo_format 5 . +However, care must be taken to avoid using a value directly as the +format, since characters like '{', '%', and '}' will be interpreted +as formatting directives, and may cause +.Nm +to dereference arbitrary values off the stack, leading to bugs, +core files, and gnashing of teeth. +.Sh EXAMPLES +In this example, a set of four values is emitted using the following +source code: +.Bd -literal -offset indent + xo_emit_field("T", title, NULL, NULL, NULL); + xo_emit_field("Vt", "max-chaos", NULL, NULL, " very "); + xo_emit_field("V", "min-chaos", "%02d", "%d", 42); + xo_emit_field_h(NULL, ",leaf-list,quotes", "sku", "%s-%u", "%s-000-%u", + "gum", 1412); +.Ed +.Sh RETURN CODE +.Nm +returns a negative value on error. If the +.Nm XOF_COLUMNS +flag has been turned on for the specific handle using +.Xr xo_set_flags 3 , +then the number of display columns consumed by the output will be returned. +.Sh SEE ALSO +.Xr xo_format 5 , +.Xr libxo 3 +.Sh HISTORY +The +.Nm libxo +library first appeared in +.Fx 11.0 . +.Sh AUTHORS +.Nm libxo +was written by +.An Phil Shafer Aq Mt phil@freebsd.org . diff --git a/libxo/xo_open_container.3 b/libxo/xo_open_container.3 index 7037974d..303f3f06 100644 --- a/libxo/xo_open_container.3 +++ b/libxo/xo_open_container.3 @@ -141,7 +141,7 @@ flag is set. .Bd -literal -offset indent -compact EXAMPLE: xo_open_container("system"); - xo_emit("The host name is {:host-name}\n", hn); + xo_emit("The host name is {:host-name}\\n", hn); xo_close_container("system"); XML: foo diff --git a/libxo/xo_open_list.3 b/libxo/xo_open_list.3 index f28c9b63..e61e1593 100644 --- a/libxo/xo_open_list.3 +++ b/libxo/xo_open_list.3 @@ -77,7 +77,7 @@ close each instance of the list: for (ip = list; ip->i_title; ip++) { xo_open_instance("item"); - xo_emit("{L:Item} '{:name/%s}':\n", ip->i_title); + xo_emit("{L:Item} '{:name/%s}':\\n", ip->i_title); xo_close_instance("item"); } @@ -91,7 +91,7 @@ generation of XML and JSON data. xo_open_list("user"); for (i = 0; i < num_users; i++) { xo_open_instance("user"); - xo_emit("{k:name}:{:uid/%u}:{:gid/%u}:{:home}\n", + xo_emit("{k:name}:{:uid/%u}:{:gid/%u}:{:home}\\n", pw[i].pw_name, pw[i].pw_uid, pw[i].pw_gid, pw[i].pw_dir); xo_close_instance("user"); @@ -138,7 +138,7 @@ To emit a leaf list, call the function using the ""l"" modifier: .Bd -literal -offset indent -compact for (ip = list; ip->i_title; ip++) { - xo_emit("{Lwc:Item}{l:item}\n", ip->i_title); + xo_emit("{Lwc:Item}{l:item}\\n", ip->i_title); } .Ed .Pp diff --git a/libxo/xo_parse_args.3 b/libxo/xo_parse_args.3 index b014e608..543ffec9 100644 --- a/libxo/xo_parse_args.3 +++ b/libxo/xo_parse_args.3 @@ -7,7 +7,7 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd December 4, 2014 +.Dd November 17, 2020 .Dt LIBXO 3 .Os .Sh NAME @@ -79,7 +79,7 @@ string lookup .It Dv log-syslog Log (via stderr) each syslog message (via .Xr xo_syslog 3 ) -.If Dv no-humanize +.It Dv no-humanize Ignore the {h:} modifier (TEXT, HTML) .It Dv no-locale Do not initialize the locale setting @@ -95,7 +95,7 @@ Emit pretty-printed output Force retaining formatting information .It Dv text Emit TEXT output -.If Dv underscores +.It Dv underscores Replace XML-friendly "-"s with JSON friendly "_"s e .It Dv units Add the 'units' (XML) or 'data-units (HTML) attribute diff --git a/tests/core/Makefile.am b/tests/core/Makefile.am index a1dad2cc..9ed59b6c 100644 --- a/tests/core/Makefile.am +++ b/tests/core/Makefile.am @@ -91,7 +91,7 @@ echo "... $$test ... $$fmt ..."; \ xoopts==warn,$$csv ; \ ${TEST_JIG}; true; -TEST_FORMATS = T XP JP HP X J H HIPx +TEST_FORMATS = T XP JP JPu HP X J H HIPx test tests: ${bin_PROGRAMS} @${MKDIR} -p out @@ -113,7 +113,7 @@ test tests: ${bin_PROGRAMS} -@ (${TEST_TRACE} test=test_01.c; base=test_01; \ ( fmt=Ecsv1; csv=encoder=csv ; \ ${TEST_JIG2} ); \ - ( fmt=Ecsv2; csv=encoder=csv:path=top/data/item:no-header ; \ + ( fmt=Ecsv2; csv=encoder=csv:path=top-level/data/item:no-header ; \ ${TEST_JIG2} ); \ ( fmt=Ecsv3; csv=@csv:path=item:leafs=sku.sold:no-quotes ; \ ${TEST_JIG2} ); \ diff --git a/tests/core/saved/test_01.E.out b/tests/core/saved/test_01.E.out index ba063634..506bfa83 100644 --- a/tests/core/saved/test_01.E.out +++ b/tests/core/saved/test_01.E.out @@ -1,5 +1,5 @@ op create: [test] [] [0] -op open_container: [top] [] [0x810] +op open_container: [top-level] [] [0x810] op string: [type] [ethernet] [0] op content: [type] [bridge] [0] op content: [type] [18u] [0] @@ -21,6 +21,10 @@ op string: [label] [value] [0x200000] op string: [max-chaos] [very] [0x1000] op content: [min-chaos] [42] [0] op string: [some-chaos] [[42]] [0] +op attr: [test-attr] [attr-value] [0] +op open_leaf_list: [sku] [] [0] +op string: [sku] [gum-000-1412] [0x2010] +op close_leaf_list: [sku] [] [0] op string: [host] [my-box] [0] op string: [domain] [example.com] [0] op attr: [test] [value] [0] @@ -197,6 +201,6 @@ op content: [mode_octal] [640] [0x8] op content: [links] [1] [0x1000] op string: [user] [user] [0x1000] op string: [group] [group] [0x1000] -op close_container: [top] [] [0] +op close_container: [top-level] [] [0] op finish: [] [] [0] op flush: [] [] [0] diff --git a/tests/core/saved/test_01.H.out b/tests/core/saved/test_01.H.out index e8ea9fe9..b58816d8 100644 --- a/tests/core/saved/test_01.H.out +++ b/tests/core/saved/test_01.H.out @@ -1,2 +1,3 @@ -
static
ethernet
bridge
18u
24
anchor
0x0
..
1
anchor
0x0
..
1
anchor
0x0
..
1
df
12
%
testing argument modifier
my-box
.
example.com
...
testing argument modifier with encoding to
.
example.com
...
Label text
value
very
42
42 -
Connecting to
my-box
.
example.com
...
Item
Total Sold
In Stock
On Order
SKU
gum
1412
54
10
GRO-000-415
rope
85
4
2
HRD-000-212
ladder
0
2
1
HRD-000-517
bolt
4123
144
42
HRD-000-632
water
17
14
2
GRO-000-2331
Item
'
gum
':
Total sold
:
1412.0
In stock
:
54
On order
:
10
SKU
:
GRO-000-415
Item
'
rope
':
Total sold
:
85.0
In stock
:
4
On order
:
2
SKU
:
HRD-000-212
Item
'
ladder
':
Total sold
:
0
In stock
:
2
On order
:
1
SKU
:
HRD-000-517
Item
'
bolt
':
Total sold
:
4123.0
In stock
:
144
On order
:
42
SKU
:
HRD-000-632
Item
'
water
':
Total sold
:
17.0
In stock
:
14
On order
:
2
SKU
:
GRO-000-2331
Item
'
fish
':
Total sold
:
1321.0
In stock
:
45
On order
:
1
SKU
:
GRO-000-533
Item
:
gum
Item
:
rope
Item
:
ladder
Item
:
bolt
Item
:
water
Item
Total Sold
In Stock
On Order
SKU
gum
1412
10
54
GRO-000-415
rope
85
Extra:
special
2
4
HRD-000-212
ladder
0
Extra:
special
1
2
HRD-000-517
bolt
4123
42
144
HRD-000-632
water
17
Extra:
special
2
14
GRO-000-2331
X
X
X
X
X
X
X
X
X
X
Cost
:
425
X
X
Cost
:
455
links
user
group
3
this
/some/file
1
user
group
\ No newline at end of file +
static
ethernet
bridge
18u
24
anchor
0x0
..
1
anchor
0x0
..
1
anchor
0x0
..
1
df
12
%
testing argument modifier
my-box
.
example.com
...
testing argument modifier with encoding to
.
example.com
...
Label text
value
My Title +
very
42
42 +
gum-1412
Connecting to
my-box
.
example.com
...
Item
Total Sold
In Stock
On Order
SKU
gum
1412
54
10
GRO-000-415
rope
85
4
2
HRD-000-212
ladder
0
2
1
HRD-000-517
bolt
4123
144
42
HRD-000-632
water
17
14
2
GRO-000-2331
Item
'
gum
':
Total sold
:
1412.0
In stock
:
54
On order
:
10
SKU
:
GRO-000-415
Item
'
rope
':
Total sold
:
85.0
In stock
:
4
On order
:
2
SKU
:
HRD-000-212
Item
'
ladder
':
Total sold
:
0
In stock
:
2
On order
:
1
SKU
:
HRD-000-517
Item
'
bolt
':
Total sold
:
4123.0
In stock
:
144
On order
:
42
SKU
:
HRD-000-632
Item
'
water
':
Total sold
:
17.0
In stock
:
14
On order
:
2
SKU
:
GRO-000-2331
Item
'
fish
':
Total sold
:
1321.0
In stock
:
45
On order
:
1
SKU
:
GRO-000-533
Item
:
gum
Item
:
rope
Item
:
ladder
Item
:
bolt
Item
:
water
Item
Total Sold
In Stock
On Order
SKU
gum
1412
10
54
GRO-000-415
rope
85
Extra:
special
2
4
HRD-000-212
ladder
0
Extra:
special
1
2
HRD-000-517
bolt
4123
42
144
HRD-000-632
water
17
Extra:
special
2
14
GRO-000-2331
X
X
X
X
X
X
X
X
X
X
Cost
:
425
X
X
Cost
:
455
links
user
group
3
this
/some/file
1
user
group
\ No newline at end of file diff --git a/tests/core/saved/test_01.HIPx.out b/tests/core/saved/test_01.HIPx.out index fa5fd831..da30b72a 100644 --- a/tests/core/saved/test_01.HIPx.out +++ b/tests/core/saved/test_01.HIPx.out @@ -1,64 +1,67 @@
static
-
ethernet
+
ethernet
-
bridge
+
bridge
-
18u
+
18u
-
24
+
24
anchor
-
0x0
+
0x0
..
-
1
+
1
anchor
-
0x0
+
0x0
..
-
1
+
1
anchor
-
0x0
+
0x0
..
-
1
+
1
df
-
12
+
12
%
testing argument modifier
-
my-box
+
my-box
.
-
example.com
+
example.com
...
testing argument modifier with encoding to
.
-
example.com
+
example.com
...
Label text
-
value
+
value
-
very
-
42
-
42 +
My Title
+
very
+
42
+
42 +
+
gum-1412
Connecting to
-
my-box
+
my-box
.
-
example.com
+
example.com
...
@@ -69,39 +72,39 @@
SKU
-
gum
-
1412
-
54
-
10
-
GRO-000-415
+
gum
+
1412
+
54
+
10
+
GRO-000-415
-
rope
-
85
-
4
-
2
-
HRD-000-212
+
rope
+
85
+
4
+
2
+
HRD-000-212
-
ladder
-
0
-
2
-
1
-
HRD-000-517
+
ladder
+
0
+
2
+
1
+
HRD-000-517
-
bolt
-
4123
-
144
-
42
-
HRD-000-632
+
bolt
+
4123
+
144
+
42
+
HRD-000-632
-
water
-
17
-
14
-
2
-
GRO-000-2331
+
water
+
17
+
14
+
2
+
GRO-000-2331
@@ -110,224 +113,224 @@
Item
'
-
gum
+
gum
':
Total sold
:
-
1412.0
+
1412.0
In stock
:
-
54
+
54
On order
:
-
10
+
10
SKU
:
-
GRO-000-415
+
GRO-000-415
Item
'
-
rope
+
rope
':
Total sold
:
-
85.0
+
85.0
In stock
:
-
4
+
4
On order
:
-
2
+
2
SKU
:
-
HRD-000-212
+
HRD-000-212
Item
'
-
ladder
+
ladder
':
Total sold
:
-
0
+
0
In stock
:
-
2
+
2
On order
:
-
1
+
1
SKU
:
-
HRD-000-517
+
HRD-000-517
Item
'
-
bolt
+
bolt
':
Total sold
:
-
4123.0
+
4123.0
In stock
:
-
144
+
144
On order
:
-
42
+
42
SKU
:
-
HRD-000-632
+
HRD-000-632
Item
'
-
water
+
water
':
Total sold
:
-
17.0
+
17.0
In stock
:
-
14
+
14
On order
:
-
2
+
2
SKU
:
-
GRO-000-2331
+
GRO-000-2331
Item
'
-
fish
+
fish
':
Total sold
:
-
1321.0
+
1321.0
In stock
:
-
45
+
45
On order
:
-
1
+
1
SKU
:
-
GRO-000-533
+
GRO-000-533
Item
:
-
gum
+
gum
Item
:
-
rope
+
rope
Item
:
-
ladder
+
ladder
Item
:
-
bolt
+
bolt
Item
:
-
water
+
water
Item
@@ -337,45 +340,45 @@
SKU
-
gum
-
1412
-
10
-
54
-
GRO-000-415
+
gum
+
1412
+
10
+
54
+
GRO-000-415
-
rope
-
85
+
rope
+
85
Extra:
-
special
-
2
-
4
-
HRD-000-212
+
special
+
2
+
4
+
HRD-000-212
-
ladder
-
0
+
ladder
+
0
Extra:
-
special
-
1
-
2
-
HRD-000-517
+
special
+
1
+
2
+
HRD-000-517
-
bolt
-
4123
-
42
-
144
-
HRD-000-632
+
bolt
+
4123
+
42
+
144
+
HRD-000-632
-
water
-
17
+
water
+
17
Extra:
-
special
-
2
-
14
-
GRO-000-2331
+
special
+
2
+
14
+
GRO-000-2331
@@ -398,7 +401,7 @@
Cost
:
-
425
+
425
X
@@ -407,28 +410,28 @@
Cost
:
-
455
+
455
-
links
+
links
-
user
+
user
-
group
+
group
-
3
-
this
+
3
+
this
-
/some/file
+
/some/file
-
1
+
1
-
user
+
user
-
group
+
group
diff --git a/tests/core/saved/test_01.HP.out b/tests/core/saved/test_01.HP.out index 9eadb4a1..5a7aed05 100644 --- a/tests/core/saved/test_01.HP.out +++ b/tests/core/saved/test_01.HP.out @@ -51,10 +51,13 @@
value
+
My Title +
very
42
42
+
gum-1412
Connecting to
my-box
.
diff --git a/tests/core/saved/test_01.J.out b/tests/core/saved/test_01.J.out index 4a3b05f9..b8c78267 100644 --- a/tests/core/saved/test_01.J.out +++ b/tests/core/saved/test_01.J.out @@ -1 +1 @@ -{"top": {"type":"ethernet","type":"bridge","type":"18u","type":24,"address":"0x0","port":1,"address":"0x0","port":1,"address":"0x0","port":1,"used-percent":12,"kve_start":"0xdeadbeef","kve_end":"0xcabb1e","host":"my-box","domain":"example.com","host":"my-box","domain":"example.com","label":"value","max-chaos":"very","min-chaos":42,"some-chaos":"[42]","host":"my-box","domain":"example.com", "data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17,"in-stock":14,"on-order":2}]}, "data2": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412.0,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85.0,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123.0,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17.0,"in-stock":14,"on-order":2}]}, "data3": {"item": [{"sku":"GRO-000-533","name":"fish","sold":1321.0,"in-stock":45,"on-order":1}]}, "data4": {"item": ["gum","rope","ladder","bolt","water"]}, "data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412,"on-order":10,"in-stock":54}, {"sku":"HRD-000-212","name":"rope","sold":85,"extra":"special","on-order":2,"in-stock":4}, {"sku":"HRD-000-517","name":"ladder","sold":0,"extra":"special","on-order":1,"in-stock":2}, {"sku":"HRD-000-632","name":"bolt","sold":4123,"on-order":42,"in-stock":144}, {"sku":"GRO-000-2331","name":"water","sold":17,"extra":"special","on-order":2,"in-stock":14}]},"cost":425,"cost":455,"mode":"mode","mode_octal":"octal","links":"links","user":"user","group":"group","pre":"that","links":3,"post":"this","mode":"/some/file","mode_octal":640,"links":1,"user":"user","group":"group"}} +{"top-level": {"type":"ethernet","type":"bridge","type":"18u","type":24,"address":"0x0","port":1,"address":"0x0","port":1,"address":"0x0","port":1,"used-percent":12,"kve_start":"0xdeadbeef","kve_end":"0xcabb1e","host":"my-box","domain":"example.com","host":"my-box","domain":"example.com","label":"value","max-chaos":"very","min-chaos":42,"some-chaos":"[42]", "sku": ["gum-000-1412"],"host":"my-box","domain":"example.com", "data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17,"in-stock":14,"on-order":2}]}, "data2": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412.0,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85.0,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123.0,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17.0,"in-stock":14,"on-order":2}]}, "data3": {"item": [{"sku":"GRO-000-533","name":"fish","sold":1321.0,"in-stock":45,"on-order":1}]}, "data4": {"item": ["gum","rope","ladder","bolt","water"]}, "data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412,"on-order":10,"in-stock":54}, {"sku":"HRD-000-212","name":"rope","sold":85,"extra":"special","on-order":2,"in-stock":4}, {"sku":"HRD-000-517","name":"ladder","sold":0,"extra":"special","on-order":1,"in-stock":2}, {"sku":"HRD-000-632","name":"bolt","sold":4123,"on-order":42,"in-stock":144}, {"sku":"GRO-000-2331","name":"water","sold":17,"extra":"special","on-order":2,"in-stock":14}]},"cost":425,"cost":455,"mode":"mode","mode_octal":"octal","links":"links","user":"user","group":"group","pre":"that","links":3,"post":"this","mode":"/some/file","mode_octal":640,"links":1,"user":"user","group":"group"}} diff --git a/tests/core/saved/test_01.JP.out b/tests/core/saved/test_01.JP.out index 5c226354..71a77cea 100644 --- a/tests/core/saved/test_01.JP.out +++ b/tests/core/saved/test_01.JP.out @@ -1,5 +1,5 @@ { - "top": { + "top-level": { "type": "ethernet", "type": "bridge", "type": "18u", @@ -21,6 +21,9 @@ "max-chaos": "very", "min-chaos": 42, "some-chaos": "[42]", + "sku": [ + "gum-000-1412" + ], "host": "my-box", "domain": "example.com", "data": { diff --git a/tests/core/saved/test_01.JPu.err b/tests/core/saved/test_01.JPu.err new file mode 100644 index 00000000..e69de29b diff --git a/tests/core/saved/test_01.JPu.out b/tests/core/saved/test_01.JPu.out new file mode 100644 index 00000000..747db16f --- /dev/null +++ b/tests/core/saved/test_01.JPu.out @@ -0,0 +1,185 @@ +{ + "top_level": { + "type": "ethernet", + "type": "bridge", + "type": "18u", + "type": 24, + "address": "0x0", + "port": 1, + "address": "0x0", + "port": 1, + "address": "0x0", + "port": 1, + "used_percent": 12, + "kve_start": "0xdeadbeef", + "kve_end": "0xcabb1e", + "host": "my-box", + "domain": "example.com", + "host": "my-box", + "domain": "example.com", + "label": "value", + "max_chaos": "very", + "min_chaos": 42, + "some_chaos": "[42]", + "sku": [ + "gum-000-1412" + ], + "host": "my-box", + "domain": "example.com", + "data": { + "item": [ + { + "sku": "GRO-000-415", + "name": "gum", + "sold": 1412, + "in_stock": 54, + "on_order": 10 + }, + { + "sku": "HRD-000-212", + "name": "rope", + "sold": 85, + "in_stock": 4, + "on_order": 2 + }, + { + "sku": "HRD-000-517", + "name": "ladder", + "sold": 0, + "in_stock": 2, + "on_order": 1 + }, + { + "sku": "HRD-000-632", + "name": "bolt", + "sold": 4123, + "in_stock": 144, + "on_order": 42 + }, + { + "sku": "GRO-000-2331", + "name": "water", + "sold": 17, + "in_stock": 14, + "on_order": 2 + } + ] + }, + "data2": { + "item": [ + { + "sku": "GRO-000-415", + "name": "gum", + "sold": 1412.0, + "in_stock": 54, + "on_order": 10 + }, + { + "sku": "HRD-000-212", + "name": "rope", + "sold": 85.0, + "in_stock": 4, + "on_order": 2 + }, + { + "sku": "HRD-000-517", + "name": "ladder", + "sold": 0, + "in_stock": 2, + "on_order": 1 + }, + { + "sku": "HRD-000-632", + "name": "bolt", + "sold": 4123.0, + "in_stock": 144, + "on_order": 42 + }, + { + "sku": "GRO-000-2331", + "name": "water", + "sold": 17.0, + "in_stock": 14, + "on_order": 2 + } + ] + }, + "data3": { + "item": [ + { + "sku": "GRO-000-533", + "name": "fish", + "sold": 1321.0, + "in_stock": 45, + "on_order": 1 + } + ] + }, + "data4": { + "item": [ + "gum", + "rope", + "ladder", + "bolt", + "water" + ] + }, + "data": { + "item": [ + { + "sku": "GRO-000-415", + "name": "gum", + "sold": 1412, + "on_order": 10, + "in_stock": 54 + }, + { + "sku": "HRD-000-212", + "name": "rope", + "sold": 85, + "extra": "special", + "on_order": 2, + "in_stock": 4 + }, + { + "sku": "HRD-000-517", + "name": "ladder", + "sold": 0, + "extra": "special", + "on_order": 1, + "in_stock": 2 + }, + { + "sku": "HRD-000-632", + "name": "bolt", + "sold": 4123, + "on_order": 42, + "in_stock": 144 + }, + { + "sku": "GRO-000-2331", + "name": "water", + "sold": 17, + "extra": "special", + "on_order": 2, + "in_stock": 14 + } + ] + }, + "cost": 425, + "cost": 455, + "mode": "mode", + "mode_octal": "octal", + "links": "links", + "user": "user", + "group": "group", + "pre": "that", + "links": 3, + "post": "this", + "mode": "/some/file", + "mode_octal": 640, + "links": 1, + "user": "user", + "group": "group" + } +} diff --git a/tests/core/saved/test_01.T.out b/tests/core/saved/test_01.T.out index 0b051da2..89d31573 100644 --- a/tests/core/saved/test_01.T.out +++ b/tests/core/saved/test_01.T.out @@ -5,8 +5,9 @@ df 12% testing argument modifier my-box.example.com... testing argument modifier with encoding to .example.com... Label text value +My Title very 4242 -Connecting to my-box.example.com... +gum-1412Connecting to my-box.example.com... Item Total Sold In Stock On Order SKU gum 1412 54 10 GRO-000-415 rope 85 4 2 HRD-000-212 diff --git a/tests/core/saved/test_01.X.out b/tests/core/saved/test_01.X.out index 2ba5583f..2f1fa826 100644 --- a/tests/core/saved/test_01.X.out +++ b/tests/core/saved/test_01.X.out @@ -1 +1 @@ -ethernetbridge18u24
0x0
1
0x0
1
0x0
1120xdeadbeef0xcabb1emy-boxexample.commy-boxexample.comvery42[42]my-boxexample.comGRO-000-415gum14125410HRD-000-212rope8542HRD-000-517ladder021HRD-000-632bolt412314442GRO-000-2331water17142GRO-000-415gum1412.05410HRD-000-212rope85.042HRD-000-517ladder021HRD-000-632bolt4123.014442GRO-000-2331water17.0142GRO-000-533fish1321.0451gumropeladderboltwaterGRO-000-415gum14121054HRD-000-212rope85special24HRD-000-517ladder0special12HRD-000-632bolt412342144GRO-000-2331water17special214425455modeoctallinksusergroup
that
3this/some/file6401usergroup
\ No newline at end of file +ethernetbridge18u24
0x0
1
0x0
1
0x0
1120xdeadbeef0xcabb1emy-boxexample.commy-boxexample.comvery42[42]gum-000-1412my-boxexample.comGRO-000-415gum14125410HRD-000-212rope8542HRD-000-517ladder021HRD-000-632bolt412314442GRO-000-2331water17142GRO-000-415gum1412.05410HRD-000-212rope85.042HRD-000-517ladder021HRD-000-632bolt4123.014442GRO-000-2331water17.0142GRO-000-533fish1321.0451gumropeladderboltwaterGRO-000-415gum14121054HRD-000-212rope85special24HRD-000-517ladder0special12HRD-000-632bolt412342144GRO-000-2331water17special214425455modeoctallinksusergroup
that
3this/some/file6401usergroup
\ No newline at end of file diff --git a/tests/core/saved/test_01.XP.out b/tests/core/saved/test_01.XP.out index e40055a2..afa79ada 100644 --- a/tests/core/saved/test_01.XP.out +++ b/tests/core/saved/test_01.XP.out @@ -1,4 +1,4 @@ - + ethernet bridge 18u @@ -20,6 +20,7 @@ very 42 [42] + gum-000-1412 my-box example.com @@ -167,4 +168,4 @@ 1 user group - + diff --git a/tests/core/saved/test_02.JPu.err b/tests/core/saved/test_02.JPu.err new file mode 100644 index 00000000..cedb03e0 --- /dev/null +++ b/tests/core/saved/test_02.JPu.err @@ -0,0 +1 @@ +test_02: key field emitted after normal value field: 'name' diff --git a/tests/core/saved/test_02.JPu.out b/tests/core/saved/test_02.JPu.out new file mode 100644 index 00000000..83b1029e --- /dev/null +++ b/tests/core/saved/test_02.JPu.out @@ -0,0 +1,98 @@ +{ + "top": { + "data": { + "name": "em0", + "flags": "0x8843", + "name": "em0", + "flags": "0x8843", + "what": "braces", + "length": "abcdef", + "fd": -1, + "error": "Bad file descriptor", + "test": "good", + "fd": -1, + "error": "Bad fi", + "test": "good", + "lines": 20, + "words": 30, + "characters": 40, + "bytes": [ + 0, + 1, + 2, + 3, + 4 + ], + "mbuf_current": 10, + "mbuf_cache": 20, + "mbuf_total": 30, + "distance": 50, + "location": "Boston", + "memory": 64, + "total": 640, + "memory": 64, + "total": 640, + "ten": 10, + "eleven": 11, + "unknown": 1010, + "unknown": 1010, + "min": 15, + "cur": 20, + "max": 125, + "min": 15, + "cur": 20, + "max": 125, + "min": 15, + "cur": 20, + "max": 125, + "min": 15, + "cur": 20, + "max": 125, + "val1": 21, + "val2": 58368, + "val3": 100663296, + "val4": 44470272, + "val5": 1342172800, + "flag": [ + "one", + "two", + "three" + ], + "works": null, + "empty_tag": true, + "t1": "1000", + "t2": "test5000", + "t3": "ten-longx", + "t4": "xtest", + "__error": { + "message": "this is an error" + }, + "__error": { + "message": "two more errors" + }, + "__warning": { + "message": "this is an warning" + }, + "__warning": { + "message": "two more warnings" + }, + "count": 10, + "test": 4, + "error": { + "message": "Shut 'er down, Clancey! She's a-pumpin' mud! <>!,\"!<>\n" + }, + "error": { + "message": "err message (1)" + }, + "error": { + "message": "err message (2)\n" + }, + "error": { + "message": "err message (1)\n" + }, + "error": { + "message": "err message (2)\n" + } + } + } +} diff --git a/tests/core/saved/test_03.JPu.err b/tests/core/saved/test_03.JPu.err new file mode 100644 index 00000000..e69de29b diff --git a/tests/core/saved/test_03.JPu.out b/tests/core/saved/test_03.JPu.out new file mode 100644 index 00000000..d0c3ccf4 --- /dev/null +++ b/tests/core/saved/test_03.JPu.out @@ -0,0 +1,33 @@ +{ + "employees": { + "employee": [ + ], + "extra": "", + "memory": [ + { + "type": "name", + "in_use": 12345, + "memory_use": 54321, + "high_use": "-", + "requests": 32145 + } + ], + "employee": [ + { + "first_name": "Terry", + "last_name": "Jones", + "department": 660 + }, + { + "first_name": "Leslie", + "last_name": "Patterson", + "department": 341 + }, + { + "first_name": "Ashley", + "last_name": "Smith", + "department": 1440 + } + ] + } +} diff --git a/tests/core/saved/test_04.JPu.err b/tests/core/saved/test_04.JPu.err new file mode 100644 index 00000000..e69de29b diff --git a/tests/core/saved/test_04.JPu.out b/tests/core/saved/test_04.JPu.out new file mode 100644 index 00000000..b0f802dc --- /dev/null +++ b/tests/core/saved/test_04.JPu.out @@ -0,0 +1,21 @@ +{ + "employees": { + "employee": [ + { + "first_name": "Terry", + "last_name": "Jones", + "department": 660 + }, + { + "first_name": "Leslie", + "last_name": "Patterson", + "department": 341 + }, + { + "first_name": "Ashley", + "last_name": "Smith", + "department": 1440 + } + ] + } +} diff --git a/tests/core/saved/test_05.JPu.err b/tests/core/saved/test_05.JPu.err new file mode 100644 index 00000000..e69de29b diff --git a/tests/core/saved/test_05.JPu.out b/tests/core/saved/test_05.JPu.out new file mode 100644 index 00000000..9bcbf69d --- /dev/null +++ b/tests/core/saved/test_05.JPu.out @@ -0,0 +1,91 @@ +{ + "indian_languages": { + "gurmukhi": "ਲਹੌਰ ਪਾਕਿਸਤਾਨੀ ਪੰਜਾਬ ਦੀ ਰਾਜਧਾਨੀ ਹੈ । ਲੋਕ ਗਿਣਤੀ ਦੇ ਨਾਲ ਕਰਾਚੀ ਤੋਂ ਬਾਅਦ ਲਹੌਰ ਦੂਜਾ ਸਭ ਤੋਂ ਵੱਡਾ ਸ਼ਹਿਰ ਹੈ । ਲਹੌਰ ਪਾਕਿਸਤਾਨ ਦਾ ਸਿਆਸੀ, ਰਹਤਲੀ ਤੇ ਪੜ੍ਹਾਈ ਦਾ ਗੜ੍ਹ ਹੈ ਅਤੇ ਇਸ ਲਈ ਇਹਨੂੰ ਪਾਕਿਸਤਾਨ ਦਾ ਦਿਲ ਵੀ ਕਿਹਾ ਜਾਂਦਾ ਹੈ । ਲਹੌਰ ਦਰਿਆ-ਏ-ਰਾਵੀ ਦੇ ਕੰਢੇ ਤੇ ਵਸਦਾ ਹੈ ਤੇ ਇਸਦੀ ਲੋਕ ਗਿਣਤੀ ਇੱਕ ਕਰੋੜ ਦੇ ਨੇੜੇ ਹੈ ।", + "shahmukhi": "لہور پاکستانی پنجاب دا دارالحکومت اے۔ لوک گنتی دے نال کراچی توں بعد لہور دوجا سبھ توں وڈا شہر اے۔ لہور پاکستان دا سیاسی، رہتلی تے پڑھائی دا گڑھ اے تے اس لئی ایھنوں پاکستان دا دل وی کیھا جاندا اے۔ لہور دریاۓ راوی دے کنڈھے تے وسدا اے اسدی لوک گنتی اک کروڑ دے نیڑے اے ۔", + "tranliteration": "lahor pākistān panjāb dā dārul hakūmat ē. lōk giṇtī dē nāḷ karācī tō᷈ bāad lahor dūjā sab tō᷈ vaḍḍā shahr ē. lahor pākistān dā siāsī, rahtalī tē paṛā̀ī dā gā́ṛ ē tē is laī ihnū᷈ pākistān dā dil vī kehā jāndā ē. lahor dariāē rāvī dē kanḍē tē vasdā ē. isdī lōk giṇtī ikk karōṛ dē nēṛē ē." + }, + "employees": { + "wc": [ + "෴ - 0xdf4 - 1", + "ණ - 0xdab - 1", + "් - 0xdca - 0", + "ණ - 0xdab - 1", + "្ - 0x17d2 - 0", + "෴ - 0xdf4 - 1", + "1 - 0x31 - 1", + "͏ - 0x34f - 0", + "2 - 0x32 - 1", + "⃝ - 0x20dd - 0" + ], + "fancy": "1͏2⃝", + "v1": "γιγνώσκειν", + "v2": "ὦ ἄνδρες ᾿Αθηναῖοι", + "v1": "ახლავე გაიაროთ რეგისტრაცია", + "v2": "Unicode-ის მეათე საერთაშორისო", + "width": 55, + "sinhala": "෴ණ්ණ෴", + "width": 4, + "sinhala": "෴", + "width": 1, + "sinhala": "෴ණ්ණ෴෴ණ්ණ෴", + "width": 8, + "not_sinhala": "123456", + "tag": "ර්‍ඝ", + "width": 2, + "employee": [ + { + "first_name": "Jim", + "nic_name": "\"რეგტ\"", + "last_name": "გთხოვთ ახ", + "department": 431, + "percent_time": 90, + "benefits": "full" + }, + { + "first_name": "Terry", + "nic_name": "\"1 2015-06-23T13:47:09.123-0500 worker-host test-program 222 animal-status [animal-status@42 animal="snake" state="loose"] The snake is loose}} +{{test-program: }} +{{The snake is loose}} + +{{<22>1 2015-06-23T13:47:09.123-0500 worker-host test-program 222 animal-consumed [animal-consumed@42 animal="snake" pet="hamster"] My snake ate your hamster}} +{{test-program: }} +{{My snake ate your hamster}} + +{{<29>1 2015-06-23T13:47:09.123-0500 worker-host test-program 222 animal-talk [animal-talk@42 count="1" animal="owl" quote="\"e=m\\c[2\]\""] 1 owl said "e=m\c[2]"}} +{{test-program: }} +{{1 owl said "e=m\c[2]"}} + +{{<165>1 2015-06-23T13:47:09.123-0500 worker-host test-program 222 ID47 [ID47@32473 iut="3" event-source="application" event-id="1011"] An application 1011 log entry}} +{{test-program: }} +{{An application 1011 log entry}} + +{ + "__version": "3.1.4", + "top": { + + } +} diff --git a/tests/core/saved/test_12.JPu.err b/tests/core/saved/test_12.JPu.err new file mode 100644 index 00000000..6e563c3c --- /dev/null +++ b/tests/core/saved/test_12.JPu.err @@ -0,0 +1,4 @@ +test_12: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '4x4' +test_12: invalid XML tag name: '2morrow' +test_12: invalid XML tag name: '2by4' diff --git a/tests/core/saved/test_12.JPu.out b/tests/core/saved/test_12.JPu.out new file mode 100644 index 00000000..0095d8dc --- /dev/null +++ b/tests/core/saved/test_12.JPu.out @@ -0,0 +1,94 @@ +{ + "top": { + "data": { + "animal": "fish", + "animal": "fish", + "thing": [ + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45" + }, + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45" + }, + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45" + }, + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45" + }, + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45" + }, + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45" + }, + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45" + }, + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45" + }, + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45" + }, + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45", + "2by4": { + "4x4": "truck", + "2morrow": "tomorrow" + } + } + ] + } + } +} diff --git a/tests/core/test_01.c b/tests/core/test_01.c index aeeb0c9c..8311efbf 100644 --- a/tests/core/test_01.c +++ b/tests/core/test_01.c @@ -82,7 +82,7 @@ main (int argc, char **argv) xo_set_info(NULL, info, -1); xo_set_flags(NULL, XOF_KEYS); - xo_open_container_h(NULL, "top"); + xo_open_container_h(NULL, "top-level"); xo_emit("static {:type/ethernet} {:type/bridge} {:type/%4du} {:type/%3d}", 18, 24); @@ -104,10 +104,17 @@ main (int argc, char **argv) xo_emit("{La:} {a:}\n", "Label text", "label", "value"); + const char *title = "My Title"; + xo_emit_field("T", title, "%s\n", NULL, NULL); + xo_emit_field("Vt", "max-chaos", NULL, NULL, " very "); xo_emit_field("V", "min-chaos", "%d", NULL, 42); xo_emit_field("V", "some-chaos", "%d\n", "[%d]", 42); + xo_attr("test-attr", "attr-value"); + xo_emit_field_h(NULL, ",leaf-list,quotes", "sku", "%s-%u", "%s-000-%u", + "gum", 1412); + xo_emit("Connecting to {:host}.{:domain}...\n", "my-box", "example.com"); xo_attr("test", "value"); @@ -248,7 +255,7 @@ main (int argc, char **argv) "/some/file", (int) 0640, 8, 1, 10, "user", 12, "group"); - xo_close_container_h(NULL, "top"); + xo_close_container_h(NULL, "top-level"); xo_finish(); diff --git a/tests/core/test_08.c b/tests/core/test_08.c index 80cbff2a..b82a7c1d 100644 --- a/tests/core/test_08.c +++ b/tests/core/test_08.c @@ -115,11 +115,11 @@ main (int argc, char **argv) ip->i_title, ip->i_count); } - xo_close_container("data3"); /* Should be a noop */ + xo_close_container("data3"); /* warn: fails at marker 'm1' */ xo_emit("{:test}", "one"); xo_close_marker("m1"); - xo_close_container("data3"); /* Should be a noop */ + xo_close_container("data3"); /* this one works, post-marker */ xo_emit("\n\n"); @@ -139,13 +139,13 @@ main (int argc, char **argv) for (i = 0; i < 3; i++) { xo_open_instance("sub"); xo_emit("{Lwc:/Name}{:name/%d} + 1 = {:next/%d}\n", i, i + 1); - xo_close_container("data4"); + xo_close_container("data4"); /* warn: fails at marker 'm2' */ } xo_close_marker("m2"); xo_emit("{Lwc:/Last}{:last/%d}\n", i); } - xo_close_container("data4"); /* Should be a noop */ + xo_close_container("data4"); /* warn: fails at marker 'm1' */ xo_emit("{:test}", "one"); xo_emit("\n\n"); diff --git a/xo/xo.1 b/xo/xo.1 index cd885b3d..c3d062f7 100644 --- a/xo/xo.1 +++ b/xo/xo.1 @@ -179,7 +179,7 @@ prepend data to the XPath values used for HTML output style. .Bd -literal -offset indent #!/bin/sh xo --open top/data - xo --depth 2 '{tag}' value + xo --depth 2 '{:tag}' value xo --close top/data .Pp XML: