diff options
author | David Robillard <d@drobilla.net> | 2021-02-25 10:27:59 -0500 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2021-03-08 23:23:05 -0500 |
commit | c4821c8e6bf1f81c6ea31e11ebc0fc1666e9337b (patch) | |
tree | a62995534f5f606ac2f8bae22d525532b824cb5e /subprojects/exess/doc | |
parent | 6bcd18ae60482790b645a345f718e7099250f261 (diff) | |
download | serd-c4821c8e6bf1f81c6ea31e11ebc0fc1666e9337b.tar.gz serd-c4821c8e6bf1f81c6ea31e11ebc0fc1666e9337b.tar.bz2 serd-c4821c8e6bf1f81c6ea31e11ebc0fc1666e9337b.zip |
Add exess from git@gitlab.com:drobilla/exess.git 4638b1f
Diffstat (limited to 'subprojects/exess/doc')
-rw-r--r-- | subprojects/exess/doc/c/Doxyfile.in | 39 | ||||
-rw-r--r-- | subprojects/exess/doc/c/api/meson.build | 5 | ||||
-rw-r--r-- | subprojects/exess/doc/c/index.rst | 10 | ||||
-rw-r--r-- | subprojects/exess/doc/c/man/manlink.in | 1 | ||||
-rw-r--r-- | subprojects/exess/doc/c/man/meson.build | 122 | ||||
-rw-r--r-- | subprojects/exess/doc/c/meson.build | 53 | ||||
-rw-r--r-- | subprojects/exess/doc/c/overview.rst | 151 | ||||
-rw-r--r-- | subprojects/exess/doc/c/xml/meson.build | 12 | ||||
-rw-r--r-- | subprojects/exess/doc/conf.py.in | 112 | ||||
-rw-r--r-- | subprojects/exess/doc/cpp/Doxyfile.in | 44 | ||||
-rw-r--r-- | subprojects/exess/doc/cpp/api/meson.build | 5 | ||||
-rw-r--r-- | subprojects/exess/doc/cpp/index.rst | 11 | ||||
-rw-r--r-- | subprojects/exess/doc/cpp/meson.build | 42 | ||||
-rw-r--r-- | subprojects/exess/doc/cpp/overview.rst | 151 | ||||
-rw-r--r-- | subprojects/exess/doc/cpp/xml/meson.build | 14 | ||||
-rw-r--r-- | subprojects/exess/doc/meson.build | 17 | ||||
-rw-r--r-- | subprojects/exess/doc/summary.rst | 3 |
17 files changed, 792 insertions, 0 deletions
diff --git a/subprojects/exess/doc/c/Doxyfile.in b/subprojects/exess/doc/c/Doxyfile.in new file mode 100644 index 00000000..9a768f89 --- /dev/null +++ b/subprojects/exess/doc/c/Doxyfile.in @@ -0,0 +1,39 @@ +PROJECT_NAME = Exess +PROJECT_BRIEF = "A library for reading and writing XSD datatypes" + +QUIET = YES +WARN_AS_ERROR = YES +WARN_IF_UNDOCUMENTED = NO +WARN_NO_PARAMDOC = NO + +JAVADOC_AUTOBRIEF = YES + +FULL_PATH_NAMES = NO +CASE_SENSE_NAMES = YES +HIDE_IN_BODY_DOCS = YES +REFERENCES_LINK_SOURCE = NO + +GENERATE_HTML = NO +GENERATE_LATEX = NO +GENERATE_XML = YES +XML_PROGRAMLISTING = NO +SHOW_FILES = NO + +ENABLE_PREPROCESSING = YES +SKIP_FUNCTION_MACROS = NO + +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +PREDEFINED = EXESS_API \ + EXESS_CONST_API \ + EXESS_CONST_FUNC= \ + EXESS_NONNULL= \ + EXESS_NULLABLE= \ + EXESS_PURE_API \ + EXESS_PURE_FUNC= \ + +RECURSIVE = YES +STRIP_FROM_PATH = @EXESS_SRCDIR@ +INPUT = @EXESS_SRCDIR@/include + +OUTPUT_DIRECTORY = @DOX_OUTPUT@ diff --git a/subprojects/exess/doc/c/api/meson.build b/subprojects/exess/doc/c/api/meson.build new file mode 100644 index 00000000..1a3d6f94 --- /dev/null +++ b/subprojects/exess/doc/c/api/meson.build @@ -0,0 +1,5 @@ +c_exess_rst = custom_target( + 'Exess C API Sphinx Input', + command: [dox_to_sphinx, '-f', '@INPUT0@', meson.current_build_dir()], + input: [c_index_xml] + c_rst_files, + output: 'exess.rst') diff --git a/subprojects/exess/doc/c/index.rst b/subprojects/exess/doc/c/index.rst new file mode 100644 index 00000000..396a2333 --- /dev/null +++ b/subprojects/exess/doc/c/index.rst @@ -0,0 +1,10 @@ +##### +Exess +##### + +.. include:: summary.rst + +.. toctree:: + + overview + api/exess diff --git a/subprojects/exess/doc/c/man/manlink.in b/subprojects/exess/doc/c/man/manlink.in new file mode 100644 index 00000000..95accb8a --- /dev/null +++ b/subprojects/exess/doc/c/man/manlink.in @@ -0,0 +1 @@ +.so @TARGET@ diff --git a/subprojects/exess/doc/c/man/meson.build b/subprojects/exess/doc/c/man/meson.build new file mode 100644 index 00000000..d2a31557 --- /dev/null +++ b/subprojects/exess/doc/c/man/meson.build @@ -0,0 +1,122 @@ +# Run Sphinx to generate group man pages + +# Group man pages generated by Sphinx +man_pages = [ + 'exess_base64.3', + 'exess_binary.3', + 'exess_boolean.3', + 'exess_coercion.3', + 'exess_byte.3', + 'exess_datatypes.3', + 'exess_date.3', + 'exess_datetime.3', + 'exess_decimal.3', + 'exess_double.3', + 'exess_duration.3', + 'exess_float.3', + 'exess_hex.3', + 'exess_int.3', + 'exess_long.3', + # 'exess_numbers.3', + 'exess_short.3', + 'exess_status.3', + 'exess_time.3', + 'exess_timezone.3', + 'exess_ubyte.3', + 'exess_uint.3', + 'exess_ulong.3', + 'exess_ushort.3', + 'exess_variant.3', +] + +# Run Sphinx to generate man pages +man_docs = custom_target( + 'man pages for exess', + command: [sphinx_build, '-M', 'man', + meson.current_build_dir() / '..', meson.current_build_dir() / '..', + '-E', '-q', '-t', 'man'], + input: [c_rst_files, c_exess_rst, c_index_xml], + output: man_pages, + build_by_default: true, + install: true, + install_dir: get_option('mandir') / 'man3') + + + +# message(man_docs.extract_all_objects()) + +# foreach man_page : man_pages +# install_man(man_docs[0])#meson.current_build_dir() / man_page) +# endforeach + +# "Links" from symbol names to corresponding page (one-line includes) +man_links = [ + ['ExessStatus.3', 'exess_status.3'], + ['ExessResult.3', 'exess_status.3'], + ['exess_strerror.3', 'exess_status.3'], + ['exess_read_decimal.3', 'exess_decimal.3'], + ['exess_write_decimal.3', 'exess_decimal.3'], + ['exess_read_double.3', 'exess_double.3'], + ['exess_write_double.3', 'exess_double.3'], + ['exess_read_float.3', 'exess_float.3'], + ['exess_write_float.3', 'exess_float.3'], + ['exess_read_boolean.3', 'exess_boolean.3'], + ['exess_write_boolean.3', 'exess_boolean.3'], + ['exess_read_long.3', 'exess_long.3'], + ['exess_write_long.3', 'exess_long.3'], + ['exess_read_int.3', 'exess_int.3'], + ['exess_write_int.3', 'exess_int.3'], + ['exess_read_short.3', 'exess_short.3'], + ['exess_write_short.3', 'exess_short.3'], + ['exess_read_byte.3', 'exess_byte.3'], + ['exess_write_byte.3', 'exess_byte.3'], + ['exess_read_ulong.3', 'exess_ulong.3'], + ['exess_write_ulong.3', 'exess_ulong.3'], + ['exess_read_uint.3', 'exess_uint.3'], + ['exess_write_uint.3', 'exess_uint.3'], + ['exess_read_ushort.3', 'exess_ushort.3'], + ['exess_write_ushort.3', 'exess_ushort.3'], + ['exess_read_ubyte.3', 'exess_ubyte.3'], + ['exess_write_ubyte.3', 'exess_ubyte.3'], + ['ExessDuration.3', 'exess_duration.3'], + ['exess_read_duration.3', 'exess_duration.3'], + ['exess_write_duration.3', 'exess_duration.3'], + ['ExessDateTime.3', 'exess_datetime.3'], + ['exess_read_datetime.3', 'exess_datetime.3'], + ['exess_write_datetime.3', 'exess_datetime.3'], + ['ExessTimezone.3', 'exess_timezone.3'], + ['ExessDate.3', 'exess_date.3'], + ['exess_read_date.3', 'exess_date.3'], + ['exess_write_date.3', 'exess_date.3'], + ['ExessTime.3', 'exess_time.3'], + ['exess_read_time.3', 'exess_time.3'], + ['exess_write_time.3', 'exess_time.3'], + ['ExessBlob.3', 'exess_binary.3'], + ['ExessDatatype.3', 'exess_datatypes.3'], + ['ExessValue.3', 'exess_variant.3'], + ['ExessVariant.3', 'exess_variant.3'], + ['exess_read_variant.3', 'exess_variant.3'], + ['exess_write_variant.3', 'exess_variant.3'], + ['exess_write_canonical.3', 'exess_variant.3'], + ['ExessCoercionFlag.3', 'exess_variant.3'], + ['ExessCoercionFlags.3', 'exess_variant.3'], + ['exess_coerce.3', 'exess_variant.3'], +] + +foreach man_link : man_links + link = man_link[0] + target = man_link[1] + + config = configuration_data() + config.set('TARGET', target) + + manlink = configure_file(configuration: config, + input: 'manlink.in', + output: link, + install: true, + install_dir: get_option('mandir') / 'man3') + + # message(target) + + # install_man(manlink) +endforeach diff --git a/subprojects/exess/doc/c/meson.build b/subprojects/exess/doc/c/meson.build new file mode 100644 index 00000000..64c02180 --- /dev/null +++ b/subprojects/exess/doc/c/meson.build @@ -0,0 +1,53 @@ +config = configuration_data() +config.set('EXESS_VERSION', meson.project_version()) + +conf_py = configure_file(configuration: config, + input: '../conf.py.in', + output: 'conf.py') + +configure_file(copy: true, input: '../summary.rst', output: 'summary.rst') + +c_rst_files = files( + 'index.rst', + 'overview.rst', +) + +foreach f : c_rst_files + configure_file(copy: true, input: f, output: '@PLAINNAME@') +endforeach + +subdir('xml') +subdir('api') + +custom_target( + 'Exess C API Documentation (singlehtml)', + command: [sphinx_build, '-M', 'singlehtml', + meson.current_build_dir(), meson.current_build_dir(), + '-E', '-q', '-t', 'singlehtml'], + input: [c_rst_files, c_exess_rst, c_index_xml], + output: 'singlehtml', + build_by_default: true, + install: true, + install_dir: docdir / 'exess-0') + +custom_target( + 'Exess C API Documentation (html)', + command: [sphinx_build, '-M', 'html', + meson.current_build_dir(), meson.current_build_dir(), + '-E', '-q', '-t', 'html'], + input: [c_rst_files, c_exess_rst, c_index_xml], + output: 'html', + build_by_default: true, + install: true, + install_dir: docdir / 'exess-0') + +# custom_target( +# 'man pages for exess', +# command: [sphinx_build, '-M', 'man', +# meson.current_build_dir(), meson.current_build_dir(), +# '-E', '-q', '-t', 'man'], +# input: [c_rst_files, c_exess_rst, c_index_xml], +# output: ['man/exess_base64.3'], +# build_by_default: true) + +subdir('man') diff --git a/subprojects/exess/doc/c/overview.rst b/subprojects/exess/doc/c/overview.rst new file mode 100644 index 00000000..1a2d3f6c --- /dev/null +++ b/subprojects/exess/doc/c/overview.rst @@ -0,0 +1,151 @@ +######## +Overview +######## + +.. default-domain:: c +.. highlight:: c + +The complete API is declared in ``exess.h``: + +.. code-block:: c + + #include <exess/exess.h> + +************** +Reading Values +************** + +Each supported type has a read function that takes a pointer to an output value, +and a string to read. +It reads the value after skipping any leading whitespace, +then returns an :struct:`ExessResult` with a ``status`` code and the ``count`` of characters read. +For example: + +.. code-block:: c + + int32_t value = 0; + ExessResult r = exess_read_int(&value, "1234"); + if (!r.status) { + fprintf(stderr, "Read %zu bytes as int %d\n", r.count, value); + } + +If there was a syntax error, +the status code indicates the specific problem. +If a value was read but didn't end at whitespace or the end of the string, +the status :enumerator:`EXESS_EXPECTED_END` is returned. +This indicates that there is trailing garbage in the string, +so the parse may not be complete or correct depending on the context. + + +************** +Writing Values +************** + +The corresponding write function takes a value to write, +a buffer size in bytes, and a buffer to write to. +It returns an :struct:`ExessResult`, +with a ``status`` code and the ``count`` of characters written, +not including the trailing null byte. + +For datatypes with a bounded length, +a constant like :var:`EXESS_MAX_INT_LENGTH` is the maximum length of the canonical representation of any value. +This can be used to allocate buffers statically or on the stack, +for example: + +.. code-block:: c + + char buf[EXESS_MAX_INT_LENGTH + 1] = {0}; + + ExessResult r = exess_write_int(1234, sizeof(buf), buf); + if (!r.status) { + printf("Write error: %s\n", exess_strerror(r.status)); + } + +****************** +Allocating Strings +****************** + +Exess doesn't do any allocation itself, +so the calling code is responsible for providing a large enough buffer for output. +The `count` returned by write functions can be used to determine the space required for a specific value. +If the write function is called with a null output buffer, +then this count is still returned as if a value were written. +This can be used to precisely allocate memory for the string, +taking care to allocate an extra byte for the null terminator. +For example: + +.. code-block:: c + + ExessResult r = exess_write_int(1234, 0, NULL); + char* str = (char*)calloc(r.count + 1, 1); + + r = exess_write_int(1234, r.count + 1, buf); + +Note that for some types, +this operation can be about as expensive as actually writing the value. +For example, it requires binary to decimal conversion for floating point numbers. +For ``float`` and ``double``, +since the length is bounded and relatively small, +it may be better to write immediately to a static buffer, +then copy the result to the final destination. + +******** +Variants +******** + +The fundamental read and write functions all have similar semantics, +but different type signatures since they use different value types. +:struct:`ExessVariant` is a tagged union that can hold any supported value, +allowing generic code to work with values of any type. + +Any value can be read with :func:`exess_read_variant` and written with :func:`exess_write_variant`, +which work similarly to the fundamental read and write functions, +except the read function takes an additional ``datatype`` parameter. +The expected datatype must be provided, +attempting to infer a datatype from the string content is not supported. + +Datatypes +========= + +:enum:`ExessDatatype` enumerates all of the supported variant datatypes. +The special value :enumerator:`EXESS_NOTHING` is used as a sentinel for unknown datatypes or other errors. + +If you have a datatype URI, then :func:`exess_datatype_from_uri()` can be used +to map it to a datatype. If the URI is not for a supported datatype, then it will return :enumerator:`EXESS_NOTHING`. + +Unbounded Numeric Types +======================= + +There are 6 unbounded numeric types: +decimal, integer, nonPositiveInteger, negativeInteger, nonNegativeInteger, and positiveInteger. +:struct:`ExessVariant` supports reading and writing these types, +but stores them in the largest corresponding native type: +``double``, ``int64_t``, or ``uint64_t``. +If the value doesn't fit in this type, +then :func:`exess_read_variant` will return an :enumerator:`EXESS_OUT_OF_RANGE` error. + +Writing Canonical Form +====================== + +Since values are always written in canonical form, +:struct:`ExessVariant` can be used as a generic mechanism to convert any string to canonical form: +simply read a value, +then write it. +If the value itself isn't required, +then :func:`exess_write_canonical` can be used to do this in a single step. +For example, this will print ``123``: + +.. code-block:: c + + char buf[4] = {0}; + + ExessResult r = exess_write_canonical(" +123", EXESS_INT, sizeof(buf), buf); + if (!r) { + printf("%s\n", buf); + } + +Note that it is better to use :func:`exess_write_canonical` if the value isn't required, +since it supports transforming some values outside the range of :struct:`ExessVariant`. +Specifically, +decimal and integer strings will be transformed directly, +avoiding conversion into values and the limits of the machine's numeric types. diff --git a/subprojects/exess/doc/c/xml/meson.build b/subprojects/exess/doc/c/xml/meson.build new file mode 100644 index 00000000..cfa726ed --- /dev/null +++ b/subprojects/exess/doc/c/xml/meson.build @@ -0,0 +1,12 @@ +config = configuration_data() +config.set('EXESS_SRCDIR', exess_src_root) +config.set('DOX_OUTPUT', meson.current_build_dir() / '..') + +c_doxyfile = configure_file(configuration: config, + input: '../Doxyfile.in', + output: 'Doxyfile') + +c_index_xml = custom_target('exess-c-index.xml', + command: [doxygen, '@INPUT0@'], + input: [c_doxyfile] + c_header_files, + output: 'index.xml') diff --git a/subprojects/exess/doc/conf.py.in b/subprojects/exess/doc/conf.py.in new file mode 100644 index 00000000..3eba5bc1 --- /dev/null +++ b/subprojects/exess/doc/conf.py.in @@ -0,0 +1,112 @@ +# Project information + +project = "Exess" +copyright = "2021, David Robillard" +author = "David Robillard" +release = "@EXESS_VERSION@" + +# General configuration + +exclude_patterns = ["xml"] +language = "en" +nitpicky = True +pygments_style = "friendly" + +# Ignore everything opaque or external for nitpicky mode +_opaque = [ + "int16_t", + "int32_t", + "int64_t", + "int8_t", + "size_t", + "uint16_t", + "uint32_t", + "uint64_t", + "uint8_t", +] + +_c_nitpick_ignore = map(lambda x: ("c:identifier", x), _opaque) +_cpp_nitpick_ignore = map(lambda x: ("cpp:identifier", x), _opaque) +nitpick_ignore = list(_c_nitpick_ignore) + list(_cpp_nitpick_ignore) + +# HTML output + +html_copy_source = False +html_short_title = "Exess" +html_theme = "sphinx_lv2_theme" + +if tags.has("singlehtml"): + html_sidebars = { + "**": [ + "globaltoc.html", + ] + } + + html_theme_options = { + "body_max_width": "48em", + "body_min_width": "48em", + "description": "A library for reading and writing XSD datatypes", + "show_footer_version": True, + "show_logo_version": False, + "logo_name": True, + "logo_width": "8em", + "nosidebar": False, + "page_width": "80em", + "sidebar_width": "18em", + "globaltoc_maxdepth": 3, + "globaltoc_collapse": False, + } + +else: + html_theme_options = { + "body_max_width": "60em", + "body_min_width": "40em", + "description": "A library for reading and writing XSD datatypes", + "show_footer_version": True, + "show_logo_version": False, + "logo_name": True, + "logo_width": "8em", + "nosidebar": True, + "page_width": "60em", + "sidebar_width": "14em", + "globaltoc_maxdepth": 1, + "globaltoc_collapse": True, + } + +# Man page output + +groups = { + "status": "Status", + # "numbers": "", + "decimal": "Decimal Strings", + "double": "Double Strings", + "float": "Float Strings", + "boolean": "Boolean Strings", + "long": "Long Strings", + "int": "Int Strings", + "short": "Short Strings", + "byte": "Byte Strings", + "ulong": "Unsigned Long Strings", + "uint": "Unsigned Int Strings", + "ushort": "Unsigned Short Strings", + "ubyte": "Unsigned Byte Strings", + # 'time_and_date': "", + "duration": "Duration Strings", + "datetime": "Datetime Strings", + "timezone": "Time zone strings", + "date": "Date strings", + "time": "Time strings", + "binary": "", + "hex": "Hex Binary Strings", + "base64": "Base64 Binary Strings", + "datatypes": "Datatypes", + "variant": "Value Variant", + # 'generics': "", + "coercion": "Value Type Coercion", +} + +author = "David Robillard <d@drobilla.net>" +man_pages = [] +for group, title in groups.items(): + name = "exess_" + group + man_pages += [("api/" + name, name, title, author, 3)] diff --git a/subprojects/exess/doc/cpp/Doxyfile.in b/subprojects/exess/doc/cpp/Doxyfile.in new file mode 100644 index 00000000..d254aa77 --- /dev/null +++ b/subprojects/exess/doc/cpp/Doxyfile.in @@ -0,0 +1,44 @@ +PROJECT_NAME = Exess +PROJECT_BRIEF = "A library for reading and writing XSD datatypes" + +QUIET = YES +WARN_AS_ERROR = YES +WARN_IF_UNDOCUMENTED = NO +WARN_NO_PARAMDOC = NO + +JAVADOC_AUTOBRIEF = YES + +CASE_SENSE_NAMES = YES +EXCLUDE_SYMBOLS = exess::detail +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_PRIVATE = NO +HIDE_IN_BODY_DOCS = YES +HIDE_UNDOC_CLASSES = YES +HIDE_UNDOC_MEMBERS = YES +REFERENCES_LINK_SOURCE = NO + +GENERATE_HTML = NO +GENERATE_LATEX = NO +GENERATE_XML = YES +XML_PROGRAMLISTING = NO +SHOW_FILES = NO + +ENABLE_PREPROCESSING = YES +SKIP_FUNCTION_MACROS = NO + +EXPAND_ONLY_PREDEF = YES +MACRO_EXPANSION = YES +PREDEFINED = EXESS_API \ + EXESS_CONST_API \ + EXESS_CONST_FUNC= \ + EXESS_NONNULL= \ + EXESS_NULLABLE= \ + EXESS_PURE_API \ + EXESS_PURE_FUNC= \ + +RECURSIVE = YES +STRIP_FROM_PATH = @EXESS_SRCDIR@ +INPUT = @EXESS_SRCDIR@/include \ + @EXESS_SRCDIR@/bindings/cpp/include + +OUTPUT_DIRECTORY = @DOX_OUTPUT@ diff --git a/subprojects/exess/doc/cpp/api/meson.build b/subprojects/exess/doc/cpp/api/meson.build new file mode 100644 index 00000000..6cdf4e04 --- /dev/null +++ b/subprojects/exess/doc/cpp/api/meson.build @@ -0,0 +1,5 @@ +cpp_exess_rst = custom_target( + 'Exess C++ API Sphinx Input', + command: [dox_to_sphinx, '-l', 'cpp', '-f', '@INPUT@', 'doc/cpp/api'], + input: cpp_index_xml, + output: 'exess.rst') diff --git a/subprojects/exess/doc/cpp/index.rst b/subprojects/exess/doc/cpp/index.rst new file mode 100644 index 00000000..a88d3007 --- /dev/null +++ b/subprojects/exess/doc/cpp/index.rst @@ -0,0 +1,11 @@ +##### +Exess +##### + +.. include:: summary.rst + +.. toctree:: + + overview + api/exesspp + api/exess diff --git a/subprojects/exess/doc/cpp/meson.build b/subprojects/exess/doc/cpp/meson.build new file mode 100644 index 00000000..27dc34c5 --- /dev/null +++ b/subprojects/exess/doc/cpp/meson.build @@ -0,0 +1,42 @@ +config = configuration_data() +config.set('EXESS_VERSION', meson.project_version()) + +conf_py = configure_file(configuration: config, + input: '../conf.py.in', + output: 'conf.py') + +configure_file(copy: true, input: '../summary.rst', output: 'summary.rst') + +cpp_rst_files = files( + 'index.rst', + 'overview.rst', +) + +foreach f : cpp_rst_files + configure_file(copy: true, input: f, output: '@PLAINNAME@') +endforeach + +subdir('xml') +subdir('api') + +docs = custom_target( + 'Exess C++ API Documentation (singlehtml)', + command: [sphinx_build, '-M', 'singlehtml', + meson.current_build_dir(), meson.current_build_dir(), + '-E', '-q', '-t', 'singlehtml'], + input: [cpp_rst_files, cpp_exess_rst, cpp_index_xml], + output: 'singlehtml', + build_by_default: true, + install: true, + install_dir: docdir / 'exessxx-0') + +docs = custom_target( + 'Exess C++ API Documentation (html)', + command: [sphinx_build, '-M', 'html', + meson.current_build_dir(), meson.current_build_dir(), + '-E', '-q', '-t', 'html'], + input: [cpp_rst_files, cpp_exess_rst, cpp_index_xml], + output: 'html', + build_by_default: true, + install: true, + install_dir: docdir / 'exessxx-0') diff --git a/subprojects/exess/doc/cpp/overview.rst b/subprojects/exess/doc/cpp/overview.rst new file mode 100644 index 00000000..3e59a953 --- /dev/null +++ b/subprojects/exess/doc/cpp/overview.rst @@ -0,0 +1,151 @@ +######## +Overview +######## + +.. default-domain:: cpp +.. highlight:: cpp +.. namespace:: exess + +The complete API is declared in ``exess.hpp``: + +.. code-block:: cpp + + #include <exess/exess.hpp> + +************** +Reading Values +************** + +Each supported type has a read function that takes a pointer to an output value, +and a string to read. +It reads the value after skipping any leading whitespace, +then returns an :struct:`ExessResult` with a ``status`` code and the ``count`` of characters read. +For example: + +.. code-block:: cpp + + int32_t value = 0; + ExessResult r = exess_read_int(&value, "1234"); + if (!r.status) { + fprintf(stderr, "Read %zu bytes as int %d\n", r.count, value); + } + +If there was a syntax error, +the status code indicates the specific problem. +If a value was read but didn't end at whitespace or the end of the string, +the status :enumerator:`EXESS_EXPECTED_END` is returned. +This indicates that there is trailing garbage in the string, +so the parse may not be complete or correct depending on the context. + +************** +Writing Values +************** + +The corresponding write function takes a value to write, +a buffer size in bytes, and a buffer to write to. +It returns an :struct:`ExessResult`, +with a ``status`` code and the ``count`` of characters written, +not including the trailing null byte. + +For datatypes with a bounded length, +the `constexpr` function template :func:`max_length` returns the maximum length of the canonical representation of any value. +This can be used to allocate buffers statically or on the stack, +for example: + +.. code-block:: cpp + + char buf[exess::max_length<int>() + 1] = {0}; + + exess::Result r = exess::write(1234, sizeof(buf), buf); + if (r.status != exess::Status::success) { + std::cerr << "Write error: " << exess::strerror(r.status) << "\n"; + } + +****************** +Allocating Strings +****************** + +Exess doesn't do any allocation itself, +so the calling code is responsible for providing a large enough buffer for output. +The `count` returned by write functions can be used to determine the space required for a specific value. +If the write function is called with a null output buffer, +then this count is still returned as if a value were written. +This can be used to precisely allocate memory for the string, +taking care to allocate an extra byte for the null terminator. +For example: + +.. code-block:: cpp + + exess::Result r = exess::write(1234, 0, NULL); + char* str = (char*)calloc(r.count + 1, 1); + + r = exess_write_int(1234, r.count + 1, buf); + +Note that for some types, +this operation can be about as expensive as actually writing the value. +For example, it requires binary to decimal conversion for floating point numbers. +For ``float`` and ``double``, +since the length is bounded and relatively small, +it may be better to write immediately to a static buffer, +then copy the result to the final destination. + +******** +Variants +******** + +The fundamental read and write functions all have similar semantics, +but different type signatures since they use different value types. +:struct:`ExessVariant` is a tagged union that can hold any supported value, +allowing generic code to work with values of any type. + +Any value can be read with :func:`exess_read_variant` and written with :func:`exess_write_variant`, +which work similarly to the fundamental read and write functions, +except the read function takes an additional ``datatype`` parameter. +The expected datatype must be provided, +attempting to infer a datatype from the string content is not supported. + +Datatypes +========= + +:enum:`ExessDatatype` enumerates all of the supported variant datatypes. +The special value :enumerator:`EXESS_NOTHING` is used as a sentinel for unknown datatypes or other errors. + +If you have a datatype URI, then :func:`exess_datatype_from_uri()` can be used +to map it to a datatype. If the URI is not for a supported datatype, then it will return :enumerator:`EXESS_NOTHING`. + +Unbounded Numeric Types +======================= + +There are 6 unbounded numeric types: +decimal, integer, nonPositiveInteger, negativeInteger, nonNegativeInteger, and positiveInteger. +:struct:`ExessVariant` supports reading and writing these types, +but stores them in the largest corresponding native type: +``double``, ``int64_t``, or ``uint64_t``. +If the value doesn't fit in this type, +then :func:`exess_read_variant` will return an :enumerator:`EXESS_OUT_OF_RANGE` error. + +Writing Canonical Form +====================== + +Since values are always written in canonical form, +:struct:`ExessVariant` can be used as a generic mechanism to convert any string to canonical form: +simply read a value, +then write it. +If the value itself isn't required, +then :func:`exess_write_canonical` can be used to do this in a single step. +For example, this will print ``123``: + +.. code-block:: cpp + + char buf[4] = {0}; + + ExessResult r = exess_write_canonical(" +123", EXESS_INT, sizeof(buf), buf); + if (!r) { + printf("%s\n", buf); + } + +Note that it is better to use :func:`exess_write_canonical` if the value isn't required, +since it supports transforming some values outside the range of :struct:`ExessVariant`. +Specifically, +decimal and integer strings will be transformed directly, +avoiding conversion into values and the limits of the machine's numeric types. diff --git a/subprojects/exess/doc/cpp/xml/meson.build b/subprojects/exess/doc/cpp/xml/meson.build new file mode 100644 index 00000000..ee529bca --- /dev/null +++ b/subprojects/exess/doc/cpp/xml/meson.build @@ -0,0 +1,14 @@ +config = configuration_data() +config.set('EXESS_SRCDIR', exess_src_root) +config.set('DOX_OUTPUT', meson.current_build_dir() / '..') + +cpp_doxyfile = configure_file(configuration: config, + input: '../Doxyfile.in', + output: 'Doxyfile') + +cpp_index_xml = custom_target( + 'exess-cpp-index.xml', + command: [doxygen, '@INPUT0@'], + input: [cpp_doxyfile] + c_header_files + cpp_header_files, + output: 'index.xml') + diff --git a/subprojects/exess/doc/meson.build b/subprojects/exess/doc/meson.build new file mode 100644 index 00000000..e69c4f05 --- /dev/null +++ b/subprojects/exess/doc/meson.build @@ -0,0 +1,17 @@ +docdir = get_option('datadir') / 'doc' + +doxygen = find_program('doxygen', required: get_option('docs')) +dox_to_sphinx = find_program('../scripts/dox_to_sphinx.py') +sphinx_build = find_program('sphinx-build', required: get_option('docs')) + +build_docs = doxygen.found() and sphinx_build.found() + +if build_docs + subdir('c') + subdir('cpp') +endif + +if meson.version().version_compare('>=0.53.0') + summary('Documentation', build_docs, bool_yn: true) +endif + diff --git a/subprojects/exess/doc/summary.rst b/subprojects/exess/doc/summary.rst new file mode 100644 index 00000000..7e4dd84f --- /dev/null +++ b/subprojects/exess/doc/summary.rst @@ -0,0 +1,3 @@ +Exess is a simple C library for reading and writing XSD_ datatypes. + +.. _XSD: https://www.w3.org/TR/xmlschema-2/ |