diff options
author | unknown <unknown@unknown> | 2009-10-23 04:29:39 +0000 |
---|---|---|
committer | unknown <unknown@unknown> | 2009-10-23 04:29:39 +0000 |
commit | ddf5c42f67757000d6ec7686b92a667c2a252dca (patch) | |
tree | e070b352fab4b285b7a4ea547d0cbfff9b7fb4d1 /doc/iksemel.texi | |
download | iksemel-ddf5c42f67757000d6ec7686b92a667c2a252dca.tar.gz iksemel-ddf5c42f67757000d6ec7686b92a667c2a252dca.tar.xz iksemel-ddf5c42f67757000d6ec7686b92a667c2a252dca.zip |
Imported from iksemel-1.3.tar.gz.
Diffstat (limited to 'doc/iksemel.texi')
-rw-r--r-- | doc/iksemel.texi | 1534 |
1 files changed, 1534 insertions, 0 deletions
diff --git a/doc/iksemel.texi b/doc/iksemel.texi new file mode 100644 index 0000000..fd683e2 --- /dev/null +++ b/doc/iksemel.texi @@ -0,0 +1,1534 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename iksemel +@setcontentsaftertitlepage +@settitle Iksemel Programmers Manual +@set VERSION 1.2 +@c %**end of header + +@titlepage +@title iksemel programmers manual +@subtitle A tutorial and API reference for the iksemel library @value{VERSION} +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 2001-2003 G@"urer @"Ozen + +This is a free document; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2, or +(at your option) any later version.You may obtain a copy of the +GNU General Public License from the Free Software Foundation +by visiting their Web site or by writing to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. + +@end titlepage + +@ifinfo +@node Top, , , (dir) +@top iksemel Programmers Manual + +Copyright @copyright{} 2001-2003 G@"urer @"Ozen + +This is a free document; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2, or +(at your option) any later version.You may obtain a copy of the +GNU General Public License from the Free Software Foundation +by visiting their Web site or by writing to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. + +@menu +* Introduction:: + +* Tutorials:: + +* Development:: + +* Datatype Index:: + +* Function Index:: +@end menu +@end ifinfo + +@node Introduction, Tutorials, ,Top +@chapter Introduction + +iksemel is an XML (eXtensible Markup Language) parser library +designed for Jabber applications. It is coded in ANSI C for POSIX +compatible environments, thus highly portable. It is free software +released under the GNU Lesser General Public License. + +The purprose of this manual is to tell you how to use the facilities +of the iksemel library. Manual is written with the assumption that you +are familiar with the C programming language, basic programming +concepts, XML and Jabber protocol. + +@section Compiling the Library + +You need to install MinGW (@url{http://mingw.org}) under Windows to be able +to compile iksemel. Although not tested by the author, Cygwin should +work equally well. + +Library can be built with: + +@example +./configure +make +@end example + +If you want to make a self test: + +@example +make test +@end example + +Now you can install it with: + +@example +make install +@end example + + +@section Using iksemel in Applications + +You need to include @file{iksemel.h} file in your source to access library API. +You can do this with: + +@code{#include "iksemel.h"} + +Now you can use iksemel functions and compile your source. In able to link +your compiled object files and generate your executable program, you have to +link with iksemel library. This can be done with: + +@example +gcc -o myprg src1.o src2.o src3.o -liksemel +@end example + +iksemel registers itself with pkg-config while installing, so if you are using +autotools in your program, you can simply check the availability of iksemel +and configure your build process accordingly with: + +@example +PKG_CHECK_MODULES(IKSEMEL,iksemel,,exit) +@end example + +This would result in IKSEMEL_LIBS and IKSEMEL_CFLAGS substitution variables +set to correct values. + +@node Tutorials,Development,Introduction,Top +@chapter Tutorials + +@ifinfo +@menu +* Parsing an XML Document:: + +* Working with XML Trees:: + +* XML Streams:: + +* Writing a Jabber Client:: + +* Utility Functions:: +@end menu +@end ifinfo + + +@comment ============================================================ +@node Parsing an XML Document,Working with XML Trees,,Tutorials +@section Parsing an XML Document + +iksemel parser sequentally processes the XML document. Each encountered XML +element (i.e. tags, character data, comments, processing instructions, etc.) +is reported to your application by calling the hook functions you have provided. +This type of interface is called SAX (serial access) interface. + +@tindex iksparser +Parser stores its state in a small structure. This structure is referenced by +@code{iksparser} type, and managed with following functions: + +@deftypefun iksparser* iks_sax_new (void* @var{user_data}, iksTagHook* @var{tagHook}, iksCDataHook* @var{cdataHook}); +This function allocates and initializes a parser structure. If allocation fails, +NULL value is returned. @var{user_data} is passed directly to hook functions. +@end deftypefun + +@deftp Typedef iksTagHook +int iksTagHook (void* @var{user_data}, char* @var{name}, char** @var{atts}, int @var{type}); + +This function is called when a tag parsed. @var{name} is the name of the tag. If tag has +no attributes @var{atts} is NULL, otherwise it contains a null terminated list of +pointers to tag's attributes and their values. If return value isn't @code{IKS_OK}, +it is passed immediately to the caller of the @code{iks_parse}. + +@var{type} is one of the following: +@table @code +@item IKS_OPEN +Opening tag, i.e. <tag attr='value'> +@item IKS_CLOSE +Closing tag, i.e. </tag> +@item IKS_SINGLE +Standalone tag, i.e. <tag attr='value'/> +@end table +@end deftp + +@deftp Typedef iksCDataHook +int iksCDataHook (void* @var{user_data}, char* @var{data}, size_t @var{len}); + +@var{data} is a pointer to the character data. Encoding is UTF-8 and it isn't terminated +with a null character. Size of the data is given with @var{len} in bytes. This function +can be called several times with smaller sized data for a single string. If +return value isn't @code{IKS_OK}, it is passed immediately to the caller of the +@code{iks_parse}. +@end deftp + +@deftypefun int iks_parse (iksparser* @var{prs}, char *@var{data}, size_t @var{len}, int @var{finish}); +You give XML document to the parser with this function. @var{data} +is a @var{len} bytes string. If @var{len} is zero, data must be a null +terminated string. + +If @var{finish} value is zero, parser waits for more data later. If you +want to finish parsing without giving data, call it like: +@example +iks_parse (my_parser, NULL, 0, 1); +@end example + +You should check the return value for following conditions: +@table @code +@item IKS_OK +There isn't any problem. +@item IKS_NOMEM +Not enough memory. +@item IKS_BADXML +Document is not well-formed. +@item IKS_HOOK +Your hook decided that there is an error. +@end table +@end deftypefun + +@deftypefun void iks_parser_delete (iksparser* @var{prs}); +This function frees parser structure and associated data. +@end deftypefun + +Now we have learned how to create and use a sax parser. Lets parse a simple +XML document. Write following code into a @file{test.c} file. + +@smallexample +#include <stdio.h> +#include <iksemel.h> + +int pr_tag (void *udata, char *name, char **atts, int type) +@{ + switch (type) @{ + case IKS_OPEN: + printf ("TAG <%s>\n", name); + break; + case IKS_CLOSE: + printf ("TAG </%s>\n", name); + break; + case IKS_SINGLE: + printf ("TAG <%s/>\n", name); + break; + @} + if (atts) @{ + int i = 0; + while (atts[i]) @{ + printf (" ATTRIB %s='%s'\n", atts[i], atts[i+1]); + i += 2; + @} + @} + return IKS_OK; +@} + +enum ikserror pr_cdata (void *udata, char *data, size_t len) +@{ + int i; + printf ("CDATA ["); + for (i = 0; i < len; i++) + putchar (data[i]); + printf ("]\n"); + return IKS_OK; +@} + +int main (int argc, char *argv[]) +@{ + iksparser *p; + p = iks_sax_new (NULL, pr_tag, pr_cdata); + switch (iks_parse (p, argv[1], 0, 1)) @{ + case IKS_OK: + puts ("OK"); + break; + case IKS_NOMEM: + puts ("Not enough memory"); + exit (1); + case IKS_BADXML: + puts ("XML document is not well-formed"); + exit (2); + case IKS_HOOK: + puts ("Our hooks didn't like something"); + exit (2); + @} + iks_parser_delete (p); + return 0; +@} +@end smallexample + +Now compile and test it with: + +@example +gcc -o test test.c -liksemel +./test "<test>Hello<br/>World!</test>" +./test "<lala a='12' b='42'/>" +@end example + +@heading Error Handling + +XML standart states that once an error is detected, the processor must not continue +normal processing (i.e. it must not pass character data or markup information to +the application). So iksemel stops processing immediately when it encounters a +syntax error, or one of your hook functions return any one value than @code{IKS_OK}, +and @code{iks_parse} function returns with the error code. + +Since it is useful for debugging, iksemel provides functions to get position of +the error. Position is usually at the starting character for syntax errors. Since +your hooks are called after whole element (i.e. markup or character data) is +passed, position is at the end of the erroneous element for @code{IKS_HOOK} errors. + +@deftypefun {unsigned long} iks_nr_bytes (iksparser* @var{prs}); +Returns how many number of bytes parsed. +@end deftypefun + +@deftypefun {unsigned long} iks_nr_lines (iksparser* @var{prs}); +Returns how many number of lines parsed. +@end deftypefun + +If you want to parse another document with your parser again, you should use +the following function to reset your parser. + +@deftypefun void iks_parser_reset (iksparser* @var{prs}); +Resets the parser's internal state. +@end deftypefun + + +@comment ============================================================ +@node Working with XML Trees,XML Streams,Parsing an XML Document,Tutorials +@section Working with XML Trees + +SAX interface uses very little memory, but it forces you to access XML +documents sequentally. In many cases you want to keep a tree like +representation of XML document in memory and want to access and +modify its content randomly. + +iksemel provides functions for efficiently creating such trees either +from documents or programmaticaly. You can access and modify this +tree and can easily generate a new XML document from the tree. + +This is called DOM (Document Object Model) interface. + +@ifinfo +@menu +* Memory Management:: + +* Creating a Tree:: + +* Accessing the Tree:: + +* Converting a Tree into an XML Document:: + +* Parsing an XML Document into a Tree:: +@end menu +@end ifinfo + + +@comment ============================================================ +@node Memory Management,Creating a Tree,,Working with XML Trees +@subsection Memory Management + +Since keeping whole document content uses a lot of memory and requires +many calls to OS's memory allocation layer, iksemel uses a simple object +stack system for minimizing calls to the @code{malloc} function and releasing +all the memory associated with a tree in a single step. + +A parsed XML tree contains following objects: +@table @samp +@item Nodes +These are basic blocks of document. They can contain a tag, attribute pair +of a tag, or character data. Tag nodes can also contain other nodes as +children. Node structure has a small fixed size depending on the node type. +@item Names +Names of tags and attributes. They are utf-8 encoded small strings. +@item Character Data +They are similar to names but usually much bigger. +@end table + +iksemel's object stack has two separate areas for keeping these data objects. +Meta chunk contains all the structures and aligned data, while the data chunk +contains strings. Each chunk starts with a choosen size memory block, then +when necessary more blocks allocated for providing space. Unless there is a big +request, each block is double the size of the previous block, thus real memory +needs are quickly reached without allocating too many blocks, or wasting +memory with too big blocks. + +@deftp Typedef ikstack +This is a structure defining the object stack. Its fields are private +and subject to change with new iksemel releases. +@end deftp + +@deftypefun {ikstack *} iks_stack_new (size_t @var{meta_chunk}, size_t @var{data_chunk}); +Creates an object stack. @var{meta_chunk} is the initial size of the +data block used for structures and aligned data. @var{data_chunk} is +the initial size of the data block used for strings. They are both in byte units. + +These two initial chunks and a small object stack structure is allocated in +one @code{malloc} call for optimization purproses. +@end deftypefun + +@deftypefun {void *} iks_stack_alloc (ikstack * @var{stack}, size_t @var{size}); +Allocates @var{size} bytes of space from the object stack's meta chunk. +Allocated space is aligned on platform's default alignment boundary and +isn't initialized. Returns a pointer to the space, or NULL if there isn't enough +space available and allocating a new block fails. +@end deftypefun + +@deftypefun {void *} iks_stack_strdup (ikstack * @var{stack}, const char * @var{src}, size_t @var{len}); +Copies given string @var{src} into the object stack's data chunk. Returns a +pointer to the new string, or NULL if there isn't enough space in the stack. +If @var{len} is zero string must be null terminated. +@end deftypefun + +@deftypefun void iks_stack_delete (ikstack * @var{stack}); +Gives all memory associated with object stack to the system. +@end deftypefun + +Since character data sections are usually parsed in separate blocks, +a growable string implementation is necessary for saving memory. + +@deftypefun {char *} iks_stack_strcat (ikstack *@var{stack}, char *@var{old}, size_t @var{old_len}, const char *@var{src}, size_t @var{src_len}); +This function appends the string @var{src} to the string @var{old} in the +stack's data chunk. If @var{old} is NULL it behaves like @code{iks_stack_strdup}. +Otherwise @var{old} has to be a string created with @code{iks_stack_strdup} +or @code{iks_stack_strcat} functions. + +If @var{old_len} or @var{src_len} is zero, corresponding string must be null +terminated. + +Since string can be moved into another block of the data chunk, you must use the +returned value for new string, and must not reference to @var{old} anymore. +Return value can be NULL if there isn't enough space in stack, and allocating a +new block fails. +@end deftypefun + + +@comment ============================================================ +@node Creating a Tree,Accessing the Tree,Memory Management,Working with XML Trees +@subsection Creating a Tree + +@deftp Typedef iks +This is a structure defining a XML node. Its fields are private and only +accessed by following functions. +@end deftp + +@deftypefun iks* iks_new (const char *@var{name}); +Creates an object stack and creates a IKS_TAG type of node with given +tag name inside the stack. Tag name is also copied into the stack. +Returns the node pointer, or NULL if there isn't enough memory. +@end deftypefun + +@deftypefun iks* iks_new_within (const char *@var{name}, ikstack* @var{stack}); +Creates a IKS_TAG type of node with the given tag name. Node and tag +name is allocated inside the given object stack. Returns the node +pointer, or NULL if there isn't enough memory. +@end deftypefun + +@deftypefun iks* iks_insert (iks *@var{x}, const char *@var{name}); +Creates a IKS_TAG type of node with the given tag name. Node and tag +name is allocated inside the @var{x} node's object stack and linked +to @var{x} as a child node. Returns the node pointer, or NULL if there +isn't enough memory. +@end deftypefun + +@deftypefun iks* iks_insert_cdata (iks* @var{x}, const char* @var{data}, size_t @var{len}); +Creates a IKS_CDATA type of node with given character data. Node is +allocated inside the @var{x} node's object stack and linked to @var{x} +as a child node. Data is copied as well. If @var{len} is zero data must +be a null terminated string. Returns the node pointer, or NULL if +there isn't enough memory. +@end deftypefun + +@deftypefun iks* iks_insert_attrib (iks* @var{x}, const char* @var{name}, const char* @var{value}); +Creates a IKS_ATTRIBUTE type of node with given attribute name and the +value. Node is allocated inside the @var{x} node's object stack and +linked to @var{x} as an attribute node. Attribute name and value is +copied as well. Returns the node pointer, or NULL if there isn't +enough memory. + +Reinserting another value with same attribute name changes an attribute's +value. If @var{value} is NULL, attribute is removed from the tag. +@end deftypefun + +@deftypefun iks* iks_insert_node (iks* @var{x}, iks* @var{y}); +Links node @var{y} to node @var{x} as a child node. Nodes are not copied +between object stacks, be careful. +@end deftypefun + +@deftypefun void iks_hide (iks *@var{x}); +Changes the links of the other nodes so that @var{x} becomes invisible. +It stays in the same object stack with neighbour nodes, be careful. +@end deftypefun + +@deftypefun void iks_delete (iks *@var{x}); +Frees the object stack of the node @var{x}. +@end deftypefun + +Now lets create a tree representation of following XML document: + +@example +<message type='chat' from='bob@@bd.com'> +<subject>song lyric</subject><priority>high</priority> +<body> +<em style='underline'>here is the correct version:</em> +i just don't see why i should even care +it's not dark yet, but it's getting there +</body> +</message> +@end example + +here is the code: + +@example +iks *x, *y, *z; + +x = iks_new ("message"); +iks_insert_attrib (x, "type", "chat"); +iks_insert_attrib (x, "from", "bob@@bd.com"); +iks_insert_cdata (x, "\n", 1); +iks_insert_cdata (iks_insert (x, "subject"), "song lyric", 10); +iks_insert_cdata (iks_insert (x, "priority"), "high", 4); +iks_insert_cdata (x, "\n", 1); +y = iks_insert (x, "body"); +iks_insert_cdata (y, "\n", 1); +z = iks_insert (y, "em"); +iks_insert_attrib (z, "style", "underline"); +iks_insert_cdata (z, "here is the correct version", 0); +iks_insert_cdata (y, "\n", 1); +iks_insert_cdata (y, "i just don't see why", 0); +iks_insert_cdata (y, "i should even care\n", 0); +iks_insert_cdata (y, "it's not dark yet,", 0); +iks_insert_cdata (y, "but it's getting there\n", 0); +iks_insert_cdata (x, "\n", 1); +@end example + +Notice how newlines are inserted for proper formatting of document. They aren't +necessary for representing data, but they make it easier to read document for +humans. + +Also notice how @code{iks_insert} and @code{iks_insert_cdata} chained. + +There are also functions for duplicating xml trees. They are: + +@deftypefun {iks *} iks_copy (iks* @var{x}); +Creates a full copy of the tree in a newly created object stack. +@end deftypefun + +@deftypefun {iks *} iks_copy_within (iks* @var{x}, ikstack *@var{s}); +Creates a full copy of the tree in given object stack. +@end deftypefun + +@comment ============================================================ +@node Accessing the Tree,Converting a Tree into an XML Document,Creating a Tree,Working with XML Trees +@subsection Accessing a Tree + +Basic access functions allow you to move on the tree: + +@deftypefun iks* iks_next (iks* @var{x}); +@end deftypefun +@deftypefun iks* iks_prev (iks* @var{x}); +@end deftypefun +@deftypefun iks* iks_parent (iks* @var{x}); +@end deftypefun +@deftypefun iks* iks_child (iks* @var{x}); +@end deftypefun +@deftypefun iks* iks_attrib (iks* @var{x}); +@end deftypefun + +These functions return a pointer to the next, previous, parent, first child, +and first attribute node of the given node @var{x}. If that node doesn't +exist or @var{x} is NULL, a NULL value is returned. + +@deftypefun {iks *} iks_root (iks *@var{x}); +Returns the topmost parent node of the @var{x}. +@end deftypefun + +@deftypefun iks* iks_next_tag (iks* @var{x}); +@end deftypefun +@deftypefun iks* iks_prev_tag (iks* @var{x}); +@end deftypefun +@deftypefun iks* iks_first_tag (iks* @var{x}); +@end deftypefun + +These functions return a pointer to the next, previous, first child node +of the given node @var{x}. Only tag nodes are considered, other type +of the nodes are skipped. If such a node doesn't exist or @var{x} is NULL, +a NULL value is returned. + +Another group of functions allow you to access specific information and +content of the nodes: + +@deftypefun ikstack* iks_stack (iks* @var{x}); +Returns the object stack which node @var{x} stays. +@end deftypefun + +@deftypefun {enum ikstype} iks_type (iks* @var{x}); +Returns the type of the node. + +@tindex ikstype +@table @code +@item IKS_TAG +Node is a tag and can contain child nodes and attributes. +@item IKS_CDATA +Node contains character data. +@item IKS_ATTRIBUTE +Node contains an attribute and its value. +@end table +@end deftypefun + +@deftypefun char* iks_name (iks* @var{x}); +Returns the name of the tag for nodes with the type @var{IKS_TAG}. +Returns an attribute's name for nodes of type IKS_ATTRIBUTE. +@end deftypefun + +@deftypefun char* iks_cdata (iks* @var{x}); +Returns a pointer to node's character data if available, NULL otherwise. +Returns an attribute's value for nodes of type IKS_ATTRIBUTE. +@end deftypefun + +@deftypefun size_t iks_cdata_size (iks *@var{x}); +Returns the size of the node's character data in bytes. +@end deftypefun + +@deftypefun int iks_has_children (iks *@var{x}); +Returns a non-zero value if node @var{x} has a child node. +@end deftypefun + +@deftypefun int iks_has_attribs (iks *@var{x}); +Returns a non-zero value if node @var{x} has attributes. +@end deftypefun + +Last group of the functions simplifies finding and accessing the content +of a specific node: + +@deftypefun iks* iks_find (iks *@var{x}, const char *@var{name}); +Searches a IKS_TAG type of node with @var{name} as tag name in child +nodes of @var{x}. Returns a pointer to the node if found, NULL otherwise. +@end deftypefun + +@deftypefun char* iks_find_cdata (iks* @var{x}, const char* @var{name}); +Searches a IKS_TAG type of node with @var{name} as tag name in child +nodes of @var{x}. Returns a pointer to the character data of the node's +first child node if found, NULL otherwise. +@end deftypefun + +@deftypefun char* iks_find_attrib (iks* @var{x}, const char* @var{name}); +Searches an attribute with given name in attributes of the @var{x}. +Returns a pointer to attribute value if found, NULL otherwise. +@end deftypefun + +@deftypefun {iks *} iks_find_with_attrib (iks *@var{x}, const char *@var{tagname}, const char *@var{attrname}, const char *@var{value}); +Searches for a child tag of @var{x} which has an attribute with name +@var{attrname} and value @var{value}. If @var{tagname} isn't NULL, +name of the tag must also match. Returns a pointer to the node if found, +NULL otherwise. +@end deftypefun + +Here is an example which demonstrates accessing file names in a fictitious +XML playlist file: + +@example +<playlist> + <item type='mpg'> + <name>/home/madcat/download/matrix_rev_trailer.mpg</name> + <duration>1:17</duration> + </item> + <item type='rm'> + <name>/home/madcat/anim/clementine_ep1.rm</name> + <duration>22:00</duration> + </item> + <item type='avi'> + <name>/home/madcat/anim/futurama/ep101.avi</name> + <subtitle>/home/madcat/subs/futurama/ep101.txt</subtitle> + <duration>30:00</duration> + </item> + <repeat/> + <fullscreen/> + <noui/> +</playlist> +@end example + +and here is the code: + +@example +#include <stdio.h> +#include <iksemel.h> + +int main (int argc, char *argv[]) +@{ + iks *x, *y; + int e; + + if (argc < 2) @{ + printf ("usage: %s <playlistfile>", argv[0]); + return 0; + @} + e = iks_load (argv[1], &x); + if (e != IKS_OK) @{ + printf ("parse error %d\n", e); + return 1; + @} + if (iks_find (x, "repeat")) puts ("repeat mode enabled"); + y = iks_child (x); + while (y) @{ + if (iks_type (y) == IKS_TAG + && strcmp (iks_name (y), "item") == 0) @{ + printf ("Filename: [%s]\n", iks_find_cdata (y, "name")); + @} + y = iks_next (y); + @} + iks_delete (x); + return 0; +@} +@end example + + +@comment ============================================================ +@node Converting a Tree into an XML Document,Parsing an XML Document into a Tree,Accessing the Tree,Working with XML Trees +@subsection Converting a Tree to an XML Document + +There is a function for converting given XML tree into a null terminated string. + +@deftypefun {char *} iks_string (ikstack* @var{stack}, iks* @var{x}); +Converts given tree into a string. String is created inside the given object +stack. Returns a pointer to the string, or NULL if there isn't enough memory +available. + +If @var{stack} is NULL, string is created inside an @code{iks_malloc}ed buffer. +You can free it later with @code{iks_free} function. +@end deftypefun + +Here is an example which builds a tree and print it. + +@example +iks *x; +char *t; + +x = iks_new ("test"); +iks_insert_cdata (iks_insert (x, "a"), "1234", 4); +iks_insert (x, "br"); +iks_insert_cdata (x, "1234", 4); +t = iks_string (iks_stack (x), x); +puts (t); +iks_delete (x); +@end example + + +@comment ============================================================ +@node Parsing an XML Document into a Tree,,Converting a Tree into an XML Document,Working with XML Trees +@subsection Parsing a Document into a Tree + +If you want to automatically convert an XML document into a tree, you can use +iksemel's DOM parser. It is created with following function: + +@deftypefun iksparser* iks_dom_new (iks **@var{iksptr}); +Creates a DOM parser. A pointer to the created XML tree is put into the +variable pointed by @var{iksptr}. Returns a pointer to the parser, or NULL +is there isn't enough memory. +@end deftypefun + +Usage is same as SAX parser. You feed the data with @code{iks_parse}, and if +there isn't an error, you can access to your tree from variable @code{*iksptr}. + +Here is a simple example: + +@example +iks *x; +iksparser *p; + +p = iks_dom_new (&x); +if (IKS_OK != iks_parse (p, "<a>bcd</a>", 9, 1)) @{ + puts ("parse error"); +@} +/* x is useable after that point */ + +/* this will print 'bcd' */ +printf ("%s\n", iks_cdata (iks_child (x))); +@end example + +If you know the size of the file ahead, or you have an approximate idea, +you can tell this to the dom parser for choosing a better memory allocation +strategy. Here is the function for this. + +@deftypefun void iks_set_size_hint (iksparser *@var{prs}, size_t @var{approx_size}); +Parser @var{prs} must be a dom type parser. @var{approx_size} is the +expected size of the xml document. Parser chooses its chunk size +based on this information. Helps performance while processing big files. +@end deftypefun + +If you already have your XML document in memory, you can simply parse +it with: + +@deftypefun {iks *} iks_tree (const char *@var{xml_str}, size_t @var{len}, int *@var{err}); +This function parses the buffer pointed by @var{xml_str}. If @var{len} is zero +buffer is considered as a null terminated utf8 string. Returns the parsed tree, +or NULL if there is an error. If @var{err} is not NULL, actual error code (returned +by iks_parse) is put there. +@end deftypefun + +Most of the times you want to load your configuration (or similar) files directly +into trees. iksemel provides two functions to greatly simplify this: + +@deftypefun int iks_load (const char *@var{fname}, iks **@var{xptr}); +Loads the XML file. Tree is placed into the variable pointed by @var{xptr}. +@end deftypefun + +@deftypefun int iks_save (const char *@var{fname}, iks *@var{x}); +Converts tree @var{x} into a string and saves to the file. +@end deftypefun + +Both functions return same error codes as @code{iks_parse}. Some additional +error codes are defined for indicating file problems. They are: + +@table @code +@item IKS_FILE_NOFILE +A file with the given name doesn't exist. +@item IKS_FILE_NOACCESS +Cannot open file. Possibly a permission problem. +@item IKS_FILE_RWERR +Read or write operation failed. +@end table + +Here is a simple example which parses a file and saves it into another: + +@example +iks *x; + +if (IKS_OK != iks_load ("file1.xml", &x)) @{ + puts ("loading error"); +@} +if (IKS_OK != iks_save ("file2.xml", x)) @{ + puts ("saving error"); +@} +@end example + + +@comment ============================================================ +@node XML Streams,Writing a Jabber Client,Working with XML Trees,Tutorials +@section XML Streams + +XML streams function as containers for any XML chunks sent asynchronously +between network endpoints. They are used for asyncronously exchanging +relatively small payload of structured information between entities. + +A stream is initiated by one of hosts connecting to the other, and sending a +<stream:stream> tag. Receiving entity replies with a second XML stream +back to the initiating entity within the same connection. Each unit of +information is send as a direct child tag of the <stream:stream> tag. +Stream is closed with </stream:stream>. + +XML streams use a subset of XML. Specifically they should not contain +processing instructions, non-predefined entities, comments, or DTDs. + +Jabber protocol uses XML streams for exchanging messages, presence +information, and other information like authorization, search, time and +version queries, protocol extensions. + +iksemel provides you a stream parser, which automatically handles connection +to the server, and calls your hook function with incoming information +parsed and converted to an XML tree. + +You can create such a parser with: + +@deftypefun iksparser* iks_stream_new (char* @var{name_space}, void* @var{user_data}, iksStreamHook* @var{streamHook}); +Allocates and initalizes a stream parser. @var{name_space} indicates the +stream type, jabber clients use "jabber:client" namespace. @var{user_data} +is passed directly to your hook function. +@end deftypefun + +@deftp Typedef iksStreamHook +int iksStreamHook (void* @var{user_data}, int @var{type}, iks* @var{node}); + +Depending on the value of the @var{type}, @var{node} contains: +@table @code +@item IKS_NODE_START +Got the <stream:stream> tag, namespace, stream id and other information +is contained in the @var{node}. +@item IKS_NODE_NORMAL +A first level child of the <stream:stream> tag is received. @var{node} contains +the parsed tag. If you are connected to a jabber server, you can get <message>, +<presence>, or <iq> tags. +@item IKS_NODE_ERROR +Got a <stream:error> tag, details can be accessed from @var{node}. +@item IKS_NODE_STOP +</stream:stream> tag is received or connection is closed, @var{node} is @code{NULL}. +@end table + +Freeing the node with @code{iks_delete} is up to you. +@end deftp + +You can manually feed this parser with @code{iks_parse} function, but using +iksemel's connection facilities is easier for most of the cases. + +This functions return @code{IKS_OK} for success. Error codes of @code{iks_parse} +are used in same manner. Following additional codes are defined for +network related problems: + +@table @code +@item IKS_NET_NODNS +Hostname lookup failed. Possible reasons: hostname is incorrect, +you are not online, your dns server isn't accessible. +@item IKS_NET_NOSOCK +Socket cannot created. +@item IKS_NET_NOCONN +Connection attemp failed. Possible reasons: host is not an XML stream +server, port number is wrong, server is busy or closed for the moment. +@item IKS_NET_RWERR +@code{send} or @code{recv} call is failed when attempting to exchange +the data with the server. You should close the connection with @code{iks_disconnect} +after getting this error from data transfer functions. +@end table + +@deftypefun int iks_connect_tcp (iksparser *@var{prs}, const char *@var{server}, int @var{port}); +This function connects the parser to a server and sends stream header for you. +@var{server} is the host name of the server and @var{port} is the tcp port +number which server is listening to. You can use @code{IKS_JABBER_PORT} +macro for the default jabber client port (5222). +@end deftypefun + +@deftypefun int iks_connect_fd (iksparser *@var{prs}, int @var{fd}); +Attaches parser to an already opened connection. @var{fd} is the socket +descriptor. Note that @code{iks_disconnect} doesn't close the socket +for this kind of connection, opening and closing of the socket is up to your +application. Stream header is not sent automatically. You can use +@code{iks_send_header} function for sending it. +@end deftypefun + +@deftypefun void iks_disconnect (iksparser *@var{prs}); +Closes connection to the server, and frees connection resources. +@end deftypefun + +After successfully connecting to a server, you can use following functions +for exchanging information with server. + +@deftypefun int iks_recv (iksparser* @var{prs}, int @var{timeout}); +If @var{timeout} is @code{-1}, waits until some data arrives from server, +and process the data. Your stream hook can be called if a complete +chunk is arrived. + +If @var{timeout} is a positive integer, @code{iks_recv} returns if no data +arrives for @var{timeout} seconds. + +If @var{timeout} is zero, @code{iks_recv} checks if there is any data +waiting at the network buffer, and returns without waiting for data. +@end deftypefun + +@deftypefun int iks_fd (iksparser* @var{prs}); +Returns the file descriptor of the connected socket. You can use this in +your @code{select} function or some other input loop to act whenever +some data from the server arrives. This value of only valid between +a successful @code{iks_connect_tcp} and @code{iks_disconnect}. +@end deftypefun + +@deftypefun int iks_send (iksparser* @var{prs}, iks* @var{x}); +Converts the tree given in @var{x} to a string, and sends to the server. +String is created inside the object stack of @var{x}. +@end deftypefun + +@deftypefun int iks_send_raw (iksparser* @var{prs}, char* @var{xmlstr}); +Sends the string given in @var{xmlstr} to the server. +@end deftypefun + +@deftypefun int iks_send_header (iksparser *@var{prs}, char *@var{to}); +Sends the stream header. @var{to} is the name of the server. +Normally @code{iks_connect_tcp} function calls this for you. This +is only useful if you are using @code{iks_connect_fd}. +@end deftypefun + +Sometimes it is useful to log incoming and outgoing data to your parser +for debugging your applications. iksemel provides a logging facility for you. + +@deftypefun void iks_set_log_hook (iksparser* @var{prs}, iksLogHook* @var{logHook}); +Sets the log function for your stream parser. You can't use this function +on any other type of parser. +@end deftypefun + +@deftp Typedef iksLogHook +void iksLogHook (void* @var{user_data}, const char* @var{data}, size_t @var{size}, int @var{is_incoming}); + +@var{user_data} is same value which you give with @code{iks_stream_new}. +@var{data} is @var{size} bytes of data. Be very careful that this data may be +coming from other side of the connection and can contain malicius bytes. It isn't +checked by iksemel yet, so you should check it yourself before displaying or +passing to other systems in your application or computer. If @var{is_incoming} +is a non-zero value, data is incoming from server, otherwise it is outgoing to the +server. +@end deftp + + +@comment ============================================================ +@node Writing a Jabber Client,Utility Functions,XML Streams,Tutorials +@section Writing a Jabber Client + +@ifinfo +@menu +* Security:: + +* Packets:: + +* Packet Filter:: + +* Creating Common Packets:: + +@end menu +@end ifinfo + +@comment ============================================================ +@node Security,Packets,,Writing a Jabber Client +@subsection Security + +iksemel supports TLS protocol for encrypted communication and SASL +protocol for authentication. TLS is handled by gnutls library. + +@deftypefun int iks_has_tls (void); +If iksemel is compiled with gnutls library, this function returns a non-zero +value indicating you can try encrypted connection with the server. +@end deftypefun + +@deftypefun int iks_start_tls (iksparser* @var{prs}); +Starts a TLS handshake over already connected parser. Returns IKS_OK or +one of the IKS_NET_ errors. If handshake succeeds you'll get another +stream header from server. +@end deftypefun + +@deftypefun int iks_is_secure (iksparser* @var{prs}); +Returns a non-zero value if a secure connection is fully established +between server. +@end deftypefun + +@deftypefun int iks_start_sasl (iksparser* @var{prs}, enum ikssasltype @var{type}, char* @var{username}, char* @var{pass}); +Starts SASL operation. +@end deftypefun + +See tools/iksroster.c for a good example. + +@comment ============================================================ +@node Packets,Packet Filter,Security,Writing a Jabber Client +@subsection Packets + +iksemel can parse a jabber XML node and provide you a public packet +structure which contains information like node type and subtype, id, +namespace, sender's jabber id, etc. + +This handles a lot of node parsing for you. Packets are also used in +the packet filter subsystem. + +@deftypefun {ikspak *} iks_packet (iks *@var{x}); +Takes a node from stream and extracts information from it to a packet structure. +Structure is allocated inside the node's object stack. +@end deftypefun + +@tindex ikspak +@code{ikspak} structure has following fields: + +@table @code +@item iks *x; +This is a pointer to the node. +@item iksid *from; +Sender's jabber id in parsed form. See below for @code{iksid} structure. +@item iks *query; +A pointer to the <query> tag for IQ nodes. +@item char *ns; +Namespace of the content for IQ nodes. +@item char *id; +ID of the node. +@item enum ikspaktype type; +Type of the node. Possible types are: + +@table @code +@item IKS_PAK_NONE +Unknown node. +@item IKS_PAK_MESSAGE +Message node. +@item IKS_PAK_PRESENCE +Presence node with presence publishing operation. +@item IKS_PAK_S10N +Presence node with subscription operation. +@item IKS_PAK_IQ +IQ node. +@end table +@item enum iksubtype subtype; +Sub type of the node. Sub types for message nodes: + +@table @code +@item IKS_TYPE_NONE +A normal message. +@item IKS_TYPE_CHAT +Private chat message. +@item IKS_TYPE_GROUPCHAT +Multi user chat message. +@item IKS_TYPE_HEADLINE +Message from a news source. +@item IKS_TYPE_ERROR +Message error. +@end table + +Sub types for IQ nodes: + +@table @code +@item IKS_TYPE_GET +Asks for some information. +@item IKS_TYPE_SET +Request for changing information. +@item IKS_TYPE_RESULT +Reply to get and set requests. +@item IKS_TYPE_ERROR +IQ error. +@end table + +Sub types for subscription nodes: + +@table @code +@item IKS_TYPE_SUBSCRIBE, +Asks for subscribing to the presence. +@item IKS_TYPE_SUBSCRIBED, +Grants subscription. +@item IKS_TYPE_UNSUBSCRIBE, +Asks for unsubscribing to the presence. +@item IKS_TYPE_UNSUBSCRIBED, +Cancels subscription. +@item IKS_TYPE_ERROR +Presence error. +@end table + +Sub types for presence nodes: + +@table @code +@item IKS_TYPE_PROBE, +Asks presence status. +@item IKS_TYPE_AVAILABLE, +Publishes entity as available. More information can be found in @code{show} field. +@item IKS_TYPE_UNAVAILABLE +Publishes entity as unavailable. More information can be found in @code{show} field. +@end table +@item enum ikshowtype show; +Presence state for the presence nodes. + +@table @code +@item IKS_SHOW_UNAVAILABLE +Entity is unavailable. +@item IKS_SHOW_AVAILABLE +Entity is available. +@item IKS_SHOW_CHAT +Entity is free for chat. +@item IKS_SHOW_AWAY +Entity is away for a short time. +@item IKS_SHOW_XA +Entity is away for a long time. +@item IKS_SHOW_DND +Entity doesn't want to be disturbed. +@end table +@end table + +iksemel has two functions to parse and compare jabber IDs. + +@deftypefun {iksid *} iks_id_new (ikstack *@var{s}, const char *@var{jid}); +Parses a jabber id into its parts. @code{iksid} structure is created inside +the @var{s} object stack. +@end deftypefun + +@tindex iksid +@code{iksid} structure has following fields: + +@table @code +@item char *user; +User name. +@item char *server; +Server name. +@item char *resource; +Resource. +@item char *partial; +User name and server name. +@item char *full; +User name, server name and resource. +@end table + +You can access this fields and read their values. Comparing two parsed jabber +ids can be done with: + +@deftypefun int iks_id_cmp (iksid *@var{a}, iksid *@var{b}, int @var{parts}); +Compares @var{parts} of @var{a} and @var{b}. Part values are: + +@table @code +@item IKS_ID_USER +@item IKS_ID_SERVER +@item IKS_ID_RESOURCE +@end table + +@sp 1 +You can combine this values with @code{or} operator. Some common combinations +are predefined for you: + +@table @code +@item IKS_ID_PARTIAL +@code{IKS_ID_USER | IKS_ID_SERVER} +@item IKS_ID_FULL +@code{IKS_ID_USER | IKS_ID_SERVER | IKS_ID_RESOURCE} +@end table + +Return value is @code{0} for equality. If entities are not equal a combination of +part values showing different parts is returned. +@end deftypefun + + +@comment ============================================================ +@node Packet Filter,Creating Common Packets,Packets,Writing a Jabber Client +@subsection Packet Filter + +Packet filter handles routing incoming packets to related functions. + +@tindex iksfilter +@deftypefun {iksfilter *} iks_filter_new (void); +Creates a new packet filter. +@end deftypefun + +@deftypefun void iks_filter_packet (iksfilter *@var{f}, ikspak *@var{pak}); +Feeds the filter with given packet. Packet is compared to registered rules and +hook functions of the matching rules are called in most matched to least +matched order. +@end deftypefun + +@deftypefun void iks_filter_delete (iksfilter *@var{f}); +Frees filter and rules. +@end deftypefun + +Rules are created with following function: + +@tindex iksrule +@deftypefun {iksrule *} iks_filter_add_rule (iksfilter *@var{f}, iksFilterHook *@var{filterHook}, void *@var{user_data}, @dots{}); +Adds a rule to the filter @var{f}. @var{user_data} is passed directly to your +hook function @var{filterHook}. + +A rule consist of one or more type and value pairs. Possible types: +@table @code +@item IKS_RULE_ID +Compares @code{char *} value to packet ids. +@item IKS_RULE_FROM +Compares @code{char *} value to packet senders. +@item IKS_RULE_FROM_PARTIAL +Compares @code{char *} value to packet sender. Ignores resource part of jabber id. +@item IKS_RULE_NS +Compares @code{char *} value to namespace of iq packets. +@item IKS_RULE_TYPE +Compares @code{int} value to packet types. +@item IKS_RULE_SUBTYPE +Compares @code{int} value to packet sub types. +@item IKS_RULE_DONE +Terminates the rule pairs. +@end table +@end deftypefun + +Here is an example which creates a filter and adds three rules: +@example +iksfilter *f; + +f = iks_filter_new (); +iks_filter_add_rule (f, on_msg, NULL, + IKS_RULE_TYPE, IKS_PAK_MESSAGE, + IKS_RULE_DONE); +iks_filter_add_rule (f, on_auth_result, NULL, + IKS_RULE_TYPE, IKS_PAK_IQ, + IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, + IKS_RULE_ID, "auth", + IKS_RULE_DONE); +iks_filter_add_rule (f, on_roster_push, NULL, + IKS_RULE_TYPE, IKS_PAK_IQ, + IKS_RULE_SUBTYPE, IKS_TYPE_SET, + IKS_RULE_NS, "jabber:iq:roster", + IKS_RULE_DONE); +@end example + +@deftp Typedef iksFilterHook +int iksFilterHook (void *user_data, ikspak *pak); + +Your hook is called with your @var{user_data} and matching packet @var{pak}. +You can return two different values from your hook: +@table @code +@item IKS_FILTER_PASS +Packet is forwarded to least matching rules. +@item IKS_FILTER_EAT +Filtering process for the packet ends. +@end table +@end deftp + +You can remove the rules with following functions: + +@deftypefun void iks_filter_remove_rule (iksfilter *@var{f}, iksrule *@var{rule}); +Removes the rule from filter. +@end deftypefun + +@deftypefun void iks_filter_remove_hook (iksfilter *@var{f}, iksFilterHook *@var{filterHook}); +Remove the rules using @var{filterHook} function from filter. +@end deftypefun + + +@comment ============================================================ +@node Creating Common Packets,,Packet Filter,Writing a Jabber Client +@subsection Creating Common Packets + +A usual jabber network traffic contains many similar XML constructs. iksemel +provides several utility functions for creating them. They all generate an XML +tree, so you can add or modify some parts of the tree, and send to server then. + +@deftypefun {iks *} iks_make_auth (iksid *@var{id}, const char *@var{pass}, const char *@var{sid}); +Creates an authorization packet. @var{id} is your parsed jabber id, and @var{pass} +is your password. + +If stream id @var{sid} isn't NULL, SHA1 authentication is used, otherwise password +is attached in plain text. You can learn stream id from @code{IKS_STREAM_START} +packet in your stream hook like this: + +@example +char *sid; + +if (type == IKS_STREAM_START) @{ + sid = iks_find_attrib (node, "id"); +@} +@end example +@end deftypefun + +@deftypefun {iks *} iks_make_msg (enum iksubtype @var{type}, const char *@var{to}, const char *@var{body}); +Creates a message packet. @var{type} is the message type, @var{to} is jabber id +of the recipient, @var{body} is the message. +@end deftypefun + +@deftypefun {iks *} iks_make_s10n (enum iksubtype @var{type}, const char *@var{to}, const char *@var{msg}); +Creates a presence packet for subscription operations. @var{type} is operation, +@var{to} is jabber id of the recipient, @var{msg} is a small message for +introducing yourself, or explaning the reason of why you are subscribing or +unsubscribing. +@end deftypefun + +@deftypefun {iks *} iks_make_pres (enum ikshowtype @var{show}, const char *@var{status}); +Creates a presence packet for publishing your presence. @var{show} is your +presence state and @var{status} is a message explaining why you are not +available at the moment, or what you are doing now. +@end deftypefun + +@deftypefun {iks *} iks_make_iq (enum iksubtype @var{type}, const char *@var{xmlns}); +Creates an IQ packet. @var{type} is operation type and @var{xmlns} is the +namespace of the content. You usually have to add real content to the <query> +tag before sending this packet. +@end deftypefun + + +@comment ============================================================ +@node Utility Functions,,Writing a Jabber Client,Tutorials +@section Utility Functions + +@subsection Memory Utilities + +@deftypefun {void *} iks_malloc (size_t @var{size}); +@end deftypefun +@deftypefun void iks_free (void *@var{ptr}); +@end deftypefun + +These are wrappers around ANSI malloc and free functions used by the +iksemel library itself. You can free the output of iks_string (only if you +passed it a NULL stack) with iks_free for example. That is important +if you are using a malloc debugger in your application but not in iksemel +or vice versa. + +@comment ============================================================ +@subsection String Utilities + +@deftypefun {char *} iks_strdup (const char *@var{src}); +@end deftypefun +@deftypefun int iks_strcmp (const char *@var{a}, const char *@var{b}); +@end deftypefun +@deftypefun int iks_strcasecmp (const char *@var{a}, const char *@var{b}); +@end deftypefun +@deftypefun int iks_strncmp (const char *@var{a}, const char *@var{b}, size_t @var{n}); +@end deftypefun +@deftypefun int iks_strncasecmp (const char *@var{a}, const char *@var{b}, size_t @var{n}); +@end deftypefun +@deftypefun size_t iks_strlen (const char *@var{src}); +@end deftypefun + +These functions work exactly like their ANSI equivalents except that they allow +NULL values for string pointers. If @var{src} is NULL, iks_strdup and iks_strlen +returns zero. If @var{a} or @var{b} is NULL in string comparisation functions +they return -1. + +Their usefulness comes from the fact that they can chained with DOM traversing +functions like this: + +@smallexample +if (iks_strcmp (iks_find_attrib (x, "id"), "x1") == 0) count++; +@end smallexample + +That example works even x doesn't have an 'id' attribute and iks_find_attrib +returns NULL. So you don't need to use temporary variables in such +situations. + +@comment ============================================================ +@subsection SHA1 Hash + +Secure Hash Algorithm (SHA1) is used in the Jabber authentication +protocol for encoding your password when sending to the server. +This is normally handled by iks_make_auth() function, but if you +want to handle it manually, or if you need a good hash function +for other purproses you can use these functions. + +@deftypefun iksha* iks_sha_new (void); +Allocates a structure for keeping calculation values and the state. +@end deftypefun + +@deftypefun void iks_sha_reset (iksha *@var{sha}); +Resets the state of the calculation. +@end deftypefun + +@deftypefun void iks_sha_hash (iksha *@var{sha}, const unsigned char *@var{data}, int @var{len}, int @var{finish}); +Calculates the hash value of the given data. If @var{finish} is non +zero, applies the last step of the calculation. +@end deftypefun + +@deftypefun void iks_sha_print (iksha *@var{sha}, char *@var{hash}); +Prints the result of a finished calculation into the buffer pointed by @var{hash} +in hexadecimal string form. Buffer must be at least 40 bytes long. String +is not null terminated. +@end deftypefun + +@deftypefun void iks_sha (const char *@var{data}, char *@var{hash}); +Calculates the hash value of @var{data} and prints into @var{hash}. +This is a helper function for simple hash calculations. It calls +other functions for the actual work. +@end deftypefun + + +@comment ============================================================ + + +@node Development,Datatype Index,Tutorials,Top +@chapter Development + +This chapter contains information on plan, procedure and standarts of +iksemel development. + +@section Roadmap + +There are three main functions iksemel tries to provide to applications: +@itemize @bullet +@item +A generic XML parser with SAX and DOM interfaces. +@item +XML stream client and server functionality. +@item +Utilities for Jabber clients. +@end itemize + +Goal of the iksemel is providing these functions while supporting embedded +environments, keeping usage simple, and having a robust implementation. + +Some decisions are made to reach this goal: + +Code is written in ANSI C with a single dependency on C library. Instead of +using expat or libxml, a simple built-in parser is used. Similarly glib and +gnu only features of glibc (like object stacks) are avoided and built-in +memory and string utilities are used. This may seem like code duplication +but since they are optimized for iksemel and only a few kb in size, +it isn't a big disadvantage. + +Code is placed files in a modular fashion, and different modules don't depend +on others' internal details. This allows taking unneeded functionality out when +building for low resource situations. + +It is tried to give functions names which are consistent, clear and short. + +API is documented with texinfo for high quality printed output and info file +output for fast and simple access during application development. Instead +of using an autogenerated system or simply listing function descriptions, +a task oriented tutorial approach is used. + +@section Coding Style + +Here is a short list describing preferred coding style for iksemel. +Please keep in mind when sending patches. + +@itemize @bullet +@item +Indentation is done with tabs. Aligning is done with spaces. +@item +Placement of braces is K&R style. +@item +Function names are put at the start of line. +@item +Function names are lowercase. +@item +Words of the function names are separated with underscore character. +@item +Structure and variable names are lowercase. +@item +Macro and enumarations names are uppercase. +@item +Exported library API is contained in the single iksemel.h file. +@item +Exported function names start with iks_ +@item +Exported structure and type names start with iks +@item +Exported macro and enumaration names start with IKS_ +@end itemize + +Here is an example: + +@smallexample +int +iks_new_func (char *text) +@{ + int i; + + i = an_internal_func (text); + if (IKS_SOME_VALUE == i) @{ + iks_some_func (text); + i++; + @} + return i; +@} +@end smallexample + +@section Resources + +@itemize @bullet +@item +RFC 2279, UTF-8 format @url{http://www.ietf.org/rfc/rfc2279.txt} +@item +W3C Recommendation, Extensible Markup Language 1.0 @url{http://www.w3.org/TR/REC-xml} +@item +Annotated XML Specification @url{http://www.xml.com/axml/testaxml.htm} +@item +Jabber Protocol Documents @url{http://www.jabber.org/protocol/} +@end itemize + + +@comment ============================================================ + + +@node Datatype Index,Function Index,Development,Top +@unnumbered Datatype Index +@printindex tp + + +@node Function Index,,Datatype Index,Top +@unnumbered Function Index +@printindex fn + + +@contents +@bye |