From b0396809c19f436e051430d5e81d59a725611195 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 24 Jul 2020 09:13:21 +0200 Subject: Convert to build2-based build Also add symbol exporting, missing const in a few places in the API, as well as a basic test. --- .gitattributes | 19 + .gitignore | 6 +- README.md | 24 + buildfile | 5 + char-props.c | 394 ------ genx.c | 2543 ----------------------------------- genx.h | 390 ------ libgenx/.gitignore | 19 + libgenx/LICENSE | 1 + libgenx/README.md | 1 + libgenx/build/.gitignore | 4 + libgenx/build/bootstrap.build | 7 + libgenx/build/export.build | 6 + libgenx/build/root.build | 8 + libgenx/buildfile | 5 + libgenx/libgenx/.gitignore | 3 + libgenx/libgenx/buildfile | 51 + libgenx/libgenx/char-props.c | 394 ++++++ libgenx/libgenx/export.h | 33 + libgenx/libgenx/genx.c | 2542 ++++++++++++++++++++++++++++++++++ libgenx/libgenx/genx.h | 453 +++++++ libgenx/libgenx/version.h.in | 37 + libgenx/manifest | 12 + libgenx/tests/.gitignore | 8 + libgenx/tests/basics/buildfile | 3 + libgenx/tests/basics/driver.c | 41 + libgenx/tests/basics/testscript | 3 + libgenx/tests/build/.gitignore | 4 + libgenx/tests/build/bootstrap.build | 5 + libgenx/tests/build/root.build | 12 + libgenx/tests/buildfile | 1 + makefile | 20 - packages.manifest | 2 + 33 files changed, 3707 insertions(+), 3349 deletions(-) create mode 100644 .gitattributes create mode 100644 README.md create mode 100644 buildfile delete mode 100644 char-props.c delete mode 100644 genx.c delete mode 100644 genx.h create mode 100644 libgenx/.gitignore create mode 120000 libgenx/LICENSE create mode 120000 libgenx/README.md create mode 100644 libgenx/build/.gitignore create mode 100644 libgenx/build/bootstrap.build create mode 100644 libgenx/build/export.build create mode 100644 libgenx/build/root.build create mode 100644 libgenx/buildfile create mode 100644 libgenx/libgenx/.gitignore create mode 100644 libgenx/libgenx/buildfile create mode 100644 libgenx/libgenx/char-props.c create mode 100644 libgenx/libgenx/export.h create mode 100644 libgenx/libgenx/genx.c create mode 100644 libgenx/libgenx/genx.h create mode 100644 libgenx/libgenx/version.h.in create mode 100644 libgenx/manifest create mode 100644 libgenx/tests/.gitignore create mode 100644 libgenx/tests/basics/buildfile create mode 100644 libgenx/tests/basics/driver.c create mode 100644 libgenx/tests/basics/testscript create mode 100644 libgenx/tests/build/.gitignore create mode 100644 libgenx/tests/build/bootstrap.build create mode 100644 libgenx/tests/build/root.build create mode 100644 libgenx/tests/buildfile delete mode 100644 makefile create mode 100644 packages.manifest diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1631641 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,19 @@ +# This is a good default: files that are auto-detected by git to be text are +# converted to the platform-native line ending (LF on Unix, CRLF on Windows) +# in the working tree and to LF in the repository. +# +* text=auto + +# Use `eol=crlf` for files that should have the CRLF line ending both in the +# working tree (even on Unix) and in the repository. +# +#*.bat text eol=crlf + +# Use `eol=lf` for files that should have the LF line ending both in the +# working tree (even on Windows) and in the repository. +# +#*.sh text eol=lf + +# Use `binary` to make sure certain files are never auto-detected as text. +# +#*.png binary diff --git a/.gitignore b/.gitignore index 5ae09b2..dd04439 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ -# Compiler/linker output. +.bdep/ + +# Local default options files. # -*.o +.build2/local/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..3a0d8c4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# libgenx - XML serializer C library + +A portable, dependency-free, MIT-licensed XML push-serializer library for C. + +``` +#include + +int main() +{ + genxWriter w = genxNew(NULL, NULL, stdout); + genxStartDocSender(w, &stdioSender); + genxStartElementLiteral(w, (utf8)"http://example.org/1", (utf8)"greeting"); + genxAddAttributeLiteral(w, (utf8)"http://example.com/2", (utf8)"type", (utf8)"well-formed"); + genxAddText(w, (utf8)"Hello world!"); + genxEndElement(w); + genxEndDocument(w); + genxDispose(w); +} +``` + +This is a cleaned up, fixed, and enhanced version of [Tim Bray's +Genx](https://www.tbray.org/ongoing/genx/docs/Guide.html). Note that support +for `genxStartDocFile()` (which depends on ``) has been removed. +See the `basics` test for an example of how to achieve the same yourself. diff --git a/buildfile b/buildfile new file mode 100644 index 0000000..aad5e21 --- /dev/null +++ b/buildfile @@ -0,0 +1,5 @@ +# Glue buildfile that "pulls" all the packages in the project. +# +import pkgs = */ + +./: $pkgs diff --git a/char-props.c b/char-props.c deleted file mode 100644 index 334ffc2..0000000 --- a/char-props.c +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Copyright (c) 2004 by Tim Bray and Sun Microsystems. - * Copyright (c) Code Synthesis Tools CC (see the LICENSE file). - * - * For copying permission, see the accompanying LICENSE file. - */ - -/* - * Construct character-properties tables for genx. - * Quite likely there's a better way. - * This version is generated semi-automatically from the source code of the - * XML specification via emacs global replace and keyboard macros - */ -#include "genx.h" - -static void charProp(char * p, int c, int prop) -{ - p[c] |= prop; -} - -static void rangeProp(char * p, size_t start, size_t end, int prop) -{ - size_t i; - for (i = start; i <= end; i++) - p[i] |= prop; -} - -void genxSetCharProps(char * p) -{ - size_t i; - - for (i = 0; i < GENX_CHAR_TABLE_SIZE; i++) - p[i] = 0; - - /* per XML 1.0 */ - charProp(p, 0x9, GENX_XML_CHAR); - charProp(p, 0xa, GENX_XML_CHAR); - charProp(p, 0xd, GENX_XML_CHAR); - rangeProp(p, 0x20, 0xff, GENX_XML_CHAR); - -#if GENX_CHAR_TABLE_SIZE == 0x10000 - rangeProp(p, 0x0100, 0xd7ff, GENX_XML_CHAR); - rangeProp(p, 0xe000, 0xfffd, GENX_XML_CHAR); -#endif - - /* Letter ::= BaseChar | Ideographic */ - rangeProp(p, 0x0041, 0x005A, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0061, 0x007A, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x00C0, 0x00D6, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x00D8, 0x00F6, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x00F8, 0x00FF, GENX_LETTER|GENX_NAMECHAR); - -#if GENX_CHAR_TABLE_SIZE == 0x10000 - - rangeProp(p, 0x0100, 0x0131, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0134, 0x013E, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0141, 0x0148, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x014A, 0x017E, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0180, 0x01C3, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x01CD, 0x01F0, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x01F4, 0x01F5, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x01FA, 0x0217, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0250, 0x02A8, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x02BB, 0x02C1, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0386, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0388, 0x038A, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x038C, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x038E, 0x03A1, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x03A3, 0x03CE, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x03D0, 0x03D6, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x03DA, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x03DC, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x03DE, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x03E0, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x03E2, 0x03F3, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0401, 0x040C, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x040E, 0x044F, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0451, 0x045C, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x045E, 0x0481, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0490, 0x04C4, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x04C7, 0x04C8, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x04CB, 0x04CC, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x04D0, 0x04EB, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x04EE, 0x04F5, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x04F8, 0x04F9, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0531, 0x0556, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0559, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0561, 0x0586, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x05D0, 0x05EA, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x05F0, 0x05F2, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0621, 0x063A, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0641, 0x064A, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0671, 0x06B7, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x06BA, 0x06BE, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x06C0, 0x06CE, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x06D0, 0x06D3, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x06D5, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x06E5, 0x06E6, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0905, 0x0939, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x093D, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0958, 0x0961, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0985, 0x098C, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x098F, 0x0990, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0993, 0x09A8, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x09AA, 0x09B0, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x09B2, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x09B6, 0x09B9, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x09DC, 0x09DD, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x09DF, 0x09E1, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x09F0, 0x09F1, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0A05, 0x0A0A, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0A0F, 0x0A10, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0A13, 0x0A28, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0A2A, 0x0A30, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0A32, 0x0A33, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0A35, 0x0A36, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0A38, 0x0A39, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0A59, 0x0A5C, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0A5E, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0A72, 0x0A74, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0A85, 0x0A8B, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0A8D, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0A8F, 0x0A91, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0A93, 0x0AA8, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0AAA, 0x0AB0, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0AB2, 0x0AB3, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0AB5, 0x0AB9, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0ABD, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0AE0, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0B05, 0x0B0C, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0B0F, 0x0B10, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0B13, 0x0B28, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0B2A, 0x0B30, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0B32, 0x0B33, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0B36, 0x0B39, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0B3D, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0B5C, 0x0B5D, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0B5F, 0x0B61, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0B85, 0x0B8A, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0B8E, 0x0B90, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0B92, 0x0B95, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0B99, 0x0B9A, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0B9C, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0B9E, 0x0B9F, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0BA3, 0x0BA4, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0BA8, 0x0BAA, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0BAE, 0x0BB5, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0BB7, 0x0BB9, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0C05, 0x0C0C, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0C0E, 0x0C10, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0C12, 0x0C28, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0C2A, 0x0C33, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0C35, 0x0C39, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0C60, 0x0C61, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0C85, 0x0C8C, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0C8E, 0x0C90, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0C92, 0x0CA8, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0CAA, 0x0CB3, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0CB5, 0x0CB9, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0CDE, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0CE0, 0x0CE1, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0D05, 0x0D0C, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0D0E, 0x0D10, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0D12, 0x0D28, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0D2A, 0x0D39, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0D60, 0x0D61, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0E01, 0x0E2E, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0E30, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0E32, 0x0E33, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0E40, 0x0E45, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0E81, 0x0E82, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0E84, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0E87, 0x0E88, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0E8A, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0E8D, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0E94, 0x0E97, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0E99, 0x0E9F, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0EA1, 0x0EA3, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0EA5, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0EA7, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0EAA, 0x0EAB, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0EAD, 0x0EAE, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0EB0, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0EB2, 0x0EB3, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0EBD, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0EC0, 0x0EC4, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0F40, 0x0F47, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0F49, 0x0F69, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x10A0, 0x10C5, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x10D0, 0x10F6, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x1100, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1102, 0x1103, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1105, 0x1107, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x1109, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x110B, 0x110C, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x110E, 0x1112, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x113C, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x113E, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x1140, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x114C, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x114E, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x1150, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1154, 0x1155, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x1159, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x115F, 0x1161, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x1163, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x1165, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x1167, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x1169, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x116D, 0x116E, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1172, 0x1173, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x1175, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x119E, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x11A8, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x11AB, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x11AE, 0x11AF, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x11B7, 0x11B8, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x11BA, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x11BC, 0x11C2, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x11EB, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x11F0, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x11F9, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1E00, 0x1E9B, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1EA0, 0x1EF9, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1F00, 0x1F15, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1F18, 0x1F1D, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1F20, 0x1F45, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1F48, 0x1F4D, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1F50, 0x1F57, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x1F59, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x1F5B, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x1F5D, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1F5F, 0x1F7D, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1F80, 0x1FB4, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1FB6, 0x1FBC, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x1FBE, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1FC2, 0x1FC4, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1FC6, 0x1FCC, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1FD0, 0x1FD3, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1FD6, 0x1FDB, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1FE0, 0x1FEC, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1FF2, 0x1FF4, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x1FF6, 0x1FFC, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x2126, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x212A, 0x212B, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x212E, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x2180, 0x2182, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x3041, 0x3094, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x30A1, 0x30FA, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x3105, 0x312C, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0xAC00, 0xD7A3, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x4E00, 0x9FA5, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x3007, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x3021, 0x3029, GENX_LETTER|GENX_NAMECHAR); - -#endif /* GENX_CHAR_TABLE_SIZE == 0x10000 */ - - /* - * NameChar ::= - * Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender - */ - - charProp(p, '.', GENX_NAMECHAR); - charProp(p, '-', GENX_NAMECHAR); - charProp(p, '_', GENX_NAMECHAR); - - rangeProp(p, 0x0030, 0x0039, GENX_NAMECHAR); - charProp(p, 0x00B7, GENX_LETTER|GENX_NAMECHAR); - -#if GENX_CHAR_TABLE_SIZE == 0x10000 - - rangeProp(p, 0x0660, 0x0669, GENX_NAMECHAR); - rangeProp(p, 0x06F0, 0x06F9, GENX_NAMECHAR); - rangeProp(p, 0x0966, 0x096F, GENX_NAMECHAR); - rangeProp(p, 0x09E6, 0x09EF, GENX_NAMECHAR); - rangeProp(p, 0x0A66, 0x0A6F, GENX_NAMECHAR); - rangeProp(p, 0x0AE6, 0x0AEF, GENX_NAMECHAR); - rangeProp(p, 0x0B66, 0x0B6F, GENX_NAMECHAR); - rangeProp(p, 0x0BE7, 0x0BEF, GENX_NAMECHAR); - rangeProp(p, 0x0C66, 0x0C6F, GENX_NAMECHAR); - rangeProp(p, 0x0CE6, 0x0CEF, GENX_NAMECHAR); - rangeProp(p, 0x0D66, 0x0D6F, GENX_NAMECHAR); - rangeProp(p, 0x0E50, 0x0E59, GENX_NAMECHAR); - rangeProp(p, 0x0ED0, 0x0ED9, GENX_NAMECHAR); - rangeProp(p, 0x0F20, 0x0F29, GENX_NAMECHAR); - rangeProp(p, 0x0300, 0x0345, GENX_NAMECHAR); - rangeProp(p, 0x0360, 0x0361, GENX_NAMECHAR); - rangeProp(p, 0x0483, 0x0486, GENX_NAMECHAR); - rangeProp(p, 0x0591, 0x05A1, GENX_NAMECHAR); - rangeProp(p, 0x05A3, 0x05B9, GENX_NAMECHAR); - rangeProp(p, 0x05BB, 0x05BD, GENX_NAMECHAR); - charProp(p, 0x05BF, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x05C1, 0x05C2, GENX_NAMECHAR); - charProp(p, 0x05C4, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x064B, 0x0652, GENX_NAMECHAR); - charProp(p, 0x0670, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x06D6, 0x06DC, GENX_NAMECHAR); - rangeProp(p, 0x06DD, 0x06DF, GENX_NAMECHAR); - rangeProp(p, 0x06E0, 0x06E4, GENX_NAMECHAR); - rangeProp(p, 0x06E7, 0x06E8, GENX_NAMECHAR); - rangeProp(p, 0x06EA, 0x06ED, GENX_NAMECHAR); - rangeProp(p, 0x0901, 0x0903, GENX_NAMECHAR); - charProp(p, 0x093C, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x093E, 0x094C, GENX_NAMECHAR); - charProp(p, 0x094D, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0951, 0x0954, GENX_NAMECHAR); - rangeProp(p, 0x0962, 0x0963, GENX_NAMECHAR); - rangeProp(p, 0x0981, 0x0983, GENX_NAMECHAR); - charProp(p, 0x09BC, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x09BE, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x09BF, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x09C0, 0x09C4, GENX_NAMECHAR); - rangeProp(p, 0x09C7, 0x09C8, GENX_NAMECHAR); - rangeProp(p, 0x09CB, 0x09CD, GENX_NAMECHAR); - charProp(p, 0x09D7, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x09E2, 0x09E3, GENX_NAMECHAR); - charProp(p, 0x0A02, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0A3C, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0A3E, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0A3F, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0A40, 0x0A42, GENX_NAMECHAR); - rangeProp(p, 0x0A47, 0x0A48, GENX_NAMECHAR); - rangeProp(p, 0x0A4B, 0x0A4D, GENX_NAMECHAR); - rangeProp(p, 0x0A70, 0x0A71, GENX_NAMECHAR); - rangeProp(p, 0x0A81, 0x0A83, GENX_NAMECHAR); - charProp(p, 0x0ABC, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0ABE, 0x0AC5, GENX_NAMECHAR); - rangeProp(p, 0x0AC7, 0x0AC9, GENX_NAMECHAR); - rangeProp(p, 0x0ACB, 0x0ACD, GENX_NAMECHAR); - rangeProp(p, 0x0B01, 0x0B03, GENX_NAMECHAR); - charProp(p, 0x0B3C, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0B3E, 0x0B43, GENX_NAMECHAR); - rangeProp(p, 0x0B47, 0x0B48, GENX_NAMECHAR); - rangeProp(p, 0x0B4B, 0x0B4D, GENX_NAMECHAR); - rangeProp(p, 0x0B56, 0x0B57, GENX_NAMECHAR); - rangeProp(p, 0x0B82, 0x0B83, GENX_NAMECHAR); - rangeProp(p, 0x0BBE, 0x0BC2, GENX_NAMECHAR); - rangeProp(p, 0x0BC6, 0x0BC8, GENX_NAMECHAR); - rangeProp(p, 0x0BCA, 0x0BCD, GENX_NAMECHAR); - charProp(p, 0x0BD7, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0C01, 0x0C03, GENX_NAMECHAR); - rangeProp(p, 0x0C3E, 0x0C44, GENX_NAMECHAR); - rangeProp(p, 0x0C46, 0x0C48, GENX_NAMECHAR); - rangeProp(p, 0x0C4A, 0x0C4D, GENX_NAMECHAR); - rangeProp(p, 0x0C55, 0x0C56, GENX_NAMECHAR); - rangeProp(p, 0x0C82, 0x0C83, GENX_NAMECHAR); - rangeProp(p, 0x0CBE, 0x0CC4, GENX_NAMECHAR); - rangeProp(p, 0x0CC6, 0x0CC8, GENX_NAMECHAR); - rangeProp(p, 0x0CCA, 0x0CCD, GENX_NAMECHAR); - rangeProp(p, 0x0CD5, 0x0CD6, GENX_NAMECHAR); - rangeProp(p, 0x0D02, 0x0D03, GENX_NAMECHAR); - rangeProp(p, 0x0D3E, 0x0D43, GENX_NAMECHAR); - rangeProp(p, 0x0D46, 0x0D48, GENX_NAMECHAR); - rangeProp(p, 0x0D4A, 0x0D4D, GENX_NAMECHAR); - charProp(p, 0x0D57, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0E31, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0E34, 0x0E3A, GENX_NAMECHAR); - rangeProp(p, 0x0E47, 0x0E4E, GENX_NAMECHAR); - charProp(p, 0x0EB1, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0EB4, 0x0EB9, GENX_NAMECHAR); - rangeProp(p, 0x0EBB, 0x0EBC, GENX_NAMECHAR); - rangeProp(p, 0x0EC8, 0x0ECD, GENX_NAMECHAR); - rangeProp(p, 0x0F18, 0x0F19, GENX_NAMECHAR); - charProp(p, 0x0F35, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0F37, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0F39, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0F3E, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0F3F, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0F71, 0x0F84, GENX_NAMECHAR); - rangeProp(p, 0x0F86, 0x0F8B, GENX_NAMECHAR); - rangeProp(p, 0x0F90, 0x0F95, GENX_NAMECHAR); - charProp(p, 0x0F97, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x0F99, 0x0FAD, GENX_NAMECHAR); - rangeProp(p, 0x0FB1, 0x0FB7, GENX_NAMECHAR); - charProp(p, 0x0FB9, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x20D0, 0x20DC, GENX_NAMECHAR); - charProp(p, 0x20E1, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x302A, 0x302F, GENX_NAMECHAR); - charProp(p, 0x3099, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x309A, GENX_LETTER|GENX_NAMECHAR); - - charProp(p, 0x02D0, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x02D1, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0387, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0640, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0E46, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x0EC6, GENX_LETTER|GENX_NAMECHAR); - charProp(p, 0x3005, GENX_LETTER|GENX_NAMECHAR); - rangeProp(p, 0x3031, 0x3035, GENX_NAMECHAR); - rangeProp(p, 0x309D, 0x309E, GENX_NAMECHAR); - rangeProp(p, 0x30FC, 0x30FE, GENX_NAMECHAR); - -#endif /* GENX_CHAR_TABLE_SIZE == 0x10000 */ -} diff --git a/genx.c b/genx.c deleted file mode 100644 index 5253f1a..0000000 --- a/genx.c +++ /dev/null @@ -1,2543 +0,0 @@ -/* - * Copyright (c) 2004 by Tim Bray and Sun Microsystems. - * Copyright (c) Code Synthesis Tools CC (see the LICENSE file). - * - * For copying permission, see the accompanying LICENSE file. - */ - -#define GENX_VERSION "cs-1" - -/* Use snprintf() unless instructed otherwise. */ -#ifndef GENX_SNPRINTF -# define GENX_SNPRINTF 1 -#endif - -#if defined(GENX_CUSTOM_ALLOC) != defined(GENX_CUSTOM_FREE) -# error both GENX_CUSTOM_ALLOC and GENX_CUSTOM_FREE must be defined -#endif - -#include -#include -#include - -#include "genx.h" - -#define Boolean int -#define True 1 -#define False 0 -#define STRLEN_XMLNS_COLON 6 - - -/******************************* - * writer state - */ -typedef enum -{ - SEQUENCE_NO_DOC, - SEQUENCE_PRE_DOC, - SEQUENCE_POST_DOC, - SEQUENCE_START_TAG, - SEQUENCE_ATTRIBUTES, - SEQUENCE_START_ATTR, - SEQUENCE_CONTENT -} writerSequence; - -/******************************* - * generic pointer list - */ -typedef struct -{ - genxWriter writer; - size_t count; - size_t space; - void * * pointers; -} plist; - -/******************************* - * text collector, for attribute values - */ -typedef struct -{ - utf8 buf; - size_t used; - size_t space; -} collector; - -/******************************* - * Structs with opaquely-exposed handles - */ - -/* - * This one's tricky, to handle stacking namespaces - * 'declaration' is the current attribute which would be used to - * declare the currently-effective prefix - * 'defDeclaration' is a appropriate declaration when this is being - * used with the default prefix as passed to genxDeclareNamespace - * baroque is true if this namespace has been used with more than one - * prefix, or is the default namespace but has been unset - */ -struct genxNamespace_rec -{ - genxWriter writer; - utf8 name; - size_t declCount; - Boolean baroque; - genxAttribute declaration; - genxAttribute defaultDecl; -}; - -struct genxElement_rec -{ - genxWriter writer; - utf8 name; - genxNamespace ns; -}; - -typedef enum -{ - ATTR_NSDECL, - ATTR_NAKED, - ATTR_PREFIXED -} attrType; - -struct genxAttribute_rec -{ - genxWriter writer; - utf8 name; - genxNamespace ns; - collector value; - int provided; /* provided for current element? */ - attrType atype; - genxAttribute next; /* Attribute order chain if not canonical. */ -}; - -/******************************* - * genx's sandbox - */ -struct genxWriter_rec -{ - genxSender * sender; - genxStatus status; - writerSequence sequence; - char xmlChars[GENX_CHAR_TABLE_SIZE]; - void * userData; - int nextPrefix; - utf8 empty; - Boolean defaultNsDeclared; - genxAttribute xmlnsEquals; - genxElement nowStarting; - genxAttribute nowStartingAttr; - plist namespaces; - plist elements; - plist attributes; - plist prefixes; - plist stack; - struct genxAttribute_rec arec; /* Dummy attribute used for lookup. */ - char * etext[100]; - genxAlloc alloc; - genxDealloc dealloc; - - /* Pretty-printing state */ - int ppIndent; - int ppDepth; - int ppSuspendDepth; /* Non-0 means we are suspended. */ - Boolean ppSimple; - - /* Canonicalization. */ - Boolean canonical; - - /* Attrbute order when not canonical. */ - genxAttribute firstAttribute; - genxAttribute lastAttribute; -}; - -/******************************* - * Forward declarations - */ -static genxAttribute declareAttribute(genxWriter w, genxNamespace ns, - constUtf8 name, constUtf8 valuestr, - genxStatus * statusP); -static genxStatus addNamespace(genxNamespace ns, constUtf8 prefix); -static genxStatus unsetDefaultNamespace(genxWriter w); -static genxStatus addAttribute(genxAttribute a, constUtf8 valuestr); -void genxSetCharProps(char * p); - -/******************************* - * End of declarations - */ - -/******************************* - * private memory utilities - */ -static void * allocate(genxWriter w, size_t bytes) -{ - if (w->alloc) - return (void *) (*w->alloc)(w->userData, bytes); - else -#ifdef GENX_CUSTOM_ALLOC - return (void *) GENX_CUSTOM_ALLOC(bytes); -#else - return (void *) malloc(bytes); -#endif -} - -static void deallocate(genxWriter w, void * data) -{ - if (w->dealloc) - (*w->dealloc)(w->userData, data); - else if (w->alloc == NULL) -#ifdef GENX_CUSTOM_FREE - GENX_CUSTOM_FREE(data); -#else - free(data); -#endif - -} - -static utf8 copy(genxWriter w, constUtf8 from) -{ - utf8 temp; - size_t sl = strlen((const char *) from); - - if ((temp = (utf8) allocate(w, sl + 1)) == NULL) - return NULL; - - memcpy(temp, from, sl); - temp[sl] = 0; - return temp; -} - -static genxStatus initCollector(genxWriter w, collector * c) -{ - c->space = 100; - if ((c->buf = (utf8) allocate(w, c->space)) == NULL) - return GENX_ALLOC_FAILED; - c->used = 0; - return GENX_SUCCESS; -} - -static genxStatus growCollector(genxWriter w, collector * c, size_t size) -{ - utf8 newSpace; - - c->space = size * 2; - if ((newSpace = (utf8) allocate(w, c->space)) == NULL) - return GENX_ALLOC_FAILED; - - memcpy(newSpace, c->buf, c->used); - newSpace[c->used] = 0; - deallocate(w, c->buf); - c->buf = newSpace; - return GENX_SUCCESS; -} - -static void startCollect(collector * c) -{ - c->used = 0; -} -static void endCollect(collector * c) -{ - c->buf[c->used] = 0; -} - -static genxStatus collectString(genxWriter w, collector * c, constUtf8 string) -{ - size_t sl = strlen((const char *) string); - - if (sl >= c->space) - if ((w->status = growCollector(w, c, sl)) != GENX_SUCCESS) - return GENX_ALLOC_FAILED; - - memcpy(c->buf, string, sl); - c->buf[sl] = 0; - return GENX_SUCCESS; -} - -/* Note: does not add the trailing '\0' (done by endCollect() call). */ -#define collectPiece(w,c,d,size) {if (((c)->used+(size))>=(c)->space){if (((w)->status=growCollector(w,c,(c)->used+(size)))!=GENX_SUCCESS) return (w)->status;}memcpy((char *)(c)->buf+(c)->used,d,size);(c)->used+=size;} - -/******************************* - * private list utilities - */ -static genxStatus initPlist(genxWriter w, plist * pl) -{ - pl->writer = w; - pl->count = 0; - pl->space = 10; - pl->pointers = (void * *) allocate(w, pl->space * sizeof(void *)); - if (pl->pointers == NULL) - return GENX_ALLOC_FAILED; - - return GENX_SUCCESS; -} - -/* - * make room in a plist - */ -static Boolean checkExpand(plist * pl) -{ - void * * newlist; - size_t i; - - if (pl->count < pl->space) - return True; - - pl->space *= 2; - newlist = (void * *) allocate(pl->writer, pl->space * sizeof(void *)); - if (newlist == NULL) - return False; - for (i = 0; i < pl->count; i++) - newlist[i] = pl->pointers[i]; - deallocate(pl->writer, pl->pointers); - pl->pointers = newlist; - - return True; -} - -/* - * stick something on the end of a plist - */ -static genxStatus listAppend(plist * pl, void * pointer) -{ - if (!checkExpand(pl)) - return GENX_ALLOC_FAILED; - - pl->pointers[pl->count++] = pointer; - return GENX_SUCCESS; -} - -/* - * insert in place, shuffling up - */ -static genxStatus listInsert(plist * pl, void * pointer, size_t at) -{ - size_t i; - - if (!checkExpand(pl)) - return GENX_ALLOC_FAILED; - - for (i = pl->count; i > at; i--) - pl->pointers[i] = pl->pointers[i - 1]; - pl->count++; - - pl->pointers[at] = pointer; - return GENX_SUCCESS; -} - -/******************************* - * list lookups - */ - -static genxNamespace findNamespace(plist * pl, constUtf8 uri) -{ - size_t i; - genxNamespace * nn = (genxNamespace *) pl->pointers; - - for (i = 0; i < pl->count; i++) - if (strcmp((char *) uri, (const char *) nn[i]->name) == 0) - return nn[i]; - - return NULL; -} - -static genxElement findElement(plist * pl, constUtf8 xmlns, constUtf8 name) -{ - size_t i; - genxElement * ee = (genxElement *) pl->pointers; - - for (i = 0; i < pl->count; i++) - { - if (xmlns == NULL) - { - if (ee[i]->ns == NULL && strcmp((const char *) name, - (const char *) ee[i]->name) == 0) - return ee[i]; - } - else - { - if (ee[i]->ns != NULL && - strcmp((const char *) xmlns, (const char *) ee[i]->ns->name) == 0 && - strcmp((const char *) name, (const char *) ee[i]->name) == 0) - return ee[i]; - } - } - - return NULL; -} - -/* - * store & intern a prefix, after giving it the - * "xmlns:" prefix. Don't allow storing the same one twice unless 'force' - * is set. - */ -static utf8 storePrefix(genxWriter w, constUtf8 prefix, Boolean force) -{ - int high, low; - utf8 * pp = (utf8 *) w->prefixes.pointers; - unsigned char buf[1024]; - - if (prefix[0] == 0) - prefix = (utf8) "xmlns"; - else - { - size_t pl = strlen((const char *) prefix); - - if (pl > sizeof(buf) - (6 + 1)) - { - w->status = GENX_BAD_NAMESPACE_NAME; - return NULL; - } - - memcpy (buf, "xmlns:", 6); - memcpy (buf + 6, prefix, pl); - buf[pl + 6] = 0; - - prefix = buf; - } - - high = (int) w->prefixes.count; - low = -1; - while (high - low > 1) - { - int probe = (high + low) / 2; - if (strcmp((const char *) prefix, (const char *) pp[probe]) < 0) - high = probe; - else - low = probe; - } - - /* already there? */ - if (low != -1 && strcmp((const char *) prefix, (const char *) pp[low]) == 0) - { - if (force) - return pp[low]; - - w->status = GENX_DUPLICATE_PREFIX; - return NULL; - } - - /* copy & insert */ - if ((prefix = copy(w, prefix)) == NULL) - { - w->status = GENX_ALLOC_FAILED; - return NULL; - } - - w->status = listInsert(&w->prefixes, (void *) prefix, (size_t) high); - if (w->status != GENX_SUCCESS) - return NULL; - - return (utf8) prefix; -} - -/******************************* - * UTF8 bit-banging - */ - -/* - * Retrieve the character pointed at, and advance the pointer; return -1 on - * error - */ -int genxNextUnicodeChar(constUtf8 * sp) -{ - utf8 s = (utf8) *sp; - int c; - - if (*s == 0) - return -1; - - if (*s < 0x80) - c = *s++; - - /* all this encoding sanity-checking taken from section 3.10 of Unicode 4 */ - else if (*s < 0xc2) - goto malformed; - - /* 2-byte encodings, first byte c2 .. df */ - else if (*s < 0xe0) - { - c = (*s++ & 0x1f) << 6; - - /* - * for this common idiom, if ((c & 0xc0) != 0x80) is slightly faster - * on MacOS (PPC) - */ - if (*s < 0x80 || *s > 0xbf) - goto malformed; - - c |= *s++ & 0x3f; - } - - /* 3-byte encodings, first byte e0 .. ef */ - else if (*s < 0xf0) - { - int b0 = *s; - c = (*s++ & 0x0f) << 12; - - if ((b0 == 0xe0 && (*s < 0xa0 || *s > 0xbf)) || - (b0 < 0xed && (*s < 0x80 || *s > 0xbf)) || - (b0 == 0xed && (*s < 0x80 || *s > 0x9f)) || - (b0 > 0xed && (*s < 0x80 || *s > 0xbf))) - goto malformed; - - c |= (*s++ & 0x3f) << 6; - - if (*s < 0x80 || *s > 0xbf) - goto malformed; - - c |= *s++ & 0x3f; - } - - /* 4-byte encodings, first byte f0 .. f4 */ - else if (*s < 0xf5) - { - int b0 = *s; - c = (*s++ & 0x07) << 18; - - if ((b0 == 0xf0 && (*s < 0x90 || *s > 0xbf)) || - (b0 < 0xf4 && (*s < 0x80 || *s > 0xbf)) || - (b0 >= 0xf4 && (*s < 0x80 || *s > 0x8f))) - goto malformed; - - c |= (*s++ & 0x3f) << 12; - - if (*s < 0x80 || *s > 0xbf) - goto malformed; - - c |= (*s++ & 0x3f) << 6; - - if (*s < 0x80 || *s > 0xbf) - goto malformed; - - c |= *s++ & 0x3f; - } - else - goto malformed; - - *sp = s; - return c; - - /* - * this is needed by scrubText, which wants to get the pointer moved - * past the problem area. - */ -malformed: - if (*s) - ++s; - *sp = s; - return -1; -} - -static Boolean isXMLChar(genxWriter w, int c) -{ - if (c < 0) - return False; - else if (c < GENX_CHAR_TABLE_SIZE) - return (int) w->xmlChars[c]; - else - return (c <= 0x10ffff); -} - -static Boolean isLetter(genxWriter w, int c) -{ - if (c < 0 || c > 0xffff) - return False; - else - { -#if GENX_CHAR_TABLE_SIZE == 0x10000 - return w->xmlChars[c] & GENX_LETTER; -#else - return c < GENX_CHAR_TABLE_SIZE ? (w->xmlChars[c] & GENX_LETTER) : True; -#endif - } -} - -static Boolean isNameChar(genxWriter w, int c) -{ - if (c < 0 || c > 0xffff) - return False; - else - { -#if GENX_CHAR_TABLE_SIZE == 0x10000 - return w->xmlChars[c] & GENX_NAMECHAR; -#else - return c < GENX_CHAR_TABLE_SIZE ? (w->xmlChars[c] & GENX_NAMECHAR) : True; -#endif - } -} - -/******************************* - * Constructors, setters/getters - */ - -/* - * Construct a new genxWriter - */ -genxWriter genxNew(genxAlloc alloc, genxDealloc dealloc, void * userData) -{ - genxWriter w; - genxNamespace xml; - - if (alloc) - w = (genxWriter) (*alloc)(userData, sizeof(struct genxWriter_rec)); - else -#ifdef GENX_CUSTOM_ALLOC - w = (genxWriter) GENX_CUSTOM_ALLOC(sizeof(struct genxWriter_rec)); -#else - w = (genxWriter) malloc(sizeof(struct genxWriter_rec)); -#endif - - if (w == NULL) - return NULL; - - w->status = GENX_SUCCESS; - w->alloc = alloc; - w->dealloc = dealloc; - w->userData = userData; - w->sequence = SEQUENCE_NO_DOC; - - if (initPlist(w, &w->namespaces) != GENX_SUCCESS || - initPlist(w, &w->elements) != GENX_SUCCESS || - initPlist(w, &w->attributes) != GENX_SUCCESS || - initPlist(w, &w->prefixes) != GENX_SUCCESS || - initPlist(w, &w->stack) != GENX_SUCCESS) - return NULL; - - if ((w->status = initCollector(w, &w->arec.value)) != GENX_SUCCESS) - return NULL; - - if ((w->empty = copy(w, (utf8) "")) == NULL) - { - w->status = GENX_ALLOC_FAILED; - return NULL; - } - - w->xmlnsEquals = declareAttribute(w, NULL, (utf8) "xmlns", NULL, &w->status); - if (w->xmlnsEquals == NULL || w->status != GENX_SUCCESS) - return NULL; - w->defaultNsDeclared = False; - - w->nextPrefix = 1; - - genxSetCharProps(w->xmlChars); - - w->etext[GENX_SUCCESS] = "success"; - w->etext[GENX_BAD_UTF8] = "invalid UTF-8"; - w->etext[GENX_NON_XML_CHARACTER] = "non-XML character"; - w->etext[GENX_BAD_NAME] = "invalid name"; - w->etext[GENX_ALLOC_FAILED] = "memory allocation failed"; - w->etext[GENX_BAD_NAMESPACE_NAME] = "invalid namespace name"; - w->etext[GENX_INTERNAL_ERROR] = "internal error"; - w->etext[GENX_DUPLICATE_PREFIX] = "duplicate prefix"; - w->etext[GENX_SEQUENCE_ERROR] = "call out of sequence"; - w->etext[GENX_NO_START_TAG] = "no start tag for end element call"; - w->etext[GENX_IO_ERROR] = "io error"; - w->etext[GENX_MISSING_VALUE] = "missing attribute value"; - w->etext[GENX_MALFORMED_COMMENT] = "malformed comment body"; - w->etext[GENX_MALFORMED_PI] = "?> in PI"; - w->etext[GENX_XML_PI_TARGET] = "target of PI matches [xX][mM][lL]"; - w->etext[GENX_DUPLICATE_ATTRIBUTE] = "duplicate attribute"; - w->etext[GENX_ATTRIBUTE_IN_DEFAULT_NAMESPACE] = - "attribute is default namespace"; - w->etext[GENX_DUPLICATE_NAMESPACE] = - "namespace declared twice with different prefixes"; - w->etext[GENX_BAD_DEFAULT_DECLARATION] = - "default namespace declared on an element which is not in a namespace"; - - /* the xml: namespace is pre-wired */ - xml = genxDeclareNamespace(w, (utf8) "http://www.w3.org/XML/1998/namespace", - (utf8) "xml", &w->status); - if (xml == NULL) - return NULL; - xml->declCount = 1; - xml->declaration = xml->defaultDecl; - - w->ppIndent = 0; /* Pretty-printing is disabled by default. */ - w->canonical = False; /* No canonicalization by default. */ - - w->firstAttribute = NULL; - w->lastAttribute = NULL; - return w; -} - -genxStatus genxReset (genxWriter w) -{ - size_t i; - - /* Clean up the stack. */ - w->stack.count = 0; - - /* Reset namespace declaration counts. The first entry is the pre-wired - xml namespace. */ - ((genxNamespace) w->namespaces.pointers[0])->declCount = 1; - - for (i = 1; i < w->namespaces.count; i++) - { - ((genxNamespace) w->namespaces.pointers[i])->declCount = 0; - ((genxNamespace) w->namespaces.pointers[i])->baroque = False; - } - - /* Clear provided attributes. */ - for (i = 0; i < w->attributes.count; i++) - ((genxAttribute) w->attributes.pointers[i])->provided = False; - - /* Clear attribute list. */ - if (!w->canonical) - { - while (w->firstAttribute != NULL) - { - genxAttribute t = w->firstAttribute->next; - w->firstAttribute->next = NULL; - w->firstAttribute = t; - } - - w->lastAttribute = NULL; - } - - w->status = GENX_SUCCESS; - w->sequence = SEQUENCE_NO_DOC; - - return w->status; -} - - -/* - * get/set userData - */ -void genxSetUserData(genxWriter w, void * userData) -{ - w->userData = userData; -} -void * genxGetUserData(genxWriter w) -{ - return w->userData; -} - -/* - * get/set pretty-printing - */ -genxStatus genxSetPrettyPrint(genxWriter w, int ind) -{ - if (w->sequence == SEQUENCE_NO_DOC) - w->ppIndent = ind; - else - w->status = GENX_SEQUENCE_ERROR; - - return w->status; -} - -int genxGetPrettyPrint(genxWriter w) -{ - return w->ppIndent; -} - -/* - * Suspend/resume pretty-printing. - */ -genxStatus genxSuspendPrettyPrint(genxWriter w) -{ - int d = w->ppDepth; - - if (w->ppIndent == 0) - return w->status = GENX_SEQUENCE_ERROR; - - switch (w->sequence) - { - case SEQUENCE_START_TAG: - case SEQUENCE_ATTRIBUTES: - d++; /* No start tag written, still outer depth. */ - case SEQUENCE_CONTENT: - break; - default: - return w->status = GENX_SEQUENCE_ERROR; - } - - if (w->ppSuspendDepth == 0) /* Ignore nested suspend/resume calls. */ - w->ppSuspendDepth = d; - - return w->status; -} - -genxStatus genxResumePrettyPrint(genxWriter w) -{ - int d = w->ppDepth; - - if (w->ppIndent == 0 || w->ppSuspendDepth == 0) - return w->status = GENX_SEQUENCE_ERROR; - - switch (w->sequence) - { - case SEQUENCE_START_TAG: - case SEQUENCE_ATTRIBUTES: - d++; /* No start tag written, still outer depth. */ - case SEQUENCE_CONTENT: - break; - default: - return w->status = GENX_SEQUENCE_ERROR; - } - - if (w->ppSuspendDepth == d) /* Ignore nested suspend/resume calls. */ - w->ppSuspendDepth = 0; - - return w->status; -} - -int genxPrettyPrintSuspended(genxWriter w) -{ - return w->ppSuspendDepth; -} - -/* - * get/set canonicalization. - */ -genxStatus genxSetCanonical(genxWriter w, int flag) -{ - if (w->sequence == SEQUENCE_NO_DOC) - w->canonical = flag; - else - w->status = GENX_SEQUENCE_ERROR; - - return w->status; -} - -int genxGetCanonical(genxWriter w) -{ - return w->canonical; -} - -/* - * get/set allocator - */ -void genxSetAlloc(genxWriter w, genxAlloc alloc) -{ - w->alloc = alloc; -} - -void genxSetDealloc(genxWriter w, genxDealloc dealloc) -{ - w->dealloc = dealloc; -} - -genxAlloc genxGetAlloc(genxWriter w) -{ - return w->alloc; -} - -genxDealloc genxGetDealloc(genxWriter w) -{ - return w->dealloc; -} - -/* - * Clean up - */ -void genxDispose(genxWriter w) -{ - size_t i; - genxNamespace * nn = (genxNamespace *) w->namespaces.pointers; - genxElement * ee = (genxElement *) w->elements.pointers; - genxAttribute * aa = (genxAttribute *) w->attributes.pointers; - utf8 * pp = (utf8 *) w->prefixes.pointers; - - for (i = 0; i < w->namespaces.count; i++) - { - deallocate(w, nn[i]->name); - deallocate(w, nn[i]); - } - - for (i = 0; i < w->elements.count; i++) - { - deallocate(w, ee[i]->name); - deallocate(w, ee[i]); - } - - for (i = 0; i < w->attributes.count; i++) - { - deallocate(w, aa[i]->name); - deallocate(w, aa[i]->value.buf); - deallocate(w, aa[i]); - } - - for(i = 0; i < w->prefixes.count; i++) - deallocate(w, pp[i]); - - deallocate(w, w->namespaces.pointers); - deallocate(w, w->elements.pointers); - deallocate(w, w->attributes.pointers); - deallocate(w, w->prefixes.pointers); - deallocate(w, w->stack.pointers); - - deallocate(w, w->arec.value.buf); - - deallocate(w, w->empty); - - /* how Oscar dealt with Igli */ - deallocate(w, w); -} - -/******************************* - * External utility routines - */ - -/* - * scan a buffer and report problems with UTF-8 encoding or non-XML characters - */ -genxStatus genxCheckText(genxWriter w, constUtf8 s) -{ - while (*s) - { - int c = genxNextUnicodeChar(&s); - if (c == -1) - return GENX_BAD_UTF8; - - if (!isXMLChar(w, c)) - return GENX_NON_XML_CHARACTER; - } - return GENX_SUCCESS; -} - -/* - * Purify some text - */ -int genxScrubText(genxWriter w, constUtf8 in, utf8 out) -{ - int problems = 0; - constUtf8 last = in; - - while (*in) - { - int c = genxNextUnicodeChar(&in); - if (c == -1) - { - problems++; - last = in; - continue; - } - - if (!isXMLChar(w, c)) - { - problems++; - last = in; - continue; - } - - while (last < in) - *out++ = *last++; - } - *out = 0; - return problems; -} - -/* - * check one character - */ -int genxCharClass(genxWriter w, int c) -{ - int ret = 0; - - if (isXMLChar(w, c)) - ret |= GENX_XML_CHAR; - if (isNameChar(w, c)) - ret |= GENX_NAMECHAR; - if (isLetter(w, c)) - ret |= GENX_LETTER; - return ret; -} - -static genxStatus checkNCName(genxWriter w, constUtf8 name) -{ - int c; - - if (name == NULL || *name == 0) - return GENX_BAD_NAME; - - c = genxNextUnicodeChar(&name); - if (!isLetter(w, c) && c != ':' && c != '_') - return GENX_BAD_NAME; - - while (*name) - { - c = genxNextUnicodeChar(&name); - if (c == -1) - return GENX_BAD_UTF8; - if (!isNameChar(w, c)) - return GENX_BAD_NAME; - } - return GENX_SUCCESS; -} - -char * genxGetErrorMessage(genxWriter w, genxStatus status) -{ - return w->etext[status]; -} -char * genxLastErrorMessage(genxWriter w) -{ - return w->etext[w->status]; -} - -/******************************* - * Declarations: namespace/element/attribute - */ - -/* - * DeclareNamespace - by far the most complex routine in Genx - */ -genxNamespace genxDeclareNamespace(genxWriter w, constUtf8 uri, - constUtf8 defaultPref, - genxStatus * statusP) -{ - genxNamespace ns; - genxAttribute defaultDecl; - unsigned char newPrefix[100]; - - if (uri == NULL || uri[0] == 0) - { - w->status = GENX_BAD_NAMESPACE_NAME; - goto busted; - } - - if ((w->status = genxCheckText(w, uri)) != GENX_SUCCESS) - goto busted; - - /* if a prefix is provided, it has to be an NCname */ - if (defaultPref != NULL && defaultPref[0] != 0 && - (w->status = checkNCName(w, defaultPref)) != GENX_SUCCESS) - goto busted; - - /* previously declared? */ - if ((ns = findNamespace(&w->namespaces, uri))) - { - /* just a lookup, really */ - if ((defaultPref == NULL) || - (defaultPref[0] == 0 && ns->defaultDecl == w->xmlnsEquals) || - (strcmp((const char *) ns->defaultDecl->name + STRLEN_XMLNS_COLON, - (const char *) defaultPref) == 0)) - { - w->status = *statusP = GENX_SUCCESS; - return ns; - } - } - - /* wasn't already declared */ - else - { - /* make a default prefix if none provided */ - if (defaultPref == NULL) - { -#if GENX_SNPRINTF - snprintf((char *) newPrefix, sizeof(newPrefix), "g%d", w->nextPrefix++); -#else - sprintf((char *) newPrefix, "g%d", w->nextPrefix++); -#endif - defaultPref = newPrefix; - } - - ns = (genxNamespace) allocate(w, sizeof(struct genxNamespace_rec)); - if (ns == NULL) - { - w->status = GENX_ALLOC_FAILED; - goto busted; - } - ns->writer = w; - ns->baroque = False; - - if ((ns->name = copy(w, uri)) == NULL) - { - w->status = GENX_ALLOC_FAILED; - goto busted; - } - - if ((w->status = listAppend(&w->namespaces, ns)) != GENX_SUCCESS) - goto busted; - ns->defaultDecl = ns->declaration = NULL; - ns->declCount = 0; - } - - if (defaultPref[0] == 0) - { - if (w->defaultNsDeclared) - { - w->status = GENX_DUPLICATE_PREFIX; - goto busted; - } - defaultDecl = w->xmlnsEquals; - w->defaultNsDeclared = True; - } - else - { - /* this catches dupes too */ - if ((defaultPref = storePrefix(w, defaultPref, False)) == NULL) - goto busted; - - defaultDecl = declareAttribute(w, NULL, defaultPref, ns->name, statusP); - if (defaultDecl == NULL || *statusP != GENX_SUCCESS) - { - w->status = *statusP; - return NULL; - } - } - - if (ns->defaultDecl != NULL && defaultDecl != ns->defaultDecl) - ns->baroque = True; - ns->defaultDecl = defaultDecl; - - *statusP = GENX_SUCCESS; - return ns; - -busted: - *statusP = w->status; - return NULL; -} - -/* - * get namespace prefix - */ -utf8 genxGetNamespacePrefix(genxNamespace ns) -{ - if (ns->declaration == NULL) - return NULL; - - if (ns->declaration == ns->writer->xmlnsEquals) - return ns->writer->empty; - - return ns->declaration->name + STRLEN_XMLNS_COLON; -} - -/* - * DeclareElement - see genx.h for details - */ -genxElement genxDeclareElement(genxWriter w, - genxNamespace ns, constUtf8 name, - genxStatus * statusP) -{ - genxElement old; - genxElement el; - - if ((w->status = checkNCName(w, name)) != GENX_SUCCESS) - { - *statusP = w->status; - return NULL; - } - - /* already declared? */ - old = findElement(&w->elements, (ns == NULL) ? NULL : ns->name, name); - if (old) - return old; - - if ((el = (genxElement) allocate(w, sizeof(struct genxElement_rec))) == NULL) - { - w->status = *statusP = GENX_ALLOC_FAILED; - return NULL; - } - - el->writer = w; - el->ns = ns; - if ((el->name = copy(w, name)) == NULL) - { - w->status = *statusP = GENX_ALLOC_FAILED; - return NULL; - } - - if ((w->status = listAppend(&w->elements, el)) != GENX_SUCCESS) - { - *statusP = w->status; - return NULL; - } - - *statusP = GENX_SUCCESS; - return el; -} - -/* - * C14n ordering for attributes: - * - first, namespace declarations by the prefix being declared - * - second, unprefixed attributes by attr name - * - third, prefixed attrs by ns uri then local part - */ -static int orderAttributes(genxAttribute a1, genxAttribute a2) -{ - if (a1->atype == a2->atype) - { - if (a1->atype == ATTR_PREFIXED && a1->ns != a2->ns) - return strcmp((const char *) a1->ns->name, (const char *) a2->ns->name); - else - return strcmp((const char *) a1->name, (const char *) a2->name); - } - - else if (a1->atype == ATTR_NSDECL) - return -1; - - else if (a1->atype == ATTR_NAKED) - { - if (a2->atype == ATTR_NSDECL) - return 1; - else - return -1; - } - - else - return 1; -} - -/* - * internal declare-attribute. This one allows colonized values for - * names, so that you can declare xmlns:-type attributes - */ -static genxAttribute declareAttribute(genxWriter w, genxNamespace ns, - constUtf8 name, constUtf8 valuestr, - genxStatus * statusP) -{ - int high, low; - genxAttribute * aa = (genxAttribute *) w->attributes.pointers; - genxAttribute a; - - w->arec.ns = ns; - w->arec.name = (utf8) name; - - if (ns) - w->arec.atype = ATTR_PREFIXED; - else if (strncmp((const char *) name, "xmlns", STRLEN_XMLNS_COLON - 1) == 0) - w->arec.atype = ATTR_NSDECL; - else - w->arec.atype = ATTR_NAKED; - - if (ns && (ns->defaultDecl == w->xmlnsEquals)) - { - w->status = GENX_ATTRIBUTE_IN_DEFAULT_NAMESPACE; - goto busted; - } - - /* attribute list has to be kept sorted per c14n rules */ - high = (int) w->attributes.count; - low = -1; - while (high - low > 1) - { - int probe = (high + low) / 2; - if (orderAttributes(&w->arec, aa[probe]) < 0) - high = probe; - else - low = probe; - } - - /* if it was already there */ - if (low != -1 && orderAttributes(&w->arec, aa[low]) == 0) - return aa[low]; - - /* not there, build it */ - a = (genxAttribute) allocate(w, sizeof(struct genxAttribute_rec)); - if (a == NULL) - { - w->status = GENX_ALLOC_FAILED; - goto busted; - } - - a->writer = w; - a->ns = ns; - a->provided = False; - a->atype = w->arec.atype; - a->next = NULL; - - if ((a->name = copy(w, name)) == NULL) - { - w->status = GENX_ALLOC_FAILED; - goto busted; - } - - if ((w->status = initCollector(w, &a->value)) != GENX_SUCCESS) - goto busted; - - if (valuestr) - if ((w->status = collectString(w, &a->value, valuestr)) != GENX_SUCCESS) - goto busted; - - w->status = listInsert(&w->attributes, a, (size_t) high); - if (w->status != GENX_SUCCESS) - goto busted; - - *statusP = GENX_SUCCESS; - return a; - -busted: - *statusP = w->status; - return NULL; -} - -/* - * genxDeclareAttribute - see genx.h for details - */ -genxAttribute genxDeclareAttribute(genxWriter w, - genxNamespace ns, constUtf8 name, - genxStatus * statusP) -{ - if ((w->status = checkNCName(w, name)) != GENX_SUCCESS) - { - *statusP = w->status; - return NULL; - } - - return declareAttribute(w, ns, name, NULL, statusP); -} - -/******************************* - * I/O - */ -static genxStatus sendx(genxWriter w, constUtf8 s) -{ - if (w->sender) - return (*w->sender->send)(w->userData, s); - else - return GENX_IO_ERROR; -} - -static genxStatus sendxBounded(genxWriter w, constUtf8 start, constUtf8 end) -{ - if (w->sender) - return (*w->sender->sendBounded)(w->userData, start, end); - else - return GENX_IO_ERROR; -} - -#define SendCheck(w,s) if ((w->status=sendx(w,(constUtf8)s))!=GENX_SUCCESS) return w->status - -/******************************* - * XML writing routines. The semantics of the externally-facing ones are - * written up in genx.h. Commentary here is implementation notes and - * for internal routines. - */ - -genxStatus genxStartDocSender(genxWriter w, genxSender * sender) -{ - if (w->sequence != SEQUENCE_NO_DOC) - return w->status = GENX_SEQUENCE_ERROR; - - w->sequence = SEQUENCE_PRE_DOC; - w->sender = sender; - - if (w->ppIndent) - { - w->ppDepth = 0; - w->ppSuspendDepth = 0; - w->ppSimple = True; - } - - return GENX_SUCCESS; -} - -/* - * Output new line and indentation. - */ -static genxStatus writeIndentation(genxWriter w) -{ - int i, n; - SendCheck(w, "\n"); - n = w->ppDepth * w->ppIndent; - - for (i = 0; i < n; i++) - SendCheck(w, " "); - - return w->status; -} - -/* - * Output attribute. - */ -static genxStatus writeAttribute(genxAttribute a) -{ - genxWriter w = a->writer; - - if (a->ns && a->ns->baroque && a->ns->declaration == w->xmlnsEquals) - return w->status = GENX_ATTRIBUTE_IN_DEFAULT_NAMESPACE; - - SendCheck(w, " "); - - if (a->ns) - { - SendCheck(w, a->ns->declaration->name + STRLEN_XMLNS_COLON); - SendCheck(w, ":"); - } - - SendCheck(w, a->name); - SendCheck(w, "=\""); - SendCheck(w, a->value.buf); - SendCheck(w, "\""); - - return w->status; -} - -/* - * Write out the attributes we've been gathering up for an element. We save - * them until we've gathered them all so they can be writen in canonical - * order. - * Also, we end the start-tag. - * The trick here is that we keep the attribute list properly sorted as - * we build it, then as each attribute is added, we fill in its value and - * mark the fact that it's been added, in the "provided" field. - */ -static genxStatus writeStartTag(genxWriter w, Boolean close) -{ - size_t i; - genxAttribute * aa = (genxAttribute *) w->attributes.pointers; - genxElement e = w->nowStarting; - - /* - * make sure the right namespace decls are in effect; - * if they are these might create an error, so ignore it - */ - if (e->ns) - addNamespace(e->ns, NULL); - else - unsetDefaultNamespace(w); - w->status = GENX_SUCCESS; - - if (w->ppIndent) - { - if (w->ppDepth && - /* Suspend depth could be at this element's depth (after ++ below). */ - (w->ppSuspendDepth == 0 || w->ppSuspendDepth > w->ppDepth)) - if (writeIndentation (w) != GENX_SUCCESS) - return w->status; - - if (!close) - { - w->ppDepth++; - w->ppSimple = True; - } - else - { - /* - * Conceptually we incremented/decremented the depth, so check if we - * need to resume pretty-printing. - */ - if (w->ppSuspendDepth > w->ppDepth) - w->ppSuspendDepth = 0; - } - } - - SendCheck(w, "<"); - if (e->ns && (e->ns->declaration != w->xmlnsEquals)) - { - SendCheck(w, e->ns->declaration->name + STRLEN_XMLNS_COLON); - SendCheck(w, ":"); - } - SendCheck(w, e->name); - - /* If we are canonicalizing, then write sorted attributes. Otherwise - write them in the order specified. */ - if (w->canonical) - { - for (i = 0; i < w->attributes.count; i++) - { - if (aa[i]->provided) - { - if (writeAttribute (aa[i]) != GENX_SUCCESS) - return w->status; - - aa[i]->provided = False; - } - } - } - else - { - /* Keep the chain consistent even if we bail out mid way because of - an error. This way we will still be able to clear it in reset().*/ - while (w->firstAttribute != NULL) - { - genxAttribute t = w->firstAttribute->next; - - if (writeAttribute (w->firstAttribute) != GENX_SUCCESS) - return w->status; - - w->firstAttribute->provided = False; - w->firstAttribute->next = NULL; - w->firstAttribute = t; - } - - w->lastAttribute = NULL; - } - - if (close) - SendCheck(w, "/"); - SendCheck(w, ">"); - return GENX_SUCCESS; -} - -/* - * internal clear-er; no sequence checking - */ -static genxStatus unsetDefaultNamespace(genxWriter w) -{ - int i; - Boolean found = False; - - /* don't put it in if not needed */ - i = (int) (w->stack.count) - 1; - while (found == False && i > 0) - { - while (w->stack.pointers[i] != NULL) - { - genxAttribute decl = (genxAttribute) w->stack.pointers[i--]; - genxNamespace ns = (genxNamespace) w->stack.pointers[i--]; - - /* if already unset */ - if (ns == NULL) - return w->status = GENX_SUCCESS; - - /* - * the default namespace was declared. This namespace now - * becomes baroque - */ - if (decl == w->xmlnsEquals) - { - ns->baroque = True; - found = True; - break; - } - } - i -= 2; - } - - if (!found) - return GENX_SUCCESS; - - /* - * push a signal on the stack - */ - if ((w->status = listAppend(&w->stack, NULL)) != GENX_SUCCESS) - return w->status; - w->status = listAppend(&w->stack, w->xmlnsEquals); - if (w->status != GENX_SUCCESS) - return w->status; - - /* add the xmlns= attribute, it must be the first one */ - return addAttribute(w->xmlnsEquals, w->empty); -} - -/* - * clear the default namespace declaration - */ -genxStatus genxUnsetDefaultNamespace(genxWriter w) -{ - - /* can only do this while in start-tag mode */ - if (w->sequence != SEQUENCE_START_TAG) - return w->status = GENX_SEQUENCE_ERROR; - - return unsetDefaultNamespace(w); -} - -genxStatus genxStartElement(genxElement e) -{ - genxWriter w = e->writer; - - switch (w->sequence) - { - case SEQUENCE_NO_DOC: - case SEQUENCE_POST_DOC: - case SEQUENCE_START_ATTR: - return w->status = GENX_SEQUENCE_ERROR; - case SEQUENCE_START_TAG: - case SEQUENCE_ATTRIBUTES: - if ((w->status = writeStartTag(w, False)) != GENX_SUCCESS) - return w->status; - break; - case SEQUENCE_PRE_DOC: - case SEQUENCE_CONTENT: - break; - } - - w->sequence = SEQUENCE_START_TAG; - - /* - * push the stack. We push a NULL after a pointer to this element - * because the stack will also contain pointers to the namespace - * attributes that got declared here, so we can keep track of what's - * in effect. I.e. a single stack entry consists logically of a pointer - * to an element object, a NULL, then zero or more pairs of pointers to - * namespace objects/declarations - */ - if ((w->status = listAppend(&w->stack, e)) != GENX_SUCCESS) - return w->status; - if ((w->status = listAppend(&w->stack, NULL)) != GENX_SUCCESS) - return w->status; - - w->nowStarting = e; - - return GENX_SUCCESS; -} - -/* - * internal namespace adder; no sequence checking - */ -static genxStatus addNamespace(genxNamespace ns, constUtf8 prefix) -{ - genxWriter w = ns->writer; - genxAttribute decl; - int i; - genxElement e; - - /* - * first, we'll find the declaring attribute - */ - if (prefix == NULL) - decl = ns->defaultDecl; - else - { - if (prefix[0] == 0) - decl = w->xmlnsEquals; - else - { - if ((prefix = storePrefix(w, prefix, True)) == NULL) - return w->status; - decl = declareAttribute(w, NULL, prefix, ns->name, &w->status); - if (decl == NULL || w->status != GENX_SUCCESS) - return w->status; - } - } - - if (decl != ns->defaultDecl) - ns->baroque = True; - - /* - * avoid doing anything if this namespace is already declared. If - * they've shown good taste we can do this cheaply - */ - if (!ns->baroque) - { - if (ns->declCount > 0) - return w->status = GENX_SUCCESS; - } - else - { - - /* - * First, we'll run all the way up the stack to see if there is - * another declaration for this namespace/prefix in scope, in which - * case it's a no-op; or, if there's another declaration for this - * prefix on another namespace, in which case we have to over-ride - */ - i = (int) (w->stack.count) - 1; - while (i > 0) - { - while (w->stack.pointers[i] != NULL) - { - genxAttribute otherDecl = (genxAttribute) w->stack.pointers[i--]; - genxNamespace otherNs = (genxNamespace) w->stack.pointers[i--]; - - if (ns == otherNs) - { - if (decl == otherDecl) - return w->status = GENX_SUCCESS; - else - { - i = 0; - break; - } - } - else - { - /* different namespace, same prefix? */ - if (decl == otherDecl) - { - i = 0; - break; - } - } - } - i -= 2; - } - } - - /* - * If this namespace is already declared on - * this element (with different prefix/decl) which is an error. - */ - i = (int) (w->stack.count) - 1; - while (w->stack.pointers[i] != NULL) - { - genxNamespace otherNs; - i--; /* don't need declaration */ - otherNs = (genxNamespace) w->stack.pointers[i--]; - - if (ns == otherNs) - return w->status = GENX_DUPLICATE_NAMESPACE; - } - - /* move pointer from NULL to element */ - --i; - - /* - * It's also an error if this is a default-namespace declaration and the - * element is in no namespace. - */ - e = (genxElement) w->stack.pointers[i]; - if (e->ns == NULL && decl == w->xmlnsEquals) - return w->status = GENX_BAD_DEFAULT_DECLARATION; - - if ((w->status = listAppend(&w->stack, ns)) != GENX_SUCCESS) - return w->status; - if ((w->status = listAppend(&w->stack, decl)) != GENX_SUCCESS) - return w->status; - - ns->declaration = decl; - ns->declCount++; - return addAttribute(decl, ns->name); -} - -/* - * Add a namespace declaration - */ -genxStatus genxAddNamespace(genxNamespace ns, constUtf8 prefix) -{ - if (ns->writer->sequence != SEQUENCE_START_TAG) - return ns->writer->status = GENX_SEQUENCE_ERROR; - - return addNamespace(ns, prefix); -} - -/* - * Private attribute-adding code - * most of the work here is normalizing the value, which is the same - * as regular normalization except for " is replaced by """ - */ -static genxStatus collectAttributeValue (genxWriter w, collector* value, - constUtf8 start, constUtf8 end) -{ - /* If end is NULL then the length of the value is unknown and - the value is 0-terminated. */ - - utf8 last = (utf8) start; - - while (end != NULL ? start < end : *start) - { - int c = genxNextUnicodeChar(&start); - - if (c == -1) - return w->status = GENX_BAD_UTF8; - - if (!isXMLChar(w, c)) - return w->status = GENX_NON_XML_CHARACTER; - - switch(c) - { - case 9: - collectPiece(w, value, " ", 5); - break; - case 0xa: - collectPiece(w, value, " ", 5); - break; - case 0xd: - collectPiece(w, value, " ", 5); - break; - case '"': - collectPiece(w, value, """, 6); - break; - case '<': - collectPiece(w, value, "<", 4); - break; - case '&': - collectPiece(w, value, "&", 5); - break; - /* - case '>': - collectPiece(w, value, ">", 4); - break; - */ - default: - collectPiece(w, value, (const char *) last, start - last); - break; - } - last = (utf8) start; - } - - return GENX_SUCCESS; -} - -static genxStatus addAttribute(genxAttribute a, constUtf8 valuestr) -{ - genxWriter w = a->writer; - - /* if valuestr not provided, this is an xmlns with a pre-cooked value */ - if (valuestr) - { - startCollect(&a->value); - - if (collectAttributeValue (w, &a->value, valuestr, NULL) != GENX_SUCCESS) - return w->status; - - endCollect(&a->value); - } - - /* now add the namespace attribute; might fail if it's been hand-declared */ - if (a->ns) - addNamespace(a->ns, NULL); - - if (valuestr && a->provided) - return w->status = GENX_DUPLICATE_ATTRIBUTE; - - a->provided = True; - - /* Add the attribute to the ordered list if not canonical. */ - if (!w->canonical) - { - if (w->lastAttribute != NULL) - w->lastAttribute = w->lastAttribute->next = a; - else - w->lastAttribute = w->firstAttribute = a; - } - - return GENX_SUCCESS; -} - -/* - * public attribute adder. - * The only difference is that it doesn't allow a NULL value - */ -genxStatus genxAddAttribute(genxAttribute a, constUtf8 valuestr) -{ - if (a->writer->sequence != SEQUENCE_START_TAG && - a->writer->sequence != SEQUENCE_ATTRIBUTES) - return a->writer->status = GENX_SEQUENCE_ERROR; - a->writer->sequence = SEQUENCE_ATTRIBUTES; - - if (valuestr == NULL) - return a->writer->status = GENX_MISSING_VALUE; - - return addAttribute(a, valuestr); -} - -genxStatus genxStartAttribute(genxAttribute a) -{ - genxWriter w = a->writer; - - if (w->sequence != SEQUENCE_START_TAG && - w->sequence != SEQUENCE_ATTRIBUTES) - return w->status = GENX_SEQUENCE_ERROR; - - w->sequence = SEQUENCE_START_ATTR; - w->nowStartingAttr = a; - - startCollect(&a->value); - - return GENX_SUCCESS; -} - -genxStatus genxGetCurrentAttribute (genxWriter w, - constUtf8* xmlns, constUtf8* name) -{ - genxAttribute a; - - if (w->sequence != SEQUENCE_START_ATTR) - return w->status = GENX_SEQUENCE_ERROR; - - a = w->nowStartingAttr; - - *xmlns = a->ns ? a->ns->name : NULL; - *name = a->name; - - return GENX_SUCCESS; -} - -genxStatus genxEndAttribute(genxWriter w) -{ - genxAttribute a; - - if (w->sequence != SEQUENCE_START_ATTR) - return w->status = GENX_SEQUENCE_ERROR; - - a = w->nowStartingAttr; - w->sequence = SEQUENCE_ATTRIBUTES; - - endCollect(&a->value); - - /* now add the namespace attribute; might fail if it's been hand-declared */ - if (a->ns) - addNamespace(a->ns, NULL); - - if (a->provided) - return w->status = GENX_DUPLICATE_ATTRIBUTE; - - a->provided = True; - - /* Add the attribute to the ordered list if not canonical. */ - if (!w->canonical) - { - if (w->lastAttribute != NULL) - w->lastAttribute = w->lastAttribute->next = a; - else - w->lastAttribute = w->firstAttribute = a; - } - - return GENX_SUCCESS; -} - -genxStatus genxGetCurrentElement (genxWriter w, - constUtf8* xmlns, constUtf8* name) -{ - int i; - genxElement e; - - switch (w->sequence) - { - case SEQUENCE_START_TAG: - case SEQUENCE_ATTRIBUTES: - e = w->nowStarting; - break; - case SEQUENCE_CONTENT: - /* Find the element. The same code as in EndElement() below. */ - for (i = (int) (w->stack.count) - 1; - w->stack.pointers[i] != NULL; - i -= 2) - ; - e = (genxElement) w->stack.pointers[--i]; - break; - default: - return w->status = GENX_SEQUENCE_ERROR; - } - - *xmlns = e->ns ? e->ns->name : NULL; - *name = e->name; - - return GENX_SUCCESS; -} - -genxStatus genxEndElement(genxWriter w) -{ - int i; - Boolean close = True; - - switch (w->sequence) - { - case SEQUENCE_NO_DOC: - case SEQUENCE_PRE_DOC: - case SEQUENCE_POST_DOC: - case SEQUENCE_START_ATTR: - return w->status = GENX_SEQUENCE_ERROR; - case SEQUENCE_START_TAG: - case SEQUENCE_ATTRIBUTES: - if ((w->status = writeStartTag(w, !w->canonical)) != GENX_SUCCESS) - return w->status; - close = w->canonical; - break; - case SEQUENCE_CONTENT: - break; - } - - /* - * Output the closing tag. - */ - if (close) - { - genxElement e; - - /* - * first peek into the stack to find the right namespace declaration - * (if any) so we can properly prefix the end-tag. Have to do this - * before unwinding the stack because that might reset some xmlns - * prefixes to the context in the parent element - */ - for (i = (int) (w->stack.count) - 1; - w->stack.pointers[i] != NULL; - i -= 2) - ; - e = (genxElement) w->stack.pointers[--i]; - - if (w->ppIndent) - { - w->ppDepth--; - - if (!w->ppSimple && w->ppSuspendDepth == 0) - if (writeIndentation (w) != GENX_SUCCESS) - return w->status; - - if (w->ppSuspendDepth > w->ppDepth) - w->ppSuspendDepth = 0; /* Resume pretty-printing. */ - } - - SendCheck(w, "ns && e->ns->declaration != w->xmlnsEquals) - { - SendCheck(w, e->ns->declaration->name + STRLEN_XMLNS_COLON); - SendCheck(w, ":"); - } - SendCheck(w, e->name); - SendCheck(w, ">"); - } - - /* If this element is written while pretty-printing is suspended, - treat it as simple. As an example, think of an XHTML element - for which we suspend pretty-printing before writing the opening - tag and resume it after the closing one. */ - if (w->ppIndent && w->ppSuspendDepth == 0) - w->ppSimple = False; - - /* - * pop zero or more namespace declarations, then a null, then the - * start-element declaration off the stack - */ - w->stack.count--; - while (w->stack.pointers[w->stack.count] != NULL) - { - genxNamespace ns = (genxNamespace) w->stack.pointers[--w->stack.count]; - w->stack.count--; /* don't need decl */ - - /* if not a fake unset-default namespace */ - if (ns) - { - /* - * if they've stupidly jammed in their own namespace-prefix - * declarations, we have to go looking to see if there's another - * one in effect - */ - if (ns->baroque) - { - i = (int) w->stack.count; - while (i > 0) - { - while (w->stack.pointers[i] != NULL) - { - genxAttribute otherDecl = (genxAttribute) w->stack.pointers[i--]; - genxNamespace otherNs = (genxNamespace) w->stack.pointers[i--]; - - if (otherNs == ns) - { - ns->declaration = otherDecl; - i = 0; - break; - } - } - - /* skip NULL & element */ - i -= 2; - } - } - ns->declCount--; - if (ns->declCount == 0) - ns->baroque = False; - } - } - - /* pop the NULL */ - if (w->stack.count == 0) - return w->status = GENX_NO_START_TAG; - --w->stack.count; - - if (w->stack.count == 0) - w->sequence = SEQUENCE_POST_DOC; - else - w->sequence = SEQUENCE_CONTENT; - - return GENX_SUCCESS; -} - -/* - * Internal character-adder. It tries to keep the number of sendx() - * calls down by looking at each character but only doing the output - * when it has to escape something; ordinary text gets saved up in - * chunks the start of which is indicated by *breaker. - * c is the character, next points to the UTF8 representing the next - * lastsP indirectly points to the UTF8 representing the - * character, breakerP* indirectly points to the last place genx - * changed the UTF8, e.g. by escaping a '<' - */ -static genxStatus addChar(genxWriter w, int c, constUtf8 next, - constUtf8 * lastsP, constUtf8 * breakerP) -{ - if (c == -1) - return GENX_BAD_UTF8; - - if (!isXMLChar(w, c)) - return GENX_NON_XML_CHARACTER; - - switch(c) - { - case 0xd: - if ((w->status = sendxBounded(w, *breakerP, *lastsP)) != GENX_SUCCESS) - return w->status; - *breakerP = next; - sendx(w, (utf8) " "); - break; - case '<': - if ((w->status = sendxBounded(w, *breakerP, *lastsP)) != GENX_SUCCESS) - return w->status; - *breakerP = next; - sendx(w, (utf8) "<"); - break; - case '&': - if ((w->status = sendxBounded(w, *breakerP, *lastsP)) != GENX_SUCCESS) - return w->status; - *breakerP = next; - sendx(w, (utf8) "&"); - break; - case '>': - if ((w->status = sendxBounded(w, *breakerP, *lastsP)) != GENX_SUCCESS) - return w->status; - *breakerP = next; - sendx(w, (utf8) ">"); - break; - default: - break; - } - *lastsP = next; - return GENX_SUCCESS; -} - -genxStatus genxAddText(genxWriter w, constUtf8 start) -{ - constUtf8 lasts = start; - constUtf8 breaker = start; - - if (w->sequence == SEQUENCE_START_TAG || - w->sequence == SEQUENCE_ATTRIBUTES) - { - if ((w->status = writeStartTag(w, False)) != GENX_SUCCESS) - return w->status; - w->sequence = SEQUENCE_CONTENT; - } - - if (w->sequence == SEQUENCE_CONTENT) - { - while (*start) - { - int c = genxNextUnicodeChar(&start); - - w->status = addChar(w, c, start, &lasts, &breaker); - if (w->status != GENX_SUCCESS) - return w->status; - } - return sendxBounded(w, breaker, (utf8) start); - } - else if (w->sequence == SEQUENCE_START_ATTR) - { - return collectAttributeValue (w, &w->nowStartingAttr->value, start, NULL); - } - else - return w->status = GENX_SEQUENCE_ERROR; -} - -genxStatus genxAddBoundedText(genxWriter w, constUtf8 start, constUtf8 end) -{ - constUtf8 lasts = start; - constUtf8 breaker = start; - - if (w->sequence == SEQUENCE_START_TAG || - w->sequence == SEQUENCE_ATTRIBUTES) - { - if ((w->status = writeStartTag(w, False)) != GENX_SUCCESS) - return w->status; - w->sequence = SEQUENCE_CONTENT; - } - - if (w->sequence == SEQUENCE_CONTENT) - { - while (start < end) - { - int c = genxNextUnicodeChar(&start); - - w->status = addChar(w, c, (utf8) start, &lasts, &breaker); - if (w->status != GENX_SUCCESS) - return w->status; - } - return sendxBounded(w, breaker, (utf8) start); - } - else if (w->sequence == SEQUENCE_START_ATTR) - { - return collectAttributeValue (w, &w->nowStartingAttr->value, start, end); - } - else - return w->status = GENX_SEQUENCE_ERROR; -} - -genxStatus genxAddCountedText(genxWriter w, constUtf8 start, size_t byteCount) -{ - utf8 end = (utf8) (start + byteCount); - - return genxAddBoundedText(w, start, end); -} - -genxStatus genxAddCharacter(genxWriter w, int c) -{ - unsigned char cUTF8[10]; - utf8 lasts, breaker, next; - - if (w->sequence == SEQUENCE_START_TAG || - w->sequence == SEQUENCE_ATTRIBUTES) - { - if ((w->status = writeStartTag(w, False)) != GENX_SUCCESS) - return w->status; - w->sequence = SEQUENCE_CONTENT; - } - - if (!isXMLChar(w, c)) - return w->status = GENX_NON_XML_CHARACTER; - - if (w->sequence == SEQUENCE_START_ATTR) - { - int done = 1; - collector* value = &w->nowStartingAttr->value; - - switch(c) - { - case 9: - collectPiece(w, value, " ", 5); - break; - case 0xa: - collectPiece(w, value, " ", 5); - break; - case 0xd: - collectPiece(w, value, " ", 5); - break; - case '"': - collectPiece(w, value, """, 6); - break; - case '<': - collectPiece(w, value, "<", 4); - break; - case '&': - collectPiece(w, value, "&", 5); - break; - /* - case '>': - collectPiece(w, value, ">", 4); - break; - */ - default: - done = 0; - break; - } - - if (done) - return GENX_SUCCESS; - } - - /* make UTF8 representation of character */ - lasts = breaker = next = cUTF8; - - if (c < 0x80) - *next++ = c; - else if (c < 0x800) - { - *next++ = 0xc0 | (c >> 6); - *next++ = 0x80 | (c & 0x3f); - } - else if (c < 0x10000) - { - *next++ = 0xe0 | (c >> 12); - *next++ = 0x80 | ((c & 0xfc0) >> 6); - *next++ = 0x80 | (c & 0x3f); - } - else - { - *next++ = 0xf0 | (c >> 18); - *next++ = 0x80 | ((c & 0x3f000) >> 12); - *next++ = 0x80 | ((c & 0xfc0) >> 6); - *next++ = 0x80 | (c & 0x3f); - } - *next = 0; - - if (w->sequence == SEQUENCE_CONTENT) - { - w->status = - addChar(w, c, next, (constUtf8 *) &lasts, (constUtf8 *) &breaker); - - if (w->status != GENX_SUCCESS) - return w->status; - - return sendxBounded(w, breaker, next); - } - else if (w->sequence == SEQUENCE_START_ATTR) - { - collectPiece(w, &w->nowStartingAttr->value, - (const char *) cUTF8, next - cUTF8); - return GENX_SUCCESS; - } - else - return w->status = GENX_SEQUENCE_ERROR; -} - -genxStatus genxEndDocument(genxWriter w) -{ - if (w->sequence != SEQUENCE_POST_DOC) - return w->status = GENX_SEQUENCE_ERROR; - - /* Write a newline after the closing tag. */ - SendCheck (w, "\n"); - - if ((w->status = (*w->sender->flush)(w->userData)) != GENX_SUCCESS) - return w->status; - - w->sequence = SEQUENCE_NO_DOC; - return GENX_SUCCESS; -} - -genxStatus genxXmlDeclaration(genxWriter w, - constUtf8 ver, - constUtf8 enc, - constUtf8 stl) -{ - if (w->sequence != SEQUENCE_PRE_DOC) - return w->status = GENX_SEQUENCE_ERROR; - - if ((w->status = genxCheckText(w, ver)) != GENX_SUCCESS) - return w->status; - - if (enc != NULL && (w->status = genxCheckText(w, enc)) != GENX_SUCCESS) - return w->status; - - if (stl != NULL && (w->status = genxCheckText(w, stl)) != GENX_SUCCESS) - return w->status; - - SendCheck (w, "\n"); - - return GENX_SUCCESS; -} - -genxStatus genxDoctypeDeclaration(genxWriter w, - constUtf8 re, - constUtf8 pi, - constUtf8 si, - constUtf8 is) -{ - if (w->sequence != SEQUENCE_PRE_DOC) - return w->status = GENX_SEQUENCE_ERROR; - - if ((w->status = genxCheckText(w, re)) != GENX_SUCCESS) - return w->status; - - if (pi != NULL && (w->status = genxCheckText(w, pi)) != GENX_SUCCESS) - return w->status; - - if (si != NULL && (w->status = genxCheckText(w, si)) != GENX_SUCCESS) - return w->status; - - if (is != NULL && (w->status = genxCheckText(w, is)) != GENX_SUCCESS) - return w->status; - - SendCheck (w, "\n"); - return GENX_SUCCESS; -} - -genxStatus genxComment(genxWriter w, constUtf8 text) -{ - size_t i; - - if (w->sequence == SEQUENCE_NO_DOC || - w->sequence == SEQUENCE_START_ATTR) - return w->status = GENX_SEQUENCE_ERROR; - - if ((w->status = genxCheckText(w, text)) != GENX_SUCCESS) - return w->status; - - /* no leading '-', no trailing '-', no '--' */ - if (text[0] == '-') - return w->status = GENX_MALFORMED_COMMENT; - for (i = 0; text[i]; i++) - if (text[i] == '-' && (text[i + 1] == '-' || text[i + 1] == 0)) - return w->status = GENX_MALFORMED_COMMENT; - - if (w->sequence == SEQUENCE_START_TAG || - w->sequence == SEQUENCE_ATTRIBUTES) - { - if ((w->status = writeStartTag(w, False)) != GENX_SUCCESS) - return w->status; - w->sequence = SEQUENCE_CONTENT; - } - - else if (w->sequence == SEQUENCE_POST_DOC) - if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS) - return w->status; - - if ((w->status = sendx(w, (utf8) "")) != GENX_SUCCESS) - return w->status; - - if (w->sequence == SEQUENCE_PRE_DOC) - if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS) - return w->status; - - return GENX_SUCCESS; -} - -genxStatus genxPI(genxWriter w, constUtf8 target, constUtf8 text) -{ - size_t i; - - if (w->sequence == SEQUENCE_NO_DOC || - w->sequence == SEQUENCE_START_ATTR) - return w->status = GENX_SEQUENCE_ERROR; - - if ((w->status = genxCheckText(w, target)) != GENX_SUCCESS) - return w->status; - if ((w->status = checkNCName(w, target)) != GENX_SUCCESS) - return w->status; - if ((strlen((const char *) target) >= 3) && - (target[0] == 'x' || target[0] == 'X') && - (target[1] == 'm' || target[1] == 'M') && - (target[2] == 'l' || target[2] == 'L') && - (target[3] == 0)) - return w->status = GENX_XML_PI_TARGET; - - if ((w->status = genxCheckText(w, text)) != GENX_SUCCESS) - return w->status; - - /* no ?> within */ - for (i = 1; text[i]; i++) - if (text[i] == '>' && text[i - 1] == '?') - return w->status = GENX_MALFORMED_PI; - - if (w->sequence == SEQUENCE_START_TAG || - w->sequence == SEQUENCE_ATTRIBUTES) - { - if ((w->status = writeStartTag(w, False)) != GENX_SUCCESS) - return w->status; - w->sequence = SEQUENCE_CONTENT; - } - - else if (w->sequence == SEQUENCE_POST_DOC) - if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS) - return w->status; - - if ((w->status = sendx(w, (utf8) "status; - if ((w->status = sendx(w, target)) != GENX_SUCCESS) - return w->status; - if (text[0]) - { - if ((w->status = sendx(w, (utf8) " ")) != GENX_SUCCESS) - return w->status; - if ((w->status = sendx(w, text)) != GENX_SUCCESS) - return w->status; - } - if ((w->status = sendx(w, (utf8) "?>")) != GENX_SUCCESS) - return w->status; - - if (w->sequence == SEQUENCE_PRE_DOC) - if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS) - return w->status; - - return GENX_SUCCESS; -} - -/******************************* - * Literal versions of the writing routines - */ -genxStatus genxStartElementLiteral(genxWriter w, - constUtf8 xmlns, constUtf8 name) -{ - genxNamespace ns = NULL; - genxElement e; - - if (xmlns) - { - ns = genxDeclareNamespace(w, xmlns, NULL, &w->status); - if (ns == NULL || w->status != GENX_SUCCESS) - return w->status; - } - e = genxDeclareElement(w, ns, name, &w->status); - if (e == NULL || w->status != GENX_SUCCESS) - return w->status; - - return genxStartElement(e); -} - -genxStatus genxAddAttributeLiteral(genxWriter w, constUtf8 xmlns, - constUtf8 name, constUtf8 value) -{ - genxNamespace ns = NULL; - genxAttribute a; - - if (xmlns) - { - ns = genxDeclareNamespace(w, xmlns, NULL, &w->status); - if (ns == NULL && w->status != GENX_SUCCESS) - return w->status; - } - - a = genxDeclareAttribute(w, ns, name, &w->status); - if (a == NULL || w->status != GENX_SUCCESS) - return w->status; - - return genxAddAttribute(a, value); -} - -genxStatus genxStartAttributeLiteral(genxWriter w, - constUtf8 xmlns, constUtf8 name) -{ - genxNamespace ns = NULL; - genxAttribute a; - - if (xmlns) - { - ns = genxDeclareNamespace(w, xmlns, NULL, &w->status); - if (ns == NULL && w->status != GENX_SUCCESS) - return w->status; - } - - a = genxDeclareAttribute(w, ns, name, &w->status); - if (a == NULL || w->status != GENX_SUCCESS) - return w->status; - - return genxStartAttribute(a); -} - -genxStatus genxAddNamespaceLiteral(genxWriter w, - constUtf8 uri, constUtf8 prefix) -{ - genxNamespace ns = genxDeclareNamespace(w, uri, prefix, &w->status); - if (ns == NULL && w->status != GENX_SUCCESS) - return w->status; - - return genxAddNamespace(ns, NULL); -} - -/* - * return version - */ -char * genxGetVersion() -{ - return GENX_VERSION; -} diff --git a/genx.h b/genx.h deleted file mode 100644 index 041815f..0000000 --- a/genx.h +++ /dev/null @@ -1,390 +0,0 @@ -/* - * genx - C-callable library for generating XML documents - */ - -/* - * Copyright (c) 2004 by Tim Bray and Sun Microsystems. - * Copyright (c) Code Synthesis Tools CC (see the LICENSE file). - * - * For copying permission, see the accompanying LICENSE file. - */ - -#ifndef GENX_H -#define GENX_H - -#include /* size_t */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Note on error handling: genx routines mostly return - * GENX_SUCCESS (guaranteed to be zero) in normal circumstances, one of - * these other GENX_ values on a memory allocation or I/O failure or if the - * call would result in non-well-formed output. - * You can associate an error message with one of these codes explicitly - * or with the most recent error using genxGetErrorMessage() and - * genxLastErrorMessage(); see below. - */ -typedef enum -{ - GENX_SUCCESS = 0, - GENX_BAD_UTF8, - GENX_NON_XML_CHARACTER, - GENX_BAD_NAME, - GENX_ALLOC_FAILED, - GENX_BAD_NAMESPACE_NAME, - GENX_INTERNAL_ERROR, - GENX_DUPLICATE_PREFIX, - GENX_SEQUENCE_ERROR, - GENX_NO_START_TAG, - GENX_IO_ERROR, - GENX_MISSING_VALUE, - GENX_MALFORMED_COMMENT, - GENX_XML_PI_TARGET, - GENX_MALFORMED_PI, - GENX_DUPLICATE_ATTRIBUTE, - GENX_ATTRIBUTE_IN_DEFAULT_NAMESPACE, - GENX_DUPLICATE_NAMESPACE, - GENX_BAD_DEFAULT_DECLARATION -} genxStatus; - -/* character types */ -#define GENX_XML_CHAR 1 -#define GENX_LETTER 2 -#define GENX_NAMECHAR 4 - -/* The size of the character table. Valid values are 0x100 (first 255 - chars are checked) and 0x10000 (all chars are checked). */ -#ifndef GENX_CHAR_TABLE_SIZE -# define GENX_CHAR_TABLE_SIZE 0x100 -#endif - -/* a UTF-8 string */ -typedef unsigned char * utf8; -typedef const unsigned char * constUtf8; - -/* - * genx's own types - */ -typedef struct genxWriter_rec * genxWriter; -typedef struct genxNamespace_rec * genxNamespace; -typedef struct genxElement_rec * genxElement; -typedef struct genxAttribute_rec * genxAttribute; - -typedef void * (*genxAlloc) (void * userData, size_t bytes); -typedef void (*genxDealloc) (void * userData, void* data); - -/* - * Constructors, set/get - */ - -/* - * Create a new writer. For generating multiple XML documents, it's most - * efficient to re-use the same genx object. However, you can only write - * one document at a time with a writer. - * Returns NULL if it fails, which can only be due to an allocation failure. - */ -genxWriter genxNew(genxAlloc alloc, genxDealloc dealloc, void * userData); - -/* - * Reset the writer object back into usable state after an error or - * interruption. - */ -genxStatus genxReset (genxWriter w); - -/* - * Dispose of a writer, freeing all associated memory - */ -void genxDispose(genxWriter w); - -/* - * Set/get - */ - -/* - * The userdata pointer will be passed to memory-allocation - * and I/O callbacks. If not set, genx will pass NULL - */ -void genxSetUserData(genxWriter w, void * userData); -void * genxGetUserData(genxWriter w); - -/* - * Set/get pretty-printing. If indentation is set to 0, then no pretty- - * printing is performed. - */ -genxStatus genxSetPrettyPrint(genxWriter w, int indentation); -int genxGetPrettyPrint(genxWriter w); - -/* - * Suspend/resume pretty-printing. Pretty-printing can be suspended - * only inside an element and, unless explicitly resumed, it will - * remain suspended until the end of that element. You should only - * explicitly resume pretty-printing at the element nesting level - * of suspension. If pretty-printing is already suspended at an - * outer nesting level, then subsequent calls to suspend/resume - * are ignored. The PrettyPrintSuspended() function can be used - * to check if pretty-printing is currently suspended. If it is - * not, then this function returns 0. Otherwise, it returns the - * level at which pretty-printing was suspended, with root element - * being level 1. - */ -genxStatus genxSuspendPrettyPrint(genxWriter w); -genxStatus genxResumePrettyPrint(genxWriter w); -int genxPrettyPrintSuspended(genxWriter w); - - -/* - * Set/get canonicalization. If true, then output explicit closing - * tags and sort attributes. Default is false. - */ -genxStatus genxSetCanonical(genxWriter w, int flag); -int genxGetCanonical(genxWriter w); - -/* - * User-provided memory allocator, if desired. For example, if you were - * in an Apache module, you could arrange for genx to use ap_palloc by - * making the pool accessible via the userData call. - * The "dealloc" is to be used to free memory allocated with "alloc". If - * alloc is provided but dealloc is NULL, genx will not attempt to free - * the memory; this would be appropriate in an Apache context. - * If "alloc" is not provided, genx routines use malloc() to allocate memory - */ -void genxSetAlloc(genxWriter w, genxAlloc alloc); -void genxSetDealloc(genxWriter w, genxDealloc dealloc); -genxAlloc genxGetAlloc(genxWriter w); -genxDealloc genxGetDealloc(genxWriter w); - -/* - * Get the prefix associated with a namespace - */ -utf8 genxGetNamespacePrefix(genxNamespace ns); - -/* - * Declaration functions - */ - -/* - * Declare a namespace. The provided prefix is the default but can be - * overridden by genxAddNamespace. If no default prefiix is provided, - * genx will generate one of the form g-%d. - * On error, returns NULL and signals via statusp - */ -genxNamespace genxDeclareNamespace(genxWriter w, - constUtf8 uri, constUtf8 prefix, - genxStatus * statusP); - -/* - * Declare an element - * If something failed, returns NULL and sets the status code via statusP - */ -genxElement genxDeclareElement(genxWriter w, - genxNamespace ns, constUtf8 name, - genxStatus * statusP); - -/* - * Declare an attribute - */ -genxAttribute genxDeclareAttribute(genxWriter w, - genxNamespace ns, - constUtf8 name, genxStatus * statusP); - -/* - * Writing XML - */ - -/* - * Caller-provided I/O package. - * First form is for a null-terminated string. - * for second, if you have s="abcdef" and want to send "abc", you'd call - * sendBounded(userData, s, s + 3) - */ -typedef struct -{ - genxStatus (* send)(void * userData, constUtf8 s); - genxStatus (* sendBounded)(void * userData, constUtf8 start, constUtf8 end); - genxStatus (* flush)(void * userData); -} genxSender; - -genxStatus genxStartDocSender(genxWriter w, genxSender * sender); - -/* - * End a document. Calls "flush". - */ -genxStatus genxEndDocument(genxWriter w); - -/* - * Write XML declaration. If encoding or standalone are NULL, then those - * attributes are omitted. - */ -genxStatus genxXmlDeclaration(genxWriter w, - constUtf8 version, - constUtf8 encoding, - constUtf8 standalone); -/* - * Write DOCTYPE declaration. If public_id is not NULL, then this is - * a PUBLIC DOCTYPE declaration, otherwise, if system_id is not NULL, - * then this is a SYSTEM DOCTYPE. If both are NULL, then a DOCTYPE - * that only contains the root element and, if not NULL, internal - * subset is written. - */ -genxStatus genxDoctypeDeclaration(genxWriter w, - constUtf8 root_element, - constUtf8 public_id, - constUtf8 system_id, - constUtf8 internal_subset); - -/* - * Write a comment - */ -genxStatus genxComment(genxWriter w, constUtf8 text); - -/* - * Write a PI - */ -genxStatus genxPI(genxWriter w, constUtf8 target, constUtf8 text); - -/* - * Start an element - */ -genxStatus genxStartElementLiteral(genxWriter w, - constUtf8 xmlns, constUtf8 name); - -/* - * Start a predeclared element - * - element must have been declared - */ -genxStatus genxStartElement(genxElement e); - -/* - * Get current element. The returned values are valid until this - * element ceases to be current (i.e., EndElement() is called). - * If the element is unqualified, then xmlns is set to NULL. - */ -genxStatus genxGetCurrentElement (genxWriter w, - constUtf8* xmlns, constUtf8* name); - -/* - * Write an attribute - */ -genxStatus genxAddAttributeLiteral(genxWriter w, constUtf8 xmlns, - constUtf8 name, constUtf8 value); - -/* - * Write a predeclared attribute - */ -genxStatus genxAddAttribute(genxAttribute a, constUtf8 value); - -/* - * Start an attribute - */ -genxStatus genxStartAttributeLiteral(genxWriter w, - constUtf8 xmlns, constUtf8 name); - -/* - * Start a predeclared attribute - */ -genxStatus genxStartAttribute(genxAttribute a); - -/* - * Get current attribute. The returned values are valid until this - * attribute ceases to be current (i.e., EndAttribute() is called). - * If the attribute is unqualified, then xmlns is set to NULL. - */ -genxStatus genxGetCurrentAttribute (genxWriter w, - constUtf8* xmlns, constUtf8* name); - -/* - * End an attribute - */ -genxStatus genxEndAttribute(genxWriter w); - -/* - * add a namespace declaration - */ -genxStatus genxAddNamespaceLiteral(genxWriter w, - constUtf8 uri, constUtf8 prefix); - -/* - * add a predefined namespace declaration - */ -genxStatus genxAddNamespace(genxNamespace ns, constUtf8 prefix); - -/* - * Clear default namespace declaration - */ -genxStatus genxUnsetDefaultNamespace(genxWriter w); - -/* - * Write an end tag - */ -genxStatus genxEndElement(genxWriter w); - -/* - * Write some text - * You can't write any text outside the root element, except with - * genxComment and genxPI. - */ -genxStatus genxAddText(genxWriter w, constUtf8 start); -genxStatus genxAddCountedText(genxWriter w, constUtf8 start, size_t byteCount); -genxStatus genxAddBoundedText(genxWriter w, constUtf8 start, constUtf8 end); - -/* - * Write one character. The integer value is the Unicode character - * value, as usually expressed in U+XXXX notation. - */ -genxStatus genxAddCharacter(genxWriter w, int c); - -/* - * Utility routines - */ - -/* - * Return the Unicode character encoded by the UTF-8 pointed-to by the - * argument, and advance the argument past the encoding of the character. - * Returns -1 if the UTF-8 is malformed, in which case advances the - * argument to point at the first byte past the point past the malformed - * ones. - */ -int genxNextUnicodeChar(constUtf8 * sp); - -/* - * Scan a buffer allegedly full of UTF-8 encoded XML characters; return - * one of GENX_SUCCESS, GENX_BAD_UTF8, or GENX_NON_XML_CHARACTER - */ -genxStatus genxCheckText(genxWriter w, constUtf8 s); - -/* - * return character status, the OR of GENX_XML_CHAR, - * GENX_LETTER, and GENX_NAMECHAR - */ -int genxCharClass(genxWriter w, int c); - -/* - * Silently wipe any non-XML characters out of a chunk of text. - * If you call this on a string before you pass it addText or - * addAttribute, you will never get an error from genx unless - * (a) there's a bug in your software, e.g. a malformed element name, or - * (b) there's a memory allocation or I/O error - * The output can never be longer than the input. - * Returns true if any changes were made. - */ -int genxScrubText(genxWriter w, constUtf8 in, utf8 out); - -/* - * return error messages - */ -char * genxGetErrorMessage(genxWriter w, genxStatus status); -char * genxLastErrorMessage(genxWriter w); - -/* - * return version - */ -char * genxGetVersion(); - -#ifdef __cplusplus -} -#endif - -#endif /* GENX_H */ diff --git a/libgenx/.gitignore b/libgenx/.gitignore new file mode 100644 index 0000000..cece09c --- /dev/null +++ b/libgenx/.gitignore @@ -0,0 +1,19 @@ +# Compiler/linker output. +# +*.d +*.t +*.i +*.ii +*.o +*.obj +*.so +*.dll +*.a +*.lib +*.exp +*.pdb +*.ilk +*.exe +*.exe.dlls/ +*.exe.manifest +*.pc diff --git a/libgenx/LICENSE b/libgenx/LICENSE new file mode 120000 index 0000000..ea5b606 --- /dev/null +++ b/libgenx/LICENSE @@ -0,0 +1 @@ +../LICENSE \ No newline at end of file diff --git a/libgenx/README.md b/libgenx/README.md new file mode 120000 index 0000000..32d46ee --- /dev/null +++ b/libgenx/README.md @@ -0,0 +1 @@ +../README.md \ No newline at end of file diff --git a/libgenx/build/.gitignore b/libgenx/build/.gitignore new file mode 100644 index 0000000..974e01d --- /dev/null +++ b/libgenx/build/.gitignore @@ -0,0 +1,4 @@ +/config.build +/root/ +/bootstrap/ +build/ diff --git a/libgenx/build/bootstrap.build b/libgenx/build/bootstrap.build new file mode 100644 index 0000000..9240e9d --- /dev/null +++ b/libgenx/build/bootstrap.build @@ -0,0 +1,7 @@ +project = libgenx + +using version +using config +using test +using install +using dist diff --git a/libgenx/build/export.build b/libgenx/build/export.build new file mode 100644 index 0000000..e254e62 --- /dev/null +++ b/libgenx/build/export.build @@ -0,0 +1,6 @@ +$out_root/ +{ + include libgenx/ +} + +export $out_root/libgenx/$import.target diff --git a/libgenx/build/root.build b/libgenx/build/root.build new file mode 100644 index 0000000..451fbcd --- /dev/null +++ b/libgenx/build/root.build @@ -0,0 +1,8 @@ +using c + +h{*}: extension = h +c{*}: extension = c + +# The test target for cross-testing (running tests under Wine, etc). +# +test.target = $c.target diff --git a/libgenx/buildfile b/libgenx/buildfile new file mode 100644 index 0000000..d82ab19 --- /dev/null +++ b/libgenx/buildfile @@ -0,0 +1,5 @@ +./: {*/ -build/} doc{README.md} legal{LICENSE} manifest + +# Don't install tests. +# +tests/: install = false diff --git a/libgenx/libgenx/.gitignore b/libgenx/libgenx/.gitignore new file mode 100644 index 0000000..c2f1607 --- /dev/null +++ b/libgenx/libgenx/.gitignore @@ -0,0 +1,3 @@ +# Generated version header. +# +version.h diff --git a/libgenx/libgenx/buildfile b/libgenx/libgenx/buildfile new file mode 100644 index 0000000..4331d64 --- /dev/null +++ b/libgenx/libgenx/buildfile @@ -0,0 +1,51 @@ +intf_libs = # Interface dependencies. +impl_libs = # Implementation dependencies. +#import impl_libs += libhello%lib{hello} + +lib{genx}: {h c}{** -version} h{version} $impl_libs $intf_libs + +# Include the generated version header into the distribution (so that we don't +# pick up an installed one) and don't remove it when cleaning in src (so that +# clean results in a state identical to distributed). +# +h{version}: in{version} $src_root/manifest +{ + dist = true + clean = ($src_root != $out_root) +} + +# Build options. +# +c.poptions =+ "-I$out_root" "-I$src_root" + +obja{*}: c.poptions += -DLIBGENX_STATIC_BUILD +objs{*}: c.poptions += -DLIBGENX_SHARED_BUILD + +# Export options. +# +lib{genx}: +{ + c.export.poptions = "-I$out_root" "-I$src_root" + c.export.libs = $intf_libs +} + +liba{genx}: c.export.poptions += -DLIBGENX_STATIC +libs{genx}: c.export.poptions += -DLIBGENX_SHARED + +# For pre-releases use the complete version to make sure they cannot be used +# in place of another pre-release or the final version. See the version module +# for details on the version.* variable values. +# +if $version.pre_release + lib{genx}: bin.lib.version = @"-$version.project_id" +else + lib{genx}: bin.lib.version = @"-$version.major.$version.minor" + +# Install into the libgenx/ subdirectory of, say, /usr/include/ +# recreating subdirectories. +# +{h}{*}: +{ + install = include/libgenx/ + install.subdirs = true +} diff --git a/libgenx/libgenx/char-props.c b/libgenx/libgenx/char-props.c new file mode 100644 index 0000000..1201fce --- /dev/null +++ b/libgenx/libgenx/char-props.c @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2004 by Tim Bray and Sun Microsystems. + * Copyright (c) Code Synthesis Tools CC (see the LICENSE file). + * + * For copying permission, see the accompanying LICENSE file. + */ + +/* + * Construct character-properties tables for genx. + * Quite likely there's a better way. + * This version is generated semi-automatically from the source code of the + * XML specification via emacs global replace and keyboard macros + */ +#include + +static void charProp(char * p, int c, int prop) +{ + p[c] |= prop; +} + +static void rangeProp(char * p, size_t start, size_t end, int prop) +{ + size_t i; + for (i = start; i <= end; i++) + p[i] |= prop; +} + +void genxSetCharProps(char * p) +{ + size_t i; + + for (i = 0; i < GENX_CHAR_TABLE_SIZE; i++) + p[i] = 0; + + /* per XML 1.0 */ + charProp(p, 0x9, GENX_XML_CHAR); + charProp(p, 0xa, GENX_XML_CHAR); + charProp(p, 0xd, GENX_XML_CHAR); + rangeProp(p, 0x20, 0xff, GENX_XML_CHAR); + +#if GENX_CHAR_TABLE_SIZE == 0x10000 + rangeProp(p, 0x0100, 0xd7ff, GENX_XML_CHAR); + rangeProp(p, 0xe000, 0xfffd, GENX_XML_CHAR); +#endif + + /* Letter ::= BaseChar | Ideographic */ + rangeProp(p, 0x0041, 0x005A, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0061, 0x007A, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x00C0, 0x00D6, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x00D8, 0x00F6, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x00F8, 0x00FF, GENX_LETTER|GENX_NAMECHAR); + +#if GENX_CHAR_TABLE_SIZE == 0x10000 + + rangeProp(p, 0x0100, 0x0131, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0134, 0x013E, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0141, 0x0148, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x014A, 0x017E, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0180, 0x01C3, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x01CD, 0x01F0, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x01F4, 0x01F5, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x01FA, 0x0217, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0250, 0x02A8, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x02BB, 0x02C1, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0386, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0388, 0x038A, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x038C, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x038E, 0x03A1, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x03A3, 0x03CE, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x03D0, 0x03D6, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x03DA, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x03DC, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x03DE, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x03E0, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x03E2, 0x03F3, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0401, 0x040C, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x040E, 0x044F, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0451, 0x045C, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x045E, 0x0481, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0490, 0x04C4, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x04C7, 0x04C8, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x04CB, 0x04CC, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x04D0, 0x04EB, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x04EE, 0x04F5, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x04F8, 0x04F9, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0531, 0x0556, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0559, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0561, 0x0586, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x05D0, 0x05EA, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x05F0, 0x05F2, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0621, 0x063A, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0641, 0x064A, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0671, 0x06B7, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x06BA, 0x06BE, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x06C0, 0x06CE, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x06D0, 0x06D3, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x06D5, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x06E5, 0x06E6, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0905, 0x0939, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x093D, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0958, 0x0961, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0985, 0x098C, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x098F, 0x0990, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0993, 0x09A8, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x09AA, 0x09B0, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x09B2, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x09B6, 0x09B9, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x09DC, 0x09DD, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x09DF, 0x09E1, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x09F0, 0x09F1, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0A05, 0x0A0A, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0A0F, 0x0A10, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0A13, 0x0A28, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0A2A, 0x0A30, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0A32, 0x0A33, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0A35, 0x0A36, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0A38, 0x0A39, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0A59, 0x0A5C, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0A5E, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0A72, 0x0A74, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0A85, 0x0A8B, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0A8D, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0A8F, 0x0A91, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0A93, 0x0AA8, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0AAA, 0x0AB0, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0AB2, 0x0AB3, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0AB5, 0x0AB9, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0ABD, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0AE0, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0B05, 0x0B0C, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0B0F, 0x0B10, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0B13, 0x0B28, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0B2A, 0x0B30, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0B32, 0x0B33, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0B36, 0x0B39, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0B3D, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0B5C, 0x0B5D, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0B5F, 0x0B61, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0B85, 0x0B8A, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0B8E, 0x0B90, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0B92, 0x0B95, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0B99, 0x0B9A, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0B9C, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0B9E, 0x0B9F, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0BA3, 0x0BA4, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0BA8, 0x0BAA, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0BAE, 0x0BB5, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0BB7, 0x0BB9, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0C05, 0x0C0C, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0C0E, 0x0C10, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0C12, 0x0C28, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0C2A, 0x0C33, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0C35, 0x0C39, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0C60, 0x0C61, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0C85, 0x0C8C, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0C8E, 0x0C90, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0C92, 0x0CA8, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0CAA, 0x0CB3, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0CB5, 0x0CB9, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0CDE, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0CE0, 0x0CE1, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0D05, 0x0D0C, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0D0E, 0x0D10, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0D12, 0x0D28, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0D2A, 0x0D39, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0D60, 0x0D61, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0E01, 0x0E2E, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0E30, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0E32, 0x0E33, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0E40, 0x0E45, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0E81, 0x0E82, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0E84, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0E87, 0x0E88, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0E8A, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0E8D, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0E94, 0x0E97, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0E99, 0x0E9F, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0EA1, 0x0EA3, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0EA5, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0EA7, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0EAA, 0x0EAB, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0EAD, 0x0EAE, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0EB0, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0EB2, 0x0EB3, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0EBD, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0EC0, 0x0EC4, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0F40, 0x0F47, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0F49, 0x0F69, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x10A0, 0x10C5, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x10D0, 0x10F6, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x1100, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1102, 0x1103, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1105, 0x1107, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x1109, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x110B, 0x110C, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x110E, 0x1112, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x113C, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x113E, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x1140, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x114C, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x114E, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x1150, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1154, 0x1155, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x1159, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x115F, 0x1161, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x1163, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x1165, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x1167, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x1169, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x116D, 0x116E, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1172, 0x1173, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x1175, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x119E, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x11A8, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x11AB, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x11AE, 0x11AF, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x11B7, 0x11B8, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x11BA, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x11BC, 0x11C2, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x11EB, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x11F0, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x11F9, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1E00, 0x1E9B, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1EA0, 0x1EF9, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1F00, 0x1F15, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1F18, 0x1F1D, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1F20, 0x1F45, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1F48, 0x1F4D, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1F50, 0x1F57, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x1F59, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x1F5B, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x1F5D, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1F5F, 0x1F7D, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1F80, 0x1FB4, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1FB6, 0x1FBC, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x1FBE, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1FC2, 0x1FC4, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1FC6, 0x1FCC, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1FD0, 0x1FD3, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1FD6, 0x1FDB, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1FE0, 0x1FEC, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1FF2, 0x1FF4, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x1FF6, 0x1FFC, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x2126, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x212A, 0x212B, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x212E, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x2180, 0x2182, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x3041, 0x3094, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x30A1, 0x30FA, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x3105, 0x312C, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0xAC00, 0xD7A3, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x4E00, 0x9FA5, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x3007, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x3021, 0x3029, GENX_LETTER|GENX_NAMECHAR); + +#endif /* GENX_CHAR_TABLE_SIZE == 0x10000 */ + + /* + * NameChar ::= + * Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender + */ + + charProp(p, '.', GENX_NAMECHAR); + charProp(p, '-', GENX_NAMECHAR); + charProp(p, '_', GENX_NAMECHAR); + + rangeProp(p, 0x0030, 0x0039, GENX_NAMECHAR); + charProp(p, 0x00B7, GENX_LETTER|GENX_NAMECHAR); + +#if GENX_CHAR_TABLE_SIZE == 0x10000 + + rangeProp(p, 0x0660, 0x0669, GENX_NAMECHAR); + rangeProp(p, 0x06F0, 0x06F9, GENX_NAMECHAR); + rangeProp(p, 0x0966, 0x096F, GENX_NAMECHAR); + rangeProp(p, 0x09E6, 0x09EF, GENX_NAMECHAR); + rangeProp(p, 0x0A66, 0x0A6F, GENX_NAMECHAR); + rangeProp(p, 0x0AE6, 0x0AEF, GENX_NAMECHAR); + rangeProp(p, 0x0B66, 0x0B6F, GENX_NAMECHAR); + rangeProp(p, 0x0BE7, 0x0BEF, GENX_NAMECHAR); + rangeProp(p, 0x0C66, 0x0C6F, GENX_NAMECHAR); + rangeProp(p, 0x0CE6, 0x0CEF, GENX_NAMECHAR); + rangeProp(p, 0x0D66, 0x0D6F, GENX_NAMECHAR); + rangeProp(p, 0x0E50, 0x0E59, GENX_NAMECHAR); + rangeProp(p, 0x0ED0, 0x0ED9, GENX_NAMECHAR); + rangeProp(p, 0x0F20, 0x0F29, GENX_NAMECHAR); + rangeProp(p, 0x0300, 0x0345, GENX_NAMECHAR); + rangeProp(p, 0x0360, 0x0361, GENX_NAMECHAR); + rangeProp(p, 0x0483, 0x0486, GENX_NAMECHAR); + rangeProp(p, 0x0591, 0x05A1, GENX_NAMECHAR); + rangeProp(p, 0x05A3, 0x05B9, GENX_NAMECHAR); + rangeProp(p, 0x05BB, 0x05BD, GENX_NAMECHAR); + charProp(p, 0x05BF, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x05C1, 0x05C2, GENX_NAMECHAR); + charProp(p, 0x05C4, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x064B, 0x0652, GENX_NAMECHAR); + charProp(p, 0x0670, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x06D6, 0x06DC, GENX_NAMECHAR); + rangeProp(p, 0x06DD, 0x06DF, GENX_NAMECHAR); + rangeProp(p, 0x06E0, 0x06E4, GENX_NAMECHAR); + rangeProp(p, 0x06E7, 0x06E8, GENX_NAMECHAR); + rangeProp(p, 0x06EA, 0x06ED, GENX_NAMECHAR); + rangeProp(p, 0x0901, 0x0903, GENX_NAMECHAR); + charProp(p, 0x093C, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x093E, 0x094C, GENX_NAMECHAR); + charProp(p, 0x094D, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0951, 0x0954, GENX_NAMECHAR); + rangeProp(p, 0x0962, 0x0963, GENX_NAMECHAR); + rangeProp(p, 0x0981, 0x0983, GENX_NAMECHAR); + charProp(p, 0x09BC, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x09BE, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x09BF, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x09C0, 0x09C4, GENX_NAMECHAR); + rangeProp(p, 0x09C7, 0x09C8, GENX_NAMECHAR); + rangeProp(p, 0x09CB, 0x09CD, GENX_NAMECHAR); + charProp(p, 0x09D7, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x09E2, 0x09E3, GENX_NAMECHAR); + charProp(p, 0x0A02, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0A3C, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0A3E, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0A3F, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0A40, 0x0A42, GENX_NAMECHAR); + rangeProp(p, 0x0A47, 0x0A48, GENX_NAMECHAR); + rangeProp(p, 0x0A4B, 0x0A4D, GENX_NAMECHAR); + rangeProp(p, 0x0A70, 0x0A71, GENX_NAMECHAR); + rangeProp(p, 0x0A81, 0x0A83, GENX_NAMECHAR); + charProp(p, 0x0ABC, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0ABE, 0x0AC5, GENX_NAMECHAR); + rangeProp(p, 0x0AC7, 0x0AC9, GENX_NAMECHAR); + rangeProp(p, 0x0ACB, 0x0ACD, GENX_NAMECHAR); + rangeProp(p, 0x0B01, 0x0B03, GENX_NAMECHAR); + charProp(p, 0x0B3C, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0B3E, 0x0B43, GENX_NAMECHAR); + rangeProp(p, 0x0B47, 0x0B48, GENX_NAMECHAR); + rangeProp(p, 0x0B4B, 0x0B4D, GENX_NAMECHAR); + rangeProp(p, 0x0B56, 0x0B57, GENX_NAMECHAR); + rangeProp(p, 0x0B82, 0x0B83, GENX_NAMECHAR); + rangeProp(p, 0x0BBE, 0x0BC2, GENX_NAMECHAR); + rangeProp(p, 0x0BC6, 0x0BC8, GENX_NAMECHAR); + rangeProp(p, 0x0BCA, 0x0BCD, GENX_NAMECHAR); + charProp(p, 0x0BD7, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0C01, 0x0C03, GENX_NAMECHAR); + rangeProp(p, 0x0C3E, 0x0C44, GENX_NAMECHAR); + rangeProp(p, 0x0C46, 0x0C48, GENX_NAMECHAR); + rangeProp(p, 0x0C4A, 0x0C4D, GENX_NAMECHAR); + rangeProp(p, 0x0C55, 0x0C56, GENX_NAMECHAR); + rangeProp(p, 0x0C82, 0x0C83, GENX_NAMECHAR); + rangeProp(p, 0x0CBE, 0x0CC4, GENX_NAMECHAR); + rangeProp(p, 0x0CC6, 0x0CC8, GENX_NAMECHAR); + rangeProp(p, 0x0CCA, 0x0CCD, GENX_NAMECHAR); + rangeProp(p, 0x0CD5, 0x0CD6, GENX_NAMECHAR); + rangeProp(p, 0x0D02, 0x0D03, GENX_NAMECHAR); + rangeProp(p, 0x0D3E, 0x0D43, GENX_NAMECHAR); + rangeProp(p, 0x0D46, 0x0D48, GENX_NAMECHAR); + rangeProp(p, 0x0D4A, 0x0D4D, GENX_NAMECHAR); + charProp(p, 0x0D57, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0E31, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0E34, 0x0E3A, GENX_NAMECHAR); + rangeProp(p, 0x0E47, 0x0E4E, GENX_NAMECHAR); + charProp(p, 0x0EB1, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0EB4, 0x0EB9, GENX_NAMECHAR); + rangeProp(p, 0x0EBB, 0x0EBC, GENX_NAMECHAR); + rangeProp(p, 0x0EC8, 0x0ECD, GENX_NAMECHAR); + rangeProp(p, 0x0F18, 0x0F19, GENX_NAMECHAR); + charProp(p, 0x0F35, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0F37, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0F39, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0F3E, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0F3F, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0F71, 0x0F84, GENX_NAMECHAR); + rangeProp(p, 0x0F86, 0x0F8B, GENX_NAMECHAR); + rangeProp(p, 0x0F90, 0x0F95, GENX_NAMECHAR); + charProp(p, 0x0F97, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x0F99, 0x0FAD, GENX_NAMECHAR); + rangeProp(p, 0x0FB1, 0x0FB7, GENX_NAMECHAR); + charProp(p, 0x0FB9, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x20D0, 0x20DC, GENX_NAMECHAR); + charProp(p, 0x20E1, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x302A, 0x302F, GENX_NAMECHAR); + charProp(p, 0x3099, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x309A, GENX_LETTER|GENX_NAMECHAR); + + charProp(p, 0x02D0, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x02D1, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0387, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0640, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0E46, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x0EC6, GENX_LETTER|GENX_NAMECHAR); + charProp(p, 0x3005, GENX_LETTER|GENX_NAMECHAR); + rangeProp(p, 0x3031, 0x3035, GENX_NAMECHAR); + rangeProp(p, 0x309D, 0x309E, GENX_NAMECHAR); + rangeProp(p, 0x30FC, 0x30FE, GENX_NAMECHAR); + +#endif /* GENX_CHAR_TABLE_SIZE == 0x10000 */ +} diff --git a/libgenx/libgenx/export.h b/libgenx/libgenx/export.h new file mode 100644 index 0000000..45109b8 --- /dev/null +++ b/libgenx/libgenx/export.h @@ -0,0 +1,33 @@ +#ifndef LIBGENX_EXPORT_H +#define LIBGENX_EXPORT_H + +#if defined(LIBGENX_STATIC) /* Using static. */ +# define LIBGENX_SYMEXPORT +#elif defined(LIBGENX_STATIC_BUILD) /* Building static. */ +# define LIBGENX_SYMEXPORT +#elif defined(LIBGENX_SHARED) /* Using shared. */ +# ifdef _WIN32 +# define LIBGENX_SYMEXPORT __declspec(dllimport) +# else +# define LIBGENX_SYMEXPORT +# endif +#elif defined(LIBGENX_SHARED_BUILD) /* Building shared. */ +# ifdef _WIN32 +# define LIBGENX_SYMEXPORT __declspec(dllexport) +# else +# define LIBGENX_SYMEXPORT +# endif +#else +/* If none of the above macros are defined, then we assume we are being used +// by some third-party build system that cannot/doesn't signal the library +// type. Note that this fallback works for both static and shared libraries +// provided the library only exports functions (in other words, no global +// exported data) and for the shared case the result will be sub-optimal +// compared to having dllimport. If, however, your library does export data, +// then you will probably want to replace the fallback with the (commented +// out) error since it won't work for the shared case. +*/ +# define LIBGENX_SYMEXPORT +#endif + +#endif /* LIBGENX_EXPORT_H */ diff --git a/libgenx/libgenx/genx.c b/libgenx/libgenx/genx.c new file mode 100644 index 0000000..5746c50 --- /dev/null +++ b/libgenx/libgenx/genx.c @@ -0,0 +1,2542 @@ +/* + * Copyright (c) 2004 by Tim Bray and Sun Microsystems. + * Copyright (c) Code Synthesis Tools CC (see the LICENSE file). + * + * For copying permission, see the accompanying LICENSE file. + */ + +/* Use snprintf() unless instructed otherwise. */ +#ifndef GENX_SNPRINTF +# define GENX_SNPRINTF 1 +#endif + +#if defined(GENX_CUSTOM_ALLOC) != defined(GENX_CUSTOM_FREE) +# error both GENX_CUSTOM_ALLOC and GENX_CUSTOM_FREE must be defined +#endif + +#include +#include +#include + +#include +#include + +#define Boolean int +#define True 1 +#define False 0 +#define STRLEN_XMLNS_COLON 6 + + +/******************************* + * writer state + */ +typedef enum +{ + SEQUENCE_NO_DOC, + SEQUENCE_PRE_DOC, + SEQUENCE_POST_DOC, + SEQUENCE_START_TAG, + SEQUENCE_ATTRIBUTES, + SEQUENCE_START_ATTR, + SEQUENCE_CONTENT +} writerSequence; + +/******************************* + * generic pointer list + */ +typedef struct +{ + genxWriter writer; + size_t count; + size_t space; + void * * pointers; +} plist; + +/******************************* + * text collector, for attribute values + */ +typedef struct +{ + utf8 buf; + size_t used; + size_t space; +} collector; + +/******************************* + * Structs with opaquely-exposed handles + */ + +/* + * This one's tricky, to handle stacking namespaces + * 'declaration' is the current attribute which would be used to + * declare the currently-effective prefix + * 'defDeclaration' is a appropriate declaration when this is being + * used with the default prefix as passed to genxDeclareNamespace + * baroque is true if this namespace has been used with more than one + * prefix, or is the default namespace but has been unset + */ +struct genxNamespace_rec +{ + genxWriter writer; + utf8 name; + size_t declCount; + Boolean baroque; + genxAttribute declaration; + genxAttribute defaultDecl; +}; + +struct genxElement_rec +{ + genxWriter writer; + utf8 name; + genxNamespace ns; +}; + +typedef enum +{ + ATTR_NSDECL, + ATTR_NAKED, + ATTR_PREFIXED +} attrType; + +struct genxAttribute_rec +{ + genxWriter writer; + utf8 name; + genxNamespace ns; + collector value; + int provided; /* provided for current element? */ + attrType atype; + genxAttribute next; /* Attribute order chain if not canonical. */ +}; + +/******************************* + * genx's sandbox + */ +struct genxWriter_rec +{ + const genxSender * sender; + genxStatus status; + writerSequence sequence; + char xmlChars[GENX_CHAR_TABLE_SIZE]; + void * userData; + int nextPrefix; + utf8 empty; + Boolean defaultNsDeclared; + genxAttribute xmlnsEquals; + genxElement nowStarting; + genxAttribute nowStartingAttr; + plist namespaces; + plist elements; + plist attributes; + plist prefixes; + plist stack; + struct genxAttribute_rec arec; /* Dummy attribute used for lookup. */ + char * etext[100]; + genxAlloc alloc; + genxDealloc dealloc; + + /* Pretty-printing state */ + int ppIndent; + int ppDepth; + int ppSuspendDepth; /* Non-0 means we are suspended. */ + Boolean ppSimple; + + /* Canonicalization. */ + Boolean canonical; + + /* Attrbute order when not canonical. */ + genxAttribute firstAttribute; + genxAttribute lastAttribute; +}; + +/******************************* + * Forward declarations + */ +static genxAttribute declareAttribute(genxWriter w, genxNamespace ns, + constUtf8 name, constUtf8 valuestr, + genxStatus * statusP); +static genxStatus addNamespace(genxNamespace ns, constUtf8 prefix); +static genxStatus unsetDefaultNamespace(genxWriter w); +static genxStatus addAttribute(genxAttribute a, constUtf8 valuestr); +void genxSetCharProps(char * p); + +/******************************* + * End of declarations + */ + +/******************************* + * private memory utilities + */ +static void * allocate(genxWriter w, size_t bytes) +{ + if (w->alloc) + return (void *) (*w->alloc)(w->userData, bytes); + else +#ifdef GENX_CUSTOM_ALLOC + return (void *) GENX_CUSTOM_ALLOC(bytes); +#else + return (void *) malloc(bytes); +#endif +} + +static void deallocate(genxWriter w, void * data) +{ + if (w->dealloc) + (*w->dealloc)(w->userData, data); + else if (w->alloc == NULL) +#ifdef GENX_CUSTOM_FREE + GENX_CUSTOM_FREE(data); +#else + free(data); +#endif + +} + +static utf8 copy(genxWriter w, constUtf8 from) +{ + utf8 temp; + size_t sl = strlen((const char *) from); + + if ((temp = (utf8) allocate(w, sl + 1)) == NULL) + return NULL; + + memcpy(temp, from, sl); + temp[sl] = 0; + return temp; +} + +static genxStatus initCollector(genxWriter w, collector * c) +{ + c->space = 100; + if ((c->buf = (utf8) allocate(w, c->space)) == NULL) + return GENX_ALLOC_FAILED; + c->used = 0; + return GENX_SUCCESS; +} + +static genxStatus growCollector(genxWriter w, collector * c, size_t size) +{ + utf8 newSpace; + + c->space = size * 2; + if ((newSpace = (utf8) allocate(w, c->space)) == NULL) + return GENX_ALLOC_FAILED; + + memcpy(newSpace, c->buf, c->used); + newSpace[c->used] = 0; + deallocate(w, c->buf); + c->buf = newSpace; + return GENX_SUCCESS; +} + +static void startCollect(collector * c) +{ + c->used = 0; +} +static void endCollect(collector * c) +{ + c->buf[c->used] = 0; +} + +static genxStatus collectString(genxWriter w, collector * c, constUtf8 string) +{ + size_t sl = strlen((const char *) string); + + if (sl >= c->space) + if ((w->status = growCollector(w, c, sl)) != GENX_SUCCESS) + return GENX_ALLOC_FAILED; + + memcpy(c->buf, string, sl); + c->buf[sl] = 0; + return GENX_SUCCESS; +} + +/* Note: does not add the trailing '\0' (done by endCollect() call). */ +#define collectPiece(w,c,d,size) {if (((c)->used+(size))>=(c)->space){if (((w)->status=growCollector(w,c,(c)->used+(size)))!=GENX_SUCCESS) return (w)->status;}memcpy((char *)(c)->buf+(c)->used,d,size);(c)->used+=size;} + +/******************************* + * private list utilities + */ +static genxStatus initPlist(genxWriter w, plist * pl) +{ + pl->writer = w; + pl->count = 0; + pl->space = 10; + pl->pointers = (void * *) allocate(w, pl->space * sizeof(void *)); + if (pl->pointers == NULL) + return GENX_ALLOC_FAILED; + + return GENX_SUCCESS; +} + +/* + * make room in a plist + */ +static Boolean checkExpand(plist * pl) +{ + void * * newlist; + size_t i; + + if (pl->count < pl->space) + return True; + + pl->space *= 2; + newlist = (void * *) allocate(pl->writer, pl->space * sizeof(void *)); + if (newlist == NULL) + return False; + for (i = 0; i < pl->count; i++) + newlist[i] = pl->pointers[i]; + deallocate(pl->writer, pl->pointers); + pl->pointers = newlist; + + return True; +} + +/* + * stick something on the end of a plist + */ +static genxStatus listAppend(plist * pl, void * pointer) +{ + if (!checkExpand(pl)) + return GENX_ALLOC_FAILED; + + pl->pointers[pl->count++] = pointer; + return GENX_SUCCESS; +} + +/* + * insert in place, shuffling up + */ +static genxStatus listInsert(plist * pl, void * pointer, size_t at) +{ + size_t i; + + if (!checkExpand(pl)) + return GENX_ALLOC_FAILED; + + for (i = pl->count; i > at; i--) + pl->pointers[i] = pl->pointers[i - 1]; + pl->count++; + + pl->pointers[at] = pointer; + return GENX_SUCCESS; +} + +/******************************* + * list lookups + */ + +static genxNamespace findNamespace(plist * pl, constUtf8 uri) +{ + size_t i; + genxNamespace * nn = (genxNamespace *) pl->pointers; + + for (i = 0; i < pl->count; i++) + if (strcmp((char *) uri, (const char *) nn[i]->name) == 0) + return nn[i]; + + return NULL; +} + +static genxElement findElement(plist * pl, constUtf8 xmlns, constUtf8 name) +{ + size_t i; + genxElement * ee = (genxElement *) pl->pointers; + + for (i = 0; i < pl->count; i++) + { + if (xmlns == NULL) + { + if (ee[i]->ns == NULL && strcmp((const char *) name, + (const char *) ee[i]->name) == 0) + return ee[i]; + } + else + { + if (ee[i]->ns != NULL && + strcmp((const char *) xmlns, (const char *) ee[i]->ns->name) == 0 && + strcmp((const char *) name, (const char *) ee[i]->name) == 0) + return ee[i]; + } + } + + return NULL; +} + +/* + * store & intern a prefix, after giving it the + * "xmlns:" prefix. Don't allow storing the same one twice unless 'force' + * is set. + */ +static utf8 storePrefix(genxWriter w, constUtf8 prefix, Boolean force) +{ + int high, low; + utf8 * pp = (utf8 *) w->prefixes.pointers; + unsigned char buf[1024]; + + if (prefix[0] == 0) + prefix = (utf8) "xmlns"; + else + { + size_t pl = strlen((const char *) prefix); + + if (pl > sizeof(buf) - (6 + 1)) + { + w->status = GENX_BAD_NAMESPACE_NAME; + return NULL; + } + + memcpy (buf, "xmlns:", 6); + memcpy (buf + 6, prefix, pl); + buf[pl + 6] = 0; + + prefix = buf; + } + + high = (int) w->prefixes.count; + low = -1; + while (high - low > 1) + { + int probe = (high + low) / 2; + if (strcmp((const char *) prefix, (const char *) pp[probe]) < 0) + high = probe; + else + low = probe; + } + + /* already there? */ + if (low != -1 && strcmp((const char *) prefix, (const char *) pp[low]) == 0) + { + if (force) + return pp[low]; + + w->status = GENX_DUPLICATE_PREFIX; + return NULL; + } + + /* copy & insert */ + if ((prefix = copy(w, prefix)) == NULL) + { + w->status = GENX_ALLOC_FAILED; + return NULL; + } + + w->status = listInsert(&w->prefixes, (void *) prefix, (size_t) high); + if (w->status != GENX_SUCCESS) + return NULL; + + return (utf8) prefix; +} + +/******************************* + * UTF8 bit-banging + */ + +/* + * Retrieve the character pointed at, and advance the pointer; return -1 on + * error + */ +int genxNextUnicodeChar(constUtf8 * sp) +{ + utf8 s = (utf8) *sp; + int c; + + if (*s == 0) + return -1; + + if (*s < 0x80) + c = *s++; + + /* all this encoding sanity-checking taken from section 3.10 of Unicode 4 */ + else if (*s < 0xc2) + goto malformed; + + /* 2-byte encodings, first byte c2 .. df */ + else if (*s < 0xe0) + { + c = (*s++ & 0x1f) << 6; + + /* + * for this common idiom, if ((c & 0xc0) != 0x80) is slightly faster + * on MacOS (PPC) + */ + if (*s < 0x80 || *s > 0xbf) + goto malformed; + + c |= *s++ & 0x3f; + } + + /* 3-byte encodings, first byte e0 .. ef */ + else if (*s < 0xf0) + { + int b0 = *s; + c = (*s++ & 0x0f) << 12; + + if ((b0 == 0xe0 && (*s < 0xa0 || *s > 0xbf)) || + (b0 < 0xed && (*s < 0x80 || *s > 0xbf)) || + (b0 == 0xed && (*s < 0x80 || *s > 0x9f)) || + (b0 > 0xed && (*s < 0x80 || *s > 0xbf))) + goto malformed; + + c |= (*s++ & 0x3f) << 6; + + if (*s < 0x80 || *s > 0xbf) + goto malformed; + + c |= *s++ & 0x3f; + } + + /* 4-byte encodings, first byte f0 .. f4 */ + else if (*s < 0xf5) + { + int b0 = *s; + c = (*s++ & 0x07) << 18; + + if ((b0 == 0xf0 && (*s < 0x90 || *s > 0xbf)) || + (b0 < 0xf4 && (*s < 0x80 || *s > 0xbf)) || + (b0 >= 0xf4 && (*s < 0x80 || *s > 0x8f))) + goto malformed; + + c |= (*s++ & 0x3f) << 12; + + if (*s < 0x80 || *s > 0xbf) + goto malformed; + + c |= (*s++ & 0x3f) << 6; + + if (*s < 0x80 || *s > 0xbf) + goto malformed; + + c |= *s++ & 0x3f; + } + else + goto malformed; + + *sp = s; + return c; + + /* + * this is needed by scrubText, which wants to get the pointer moved + * past the problem area. + */ +malformed: + if (*s) + ++s; + *sp = s; + return -1; +} + +static Boolean isXMLChar(genxWriter w, int c) +{ + if (c < 0) + return False; + else if (c < GENX_CHAR_TABLE_SIZE) + return (int) w->xmlChars[c]; + else + return (c <= 0x10ffff); +} + +static Boolean isLetter(genxWriter w, int c) +{ + if (c < 0 || c > 0xffff) + return False; + else + { +#if GENX_CHAR_TABLE_SIZE == 0x10000 + return w->xmlChars[c] & GENX_LETTER; +#else + return c < GENX_CHAR_TABLE_SIZE ? (w->xmlChars[c] & GENX_LETTER) : True; +#endif + } +} + +static Boolean isNameChar(genxWriter w, int c) +{ + if (c < 0 || c > 0xffff) + return False; + else + { +#if GENX_CHAR_TABLE_SIZE == 0x10000 + return w->xmlChars[c] & GENX_NAMECHAR; +#else + return c < GENX_CHAR_TABLE_SIZE ? (w->xmlChars[c] & GENX_NAMECHAR) : True; +#endif + } +} + +/******************************* + * Constructors, setters/getters + */ + +/* + * Construct a new genxWriter + */ +genxWriter genxNew(genxAlloc alloc, genxDealloc dealloc, void * userData) +{ + genxWriter w; + genxNamespace xml; + + if (alloc) + w = (genxWriter) (*alloc)(userData, sizeof(struct genxWriter_rec)); + else +#ifdef GENX_CUSTOM_ALLOC + w = (genxWriter) GENX_CUSTOM_ALLOC(sizeof(struct genxWriter_rec)); +#else + w = (genxWriter) malloc(sizeof(struct genxWriter_rec)); +#endif + + if (w == NULL) + return NULL; + + w->status = GENX_SUCCESS; + w->alloc = alloc; + w->dealloc = dealloc; + w->userData = userData; + w->sequence = SEQUENCE_NO_DOC; + + if (initPlist(w, &w->namespaces) != GENX_SUCCESS || + initPlist(w, &w->elements) != GENX_SUCCESS || + initPlist(w, &w->attributes) != GENX_SUCCESS || + initPlist(w, &w->prefixes) != GENX_SUCCESS || + initPlist(w, &w->stack) != GENX_SUCCESS) + return NULL; + + if ((w->status = initCollector(w, &w->arec.value)) != GENX_SUCCESS) + return NULL; + + if ((w->empty = copy(w, (utf8) "")) == NULL) + { + w->status = GENX_ALLOC_FAILED; + return NULL; + } + + w->xmlnsEquals = declareAttribute(w, NULL, (utf8) "xmlns", NULL, &w->status); + if (w->xmlnsEquals == NULL || w->status != GENX_SUCCESS) + return NULL; + w->defaultNsDeclared = False; + + w->nextPrefix = 1; + + genxSetCharProps(w->xmlChars); + + w->etext[GENX_SUCCESS] = "success"; + w->etext[GENX_BAD_UTF8] = "invalid UTF-8"; + w->etext[GENX_NON_XML_CHARACTER] = "non-XML character"; + w->etext[GENX_BAD_NAME] = "invalid name"; + w->etext[GENX_ALLOC_FAILED] = "memory allocation failed"; + w->etext[GENX_BAD_NAMESPACE_NAME] = "invalid namespace name"; + w->etext[GENX_INTERNAL_ERROR] = "internal error"; + w->etext[GENX_DUPLICATE_PREFIX] = "duplicate prefix"; + w->etext[GENX_SEQUENCE_ERROR] = "call out of sequence"; + w->etext[GENX_NO_START_TAG] = "no start tag for end element call"; + w->etext[GENX_IO_ERROR] = "io error"; + w->etext[GENX_MISSING_VALUE] = "missing attribute value"; + w->etext[GENX_MALFORMED_COMMENT] = "malformed comment body"; + w->etext[GENX_MALFORMED_PI] = "?> in PI"; + w->etext[GENX_XML_PI_TARGET] = "target of PI matches [xX][mM][lL]"; + w->etext[GENX_DUPLICATE_ATTRIBUTE] = "duplicate attribute"; + w->etext[GENX_ATTRIBUTE_IN_DEFAULT_NAMESPACE] = + "attribute is default namespace"; + w->etext[GENX_DUPLICATE_NAMESPACE] = + "namespace declared twice with different prefixes"; + w->etext[GENX_BAD_DEFAULT_DECLARATION] = + "default namespace declared on an element which is not in a namespace"; + + /* the xml: namespace is pre-wired */ + xml = genxDeclareNamespace(w, (utf8) "http://www.w3.org/XML/1998/namespace", + (utf8) "xml", &w->status); + if (xml == NULL) + return NULL; + xml->declCount = 1; + xml->declaration = xml->defaultDecl; + + w->ppIndent = 0; /* Pretty-printing is disabled by default. */ + w->canonical = False; /* No canonicalization by default. */ + + w->firstAttribute = NULL; + w->lastAttribute = NULL; + return w; +} + +genxStatus genxReset (genxWriter w) +{ + size_t i; + + /* Clean up the stack. */ + w->stack.count = 0; + + /* Reset namespace declaration counts. The first entry is the pre-wired + xml namespace. */ + ((genxNamespace) w->namespaces.pointers[0])->declCount = 1; + + for (i = 1; i < w->namespaces.count; i++) + { + ((genxNamespace) w->namespaces.pointers[i])->declCount = 0; + ((genxNamespace) w->namespaces.pointers[i])->baroque = False; + } + + /* Clear provided attributes. */ + for (i = 0; i < w->attributes.count; i++) + ((genxAttribute) w->attributes.pointers[i])->provided = False; + + /* Clear attribute list. */ + if (!w->canonical) + { + while (w->firstAttribute != NULL) + { + genxAttribute t = w->firstAttribute->next; + w->firstAttribute->next = NULL; + w->firstAttribute = t; + } + + w->lastAttribute = NULL; + } + + w->status = GENX_SUCCESS; + w->sequence = SEQUENCE_NO_DOC; + + return w->status; +} + + +/* + * get/set userData + */ +void genxSetUserData(genxWriter w, void * userData) +{ + w->userData = userData; +} +void * genxGetUserData(genxWriter w) +{ + return w->userData; +} + +/* + * get/set pretty-printing + */ +genxStatus genxSetPrettyPrint(genxWriter w, int ind) +{ + if (w->sequence == SEQUENCE_NO_DOC) + w->ppIndent = ind; + else + w->status = GENX_SEQUENCE_ERROR; + + return w->status; +} + +int genxGetPrettyPrint(genxWriter w) +{ + return w->ppIndent; +} + +/* + * Suspend/resume pretty-printing. + */ +genxStatus genxSuspendPrettyPrint(genxWriter w) +{ + int d = w->ppDepth; + + if (w->ppIndent == 0) + return w->status = GENX_SEQUENCE_ERROR; + + switch (w->sequence) + { + case SEQUENCE_START_TAG: + case SEQUENCE_ATTRIBUTES: + d++; /* No start tag written, still outer depth. */ + case SEQUENCE_CONTENT: + break; + default: + return w->status = GENX_SEQUENCE_ERROR; + } + + if (w->ppSuspendDepth == 0) /* Ignore nested suspend/resume calls. */ + w->ppSuspendDepth = d; + + return w->status; +} + +genxStatus genxResumePrettyPrint(genxWriter w) +{ + int d = w->ppDepth; + + if (w->ppIndent == 0 || w->ppSuspendDepth == 0) + return w->status = GENX_SEQUENCE_ERROR; + + switch (w->sequence) + { + case SEQUENCE_START_TAG: + case SEQUENCE_ATTRIBUTES: + d++; /* No start tag written, still outer depth. */ + case SEQUENCE_CONTENT: + break; + default: + return w->status = GENX_SEQUENCE_ERROR; + } + + if (w->ppSuspendDepth == d) /* Ignore nested suspend/resume calls. */ + w->ppSuspendDepth = 0; + + return w->status; +} + +int genxPrettyPrintSuspended(genxWriter w) +{ + return w->ppSuspendDepth; +} + +/* + * get/set canonicalization. + */ +genxStatus genxSetCanonical(genxWriter w, int flag) +{ + if (w->sequence == SEQUENCE_NO_DOC) + w->canonical = flag; + else + w->status = GENX_SEQUENCE_ERROR; + + return w->status; +} + +int genxGetCanonical(genxWriter w) +{ + return w->canonical; +} + +/* + * get/set allocator + */ +void genxSetAlloc(genxWriter w, genxAlloc alloc) +{ + w->alloc = alloc; +} + +void genxSetDealloc(genxWriter w, genxDealloc dealloc) +{ + w->dealloc = dealloc; +} + +genxAlloc genxGetAlloc(genxWriter w) +{ + return w->alloc; +} + +genxDealloc genxGetDealloc(genxWriter w) +{ + return w->dealloc; +} + +/* + * Clean up + */ +void genxDispose(genxWriter w) +{ + size_t i; + genxNamespace * nn = (genxNamespace *) w->namespaces.pointers; + genxElement * ee = (genxElement *) w->elements.pointers; + genxAttribute * aa = (genxAttribute *) w->attributes.pointers; + utf8 * pp = (utf8 *) w->prefixes.pointers; + + for (i = 0; i < w->namespaces.count; i++) + { + deallocate(w, nn[i]->name); + deallocate(w, nn[i]); + } + + for (i = 0; i < w->elements.count; i++) + { + deallocate(w, ee[i]->name); + deallocate(w, ee[i]); + } + + for (i = 0; i < w->attributes.count; i++) + { + deallocate(w, aa[i]->name); + deallocate(w, aa[i]->value.buf); + deallocate(w, aa[i]); + } + + for(i = 0; i < w->prefixes.count; i++) + deallocate(w, pp[i]); + + deallocate(w, w->namespaces.pointers); + deallocate(w, w->elements.pointers); + deallocate(w, w->attributes.pointers); + deallocate(w, w->prefixes.pointers); + deallocate(w, w->stack.pointers); + + deallocate(w, w->arec.value.buf); + + deallocate(w, w->empty); + + /* how Oscar dealt with Igli */ + deallocate(w, w); +} + +/******************************* + * External utility routines + */ + +/* + * scan a buffer and report problems with UTF-8 encoding or non-XML characters + */ +genxStatus genxCheckText(genxWriter w, constUtf8 s) +{ + while (*s) + { + int c = genxNextUnicodeChar(&s); + if (c == -1) + return GENX_BAD_UTF8; + + if (!isXMLChar(w, c)) + return GENX_NON_XML_CHARACTER; + } + return GENX_SUCCESS; +} + +/* + * Purify some text + */ +int genxScrubText(genxWriter w, constUtf8 in, utf8 out) +{ + int problems = 0; + constUtf8 last = in; + + while (*in) + { + int c = genxNextUnicodeChar(&in); + if (c == -1) + { + problems++; + last = in; + continue; + } + + if (!isXMLChar(w, c)) + { + problems++; + last = in; + continue; + } + + while (last < in) + *out++ = *last++; + } + *out = 0; + return problems; +} + +/* + * check one character + */ +int genxCharClass(genxWriter w, int c) +{ + int ret = 0; + + if (isXMLChar(w, c)) + ret |= GENX_XML_CHAR; + if (isNameChar(w, c)) + ret |= GENX_NAMECHAR; + if (isLetter(w, c)) + ret |= GENX_LETTER; + return ret; +} + +static genxStatus checkNCName(genxWriter w, constUtf8 name) +{ + int c; + + if (name == NULL || *name == 0) + return GENX_BAD_NAME; + + c = genxNextUnicodeChar(&name); + if (!isLetter(w, c) && c != ':' && c != '_') + return GENX_BAD_NAME; + + while (*name) + { + c = genxNextUnicodeChar(&name); + if (c == -1) + return GENX_BAD_UTF8; + if (!isNameChar(w, c)) + return GENX_BAD_NAME; + } + return GENX_SUCCESS; +} + +const char * genxGetErrorMessage(genxWriter w, genxStatus status) +{ + return w->etext[status]; +} +const char * genxLastErrorMessage(genxWriter w) +{ + return w->etext[w->status]; +} + +/******************************* + * Declarations: namespace/element/attribute + */ + +/* + * DeclareNamespace - by far the most complex routine in Genx + */ +genxNamespace genxDeclareNamespace(genxWriter w, constUtf8 uri, + constUtf8 defaultPref, + genxStatus * statusP) +{ + genxNamespace ns; + genxAttribute defaultDecl; + unsigned char newPrefix[100]; + + if (uri == NULL || uri[0] == 0) + { + w->status = GENX_BAD_NAMESPACE_NAME; + goto busted; + } + + if ((w->status = genxCheckText(w, uri)) != GENX_SUCCESS) + goto busted; + + /* if a prefix is provided, it has to be an NCname */ + if (defaultPref != NULL && defaultPref[0] != 0 && + (w->status = checkNCName(w, defaultPref)) != GENX_SUCCESS) + goto busted; + + /* previously declared? */ + if ((ns = findNamespace(&w->namespaces, uri))) + { + /* just a lookup, really */ + if ((defaultPref == NULL) || + (defaultPref[0] == 0 && ns->defaultDecl == w->xmlnsEquals) || + (strcmp((const char *) ns->defaultDecl->name + STRLEN_XMLNS_COLON, + (const char *) defaultPref) == 0)) + { + w->status = *statusP = GENX_SUCCESS; + return ns; + } + } + + /* wasn't already declared */ + else + { + /* make a default prefix if none provided */ + if (defaultPref == NULL) + { +#if GENX_SNPRINTF + snprintf((char *) newPrefix, sizeof(newPrefix), "g%d", w->nextPrefix++); +#else + sprintf((char *) newPrefix, "g%d", w->nextPrefix++); +#endif + defaultPref = newPrefix; + } + + ns = (genxNamespace) allocate(w, sizeof(struct genxNamespace_rec)); + if (ns == NULL) + { + w->status = GENX_ALLOC_FAILED; + goto busted; + } + ns->writer = w; + ns->baroque = False; + + if ((ns->name = copy(w, uri)) == NULL) + { + w->status = GENX_ALLOC_FAILED; + goto busted; + } + + if ((w->status = listAppend(&w->namespaces, ns)) != GENX_SUCCESS) + goto busted; + ns->defaultDecl = ns->declaration = NULL; + ns->declCount = 0; + } + + if (defaultPref[0] == 0) + { + if (w->defaultNsDeclared) + { + w->status = GENX_DUPLICATE_PREFIX; + goto busted; + } + defaultDecl = w->xmlnsEquals; + w->defaultNsDeclared = True; + } + else + { + /* this catches dupes too */ + if ((defaultPref = storePrefix(w, defaultPref, False)) == NULL) + goto busted; + + defaultDecl = declareAttribute(w, NULL, defaultPref, ns->name, statusP); + if (defaultDecl == NULL || *statusP != GENX_SUCCESS) + { + w->status = *statusP; + return NULL; + } + } + + if (ns->defaultDecl != NULL && defaultDecl != ns->defaultDecl) + ns->baroque = True; + ns->defaultDecl = defaultDecl; + + *statusP = GENX_SUCCESS; + return ns; + +busted: + *statusP = w->status; + return NULL; +} + +/* + * get namespace prefix + */ +constUtf8 genxGetNamespacePrefix(genxNamespace ns) +{ + if (ns->declaration == NULL) + return NULL; + + if (ns->declaration == ns->writer->xmlnsEquals) + return ns->writer->empty; + + return ns->declaration->name + STRLEN_XMLNS_COLON; +} + +/* + * DeclareElement - see genx.h for details + */ +genxElement genxDeclareElement(genxWriter w, + genxNamespace ns, constUtf8 name, + genxStatus * statusP) +{ + genxElement old; + genxElement el; + + if ((w->status = checkNCName(w, name)) != GENX_SUCCESS) + { + *statusP = w->status; + return NULL; + } + + /* already declared? */ + old = findElement(&w->elements, (ns == NULL) ? NULL : ns->name, name); + if (old) + return old; + + if ((el = (genxElement) allocate(w, sizeof(struct genxElement_rec))) == NULL) + { + w->status = *statusP = GENX_ALLOC_FAILED; + return NULL; + } + + el->writer = w; + el->ns = ns; + if ((el->name = copy(w, name)) == NULL) + { + w->status = *statusP = GENX_ALLOC_FAILED; + return NULL; + } + + if ((w->status = listAppend(&w->elements, el)) != GENX_SUCCESS) + { + *statusP = w->status; + return NULL; + } + + *statusP = GENX_SUCCESS; + return el; +} + +/* + * C14n ordering for attributes: + * - first, namespace declarations by the prefix being declared + * - second, unprefixed attributes by attr name + * - third, prefixed attrs by ns uri then local part + */ +static int orderAttributes(genxAttribute a1, genxAttribute a2) +{ + if (a1->atype == a2->atype) + { + if (a1->atype == ATTR_PREFIXED && a1->ns != a2->ns) + return strcmp((const char *) a1->ns->name, (const char *) a2->ns->name); + else + return strcmp((const char *) a1->name, (const char *) a2->name); + } + + else if (a1->atype == ATTR_NSDECL) + return -1; + + else if (a1->atype == ATTR_NAKED) + { + if (a2->atype == ATTR_NSDECL) + return 1; + else + return -1; + } + + else + return 1; +} + +/* + * internal declare-attribute. This one allows colonized values for + * names, so that you can declare xmlns:-type attributes + */ +static genxAttribute declareAttribute(genxWriter w, genxNamespace ns, + constUtf8 name, constUtf8 valuestr, + genxStatus * statusP) +{ + int high, low; + genxAttribute * aa = (genxAttribute *) w->attributes.pointers; + genxAttribute a; + + w->arec.ns = ns; + w->arec.name = (utf8) name; + + if (ns) + w->arec.atype = ATTR_PREFIXED; + else if (strncmp((const char *) name, "xmlns", STRLEN_XMLNS_COLON - 1) == 0) + w->arec.atype = ATTR_NSDECL; + else + w->arec.atype = ATTR_NAKED; + + if (ns && (ns->defaultDecl == w->xmlnsEquals)) + { + w->status = GENX_ATTRIBUTE_IN_DEFAULT_NAMESPACE; + goto busted; + } + + /* attribute list has to be kept sorted per c14n rules */ + high = (int) w->attributes.count; + low = -1; + while (high - low > 1) + { + int probe = (high + low) / 2; + if (orderAttributes(&w->arec, aa[probe]) < 0) + high = probe; + else + low = probe; + } + + /* if it was already there */ + if (low != -1 && orderAttributes(&w->arec, aa[low]) == 0) + return aa[low]; + + /* not there, build it */ + a = (genxAttribute) allocate(w, sizeof(struct genxAttribute_rec)); + if (a == NULL) + { + w->status = GENX_ALLOC_FAILED; + goto busted; + } + + a->writer = w; + a->ns = ns; + a->provided = False; + a->atype = w->arec.atype; + a->next = NULL; + + if ((a->name = copy(w, name)) == NULL) + { + w->status = GENX_ALLOC_FAILED; + goto busted; + } + + if ((w->status = initCollector(w, &a->value)) != GENX_SUCCESS) + goto busted; + + if (valuestr) + if ((w->status = collectString(w, &a->value, valuestr)) != GENX_SUCCESS) + goto busted; + + w->status = listInsert(&w->attributes, a, (size_t) high); + if (w->status != GENX_SUCCESS) + goto busted; + + *statusP = GENX_SUCCESS; + return a; + +busted: + *statusP = w->status; + return NULL; +} + +/* + * genxDeclareAttribute - see genx.h for details + */ +genxAttribute genxDeclareAttribute(genxWriter w, + genxNamespace ns, constUtf8 name, + genxStatus * statusP) +{ + if ((w->status = checkNCName(w, name)) != GENX_SUCCESS) + { + *statusP = w->status; + return NULL; + } + + return declareAttribute(w, ns, name, NULL, statusP); +} + +/******************************* + * I/O + */ +static genxStatus sendx(genxWriter w, constUtf8 s) +{ + if (w->sender) + return (*w->sender->send)(w->userData, s); + else + return GENX_IO_ERROR; +} + +static genxStatus sendxBounded(genxWriter w, constUtf8 start, constUtf8 end) +{ + if (w->sender) + return (*w->sender->sendBounded)(w->userData, start, end); + else + return GENX_IO_ERROR; +} + +#define SendCheck(w,s) if ((w->status=sendx(w,(constUtf8)s))!=GENX_SUCCESS) return w->status + +/******************************* + * XML writing routines. The semantics of the externally-facing ones are + * written up in genx.h. Commentary here is implementation notes and + * for internal routines. + */ + +genxStatus genxStartDocSender(genxWriter w, const genxSender * sender) +{ + if (w->sequence != SEQUENCE_NO_DOC) + return w->status = GENX_SEQUENCE_ERROR; + + w->sequence = SEQUENCE_PRE_DOC; + w->sender = sender; + + if (w->ppIndent) + { + w->ppDepth = 0; + w->ppSuspendDepth = 0; + w->ppSimple = True; + } + + return GENX_SUCCESS; +} + +/* + * Output new line and indentation. + */ +static genxStatus writeIndentation(genxWriter w) +{ + int i, n; + SendCheck(w, "\n"); + n = w->ppDepth * w->ppIndent; + + for (i = 0; i < n; i++) + SendCheck(w, " "); + + return w->status; +} + +/* + * Output attribute. + */ +static genxStatus writeAttribute(genxAttribute a) +{ + genxWriter w = a->writer; + + if (a->ns && a->ns->baroque && a->ns->declaration == w->xmlnsEquals) + return w->status = GENX_ATTRIBUTE_IN_DEFAULT_NAMESPACE; + + SendCheck(w, " "); + + if (a->ns) + { + SendCheck(w, a->ns->declaration->name + STRLEN_XMLNS_COLON); + SendCheck(w, ":"); + } + + SendCheck(w, a->name); + SendCheck(w, "=\""); + SendCheck(w, a->value.buf); + SendCheck(w, "\""); + + return w->status; +} + +/* + * Write out the attributes we've been gathering up for an element. We save + * them until we've gathered them all so they can be writen in canonical + * order. + * Also, we end the start-tag. + * The trick here is that we keep the attribute list properly sorted as + * we build it, then as each attribute is added, we fill in its value and + * mark the fact that it's been added, in the "provided" field. + */ +static genxStatus writeStartTag(genxWriter w, Boolean close) +{ + size_t i; + genxAttribute * aa = (genxAttribute *) w->attributes.pointers; + genxElement e = w->nowStarting; + + /* + * make sure the right namespace decls are in effect; + * if they are these might create an error, so ignore it + */ + if (e->ns) + addNamespace(e->ns, NULL); + else + unsetDefaultNamespace(w); + w->status = GENX_SUCCESS; + + if (w->ppIndent) + { + if (w->ppDepth && + /* Suspend depth could be at this element's depth (after ++ below). */ + (w->ppSuspendDepth == 0 || w->ppSuspendDepth > w->ppDepth)) + if (writeIndentation (w) != GENX_SUCCESS) + return w->status; + + if (!close) + { + w->ppDepth++; + w->ppSimple = True; + } + else + { + /* + * Conceptually we incremented/decremented the depth, so check if we + * need to resume pretty-printing. + */ + if (w->ppSuspendDepth > w->ppDepth) + w->ppSuspendDepth = 0; + } + } + + SendCheck(w, "<"); + if (e->ns && (e->ns->declaration != w->xmlnsEquals)) + { + SendCheck(w, e->ns->declaration->name + STRLEN_XMLNS_COLON); + SendCheck(w, ":"); + } + SendCheck(w, e->name); + + /* If we are canonicalizing, then write sorted attributes. Otherwise + write them in the order specified. */ + if (w->canonical) + { + for (i = 0; i < w->attributes.count; i++) + { + if (aa[i]->provided) + { + if (writeAttribute (aa[i]) != GENX_SUCCESS) + return w->status; + + aa[i]->provided = False; + } + } + } + else + { + /* Keep the chain consistent even if we bail out mid way because of + an error. This way we will still be able to clear it in reset().*/ + while (w->firstAttribute != NULL) + { + genxAttribute t = w->firstAttribute->next; + + if (writeAttribute (w->firstAttribute) != GENX_SUCCESS) + return w->status; + + w->firstAttribute->provided = False; + w->firstAttribute->next = NULL; + w->firstAttribute = t; + } + + w->lastAttribute = NULL; + } + + if (close) + SendCheck(w, "/"); + SendCheck(w, ">"); + return GENX_SUCCESS; +} + +/* + * internal clear-er; no sequence checking + */ +static genxStatus unsetDefaultNamespace(genxWriter w) +{ + int i; + Boolean found = False; + + /* don't put it in if not needed */ + i = (int) (w->stack.count) - 1; + while (found == False && i > 0) + { + while (w->stack.pointers[i] != NULL) + { + genxAttribute decl = (genxAttribute) w->stack.pointers[i--]; + genxNamespace ns = (genxNamespace) w->stack.pointers[i--]; + + /* if already unset */ + if (ns == NULL) + return w->status = GENX_SUCCESS; + + /* + * the default namespace was declared. This namespace now + * becomes baroque + */ + if (decl == w->xmlnsEquals) + { + ns->baroque = True; + found = True; + break; + } + } + i -= 2; + } + + if (!found) + return GENX_SUCCESS; + + /* + * push a signal on the stack + */ + if ((w->status = listAppend(&w->stack, NULL)) != GENX_SUCCESS) + return w->status; + w->status = listAppend(&w->stack, w->xmlnsEquals); + if (w->status != GENX_SUCCESS) + return w->status; + + /* add the xmlns= attribute, it must be the first one */ + return addAttribute(w->xmlnsEquals, w->empty); +} + +/* + * clear the default namespace declaration + */ +genxStatus genxUnsetDefaultNamespace(genxWriter w) +{ + + /* can only do this while in start-tag mode */ + if (w->sequence != SEQUENCE_START_TAG) + return w->status = GENX_SEQUENCE_ERROR; + + return unsetDefaultNamespace(w); +} + +genxStatus genxStartElement(genxElement e) +{ + genxWriter w = e->writer; + + switch (w->sequence) + { + case SEQUENCE_NO_DOC: + case SEQUENCE_POST_DOC: + case SEQUENCE_START_ATTR: + return w->status = GENX_SEQUENCE_ERROR; + case SEQUENCE_START_TAG: + case SEQUENCE_ATTRIBUTES: + if ((w->status = writeStartTag(w, False)) != GENX_SUCCESS) + return w->status; + break; + case SEQUENCE_PRE_DOC: + case SEQUENCE_CONTENT: + break; + } + + w->sequence = SEQUENCE_START_TAG; + + /* + * push the stack. We push a NULL after a pointer to this element + * because the stack will also contain pointers to the namespace + * attributes that got declared here, so we can keep track of what's + * in effect. I.e. a single stack entry consists logically of a pointer + * to an element object, a NULL, then zero or more pairs of pointers to + * namespace objects/declarations + */ + if ((w->status = listAppend(&w->stack, e)) != GENX_SUCCESS) + return w->status; + if ((w->status = listAppend(&w->stack, NULL)) != GENX_SUCCESS) + return w->status; + + w->nowStarting = e; + + return GENX_SUCCESS; +} + +/* + * internal namespace adder; no sequence checking + */ +static genxStatus addNamespace(genxNamespace ns, constUtf8 prefix) +{ + genxWriter w = ns->writer; + genxAttribute decl; + int i; + genxElement e; + + /* + * first, we'll find the declaring attribute + */ + if (prefix == NULL) + decl = ns->defaultDecl; + else + { + if (prefix[0] == 0) + decl = w->xmlnsEquals; + else + { + if ((prefix = storePrefix(w, prefix, True)) == NULL) + return w->status; + decl = declareAttribute(w, NULL, prefix, ns->name, &w->status); + if (decl == NULL || w->status != GENX_SUCCESS) + return w->status; + } + } + + if (decl != ns->defaultDecl) + ns->baroque = True; + + /* + * avoid doing anything if this namespace is already declared. If + * they've shown good taste we can do this cheaply + */ + if (!ns->baroque) + { + if (ns->declCount > 0) + return w->status = GENX_SUCCESS; + } + else + { + + /* + * First, we'll run all the way up the stack to see if there is + * another declaration for this namespace/prefix in scope, in which + * case it's a no-op; or, if there's another declaration for this + * prefix on another namespace, in which case we have to over-ride + */ + i = (int) (w->stack.count) - 1; + while (i > 0) + { + while (w->stack.pointers[i] != NULL) + { + genxAttribute otherDecl = (genxAttribute) w->stack.pointers[i--]; + genxNamespace otherNs = (genxNamespace) w->stack.pointers[i--]; + + if (ns == otherNs) + { + if (decl == otherDecl) + return w->status = GENX_SUCCESS; + else + { + i = 0; + break; + } + } + else + { + /* different namespace, same prefix? */ + if (decl == otherDecl) + { + i = 0; + break; + } + } + } + i -= 2; + } + } + + /* + * If this namespace is already declared on + * this element (with different prefix/decl) which is an error. + */ + i = (int) (w->stack.count) - 1; + while (w->stack.pointers[i] != NULL) + { + genxNamespace otherNs; + i--; /* don't need declaration */ + otherNs = (genxNamespace) w->stack.pointers[i--]; + + if (ns == otherNs) + return w->status = GENX_DUPLICATE_NAMESPACE; + } + + /* move pointer from NULL to element */ + --i; + + /* + * It's also an error if this is a default-namespace declaration and the + * element is in no namespace. + */ + e = (genxElement) w->stack.pointers[i]; + if (e->ns == NULL && decl == w->xmlnsEquals) + return w->status = GENX_BAD_DEFAULT_DECLARATION; + + if ((w->status = listAppend(&w->stack, ns)) != GENX_SUCCESS) + return w->status; + if ((w->status = listAppend(&w->stack, decl)) != GENX_SUCCESS) + return w->status; + + ns->declaration = decl; + ns->declCount++; + return addAttribute(decl, ns->name); +} + +/* + * Add a namespace declaration + */ +genxStatus genxAddNamespace(genxNamespace ns, constUtf8 prefix) +{ + if (ns->writer->sequence != SEQUENCE_START_TAG) + return ns->writer->status = GENX_SEQUENCE_ERROR; + + return addNamespace(ns, prefix); +} + +/* + * Private attribute-adding code + * most of the work here is normalizing the value, which is the same + * as regular normalization except for " is replaced by """ + */ +static genxStatus collectAttributeValue (genxWriter w, collector* value, + constUtf8 start, constUtf8 end) +{ + /* If end is NULL then the length of the value is unknown and + the value is 0-terminated. */ + + utf8 last = (utf8) start; + + while (end != NULL ? start < end : *start) + { + int c = genxNextUnicodeChar(&start); + + if (c == -1) + return w->status = GENX_BAD_UTF8; + + if (!isXMLChar(w, c)) + return w->status = GENX_NON_XML_CHARACTER; + + switch(c) + { + case 9: + collectPiece(w, value, " ", 5); + break; + case 0xa: + collectPiece(w, value, " ", 5); + break; + case 0xd: + collectPiece(w, value, " ", 5); + break; + case '"': + collectPiece(w, value, """, 6); + break; + case '<': + collectPiece(w, value, "<", 4); + break; + case '&': + collectPiece(w, value, "&", 5); + break; + /* + case '>': + collectPiece(w, value, ">", 4); + break; + */ + default: + collectPiece(w, value, (const char *) last, start - last); + break; + } + last = (utf8) start; + } + + return GENX_SUCCESS; +} + +static genxStatus addAttribute(genxAttribute a, constUtf8 valuestr) +{ + genxWriter w = a->writer; + + /* if valuestr not provided, this is an xmlns with a pre-cooked value */ + if (valuestr) + { + startCollect(&a->value); + + if (collectAttributeValue (w, &a->value, valuestr, NULL) != GENX_SUCCESS) + return w->status; + + endCollect(&a->value); + } + + /* now add the namespace attribute; might fail if it's been hand-declared */ + if (a->ns) + addNamespace(a->ns, NULL); + + if (valuestr && a->provided) + return w->status = GENX_DUPLICATE_ATTRIBUTE; + + a->provided = True; + + /* Add the attribute to the ordered list if not canonical. */ + if (!w->canonical) + { + if (w->lastAttribute != NULL) + w->lastAttribute = w->lastAttribute->next = a; + else + w->lastAttribute = w->firstAttribute = a; + } + + return GENX_SUCCESS; +} + +/* + * public attribute adder. + * The only difference is that it doesn't allow a NULL value + */ +genxStatus genxAddAttribute(genxAttribute a, constUtf8 valuestr) +{ + if (a->writer->sequence != SEQUENCE_START_TAG && + a->writer->sequence != SEQUENCE_ATTRIBUTES) + return a->writer->status = GENX_SEQUENCE_ERROR; + a->writer->sequence = SEQUENCE_ATTRIBUTES; + + if (valuestr == NULL) + return a->writer->status = GENX_MISSING_VALUE; + + return addAttribute(a, valuestr); +} + +genxStatus genxStartAttribute(genxAttribute a) +{ + genxWriter w = a->writer; + + if (w->sequence != SEQUENCE_START_TAG && + w->sequence != SEQUENCE_ATTRIBUTES) + return w->status = GENX_SEQUENCE_ERROR; + + w->sequence = SEQUENCE_START_ATTR; + w->nowStartingAttr = a; + + startCollect(&a->value); + + return GENX_SUCCESS; +} + +genxStatus genxGetCurrentAttribute (genxWriter w, + constUtf8* xmlns, constUtf8* name) +{ + genxAttribute a; + + if (w->sequence != SEQUENCE_START_ATTR) + return w->status = GENX_SEQUENCE_ERROR; + + a = w->nowStartingAttr; + + *xmlns = a->ns ? a->ns->name : NULL; + *name = a->name; + + return GENX_SUCCESS; +} + +genxStatus genxEndAttribute(genxWriter w) +{ + genxAttribute a; + + if (w->sequence != SEQUENCE_START_ATTR) + return w->status = GENX_SEQUENCE_ERROR; + + a = w->nowStartingAttr; + w->sequence = SEQUENCE_ATTRIBUTES; + + endCollect(&a->value); + + /* now add the namespace attribute; might fail if it's been hand-declared */ + if (a->ns) + addNamespace(a->ns, NULL); + + if (a->provided) + return w->status = GENX_DUPLICATE_ATTRIBUTE; + + a->provided = True; + + /* Add the attribute to the ordered list if not canonical. */ + if (!w->canonical) + { + if (w->lastAttribute != NULL) + w->lastAttribute = w->lastAttribute->next = a; + else + w->lastAttribute = w->firstAttribute = a; + } + + return GENX_SUCCESS; +} + +genxStatus genxGetCurrentElement (genxWriter w, + constUtf8* xmlns, constUtf8* name) +{ + int i; + genxElement e; + + switch (w->sequence) + { + case SEQUENCE_START_TAG: + case SEQUENCE_ATTRIBUTES: + e = w->nowStarting; + break; + case SEQUENCE_CONTENT: + /* Find the element. The same code as in EndElement() below. */ + for (i = (int) (w->stack.count) - 1; + w->stack.pointers[i] != NULL; + i -= 2) + ; + e = (genxElement) w->stack.pointers[--i]; + break; + default: + return w->status = GENX_SEQUENCE_ERROR; + } + + *xmlns = e->ns ? e->ns->name : NULL; + *name = e->name; + + return GENX_SUCCESS; +} + +genxStatus genxEndElement(genxWriter w) +{ + int i; + Boolean close = True; + + switch (w->sequence) + { + case SEQUENCE_NO_DOC: + case SEQUENCE_PRE_DOC: + case SEQUENCE_POST_DOC: + case SEQUENCE_START_ATTR: + return w->status = GENX_SEQUENCE_ERROR; + case SEQUENCE_START_TAG: + case SEQUENCE_ATTRIBUTES: + if ((w->status = writeStartTag(w, !w->canonical)) != GENX_SUCCESS) + return w->status; + close = w->canonical; + break; + case SEQUENCE_CONTENT: + break; + } + + /* + * Output the closing tag. + */ + if (close) + { + genxElement e; + + /* + * first peek into the stack to find the right namespace declaration + * (if any) so we can properly prefix the end-tag. Have to do this + * before unwinding the stack because that might reset some xmlns + * prefixes to the context in the parent element + */ + for (i = (int) (w->stack.count) - 1; + w->stack.pointers[i] != NULL; + i -= 2) + ; + e = (genxElement) w->stack.pointers[--i]; + + if (w->ppIndent) + { + w->ppDepth--; + + if (!w->ppSimple && w->ppSuspendDepth == 0) + if (writeIndentation (w) != GENX_SUCCESS) + return w->status; + + if (w->ppSuspendDepth > w->ppDepth) + w->ppSuspendDepth = 0; /* Resume pretty-printing. */ + } + + SendCheck(w, "ns && e->ns->declaration != w->xmlnsEquals) + { + SendCheck(w, e->ns->declaration->name + STRLEN_XMLNS_COLON); + SendCheck(w, ":"); + } + SendCheck(w, e->name); + SendCheck(w, ">"); + } + + /* If this element is written while pretty-printing is suspended, + treat it as simple. As an example, think of an XHTML element + for which we suspend pretty-printing before writing the opening + tag and resume it after the closing one. */ + if (w->ppIndent && w->ppSuspendDepth == 0) + w->ppSimple = False; + + /* + * pop zero or more namespace declarations, then a null, then the + * start-element declaration off the stack + */ + w->stack.count--; + while (w->stack.pointers[w->stack.count] != NULL) + { + genxNamespace ns = (genxNamespace) w->stack.pointers[--w->stack.count]; + w->stack.count--; /* don't need decl */ + + /* if not a fake unset-default namespace */ + if (ns) + { + /* + * if they've stupidly jammed in their own namespace-prefix + * declarations, we have to go looking to see if there's another + * one in effect + */ + if (ns->baroque) + { + i = (int) w->stack.count; + while (i > 0) + { + while (w->stack.pointers[i] != NULL) + { + genxAttribute otherDecl = (genxAttribute) w->stack.pointers[i--]; + genxNamespace otherNs = (genxNamespace) w->stack.pointers[i--]; + + if (otherNs == ns) + { + ns->declaration = otherDecl; + i = 0; + break; + } + } + + /* skip NULL & element */ + i -= 2; + } + } + ns->declCount--; + if (ns->declCount == 0) + ns->baroque = False; + } + } + + /* pop the NULL */ + if (w->stack.count == 0) + return w->status = GENX_NO_START_TAG; + --w->stack.count; + + if (w->stack.count == 0) + w->sequence = SEQUENCE_POST_DOC; + else + w->sequence = SEQUENCE_CONTENT; + + return GENX_SUCCESS; +} + +/* + * Internal character-adder. It tries to keep the number of sendx() + * calls down by looking at each character but only doing the output + * when it has to escape something; ordinary text gets saved up in + * chunks the start of which is indicated by *breaker. + * c is the character, next points to the UTF8 representing the next + * lastsP indirectly points to the UTF8 representing the + * character, breakerP* indirectly points to the last place genx + * changed the UTF8, e.g. by escaping a '<' + */ +static genxStatus addChar(genxWriter w, int c, constUtf8 next, + constUtf8 * lastsP, constUtf8 * breakerP) +{ + if (c == -1) + return GENX_BAD_UTF8; + + if (!isXMLChar(w, c)) + return GENX_NON_XML_CHARACTER; + + switch(c) + { + case 0xd: + if ((w->status = sendxBounded(w, *breakerP, *lastsP)) != GENX_SUCCESS) + return w->status; + *breakerP = next; + sendx(w, (utf8) " "); + break; + case '<': + if ((w->status = sendxBounded(w, *breakerP, *lastsP)) != GENX_SUCCESS) + return w->status; + *breakerP = next; + sendx(w, (utf8) "<"); + break; + case '&': + if ((w->status = sendxBounded(w, *breakerP, *lastsP)) != GENX_SUCCESS) + return w->status; + *breakerP = next; + sendx(w, (utf8) "&"); + break; + case '>': + if ((w->status = sendxBounded(w, *breakerP, *lastsP)) != GENX_SUCCESS) + return w->status; + *breakerP = next; + sendx(w, (utf8) ">"); + break; + default: + break; + } + *lastsP = next; + return GENX_SUCCESS; +} + +genxStatus genxAddText(genxWriter w, constUtf8 start) +{ + constUtf8 lasts = start; + constUtf8 breaker = start; + + if (w->sequence == SEQUENCE_START_TAG || + w->sequence == SEQUENCE_ATTRIBUTES) + { + if ((w->status = writeStartTag(w, False)) != GENX_SUCCESS) + return w->status; + w->sequence = SEQUENCE_CONTENT; + } + + if (w->sequence == SEQUENCE_CONTENT) + { + while (*start) + { + int c = genxNextUnicodeChar(&start); + + w->status = addChar(w, c, start, &lasts, &breaker); + if (w->status != GENX_SUCCESS) + return w->status; + } + return sendxBounded(w, breaker, (utf8) start); + } + else if (w->sequence == SEQUENCE_START_ATTR) + { + return collectAttributeValue (w, &w->nowStartingAttr->value, start, NULL); + } + else + return w->status = GENX_SEQUENCE_ERROR; +} + +genxStatus genxAddBoundedText(genxWriter w, constUtf8 start, constUtf8 end) +{ + constUtf8 lasts = start; + constUtf8 breaker = start; + + if (w->sequence == SEQUENCE_START_TAG || + w->sequence == SEQUENCE_ATTRIBUTES) + { + if ((w->status = writeStartTag(w, False)) != GENX_SUCCESS) + return w->status; + w->sequence = SEQUENCE_CONTENT; + } + + if (w->sequence == SEQUENCE_CONTENT) + { + while (start < end) + { + int c = genxNextUnicodeChar(&start); + + w->status = addChar(w, c, (utf8) start, &lasts, &breaker); + if (w->status != GENX_SUCCESS) + return w->status; + } + return sendxBounded(w, breaker, (utf8) start); + } + else if (w->sequence == SEQUENCE_START_ATTR) + { + return collectAttributeValue (w, &w->nowStartingAttr->value, start, end); + } + else + return w->status = GENX_SEQUENCE_ERROR; +} + +genxStatus genxAddCountedText(genxWriter w, constUtf8 start, size_t byteCount) +{ + utf8 end = (utf8) (start + byteCount); + + return genxAddBoundedText(w, start, end); +} + +genxStatus genxAddCharacter(genxWriter w, int c) +{ + unsigned char cUTF8[10]; + utf8 lasts, breaker, next; + + if (w->sequence == SEQUENCE_START_TAG || + w->sequence == SEQUENCE_ATTRIBUTES) + { + if ((w->status = writeStartTag(w, False)) != GENX_SUCCESS) + return w->status; + w->sequence = SEQUENCE_CONTENT; + } + + if (!isXMLChar(w, c)) + return w->status = GENX_NON_XML_CHARACTER; + + if (w->sequence == SEQUENCE_START_ATTR) + { + int done = 1; + collector* value = &w->nowStartingAttr->value; + + switch(c) + { + case 9: + collectPiece(w, value, " ", 5); + break; + case 0xa: + collectPiece(w, value, " ", 5); + break; + case 0xd: + collectPiece(w, value, " ", 5); + break; + case '"': + collectPiece(w, value, """, 6); + break; + case '<': + collectPiece(w, value, "<", 4); + break; + case '&': + collectPiece(w, value, "&", 5); + break; + /* + case '>': + collectPiece(w, value, ">", 4); + break; + */ + default: + done = 0; + break; + } + + if (done) + return GENX_SUCCESS; + } + + /* make UTF8 representation of character */ + lasts = breaker = next = cUTF8; + + if (c < 0x80) + *next++ = c; + else if (c < 0x800) + { + *next++ = 0xc0 | (c >> 6); + *next++ = 0x80 | (c & 0x3f); + } + else if (c < 0x10000) + { + *next++ = 0xe0 | (c >> 12); + *next++ = 0x80 | ((c & 0xfc0) >> 6); + *next++ = 0x80 | (c & 0x3f); + } + else + { + *next++ = 0xf0 | (c >> 18); + *next++ = 0x80 | ((c & 0x3f000) >> 12); + *next++ = 0x80 | ((c & 0xfc0) >> 6); + *next++ = 0x80 | (c & 0x3f); + } + *next = 0; + + if (w->sequence == SEQUENCE_CONTENT) + { + w->status = + addChar(w, c, next, (constUtf8 *) &lasts, (constUtf8 *) &breaker); + + if (w->status != GENX_SUCCESS) + return w->status; + + return sendxBounded(w, breaker, next); + } + else if (w->sequence == SEQUENCE_START_ATTR) + { + collectPiece(w, &w->nowStartingAttr->value, + (const char *) cUTF8, next - cUTF8); + return GENX_SUCCESS; + } + else + return w->status = GENX_SEQUENCE_ERROR; +} + +genxStatus genxEndDocument(genxWriter w) +{ + if (w->sequence != SEQUENCE_POST_DOC) + return w->status = GENX_SEQUENCE_ERROR; + + /* Write a newline after the closing tag. */ + SendCheck (w, "\n"); + + if ((w->status = (*w->sender->flush)(w->userData)) != GENX_SUCCESS) + return w->status; + + w->sequence = SEQUENCE_NO_DOC; + return GENX_SUCCESS; +} + +genxStatus genxXmlDeclaration(genxWriter w, + constUtf8 ver, + constUtf8 enc, + constUtf8 stl) +{ + if (w->sequence != SEQUENCE_PRE_DOC) + return w->status = GENX_SEQUENCE_ERROR; + + if ((w->status = genxCheckText(w, ver)) != GENX_SUCCESS) + return w->status; + + if (enc != NULL && (w->status = genxCheckText(w, enc)) != GENX_SUCCESS) + return w->status; + + if (stl != NULL && (w->status = genxCheckText(w, stl)) != GENX_SUCCESS) + return w->status; + + SendCheck (w, "\n"); + + return GENX_SUCCESS; +} + +genxStatus genxDoctypeDeclaration(genxWriter w, + constUtf8 re, + constUtf8 pi, + constUtf8 si, + constUtf8 is) +{ + if (w->sequence != SEQUENCE_PRE_DOC) + return w->status = GENX_SEQUENCE_ERROR; + + if ((w->status = genxCheckText(w, re)) != GENX_SUCCESS) + return w->status; + + if (pi != NULL && (w->status = genxCheckText(w, pi)) != GENX_SUCCESS) + return w->status; + + if (si != NULL && (w->status = genxCheckText(w, si)) != GENX_SUCCESS) + return w->status; + + if (is != NULL && (w->status = genxCheckText(w, is)) != GENX_SUCCESS) + return w->status; + + SendCheck (w, "\n"); + return GENX_SUCCESS; +} + +genxStatus genxComment(genxWriter w, constUtf8 text) +{ + size_t i; + + if (w->sequence == SEQUENCE_NO_DOC || + w->sequence == SEQUENCE_START_ATTR) + return w->status = GENX_SEQUENCE_ERROR; + + if ((w->status = genxCheckText(w, text)) != GENX_SUCCESS) + return w->status; + + /* no leading '-', no trailing '-', no '--' */ + if (text[0] == '-') + return w->status = GENX_MALFORMED_COMMENT; + for (i = 0; text[i]; i++) + if (text[i] == '-' && (text[i + 1] == '-' || text[i + 1] == 0)) + return w->status = GENX_MALFORMED_COMMENT; + + if (w->sequence == SEQUENCE_START_TAG || + w->sequence == SEQUENCE_ATTRIBUTES) + { + if ((w->status = writeStartTag(w, False)) != GENX_SUCCESS) + return w->status; + w->sequence = SEQUENCE_CONTENT; + } + + else if (w->sequence == SEQUENCE_POST_DOC) + if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS) + return w->status; + + if ((w->status = sendx(w, (utf8) "")) != GENX_SUCCESS) + return w->status; + + if (w->sequence == SEQUENCE_PRE_DOC) + if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS) + return w->status; + + return GENX_SUCCESS; +} + +genxStatus genxPI(genxWriter w, constUtf8 target, constUtf8 text) +{ + size_t i; + + if (w->sequence == SEQUENCE_NO_DOC || + w->sequence == SEQUENCE_START_ATTR) + return w->status = GENX_SEQUENCE_ERROR; + + if ((w->status = genxCheckText(w, target)) != GENX_SUCCESS) + return w->status; + if ((w->status = checkNCName(w, target)) != GENX_SUCCESS) + return w->status; + if ((strlen((const char *) target) >= 3) && + (target[0] == 'x' || target[0] == 'X') && + (target[1] == 'm' || target[1] == 'M') && + (target[2] == 'l' || target[2] == 'L') && + (target[3] == 0)) + return w->status = GENX_XML_PI_TARGET; + + if ((w->status = genxCheckText(w, text)) != GENX_SUCCESS) + return w->status; + + /* no ?> within */ + for (i = 1; text[i]; i++) + if (text[i] == '>' && text[i - 1] == '?') + return w->status = GENX_MALFORMED_PI; + + if (w->sequence == SEQUENCE_START_TAG || + w->sequence == SEQUENCE_ATTRIBUTES) + { + if ((w->status = writeStartTag(w, False)) != GENX_SUCCESS) + return w->status; + w->sequence = SEQUENCE_CONTENT; + } + + else if (w->sequence == SEQUENCE_POST_DOC) + if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS) + return w->status; + + if ((w->status = sendx(w, (utf8) "status; + if ((w->status = sendx(w, target)) != GENX_SUCCESS) + return w->status; + if (text[0]) + { + if ((w->status = sendx(w, (utf8) " ")) != GENX_SUCCESS) + return w->status; + if ((w->status = sendx(w, text)) != GENX_SUCCESS) + return w->status; + } + if ((w->status = sendx(w, (utf8) "?>")) != GENX_SUCCESS) + return w->status; + + if (w->sequence == SEQUENCE_PRE_DOC) + if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS) + return w->status; + + return GENX_SUCCESS; +} + +/******************************* + * Literal versions of the writing routines + */ +genxStatus genxStartElementLiteral(genxWriter w, + constUtf8 xmlns, constUtf8 name) +{ + genxNamespace ns = NULL; + genxElement e; + + if (xmlns) + { + ns = genxDeclareNamespace(w, xmlns, NULL, &w->status); + if (ns == NULL || w->status != GENX_SUCCESS) + return w->status; + } + e = genxDeclareElement(w, ns, name, &w->status); + if (e == NULL || w->status != GENX_SUCCESS) + return w->status; + + return genxStartElement(e); +} + +genxStatus genxAddAttributeLiteral(genxWriter w, constUtf8 xmlns, + constUtf8 name, constUtf8 value) +{ + genxNamespace ns = NULL; + genxAttribute a; + + if (xmlns) + { + ns = genxDeclareNamespace(w, xmlns, NULL, &w->status); + if (ns == NULL && w->status != GENX_SUCCESS) + return w->status; + } + + a = genxDeclareAttribute(w, ns, name, &w->status); + if (a == NULL || w->status != GENX_SUCCESS) + return w->status; + + return genxAddAttribute(a, value); +} + +genxStatus genxStartAttributeLiteral(genxWriter w, + constUtf8 xmlns, constUtf8 name) +{ + genxNamespace ns = NULL; + genxAttribute a; + + if (xmlns) + { + ns = genxDeclareNamespace(w, xmlns, NULL, &w->status); + if (ns == NULL && w->status != GENX_SUCCESS) + return w->status; + } + + a = genxDeclareAttribute(w, ns, name, &w->status); + if (a == NULL || w->status != GENX_SUCCESS) + return w->status; + + return genxStartAttribute(a); +} + +genxStatus genxAddNamespaceLiteral(genxWriter w, + constUtf8 uri, constUtf8 prefix) +{ + genxNamespace ns = genxDeclareNamespace(w, uri, prefix, &w->status); + if (ns == NULL && w->status != GENX_SUCCESS) + return w->status; + + return genxAddNamespace(ns, NULL); +} + +/* + * return version + */ +const char * genxGetVersion() +{ + return LIBGENX_VERSION_STR; +} diff --git a/libgenx/libgenx/genx.h b/libgenx/libgenx/genx.h new file mode 100644 index 0000000..8c03e7e --- /dev/null +++ b/libgenx/libgenx/genx.h @@ -0,0 +1,453 @@ +/* + * genx - C-callable library for generating XML documents + */ + +/* + * Copyright (c) 2004 by Tim Bray and Sun Microsystems. + * Copyright (c) Code Synthesis Tools CC (see the LICENSE file). + * + * For copying permission, see the accompanying LICENSE file. + */ + +#ifndef GENX_H +#define GENX_H + +#include /* size_t */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Note on error handling: genx routines mostly return + * GENX_SUCCESS (guaranteed to be zero) in normal circumstances, one of + * these other GENX_ values on a memory allocation or I/O failure or if the + * call would result in non-well-formed output. + * You can associate an error message with one of these codes explicitly + * or with the most recent error using genxGetErrorMessage() and + * genxLastErrorMessage(); see below. + */ +typedef enum +{ + GENX_SUCCESS = 0, + GENX_BAD_UTF8, + GENX_NON_XML_CHARACTER, + GENX_BAD_NAME, + GENX_ALLOC_FAILED, + GENX_BAD_NAMESPACE_NAME, + GENX_INTERNAL_ERROR, + GENX_DUPLICATE_PREFIX, + GENX_SEQUENCE_ERROR, + GENX_NO_START_TAG, + GENX_IO_ERROR, + GENX_MISSING_VALUE, + GENX_MALFORMED_COMMENT, + GENX_XML_PI_TARGET, + GENX_MALFORMED_PI, + GENX_DUPLICATE_ATTRIBUTE, + GENX_ATTRIBUTE_IN_DEFAULT_NAMESPACE, + GENX_DUPLICATE_NAMESPACE, + GENX_BAD_DEFAULT_DECLARATION +} genxStatus; + +/* character types */ +#define GENX_XML_CHAR 1 +#define GENX_LETTER 2 +#define GENX_NAMECHAR 4 + +/* The size of the character table. Valid values are 0x100 (first 255 + chars are checked) and 0x10000 (all chars are checked). */ +#ifndef GENX_CHAR_TABLE_SIZE +# define GENX_CHAR_TABLE_SIZE 0x100 +#endif + +/* a UTF-8 string */ +typedef unsigned char * utf8; +typedef const unsigned char * constUtf8; + +/* + * genx's own types + */ +typedef struct genxWriter_rec * genxWriter; +typedef struct genxNamespace_rec * genxNamespace; +typedef struct genxElement_rec * genxElement; +typedef struct genxAttribute_rec * genxAttribute; + +typedef void * (*genxAlloc) (void * userData, size_t bytes); +typedef void (*genxDealloc) (void * userData, void* data); + +/* + * Constructors, set/get + */ + +/* + * Create a new writer. For generating multiple XML documents, it's most + * efficient to re-use the same genx object. However, you can only write + * one document at a time with a writer. + * Returns NULL if it fails, which can only be due to an allocation failure. + */ +LIBGENX_SYMEXPORT +genxWriter genxNew(genxAlloc alloc, genxDealloc dealloc, void * userData); + +/* + * Reset the writer object back into usable state after an error or + * interruption. + */ +LIBGENX_SYMEXPORT +genxStatus genxReset (genxWriter w); + +/* + * Dispose of a writer, freeing all associated memory + */ +LIBGENX_SYMEXPORT +void genxDispose(genxWriter w); + +/* + * Set/get + */ + +/* + * The userdata pointer will be passed to memory-allocation + * and I/O callbacks. If not set, genx will pass NULL + */ +LIBGENX_SYMEXPORT +void genxSetUserData(genxWriter w, void * userData); + +LIBGENX_SYMEXPORT +void * genxGetUserData(genxWriter w); + +/* + * Set/get pretty-printing. If indentation is set to 0, then no pretty- + * printing is performed. + */ +LIBGENX_SYMEXPORT +genxStatus genxSetPrettyPrint(genxWriter w, int indentation); + +LIBGENX_SYMEXPORT +int genxGetPrettyPrint(genxWriter w); + +/* + * Suspend/resume pretty-printing. Pretty-printing can be suspended + * only inside an element and, unless explicitly resumed, it will + * remain suspended until the end of that element. You should only + * explicitly resume pretty-printing at the element nesting level + * of suspension. If pretty-printing is already suspended at an + * outer nesting level, then subsequent calls to suspend/resume + * are ignored. The PrettyPrintSuspended() function can be used + * to check if pretty-printing is currently suspended. If it is + * not, then this function returns 0. Otherwise, it returns the + * level at which pretty-printing was suspended, with root element + * being level 1. + */ +LIBGENX_SYMEXPORT +genxStatus genxSuspendPrettyPrint(genxWriter w); + +LIBGENX_SYMEXPORT +genxStatus genxResumePrettyPrint(genxWriter w); + +LIBGENX_SYMEXPORT +int genxPrettyPrintSuspended(genxWriter w); + + +/* + * Set/get canonicalization. If true, then output explicit closing + * tags and sort attributes. Default is false. + */ +LIBGENX_SYMEXPORT +genxStatus genxSetCanonical(genxWriter w, int flag); + +LIBGENX_SYMEXPORT +int genxGetCanonical(genxWriter w); + +/* + * User-provided memory allocator, if desired. For example, if you were + * in an Apache module, you could arrange for genx to use ap_palloc by + * making the pool accessible via the userData call. + * The "dealloc" is to be used to free memory allocated with "alloc". If + * alloc is provided but dealloc is NULL, genx will not attempt to free + * the memory; this would be appropriate in an Apache context. + * If "alloc" is not provided, genx routines use malloc() to allocate memory + */ +LIBGENX_SYMEXPORT +void genxSetAlloc(genxWriter w, genxAlloc alloc); + +LIBGENX_SYMEXPORT +void genxSetDealloc(genxWriter w, genxDealloc dealloc); + +LIBGENX_SYMEXPORT +genxAlloc genxGetAlloc(genxWriter w); + +LIBGENX_SYMEXPORT +genxDealloc genxGetDealloc(genxWriter w); + +/* + * Get the prefix associated with a namespace + */ +LIBGENX_SYMEXPORT +constUtf8 genxGetNamespacePrefix(genxNamespace ns); + +/* + * Declaration functions + */ + +/* + * Declare a namespace. The provided prefix is the default but can be + * overridden by genxAddNamespace. If no default prefiix is provided, + * genx will generate one of the form g-%d. + * On error, returns NULL and signals via statusp + */ +LIBGENX_SYMEXPORT +genxNamespace genxDeclareNamespace(genxWriter w, + constUtf8 uri, constUtf8 prefix, + genxStatus * statusP); + +/* + * Declare an element + * If something failed, returns NULL and sets the status code via statusP + */ +LIBGENX_SYMEXPORT +genxElement genxDeclareElement(genxWriter w, + genxNamespace ns, constUtf8 name, + genxStatus * statusP); + +/* + * Declare an attribute + */ +LIBGENX_SYMEXPORT +genxAttribute genxDeclareAttribute(genxWriter w, + genxNamespace ns, + constUtf8 name, genxStatus * statusP); + +/* + * Writing XML + */ + +/* + * Caller-provided I/O package. + * First form is for a null-terminated string. + * for second, if you have s="abcdef" and want to send "abc", you'd call + * sendBounded(userData, s, s + 3) + */ +typedef struct +{ + genxStatus (* send)(void * userData, constUtf8 s); + genxStatus (* sendBounded)(void * userData, constUtf8 start, constUtf8 end); + genxStatus (* flush)(void * userData); +} genxSender; + +LIBGENX_SYMEXPORT +genxStatus genxStartDocSender(genxWriter w, const genxSender * sender); + +/* + * End a document. Calls "flush". + */ +LIBGENX_SYMEXPORT +genxStatus genxEndDocument(genxWriter w); + +/* + * Write XML declaration. If encoding or standalone are NULL, then those + * attributes are omitted. + */ +LIBGENX_SYMEXPORT +genxStatus genxXmlDeclaration(genxWriter w, + constUtf8 version, + constUtf8 encoding, + constUtf8 standalone); +/* + * Write DOCTYPE declaration. If public_id is not NULL, then this is + * a PUBLIC DOCTYPE declaration, otherwise, if system_id is not NULL, + * then this is a SYSTEM DOCTYPE. If both are NULL, then a DOCTYPE + * that only contains the root element and, if not NULL, internal + * subset is written. + */ +LIBGENX_SYMEXPORT +genxStatus genxDoctypeDeclaration(genxWriter w, + constUtf8 root_element, + constUtf8 public_id, + constUtf8 system_id, + constUtf8 internal_subset); + +/* + * Write a comment + */ +LIBGENX_SYMEXPORT +genxStatus genxComment(genxWriter w, constUtf8 text); + +/* + * Write a PI + */ +LIBGENX_SYMEXPORT +genxStatus genxPI(genxWriter w, constUtf8 target, constUtf8 text); + +/* + * Start an element + */ +LIBGENX_SYMEXPORT +genxStatus genxStartElementLiteral(genxWriter w, + constUtf8 xmlns, constUtf8 name); + +/* + * Start a predeclared element + * - element must have been declared + */ +LIBGENX_SYMEXPORT +genxStatus genxStartElement(genxElement e); + +/* + * Get current element. The returned values are valid until this + * element ceases to be current (i.e., EndElement() is called). + * If the element is unqualified, then xmlns is set to NULL. + */ +LIBGENX_SYMEXPORT +genxStatus genxGetCurrentElement (genxWriter w, + constUtf8* xmlns, constUtf8* name); + +/* + * Write an attribute + */ +LIBGENX_SYMEXPORT +genxStatus genxAddAttributeLiteral(genxWriter w, constUtf8 xmlns, + constUtf8 name, constUtf8 value); + +/* + * Write a predeclared attribute + */ +LIBGENX_SYMEXPORT +genxStatus genxAddAttribute(genxAttribute a, constUtf8 value); + +/* + * Start an attribute + */ +LIBGENX_SYMEXPORT +genxStatus genxStartAttributeLiteral(genxWriter w, + constUtf8 xmlns, constUtf8 name); + +/* + * Start a predeclared attribute + */ +LIBGENX_SYMEXPORT +genxStatus genxStartAttribute(genxAttribute a); + +/* + * Get current attribute. The returned values are valid until this + * attribute ceases to be current (i.e., EndAttribute() is called). + * If the attribute is unqualified, then xmlns is set to NULL. + */ +LIBGENX_SYMEXPORT +genxStatus genxGetCurrentAttribute (genxWriter w, + constUtf8* xmlns, constUtf8* name); + +/* + * End an attribute + */ +LIBGENX_SYMEXPORT +genxStatus genxEndAttribute(genxWriter w); + +/* + * add a namespace declaration + */ +LIBGENX_SYMEXPORT +genxStatus genxAddNamespaceLiteral(genxWriter w, + constUtf8 uri, constUtf8 prefix); + +/* + * add a predefined namespace declaration + */ +LIBGENX_SYMEXPORT +genxStatus genxAddNamespace(genxNamespace ns, constUtf8 prefix); + +/* + * Clear default namespace declaration + */ +LIBGENX_SYMEXPORT +genxStatus genxUnsetDefaultNamespace(genxWriter w); + +/* + * Write an end tag + */ +LIBGENX_SYMEXPORT +genxStatus genxEndElement(genxWriter w); + +/* + * Write some text + * You can't write any text outside the root element, except with + * genxComment and genxPI. + */ +LIBGENX_SYMEXPORT +genxStatus genxAddText(genxWriter w, constUtf8 start); + +LIBGENX_SYMEXPORT +genxStatus genxAddCountedText(genxWriter w, constUtf8 start, size_t byteCount); + +LIBGENX_SYMEXPORT +genxStatus genxAddBoundedText(genxWriter w, constUtf8 start, constUtf8 end); + +/* + * Write one character. The integer value is the Unicode character + * value, as usually expressed in U+XXXX notation. + */ +LIBGENX_SYMEXPORT +genxStatus genxAddCharacter(genxWriter w, int c); + +/* + * Utility routines + */ + +/* + * Return the Unicode character encoded by the UTF-8 pointed-to by the + * argument, and advance the argument past the encoding of the character. + * Returns -1 if the UTF-8 is malformed, in which case advances the + * argument to point at the first byte past the point past the malformed + * ones. + */ +LIBGENX_SYMEXPORT +int genxNextUnicodeChar(constUtf8 * sp); + +/* + * Scan a buffer allegedly full of UTF-8 encoded XML characters; return + * one of GENX_SUCCESS, GENX_BAD_UTF8, or GENX_NON_XML_CHARACTER + */ +LIBGENX_SYMEXPORT +genxStatus genxCheckText(genxWriter w, constUtf8 s); + +/* + * return character status, the OR of GENX_XML_CHAR, + * GENX_LETTER, and GENX_NAMECHAR + */ +LIBGENX_SYMEXPORT +int genxCharClass(genxWriter w, int c); + +/* + * Silently wipe any non-XML characters out of a chunk of text. + * If you call this on a string before you pass it addText or + * addAttribute, you will never get an error from genx unless + * (a) there's a bug in your software, e.g. a malformed element name, or + * (b) there's a memory allocation or I/O error + * The output can never be longer than the input. + * Returns true if any changes were made. + */ +LIBGENX_SYMEXPORT +int genxScrubText(genxWriter w, constUtf8 in, utf8 out); + +/* + * return error messages + */ +LIBGENX_SYMEXPORT +const char * genxGetErrorMessage(genxWriter w, genxStatus status); + +LIBGENX_SYMEXPORT +const char * genxLastErrorMessage(genxWriter w); + +/* + * return version + */ +LIBGENX_SYMEXPORT +const char * genxGetVersion(); + +#ifdef __cplusplus +} +#endif + +#endif /* GENX_H */ diff --git a/libgenx/libgenx/version.h.in b/libgenx/libgenx/version.h.in new file mode 100644 index 0000000..92e990a --- /dev/null +++ b/libgenx/libgenx/version.h.in @@ -0,0 +1,37 @@ +#ifndef LIBGENX_VERSION_H +#define LIBGENX_VERSION_H + +/* The numeric version format is AAAAABBBBBCCCCCDDDE where: +// +// AAAAA - major version number +// BBBBB - minor version number +// CCCCC - bugfix version number +// DDD - alpha / beta (DDD + 500) version number +// E - final (0) / snapshot (1) +// +// When DDDE is not 0, 1 is subtracted from AAAAABBBBBCCCCC. For example: +// +// Version AAAAABBBBBCCCCCDDDE +// +// 0.1.0 0000000001000000000 +// 0.1.2 0000000001000020000 +// 1.2.3 0000100002000030000 +// 2.2.0-a.1 0000200001999990010 +// 3.0.0-b.2 0000299999999995020 +// 2.2.0-a.1.z 0000200001999990011 +*/ +#define LIBGENX_VERSION $libgenx.version.project_number$ULL +#define LIBGENX_VERSION_STR "$libgenx.version.project$" +#define LIBGENX_VERSION_ID "$libgenx.version.project_id$" +#define LIBGENX_VERSION_FULL "$libgenx.version$" + +#define LIBGENX_VERSION_MAJOR $libgenx.version.major$ +#define LIBGENX_VERSION_MINOR $libgenx.version.minor$ +#define LIBGENX_VERSION_PATCH $libgenx.version.patch$ + +#define LIBGENX_PRE_RELEASE $libgenx.version.pre_release$ + +#define LIBGENX_SNAPSHOT_SN $libgenx.version.snapshot_sn$ULL +#define LIBGENX_SNAPSHOT_ID "$libgenx.version.snapshot_id$" + +#endif /* LIBGENX_VERSION_H */ diff --git a/libgenx/manifest b/libgenx/manifest new file mode 100644 index 0000000..4f27c59 --- /dev/null +++ b/libgenx/manifest @@ -0,0 +1,12 @@ +: 1 +name: libgenx +version: 0.1.0-a.0.z +project: genx +summary: Genx XML serializer C library +license: MIT +description-file: README.md +url: https://git.codesynthesis.com/cgit/genx +email: boris@codesynthesis.com +builds: all +depends: * build2 >= 0.13.0 +depends: * bpkg >= 0.13.0 diff --git a/libgenx/tests/.gitignore b/libgenx/tests/.gitignore new file mode 100644 index 0000000..662178d --- /dev/null +++ b/libgenx/tests/.gitignore @@ -0,0 +1,8 @@ +# Test executables. +# +driver + +# Testscript output directories (can be symlinks). +# +test +test-* diff --git a/libgenx/tests/basics/buildfile b/libgenx/tests/basics/buildfile new file mode 100644 index 0000000..75fb5e8 --- /dev/null +++ b/libgenx/tests/basics/buildfile @@ -0,0 +1,3 @@ +import libs = libgenx%lib{genx} + +exe{driver}: {h c}{**} $libs testscript diff --git a/libgenx/tests/basics/driver.c b/libgenx/tests/basics/driver.c new file mode 100644 index 0000000..135d5ba --- /dev/null +++ b/libgenx/tests/basics/driver.c @@ -0,0 +1,41 @@ +#include +#include + +#include +#include + +static genxStatus +genxSend(void * d, constUtf8 s) +{ + size_t n = strlen((const char*)s); + return fwrite(s, 1, n, (FILE*)d) == n ? GENX_SUCCESS : GENX_IO_ERROR; +} + +static genxStatus +genxSendBounded(void * d, constUtf8 start, constUtf8 end) +{ + size_t n = end - start; + return fwrite(start, 1, n, (FILE*)d) == n ? GENX_SUCCESS : GENX_IO_ERROR; +} + +static genxStatus +genxFlush(void * d) +{ + return fflush((FILE*)d) == 0 ? GENX_SUCCESS : GENX_IO_ERROR; +} + +static const genxSender stdioSender = {&genxSend, &genxSendBounded, genxFlush}; + +int main() +{ + genxWriter w = genxNew(NULL, NULL, stdout); + genxStartDocSender(w, &stdioSender); + genxStartElementLiteral(w, (utf8)"http://example.org/1", (utf8)"greeting"); + genxAddAttributeLiteral(w, (utf8)"http://example.com/2", (utf8)"type", (utf8)"well-formed"); + genxAddText(w, (utf8)"Hello world!"); + genxEndElement(w); + genxEndDocument(w); + genxDispose(w); + + return 0; +} diff --git a/libgenx/tests/basics/testscript b/libgenx/tests/basics/testscript new file mode 100644 index 0000000..2bbfba1 --- /dev/null +++ b/libgenx/tests/basics/testscript @@ -0,0 +1,3 @@ +$* >>EOO +Hello world! +EOO diff --git a/libgenx/tests/build/.gitignore b/libgenx/tests/build/.gitignore new file mode 100644 index 0000000..974e01d --- /dev/null +++ b/libgenx/tests/build/.gitignore @@ -0,0 +1,4 @@ +/config.build +/root/ +/bootstrap/ +build/ diff --git a/libgenx/tests/build/bootstrap.build b/libgenx/tests/build/bootstrap.build new file mode 100644 index 0000000..a07b5ea --- /dev/null +++ b/libgenx/tests/build/bootstrap.build @@ -0,0 +1,5 @@ +project = # Unnamed tests subproject. + +using config +using test +using dist diff --git a/libgenx/tests/build/root.build b/libgenx/tests/build/root.build new file mode 100644 index 0000000..3b975e6 --- /dev/null +++ b/libgenx/tests/build/root.build @@ -0,0 +1,12 @@ +using c + +h{*}: extension = h +c{*}: extension = c + +# Every exe{} in this subproject is by default a test. +# +exe{*}: test = true + +# The test target for cross-testing (running tests under Wine, etc). +# +test.target = $c.target diff --git a/libgenx/tests/buildfile b/libgenx/tests/buildfile new file mode 100644 index 0000000..aeeab15 --- /dev/null +++ b/libgenx/tests/buildfile @@ -0,0 +1 @@ +./: {*/ -build/} diff --git a/makefile b/makefile deleted file mode 100644 index 0625c7a..0000000 --- a/makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Make sure everything compiles. -# -src := genx.c char-props.c - -CC := gcc -CFLAGS := -Wall -Wextra -Werror - -# Compile. -# -.PHONY: all -all: $(src:.c=.o) - -%.o: %.c - $(CC) $(CPPFLAGS) $(CFLAGS) -c $< - -# Clean. -# -.PHONY: clean -clean: - rm -f $(src:.c=.o) diff --git a/packages.manifest b/packages.manifest new file mode 100644 index 0000000..9d3a955 --- /dev/null +++ b/packages.manifest @@ -0,0 +1,2 @@ +: 1 +location: libgenx/ -- cgit v1.1