From 251722d499cc2ec0962580f6cf60ed0acdc5330e Mon Sep 17 00:00:00 2001 From: Petri Lehtinen Date: Sun, 2 Aug 2009 21:26:37 +0300 Subject: [PATCH] Add README and API reference --- .gitignore | 1 + Makefile.am | 2 +- README.rst | 63 +++++++ configure.ac | 1 + doc/.gitignore | 1 + doc/Makefile.am | 4 + doc/README | 5 + doc/apiref.rst | 442 +++++++++++++++++++++++++++++++++++++++++++++++++ doc/conf.py | 191 +++++++++++++++++++++ doc/ext/refcounting.py | 59 +++++++ doc/index.rst | 20 +++ 11 files changed, 788 insertions(+), 1 deletion(-) create mode 100644 README.rst create mode 100644 doc/.gitignore create mode 100644 doc/Makefile.am create mode 100644 doc/README create mode 100644 doc/apiref.rst create mode 100644 doc/conf.py create mode 100644 doc/ext/refcounting.py create mode 100644 doc/index.rst diff --git a/.gitignore b/.gitignore index 5efe6ed..0d4df9e 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ missing *.lo *.la stamp-h1 +*.pyc diff --git a/Makefile.am b/Makefile.am index b4b5bc3..81cad53 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1 +1 @@ -SUBDIRS = src test +SUBDIRS = doc src test diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..66243eb --- /dev/null +++ b/README.rst @@ -0,0 +1,63 @@ +Jansson README +============== + +Jansson_ is a C library for encoding, decoding and manipulating JSON +data. Its main features and design principles are: + +- Simple and intuitive API and data model + +- Good documentation + +- Full Unicode support (UTF-8) + +- Extensive test suite + +- No dependencies on other libraries + +Jansson is licensed under the `MIT license`_; see LICENSE in the +source distribution for details. + + +Compilation and Installation +---------------------------- + +If you obtained a source tarball, just use the standard autotools +commands:: + + $ ./configure && make && make install + +If the source has been checked out from a Git repository, the +./configure script has to be generated fist. The easiest way is to use +autoreconf:: + + $ autoreconf -i + +To run the test suite, invoke:: + + $ make check + +Python_ is required to run the tests. + + +Documentation +------------- + +Documentation is in the ``doc/`` subdirectory. It's written in +reStructuredText_ with Sphinx_ annotations, so reading it in plain may +be inconvenient. For this reason, prebuilt HTML documentation is +available at http://www.digip.org/jansson/doc/. + +To generate HTML documentation yourself, invoke:: + + cd doc/ + sphinx-build . .build/html + +... and point your browser to ``.build/html/index.html``. Sphinx_ is +required to generate the documentation. + + +.. _Jansson: http://www.digip.org/jansson/ +.. _`MIT license`: http://www.opensource.org/licenses/mit-license.php +.. _Python: http://www.python.org/ +.. _reStructuredText: http://docutils.sourceforge.net/rst.html +.. _Sphinx: http://sphinx.pocoo.org/ diff --git a/configure.ac b/configure.ac index 5d9200c..c0a095e 100644 --- a/configure.ac +++ b/configure.ac @@ -20,6 +20,7 @@ AC_PROG_LIBTOOL AC_CONFIG_FILES([ Makefile + doc/Makefile src/Makefile test/Makefile ]) diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 0000000..30bcfa4 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1 @@ +.build/ diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..49c98c9 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,4 @@ +EXTRA_DIST = conf.py apiref.rst index.rst + +clean-local: + rm -rf .build diff --git a/doc/README b/doc/README new file mode 100644 index 0000000..3b10d2a --- /dev/null +++ b/doc/README @@ -0,0 +1,5 @@ +To build the documentation, invoke + + sphinx-build . .build/html + +in this directory. Then point your browser to .build/html/index.html. diff --git a/doc/apiref.rst b/doc/apiref.rst new file mode 100644 index 0000000..903b48c --- /dev/null +++ b/doc/apiref.rst @@ -0,0 +1,442 @@ +************* +API Reference +************* + +.. highlight:: c + +Preliminaries +============= + +All declarations are in :file:`jansson.h`, so it's enough to + +:: + + #include + +in each source file. + +All constants are prefixed ``JSON_`` and other identifiers with +``json_``. Type names are suffixed with ``_t`` and ``typedef``\ 'd so +that the ``struct`` keyword need not be used. + + +Value Representation +==================== + +The JSON specification (:rfc:`4627`) defines the following data types: +*object*, *array*, *string*, *number*, *boolean*, and *null*. JSON +types are used dynamically; arrays and objects can hold any other data +type, including themselves. For this reason, Jansson's type system is +also dynamic in nature. There's one C type to represent all JSON +values, and this structure knows the type of the JSON value it holds. + +.. ctype:: json_t + + This data structure is used throughout the library to represent all + JSON values. It always contains the type of the JSON value it holds + and the value's reference count. The rest depends on the type of the + value. + +Objects of :ctype:`json_t` are always used through a pointer. There +are APIs for querying the type, manipulating the reference count, and +for constructing and manipulating values of different types. + + +Type +---- + +The type of a JSON value is queried and tested using the following +functions: + +.. ctype:: enum json_type + + The type of a JSON value. The following members are defined: + + +-------------------------+ + | :const:`JSON_OBJECT` | + +-------------------------+ + | :const:`JSON_ARRAY` | + +-------------------------+ + | :const:`JSON_STRING` | + +-------------------------+ + | :const:`JSON_INTEGER` | + +-------------------------+ + | :const:`JSON_REAL` | + +-------------------------+ + | :const:`JSON_TRUE` | + +-------------------------+ + | :const:`JSON_FALSE` | + +-------------------------+ + | :const:`JSON_NULL` | + +-------------------------+ + + These correspond to JSON object, array, string, number, boolean and + null. A number is represented by either a value of the type + :const:`JSON_INTEGER` or of the type :const:`JSON_REAL`. A true + boolean value is represented by a value of the type + :const:`JSON_TRUE` and false by a value of the type + :const:`JSON_FALSE`. + +.. cfunction:: int json_typeof(const json_t *json) + + Return the type of the JSON value (a :ctype:`json_type` cast to + :ctype:`int`). This function is actually implemented as a macro for + speed. + +.. cfunction:: json_is_object(const json_t *json) + json_is_array(const json_t *json) + json_is_string(const json_t *json) + json_is_integer(const json_t *json) + json_is_real(const json_t *json) + json_is_true(const json_t *json) + json_is_false(const json_t *json) + json_is_null(const json_t *json) + + These functions (actually macros) return true (non-zero) for values + of the given type, and false (zero) for values of other types. + +.. cfunction:: json_is_number(const json_t *json) + + Returns true for values of types :const:`JSON_INTEGER` and + :const:`JSON_REAL`, and false for other types. + +.. cfunction:: json_is_boolean(const json_t *json) + + Returns true for types :const:`JSON_TRUE` and :const:`JSON_FALSE`, + and false for values of other types. + + +Reference Count +--------------- + +The reference count is used to track whether a value is still in use +or not. When a value is created, it's reference count is set to 1. If +a reference to a value is kept (e.g. a value is stored somewhere for +later use), its reference count is incremented, and when the value is +no longer needed, the reference count is decremented. When the +reference count drops to zero, there are no references left, and the +value can be destroyed. + +The following functions are used to manipulate the reference count. + +.. cfunction:: json_t *json_incref(json_t *json) + + Increment the reference count of *json*. + +.. cfunction:: void json_decref(json_t *json) + + Decrement the reference count of *json*. As soon as a call to + :cfunc:`json_decref()` drops the reference count to zero, the value + is destroyed and it can no longer be used. + +Functions creating new JSON values set the reference count to 1. These +functions are said to return a **new reference**. Other functions +returning (existing) JSON values do not normally increase the +reference count. These functions are said to return a **borrowed +reference**. So, if the user will hold a reference to a value returned +as a borrowed reference, he must call :cfunc:`json_incref`. As soon as +the value is no longer needed, :cfunc:`json_decref` should be called +to release the reference. + +Normally, all functions accepting a JSON value as an argument will +manage the reference, i.e. increase and decrease the reference count +as needed. However, some functions **steal** the reference, i.e. they +have the same result as if the user called :cfunc:`json_decref()` on +the argument right after calling the function. These are usually +convenience functions for adding new references to containers and not +to worry about the reference count. + +In the following sections it is clearly documented whether a function +will return a new or borrowed reference or steal a reference to its +argument. + + +True, False and Null +==================== + +.. cfunction:: json_t *json_true(void) + + .. refcounting:: new + + Returns a value of the type :const:`JSON_TRUE`, or *NULL* on + error. + +.. cfunction:: json_t *json_false(void) + + .. refcounting:: new + + Returns a value of the type :const:`JSON_FALSE`, or *NULL* on + error. + +.. cfunction:: json_t *json_null(void) + + .. refcounting:: new + + Returns a value of the type :const:`JSON_NULL`, or *NULL* on + error. + + +String +====== + +.. cfunction:: json_t *json_string(const char *value) + + .. refcounting:: new + + Returns a new value of the type :const:`JSON_STRING`, or *NULL* on + error. *value* must be a valid UTF-8 encoded Unicode string. + +.. cfunction:: const char *json_string_value(const json_t *json) + + Returns the associated value of a :const:`JSON_STRING` value as a + null terminated UTF-8 encoded string. + + +Number +====== + +.. cfunction:: json_t *json_integer(int value) + + .. refcounting:: new + + Returns a new value of the type :const:`JSON_INTEGER`, or *NULL* on + error. + +.. cfunction:: int json_integer_value(const json_t *json) + + Returns the associated integer value of values of the type + :const:`JSON_INTEGER`, or 0 for values of other types. + +.. cfunction:: json_t *json_real(double value) + + .. refcounting:: new + + Returns a new value of the type :const:`JSON_REAL`, or *NULL* on + error. + +.. cfunction:: double json_real_value(const json_t *json) + + Returns the associated real value of values of the type + :const:`JSON_INTEGER`, or 0 for values of other types. + +In addition to the functions above, there's a common query function +for integers and reals: + +.. cfunction:: double json_number_value(const json_t *json) + + Returns the value of either ``JSON_INTEGER`` or ``JSON_REAL``, cast + to double regardless of the actual type. + + +Array +===== + +A JSON array is an ordered collection of other JSON values. + +.. cfunction:: json_t *json_array(void) + + .. refcounting:: new + + Returns a new value of the type :const:`JSON_ARRAY`, or *NULL* on + error. Initially, the array is empty. + +.. cfunction:: unsigned int json_array_size(const json_t *array) + + Returns the number of elements in *array*. + +.. cfunction:: json_t *json_array_get(const json_t *array, unsigned int index) + + .. refcounting:: borrow + + Returns the element in *array* at position *index*, or *NULL* if + *index* is out of range. The valid range for *index* is from 0 to + the return value of :cfunc:`json_array_size()` minus 1. + +.. cfunction:: int json_array_set(json_t *array, unsigned int index, json_t *value) + + Replaces the element in *array* at position *index* with *value*. + Returns 0 on success, or -1 if *index* is out of range. The valid + range for *index* is from 0 to the return value of + :cfunc:`json_array_size()` minus 1. + +.. cfunction:: int json_array_append(json_t *array, json_t *value) + + Appends *value* to the end of *array*, growing the size of *array* + by 1. Returns 0 on success and -1 on error. + + +Object +====== + +A JSON object is a dictionary of key-value pairs, where the key is a +Unicode string and the value is any JSON value. + +.. cfunction:: json_t *json_object(void) + + .. refcounting:: new + + Returns a new value of the type :const:`JSON_OBJECT`, or *NULL* on + error. Initially, the object is empty. + +.. cfunction:: json_t *json_object_get(const json_t *object, const char *key) + + .. refcounting:: borrow + + Get a value corresponding to *key* from *object*. Returns *NULL* if + *key* is not found and on error. + +.. cfunction:: int json_object_set(json_t *object, const char *key, json_t *value) + + Set the value of *key* to *value* in *object*. *key* must be a + valid terminated UTF-8 encoded Unicode string. If there already is + a value for *key*, it is replaced by the new value. Returns 0 on + success and -1 on error. + +.. cfunction:: int json_object_del(json_t *object, const char *key) + + Delete *key* from *object* if it exists. Returns 0 on success, or + -1 if *key* was not found. + + +The following functions implement an iteration protocol for objects: + +.. cfunction:: void *json_object_iter(json_t *object) + + Returns an opaque iterator which can be used to iterate over all + key-value pairs in *object*, or *NULL* if *object* is empty. + +.. cfunction:: void *json_object_iter_next(json_t *object, void *iter) + + Returns an iterator pointing to the next key-value pair in *object* + after *iter*, or *NULL* if the whole object has been iterated + through. + +.. cfunction:: const char *json_object_iter_key(void *iter) + + Extract the associated key from *iter*. + +.. cfunction:: json_t *json_object_iter_value(void *iter) + + .. refcounting:: borrow + + Extract the associated value from *iter*. + + +Encoding +======== + +This sections describes the functions that can be used to encode +values to JSON. Only objects and arrays can be encoded, since they are +the only valid "root" values of a JSON text. + +Each function takes a *flags* parameter that controls some aspects of +how the data is encoded. Its default value is 0. The following macros +can be ORed together to obtain *flags*. + +``JSON_INDENT(n)`` + Pretty-print the result, indenting arrays and objects by *n* + spaces. The valid range for *n* is between 0 and 255, other values + result in an undefined output. If ``JSON_INDENT`` is not used or + *n* is 0, no pretty-printing is done and the result is a compact + representation. + +The following functions perform the actual JSON encoding. The result +is in UTF-8. + +.. cfunction:: char *json_dumps(const json_t *root, uint32_t flags) + + Returns the JSON representation of *root* as a string, or *NULL* on + error. *flags* is described above. The return value must be freed + by the caller using :cfunc:`free()`. + +.. cfunction:: int json_dumpf(const json_t *root, FILE *output, uint32_t flags) + + Write the JSON representation of *root* to the stream *output*. + *flags* is described above. Returns 0 on success and -1 on error. + +.. cfunction:: int json_dump_file(const json_t *json, const char *path, uint32_t flags) + + Write the JSON representation of *root* to the file *path*. If + *path* already exists, it is overwritten. *flags* is described + above. Returns 0 on success and -1 on error. + + +Decoding +======== + +This sections describes the functions that can be used to decode JSON +text to the Jansson representation of JSON data. The JSON +specification requires that a JSON text is either a serialized array +or object, and this requirement is also enforced with the following +functions. + +The only supported character encoding is UTF-8 (which ASCII is a +subset of). + +.. ctype:: json_error_t + + This data structure is used to return information on decoding + errors from the decoding functions. Its definition is repeated + here:: + + #define JSON_ERROR_TEXT_LENGTH 160 + + typedef struct { + char text[JSON_ERROR_TEXT_LENGTH]; + int line; + } json_error_t; + + *line* is the line number on which the error occurred, or -1 if + this information is not available. *text* contains the error + message (in UTF-8), or an empty string if a message is not + available. + + The normal usef of :ctype:`json_error_t` is to allocate it normally + on the stack, and pass a pointer to a decoding function. Example:: + + int main() { + json_t *json; + json_error_t error; + + json = json_load_file("/path/to/file.json", &error); + if(!json) { + /* the error variable contains error information */ + } + ... + } + + Also note that if the decoding succeeded (``json != NULL`` in the + above example), the contents of ``error`` are unspecified. + + All decoding functions also accept *NULL* as the + :ctype:`json_error_t` pointer, in which case no error information + is returned to the caller. + +The following functions perform the actual JSON decoding. + +.. cfunction:: json_t *json_loads(const char *input, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON string *input* and returns the array or object it + contains, or *NULL* on error, in which case *error* is filled with + information about the error. See above for discussion on the + *error* parameter. + +.. cfunction:: json_t *json_loadf(FILE *input, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON text in stream *input* and returns the array or + object it contains, or *NULL* on error, in which case *error* is + filled with information about the error. See above for discussion + on the *error* parameter. + +.. cfunction:: json_t *json_load_file(const char *path, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON text in file *path* and returns the array or + object it contains, or *NULL* on error, in which case *error* is + filled with information about the error. See above for discussion + on the *error* parameter. diff --git a/doc/conf.py b/doc/conf.py new file mode 100644 index 0000000..05fa5eb --- /dev/null +++ b/doc/conf.py @@ -0,0 +1,191 @@ +# -*- coding: utf-8 -*- +# +# Jansson documentation build configuration file, created by +# sphinx-quickstart on Thu Jul 30 11:35:32 2009. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# The contents of this file are pickled, so don't put values in the namespace +# that aren't pickleable (module imports are okay, they're removed automatically). +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os +sys.path.insert(0, os.path.abspath('ext')) + +# If your extensions (or modules documented by autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.append(os.path.abspath('.')) + +# General configuration +# --------------------- + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['refcounting'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = [] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Jansson' +copyright = u'2009, Petri Lehtinen' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0+' +# The full version, including alpha/beta/rc tags. +release = '0+' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of documents that shouldn't be included in the build. +#unused_docs = [] + +# List of directories, relative to source directory, that shouldn't be searched +# for source files. +exclude_trees = ['.build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + + +# Options for HTML output +# ----------------------- + +# The style sheet to use for HTML and HTML Help pages. A file of that name +# must exist either in Sphinx' static/ path, or in one of the custom paths +# given in html_static_path. +html_style = 'default.css' + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_use_modindex = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, the reST sources are included in the HTML build as _sources/. +#html_copy_source = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = '' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Janssondoc' + + +# Options for LaTeX output +# ------------------------ + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, document class [howto/manual]). +latex_documents = [ + ('index', 'Jansson.tex', ur'Jansson Documentation', + ur'Petri Lehtinen', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_use_modindex = True diff --git a/doc/ext/refcounting.py b/doc/ext/refcounting.py new file mode 100644 index 0000000..506b2ee --- /dev/null +++ b/doc/ext/refcounting.py @@ -0,0 +1,59 @@ +""" + refcounting + ~~~~~~~~~~~ + + Reference count annotations for C API functions. Has the same + result as the sphinx.ext.refcounting extension but works for all + functions regardless of the signature, and the reference counting + information is written inline with the documentation instead of a + separate file. + + Adds a new directive "refcounting". The directive has no content + and one required positional parameter:: "new" or "borrow". + + Example: + + .. cfunction:: json_t *json_object(void) + + .. refcounting:: new + + + + :copyright: Copyright 2009 Petri Lehtinen + :license: MIT, see LICENSE for details. +""" + +from docutils import nodes + +class refcounting(nodes.emphasis): pass + +def visit(self, node): + self.visit_emphasis(node) + +def depart(self, node): + self.depart_emphasis(node) + +def html_visit(self, node): + self.body.append(self.starttag(node, 'em', '', CLASS='refcount')) + +def html_depart(self, node): + self.body.append('') + + +def refcounting_directive(name, arguments, options, content, lineno, + content_offset, block_text, state, state_machine): + if arguments[0] == 'borrow': + text = 'Return value: Borrowed reference.' + elif arguments[0] == 'new': + text = 'Return value: New reference.' + else: + raise Error('Valid arguments: new, borrow') + + return [refcounting(text, text)] + +def setup(app): + app.add_node(refcounting, + html=(html_visit, html_depart), + latex=(visit, depart), + text=(visit, depart)) + app.add_directive('refcounting', refcounting_directive, 0, (1, 0, 0)) diff --git a/doc/index.rst b/doc/index.rst new file mode 100644 index 0000000..d36760f --- /dev/null +++ b/doc/index.rst @@ -0,0 +1,20 @@ +Overview +======== + +This is the documentation for Jansson_ |release|, last updated |today|. + +.. _Jansson: http://www.digip.org/jansson/ + +**Contents:** + +.. toctree:: + :maxdepth: 2 + + apiref + + +Indices and Tables +================== + +* :ref:`genindex` +* :ref:`search` -- 2.1.4