diff --git a/README.md b/README.md index 938e91e..720932e 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,8 @@ Mini-XML provides the following functionality: "leaf" nodes. - Functions for creating and managing trees of data. - "Find" and "walk" functions for easily locating and navigating trees of data. +- Support for custom string memory management functions to implement string + pools and other schemes for reducing memory usage. Mini-XML doesn't do validation or other types of processing on the data based upon schema files or other sources of definition information. diff --git a/doc/body.md b/doc/body.md index 79f02a6..44e8b4c 100644 --- a/doc/body.md +++ b/doc/body.md @@ -27,6 +27,8 @@ Mini-XML provides the following functionality: - Functions for creating and managing trees of data. - "Find" and "walk" functions for easily locating and navigating trees of data. +- Support for custom string memory management functions to implement string + pools and other schemes for reducing memory usage. Mini-XML doesn't do validation or other types of processing on the data based upon schema files or other sources of definition information. @@ -54,7 +56,7 @@ integrated Mini-XML into Gutenprint and removed libxml2. Thanks to lots of feedback and support from various developers, Mini-XML has evolved since then to provide a more complete XML implementation and now stands -at a whopping 3,875 lines of code, compared to 175,808 lines of code for libxml2 +at a whopping 3,491 lines of code, compared to 175,808 lines of code for libxml2 version 2.11.7. @@ -103,15 +105,80 @@ proper compiler and linker options for your installation: Loading an XML File ------------------- -You load an XML file using the [mxmlLoadFile](@@) function: +You load an XML file using the [mxmlLoadFilename](@@) function: ```c mxml_node_t * -mxmlLoadFilename(mxml_node_t *top, const char *filename, - mxml_load_cb_t load_cb, void *load_cbdata, - mxml_sax_cb_t sax_cb, void *sax_cbdata); +mxmlLoadFilename(mxml_node_t *top, mxml_options_t *options, + const char *filename); ``` +Mini-XML also provides functions to load from a `FILE` pointer, a file +descriptor, a string, or using a callback: + +```c +mxml_node_t * +mxmlLoadFd(mxml_node_t *top, mxml_options_t *options, + int fd); + +mxml_node_t * +mxmlLoadFile(mxml_node_t *top, mxml_options_t *options, + FILE *fp); + +mxml_node_t * +mxmlLoadIO(mxml_node_t *top, mxml_options_t *options, + mxml_io_cb_t io_cb, void *io_cbdata); + +mxml_node_t * +mxmlLoadString(mxml_node_t *top, mxml_options_t *options, + const char *s); +``` + +Each accepts a pointer to the top-most ("root") node (usually `NULL`) you want +to add the XML data to, any load options, and the content to be loaded. For +example, the following code will load an XML file called "example.xml" using the +default load options: + +```c +mxml_node_t *xml; + +xml = mxmlLoadFilename(/*top*/NULL, /*options*/NULL, "example.xml"); +``` + + +### Load Options + +Load options are specified using a `mxml_options_t` object, which you create +using the [mxmlOptionsNew](@@) function: + +```c +mxml_options_t *options = mxmlOptionsNew(); +``` + +The default load options will treat any values in your XML as whitespace- +delimited text (`MXML_TYPE_TEXT`). You can specify a different type of values +using the [mxmlOptionsSetTypeValue](@@) function. For example, the following +will specify that values are opaque text strings, including whitespace +(`MXML_TYPE_OPAQUE`): + +```c +mxmlOptionsSetTypeValue(options, MXML_TYPE_OPAQUE); +``` + +For more complex XML documents, you can specify a callback that returns the type +of value for a given element node using the [mxmlOptionsSetTypeCallback](@@) +function. For example, to specify a callback function called `my_type_cb` that +has no callback data: + +```c +mxmlOptionsSetTypeValue(options, my_type_cb, /*cbdata*/NULL); +``` + +The `my_type_cb` function accepts the callback data pointer (`NULL` in this +case) and the `mxml_node_t` pointer for the current element and returns a +`mxml_type_t` enumeration value specifying the value type for child nodes: + + The `load_cb` argument specifies a function that assigns child (value) node types for each element in the document. The default callback (`NULL`) supports passing a pointer to an `mxml_type_t` variable containing the type of value @@ -127,28 +194,6 @@ tree = mxmlLoadFilename(/*top*/NULL, "filename.xml", /*sax_cb*/NULL, /*sax_cbdata*/NULL); ``` -Mini-XML also provides functions to load from a `FILE` pointer, a file -descriptor, or string: - -```c -mxml_node_t * -mxmlLoadFd(mxml_node_t *top, int fd, - mxml_load_cb_t load_cb, void *load_cbdata, - mxml_sax_cb_t sax_cb, void *sax_cbdata); - -mxml_node_t * -mxmlLoadFile(mxml_node_t *top, FILE *fp, - mxml_load_cb_t load_cb, void *load_cbdata, - mxml_sax_cb_t sax_cb, void *sax_cbdata); - -mxml_node_t * -mxmlLoadString(mxml_node_t *top, const char *s, - mxml_load_cb_t load_cb, void *load_cbdata, - mxml_sax_cb_t sax_cb, void *sax_cbdata); -``` - - -### Load Callbacks The `load_xxx` arguments to the mxmlLoadXxx functions are a callback function and a data pointer which are used to determine the value type of each data node diff --git a/mxml-file.c b/mxml-file.c index 4bd1454..8afc14b 100644 --- a/mxml-file.c +++ b/mxml-file.c @@ -71,24 +71,13 @@ static int mxml_write_ws(mxml_node_t *node, mxml_options_t *options, mxml_io_cb // 'mxmlLoadFd()' - Load a file descriptor into an XML node tree. // // This function loads the file descriptor `fd` into an XML node tree. The -// nodes in the specified file are added to the specified node `top`. If `NULL` -// is provided, the XML file MUST be well-formed with a single parent processing -// instruction node like `` at the start of the file. +// nodes in the specified file are added to the specified node `top` - if `NULL` +// the XML file MUST be well-formed with a single parent processing instruction +// node like `` at the start of the file. // -// The load callback function `load_cb` is called to obtain the node type that -// should be used for child nodes. If `NULL`, the `load_cbdata` argument points -// to a `mmd_type_t` variable that specifies the value type or `MMD_TYPE_TEXT` -// if that argument is also `NULL`. -// -// The SAX callback function `sax_cb` and associated callback data `sax_cbdata` -// are used to enable the Simple API for XML streaming mode. The callback is -// called as the XML node tree is parsed. -// -// Note: The most common programming error when using the Mini-XML library is -// to load an XML file using the `MXML_TYPE_TEXT` node type, which returns -// inline text as a series of whitespace-delimited words, instead of using the -// `MXML_TYPE_OPAQUE` node type which returns the inline text as a single string -// (including whitespace). +// Load options are provides via the `options` argument. If `NULL`, all values +// will be loaded into `MXML_TYPE_TEXT` nodes. Use the @link mxmlOptionsNew@ +// function to create options when loading XML data. // mxml_node_t * // O - First node or `NULL` if the file could not be read. @@ -110,24 +99,13 @@ mxmlLoadFd( // 'mxmlLoadFile()' - Load a file into an XML node tree. // // This function loads the `FILE` pointer `fp` into an XML node tree. The -// nodes in the specified file are added to the specified node `top`. If `NULL` -// is provided, the XML file MUST be well-formed with a single parent processing -// instruction node like `` at the start of the file. +// nodes in the specified file are added to the specified node `top` - if `NULL` +// the XML file MUST be well-formed with a single parent processing instruction +// node like `` at the start of the file. // -// The load callback function `load_cb` is called to obtain the node type that -// should be used for child nodes. If `NULL`, the `load_cbdata` argument points -// to a `mmd_type_t` variable that specifies the value type or `MMD_TYPE_TEXT` -// if that argument is also `NULL`. -// -// The SAX callback function `sax_cb` and associated callback data `sax_cbdata` -// are used to enable the Simple API for XML streaming mode. The callback is -// called as the XML node tree is parsed. -// -// Note: The most common programming error when using the Mini-XML library is -// to load an XML file using the `MXML_TYPE_TEXT` node type, which returns -// inline text as a series of whitespace-delimited words, instead of using the -// `MXML_TYPE_OPAQUE` node type which returns the inline text as a single string -// (including whitespace). +// Load options are provides via the `options` argument. If `NULL`, all values +// will be loaded into `MXML_TYPE_TEXT` nodes. Use the @link mxmlOptionsNew@ +// function to create options when loading XML data. // mxml_node_t * // O - First node or `NULL` if the file could not be read. @@ -149,24 +127,13 @@ mxmlLoadFile( // 'mxmlLoadFilename()' - Load a file into an XML node tree. // // This function loads the named file `filename` into an XML node tree. The -// nodes in the specified file are added to the specified node `top`. If `NULL` -// is provided, the XML file MUST be well-formed with a single parent processing -// instruction node like `` at the start of the file. +// nodes in the specified file are added to the specified node `top` - if `NULL` +// the XML file MUST be well-formed with a single parent processing instruction +// node like `` at the start of the file. // -// The load callback function `load_cb` is called to obtain the node type that -// should be used for child nodes. If `NULL`, the `load_cbdata` argument points -// to a `mmd_type_t` variable that specifies the value type or `MMD_TYPE_TEXT` -// if that argument is also `NULL`. -// -// The SAX callback function `sax_cb` and associated callback data `sax_cbdata` -// are used to enable the Simple API for XML streaming mode. The callback is -// called as the XML node tree is parsed. -// -// Note: The most common programming error when using the Mini-XML library is -// to load an XML file using the `MXML_TYPE_TEXT` node type, which returns -// inline text as a series of whitespace-delimited words, instead of using the -// `MXML_TYPE_OPAQUE` node type which returns the inline text as a single string -// (including whitespace). +// Load options are provides via the `options` argument. If `NULL`, all values +// will be loaded into `MXML_TYPE_TEXT` nodes. Use the @link mxmlOptionsNew@ +// function to create options when loading XML data. // mxml_node_t * // O - First node or `NULL` if the file could not be read. @@ -201,9 +168,13 @@ mxmlLoadFilename( // 'mxmlLoadIO()' - Load an XML node tree using a read callback. // // This function loads data into an XML node tree using a read callback. The -// nodes in the specified file are added to the specified node `top`. If `NULL` -// is provided, the XML file MUST be well-formed with a single parent processing -// instruction node like `` at the start of the file. +// nodes in the specified file are added to the specified node `top` - if `NULL` +// the XML file MUST be well-formed with a single parent processing instruction +// node like `` at the start of the file. +// +// Load options are provides via the `options` argument. If `NULL`, all values +// will be loaded into `MXML_TYPE_TEXT` nodes. Use the @link mxmlOptionsNew@ +// function to create options when loading XML data. // // The read callback function `io_cb` is called to read a number of bytes from // the source. The callback data pointer `io_cbdata` is passed to the read @@ -218,21 +189,6 @@ mxmlLoadFilename( // } // ``` // -// The load callback function `load_cb` is called to obtain the node type that -// should be used for child nodes. If `NULL`, the `load_cbdata` argument points -// to a `mmd_type_t` variable that specifies the value type or `MMD_TYPE_TEXT` -// if that argument is also `NULL`. -// -// The SAX callback function `sax_cb` and associated callback data `sax_cbdata` -// are used to enable the Simple API for XML streaming mode. The callback is -// called as the XML node tree is parsed. -// -// Note: The most common programming error when using the Mini-XML library is -// to load an XML file using the `MXML_TYPE_TEXT` node type, which returns -// inline text as a series of whitespace-delimited words, instead of using the -// `MXML_TYPE_OPAQUE` node type which returns the inline text as a single string -// (including whitespace). -// mxml_node_t * // O - First node or `NULL` if the file could not be read. mxmlLoadIO( @@ -254,24 +210,13 @@ mxmlLoadIO( // 'mxmlLoadString()' - Load a string into an XML node tree. // // This function loads the string into an XML node tree. The nodes in the -// specified file are added to the specified node `top`. If `NULL` is provided, -// the XML file MUST be well-formed with a single parent processing instruction -// node like `` at the start of the file. +// specified file are added to the specified node `top` - if `NULL` the XML file +// MUST be well-formed with a single parent processing instruction node like +// `` at the start of the file. // -// The load callback function `load_cb` is called to obtain the node type that -// should be used for child nodes. If `NULL`, the `load_cbdata` argument points -// to a `mmd_type_t` variable that specifies the value type or `MMD_TYPE_TEXT` -// if that argument is also `NULL`. -// -// The SAX callback function `sax_cb` and associated callback data `sax_cbdata` -// are used to enable the Simple API for XML streaming mode. The callback is -// called as the XML node tree is parsed. -// -// Note: The most common programming error when using the Mini-XML library is -// to load an XML file using the `MXML_TYPE_TEXT` node type, which returns -// inline text as a series of whitespace-delimited words, instead of using the -// `MXML_TYPE_OPAQUE` node type which returns the inline text as a single string -// (including whitespace). +// Load options are provides via the `options` argument. If `NULL`, all values +// will be loaded into `MXML_TYPE_TEXT` nodes. Use the @link mxmlOptionsNew@ +// function to create options when loading XML data. // mxml_node_t * // O - First node or `NULL` if the string has errors. @@ -308,21 +253,9 @@ mxmlLoadString( // `NULL` is returned if the node would produce an empty string or if the string // cannot be allocated. // -// The callback function `save_cb` specifies a function that returns a -// whitespace string or `NULL` before and after each element. The function -// receives the callback data pointer `save_cbdata`, the `mxml_node_t` pointer, -// and a "when" value indicating where the whitespace is being added, for -// example: -// -// ```c -// const char *my_save_cb(void *cbdata, mxml_node_t *node, mxml_ws_t when) -// { -// if (when == MXML_WS_BEFORE_OPEN || when == MXML_WS_AFTER_CLOSE) -// return ("\n"); -// else -// return (NULL); -// } -// ``` +// Save options are provides via the `options` argument. If `NULL`, the XML +// output will be wrapped at column 72 with no additional whitespace. Use the +// @link mxmlOptionsNew@ function to create options for saving XML data. // char * // O - Allocated string or `NULL` @@ -361,21 +294,9 @@ mxmlSaveAllocString( // // This function saves the XML tree `node` to a file descriptor. // -// The callback function `save_cb` specifies a function that returns a -// whitespace string or `NULL` before and after each element. The function -// receives the callback data pointer `save_cbdata`, the `mxml_node_t` pointer, -// and a "when" value indicating where the whitespace is being added, for -// example: -// -// ```c -// const char *my_save_cb(void *cbdata, mxml_node_t *node, mxml_ws_t when) -// { -// if (when == MXML_WS_BEFORE_OPEN || when == MXML_WS_AFTER_CLOSE) -// return ("\n"); -// else -// return (NULL); -// } -// ``` +// Save options are provides via the `options` argument. If `NULL`, the XML +// output will be wrapped at column 72 with no additional whitespace. Use the +// @link mxmlOptionsNew@ function to create options for saving XML data. // bool // O - `true` on success, `false` on error. @@ -406,21 +327,9 @@ mxmlSaveFd(mxml_node_t *node, // I - Node to write // // This function saves the XML tree `node` to a stdio `FILE`. // -// The callback function `save_cb` specifies a function that returns a -// whitespace string or `NULL` before and after each element. The function -// receives the callback data pointer `save_cbdata`, the `mxml_node_t` pointer, -// and a "when" value indicating where the whitespace is being added, for -// example: -// -// ```c -// const char *my_save_cb(void *cbdata, mxml_node_t *node, mxml_ws_t when) -// { -// if (when == MXML_WS_BEFORE_OPEN || when == MXML_WS_AFTER_CLOSE) -// return ("\n"); -// else -// return (NULL); -// } -// ``` +// Save options are provides via the `options` argument. If `NULL`, the XML +// output will be wrapped at column 72 with no additional whitespace. Use the +// @link mxmlOptionsNew@ function to create options for saving XML data. // bool // O - `true` on success, `false` on error. @@ -452,21 +361,9 @@ mxmlSaveFile( // // This function saves the XML tree `node` to a named file. // -// The callback function `save_cb` specifies a function that returns a -// whitespace string or `NULL` before and after each element. The function -// receives the callback data pointer `save_cbdata`, the `mxml_node_t` pointer, -// and a "when" value indicating where the whitespace is being added, for -// example: -// -// ```c -// const char *my_save_cb(void *cbdata, mxml_node_t *node, mxml_ws_t when) -// { -// if (when == MXML_WS_BEFORE_OPEN || when == MXML_WS_AFTER_CLOSE) -// return ("\n"); -// else -// return (NULL); -// } -// ``` +// Save options are provides via the `options` argument. If `NULL`, the XML +// output will be wrapped at column 72 with no additional whitespace. Use the +// @link mxmlOptionsNew@ function to create options for saving XML data. // bool // O - `true` on success, `false` on error. @@ -518,21 +415,9 @@ mxmlSaveFilename( // } // ``` // -// The callback function `save_cb` specifies a function that returns a -// whitespace string or `NULL` before and after each element. The function -// receives the callback data pointer `save_cbdata`, the `mxml_node_t` pointer, -// and a "when" value indicating where the whitespace is being added, for -// example: -// -// ```c -// const char *my_save_cb(void *cbdata, mxml_node_t *node, mxml_ws_t when) -// { -// if (when == MXML_WS_BEFORE_OPEN || when == MXML_WS_AFTER_CLOSE) -// return ("\n"); -// else -// return (NULL); -// } -// ``` +// Save options are provides via the `options` argument. If `NULL`, the XML +// output will be wrapped at column 72 with no additional whitespace. Use the +// @link mxmlOptionsNew@ function to create options for saving XML data. // bool // O - `true` on success, `false` on error. @@ -567,23 +452,11 @@ mxmlSaveIO( // // 'mxmlSaveString()' - Save an XML node tree to a string. // -// This function saves the XML tree `node` to a string buffer. +// This function saves the XML tree `node` to a fixed-size string buffer. // -// The callback function `save_cb` specifies a function that returns a -// whitespace string or `NULL` before and after each element. The function -// receives the callback data pointer `save_cbdata`, the `mxml_node_t` pointer, -// and a "when" value indicating where the whitespace is being added, for -// example: -// -// ```c -// const char *my_save_cb(void *cbdata, mxml_node_t *node, mxml_ws_t when) -// { -// if (when == MXML_WS_BEFORE_OPEN || when == MXML_WS_AFTER_CLOSE) -// return ("\n"); -// else -// return (NULL); -// } -// ``` +// Save options are provides via the `options` argument. If `NULL`, the XML +// output will be wrapped at column 72 with no additional whitespace. Use the +// @link mxmlOptionsNew@ function to create options for saving XML data. // size_t // O - Size of string diff --git a/mxml-options.c b/mxml-options.c index e6b2ac5..1f521c2 100644 --- a/mxml-options.c +++ b/mxml-options.c @@ -27,6 +27,32 @@ mxmlOptionsDelete( // // 'mxmlOptionsNew()' - Allocate load/save options. // +// This function creates a new set of load/save options to use with the +// @link mxmlLoadFd@, @link mxmlLoadFile@, @link mxmlLoadFilename@, +// @link mxmlLoadIO@, @link mxmlLoadString@, @link mxmlSaveAllocString@, +// @link mxmlSaveFd@, @link mxmlSaveFile@, @link mxmlSaveFilename@, +// @link mxmlSaveIO@, and @link mxmlSaveString@ functions. Options can be +// reused for multiple calls to these functions and should be freed using the +// @link mxmlOptionsDelete@ function. +// +// The default load/save options load values using the constant type +// `MXML_TYPE_TEXT` and save XML data with a wrap margin of 72 columns. +// The various `mxmlOptionsSet` functions are used to change the defaults, +// for example: +// +// ```c +// mxml_options_t *options = mxmlOptionsNew(); +// +// /* Load values as opaque strings */ +// mxmlOptionsSetTypeValue(options, MXML_TYPE_OPAQUE); +// ``` +// +// Note: The most common programming error when using the Mini-XML library is +// to load an XML file using the `MXML_TYPE_TEXT` node type, which returns +// inline text as a series of whitespace-delimited words, instead of using the +// `MXML_TYPE_OPAQUE` node type which returns the inline text as a single string +// (including whitespace). +// mxml_options_t * // O - Options mxmlOptionsNew(void) @@ -184,8 +210,8 @@ mxmlOptionsSetCustomCallbacks( // } // ``` // -// Mini-XML supports the "amp", "gt", "lt", and "quot" character entities, which -// are required by the base XML specification. +// Mini-XML automatically supports the "amp", "gt", "lt", and "quot" character +// entities which are required by the base XML specification. // void