From 0448f3de0bc3e9aa71bd095e87fd1cc2584e0a99 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Thu, 12 Jul 2007 21:24:08 +0000 Subject: Add DOMImplementation, DOMImplementationList Add DOMImplementationRegistry Define DOMImplementationSource and provide API to allow their registration This little lot should permit some kind of sensible DOM bootstrapping. svn path=/trunk/dom/; revision=3403 --- src/Makefile | 3 + src/bootstrap/Makefile | 53 +++++++++++++ src/bootstrap/implregistry.c | 184 +++++++++++++++++++++++++++++++++++++++++++ src/core/Makefile | 4 +- src/core/implementation.c | 157 ++++++++++++++++++++++++++++++++++++ src/core/impllist.c | 108 +++++++++++++++++++++++++ 6 files changed, 507 insertions(+), 2 deletions(-) create mode 100644 src/bootstrap/Makefile create mode 100644 src/bootstrap/implregistry.c create mode 100644 src/core/implementation.c create mode 100644 src/core/impllist.c (limited to 'src') diff --git a/src/Makefile b/src/Makefile index ae0c9eb..b0f78b2 100644 --- a/src/Makefile +++ b/src/Makefile @@ -34,14 +34,17 @@ OBJS = # Targets release: $(addprefix Release/, $(addsuffix .o, $(OBJS))) + @${MAKE} -C bootstrap release @${MAKE} -C core release @${AR} ${ARFLAGS} $(RELEASE) Release/* debug: $(addprefix Debug/, $(addsuffix .o, $(OBJS))) + @${MAKE} -C bootstrap debug @${MAKE} -C core debug @${AR} ${ARFLAGS} $(DEBUG) Debug/* clean: + @${MAKE} -C bootstrap clean @${MAKE} -C core clean ifneq (${OBJS}, ) -@${RM} ${RMFLAGS} $(addprefix Release/, $(addsuffix .o, ${OBJS})) diff --git a/src/bootstrap/Makefile b/src/bootstrap/Makefile new file mode 100644 index 0000000..6c904cc --- /dev/null +++ b/src/bootstrap/Makefile @@ -0,0 +1,53 @@ +# Makefile for libdom +# +# Toolchain is exported by top-level makefile +# +# Top-level makefile also exports the following variables: +# +# COMPONENT Name of component +# EXPORT Absolute path of export directory +# TOP Absolute path of source tree root +# +# The top-level makefile requires the following targets to exist: +# +# clean Clean source tree +# debug Create a debug binary +# distclean Fully clean source tree, back to pristine condition +# export Export distributable components to ${EXPORT} +# release Create a release binary +# setup Perform any setup required prior to compilation +# test Execute any test cases + +# Manipulate include paths +CFLAGS += -I$(CURDIR) + +# Objects +OBJS = implregistry + +.PHONY: clean debug distclean export release setup test + +# Targets +release: $(addprefix ../Release/, $(addsuffix .o, $(OBJS))) + +debug: $(addprefix ../Debug/, $(addsuffix .o, $(OBJS))) + +clean: + -@${RM} ${RMFLAGS} $(addprefix ../Release/, $(addsuffix .o, ${OBJS})) + -@${RM} ${RMFLAGS} $(addprefix ../Debug/, $(addsuffix .o, ${OBJS})) + +distclean: + +setup: + +export: + +test: + +# Pattern rules +../Release/%.o: %.c + @${ECHO} ${ECHOFLAGS} "==> $<" + @${CC} -c ${CFLAGS} -DNDEBUG -o $@ $< + +../Debug/%.o: %.c + @${ECHO} ${ECHOFLAGS} "==> $<" + @${CC} -c -g ${CFLAGS} -o $@ $< diff --git a/src/bootstrap/implregistry.c b/src/bootstrap/implregistry.c new file mode 100644 index 0000000..9407ee1 --- /dev/null +++ b/src/bootstrap/implregistry.c @@ -0,0 +1,184 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2007 John-Mark Bell + */ + +#include + +#include +#include + +#include + +/** + * Item in list of registered DOM implementation sources + */ +struct dom_impl_src_item { + struct dom_implementation_source *source; /**< Source */ + + struct dom_impl_src_item *next; /**< Next in list */ + struct dom_impl_src_item *prev; /**< Previous in list */ +}; + +static struct dom_impl_src_item *sources; /**< List of registered sources */ + +/** + * Retrieve a DOM implementation from the registry + * + * \param features String containing required features + * \param impl Pointer to location to receive implementation + * \param alloc Function to (de)allocate memory + * \param pw Pointer to client-specific private data + * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion + * + * Any memory allocated by this call should be allocated using + * the provided memory (de)allocation function. The implementation's + * destroy() method will be called once it is no longer used. + * + * The implementation will be referenced, so the client need not + * do this explicitly. The client must unref the implementation + * once it has finished with it. + */ +dom_exception dom_implregistry_get_dom_implementation( + struct dom_string *features, + struct dom_implementation **impl, + dom_alloc alloc, void *pw) +{ + struct dom_impl_src_item *item; + struct dom_implementation *found = NULL; + dom_exception err; + + for (item = sources; item; item = item->next) { + err = item->source->get_dom_implementation(features, &found, + alloc, pw); + if (err != DOM_NO_ERR) + return err; + + if (found != NULL) + break; + } + + *impl = found; + + return DOM_NO_ERR; +} + +/** + * Get a list of DOM implementations that support the requested + * features + * + * \param features String containing required features + * \param list Pointer to location to receive list + * \param alloc Function to (de)allocate memory + * \param pw Pointer to client-specific private data + * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion + * + * Any memory allocated by this call should be allocated using + * the provided memory (de)allocation function. The ::alloc/::pw + * pair must be stored on the list object, such that the list + * and its contents may be freed once they are no longer needed. + * + * List nodes reference the implementation objects they point to. + * + * The list will be referenced, so the client need not do this + * explicitly. The client must unref the list once it has finished + * with it. + */ +dom_exception dom_implregistry_get_dom_implementation_list( + struct dom_string *features, + struct dom_implementation_list **list, + dom_alloc alloc, void *pw) +{ + struct dom_implementation_list *l; + struct dom_impl_src_item *item; + dom_exception err; + + l = alloc(NULL, sizeof(struct dom_implementation_list), pw); + if (l == NULL) + return DOM_NO_MEM_ERR; + + l->head = NULL; + l->alloc = alloc; + l->pw = pw; + l->refcnt = 1; + + for (item = sources; item; item = item->next) { + struct dom_implementation_list *plist = NULL; + struct dom_implementation_list_item *plast = NULL; + + err = item->source->get_dom_implementation_list(features, + &plist, alloc, pw); + if (err != DOM_NO_ERR) { + dom_implementation_list_unref(l); + return err; + } + + if (plist == NULL) + continue; + + if (plist->head == NULL) { + dom_implementation_list_unref(plist); + continue; + } + + /* Get last item in list for this source */ + for (plast = plist->head; plast; plast = plast->next) { + if (plast->next == NULL) + break; + } + + /* Prepend list for this source onto result list */ + plast->next = l->head; + if (l->head != NULL) + l->head->prev = plast; + l->head = plist->head; + + /* Invalidate entire content of list for this source */ + plist->head = NULL; + + /* And unref it */ + dom_implementation_list_unref(plist); + } + + if (l->head == NULL) { + *list = NULL; + dom_implementation_list_unref(l); + } else { + *list = l; + } + + return DOM_NO_ERR; +} + +/** + * Register a DOM implementation source with the DOM library + * + * \param source The implementation source to register + * \param alloc Memory (de)allocation function + * \param pw Pointer to client-specific private data + * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion. + */ +dom_exception dom_register_source(struct dom_implementation_source *source, + dom_alloc alloc, void *pw) +{ + struct dom_impl_src_item *item; + + item = alloc(NULL, sizeof(struct dom_impl_src_item), pw); + if (item == NULL) + return DOM_NO_MEM_ERR; + + item->source = source; + + item->next = sources; + item->prev = NULL; + + if (sources != NULL) + sources->prev = item; + + sources = item; + + return DOM_NO_ERR; +} + diff --git a/src/core/Makefile b/src/core/Makefile index 9d21bf7..bc25ed7 100644 --- a/src/core/Makefile +++ b/src/core/Makefile @@ -22,8 +22,8 @@ CFLAGS += -I$(CURDIR) # Objects -OBJS = attr characterdata document element namednodemap node nodelist \ - string text +OBJS = attr characterdata document element implementation impllist \ + namednodemap node nodelist string text .PHONY: clean debug distclean export release setup test diff --git a/src/core/implementation.c b/src/core/implementation.c new file mode 100644 index 0000000..d9bb0fa --- /dev/null +++ b/src/core/implementation.c @@ -0,0 +1,157 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2007 John-Mark Bell + */ + +#include +#include + +/** + * Claim a reference on a DOM implementation + * + * \param impl The implementation to claim a reference on + */ +void dom_implementation_ref(struct dom_implementation *impl) +{ + impl->refcnt++; +} + +/** + * Release a reference from a DOM implementation + * + * \param impl The implementation to release the reference from + * + * If the reference count reaches zero, any memory claimed by the + * implementation will be released + */ +void dom_implementation_unref(struct dom_implementation *impl) +{ + if (--impl->refcnt == 0) { + impl->destroy(impl); + } +} + +/** + * Test whether a DOM implementation implements a specific feature + * and version + * + * \param impl The DOM implementation to query + * \param feature The feature to test for + * \param version The version number of the feature to test for + * \param result Pointer to location to receive result + * \return DOM_NO_ERR. + */ +dom_exception dom_implementation_has_feature( + struct dom_implementation *impl, + struct dom_string *feature, struct dom_string *version, + bool *result) +{ + return impl->has_feature(impl, feature, version, result); +} + +/** + * Create a document type node + * + * \param impl The implementation to create the node + * \param qname The qualified name of the document type + * \param public_id The external subset public identifier + * \param system_id The external subset system identifier + * \param doctype Pointer to location to receive result + * \param alloc Memory (de)allocation function + * \param pw Pointer to client-specific private data + * \return DOM_NO_ERR on success, + * DOM_INVALID_CHARACTER_ERR if ::qname is invalid, + * DOM_NAMESPACE_ERR if ::qname is malformed, + * DOM_NOT_SUPPORTED_ERR if ::impl does not support the feature + * "XML" and the language exposed through + * Document does not support XML + * namespaces. + * + * Any memory allocated by this call should be allocated using + * the provided memory (de)allocation function. + * + * The doctype will be referenced, so the client need not do this + * explicitly. The client must unref the doctype once it has + * finished with it. + */ +dom_exception dom_implementation_create_document_type( + struct dom_implementation *impl, struct dom_string *qname, + struct dom_string *public_id, struct dom_string *system_id, + struct dom_document_type **doctype, + dom_alloc alloc, void *pw) +{ + return impl->create_document_type(impl, qname, public_id, system_id, + doctype, alloc, pw); +} + +/** + * Create a document node + * + * \param impl The implementation to create the node + * \param namespace The namespace URI of the document element + * \param qname The qualified name of the document element + * \param doctype The type of document to create + * \param doc Pointer to location to receive result + * \param alloc Memory (de)allocation function + * \param pw Pointer to client-specific private data + * \return DOM_NO_ERR on success, + * DOM_INVALID_CHARACTER_ERR if ::qname is invalid, + * DOM_NAMESPACE_ERR if ::qname is malformed, or if ::qname + * has a prefix and ::namespace is NULL, + * or if ::qname is NULL and ::namespace + * is non-NULL, or if ::qname has a prefix + * "xml" and ::namespace is not + * "http://www.w3.org/XML/1998/namespace", + * or if ::impl does not support the "XML" + * feature and ::namespace is non-NULL, + * DOM_WRONG_DOCUMENT_ERR if ::doctype is already being used by a + * document, or if it was not created by + * ::impl, + * DOM_NOT_SUPPORTED_ERR if ::impl does not support the feature + * "XML" and the language exposed through + * Document does not support XML + * namespaces. + * + * Any memory allocated by this call should be allocated using + * the provided memory (de)allocation function. + * + * The doctype will be referenced, so the client need not do this + * explicitly. The client must unref the doctype once it has + * finished with it. + */ +dom_exception dom_implementation_create_document( + struct dom_implementation *impl, + struct dom_string *namespace, struct dom_string *qname, + struct dom_document_type *doctype, + struct dom_document **doc, + dom_alloc alloc, void *pw) +{ + return impl->create_document(impl, namespace, qname, doctype, doc, + alloc, pw); +} + +/** + * Retrieve a specialized object which implements the specified + * feature and version + * + * \param impl The implementation to create the object + * \param feature The requested feature + * \param version The version number of the feature + * \param object Pointer to location to receive object + * \param alloc Memory (de)allocation function + * \param pw Pointer to client-specific private data + * \return DOM_NO_ERR. + * + * Any memory allocated by this call should be allocated using + * the provided memory (de)allocation function. + */ +dom_exception dom_implementation_get_feature( + struct dom_implementation *impl, + struct dom_string *feature, struct dom_string *version, + void **object, + dom_alloc alloc, void *pw) +{ + return impl->get_feature(impl, feature, version, object, alloc, pw); +} diff --git a/src/core/impllist.c b/src/core/impllist.c new file mode 100644 index 0000000..522c3f7 --- /dev/null +++ b/src/core/impllist.c @@ -0,0 +1,108 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2007 John-Mark Bell + */ + +#include +#include +#include + +/** + * Claim a reference on a DOM implementation list + * + * \param list The list to claim a reference on + */ +void dom_implementation_list_ref(struct dom_implementation_list *list) +{ + list->refcnt++; +} + +/** + * Release a reference from a DOM implementation list + * + * \param list The list to release the reference from + * + * If the reference count reaches zero, any memory claimed by the + * list will be released + */ +void dom_implementation_list_unref(struct dom_implementation_list *list) +{ + struct dom_implementation_list_item *i, *j; + + if (--list->refcnt == 0) { + /* Destroy all list entries */ + for (i = list->head; i; i = j) { + j = i->next; + + /* Unreference the implementation */ + dom_implementation_unref(i->impl); + + /* And free the entry */ + list->alloc(i, 0, list->pw); + } + + /* Free the list object */ + list->alloc(list, 0, list->pw); + } +} + +/** + * Retrieve the length of a DOM implementation list + * + * \param list The list to retrieve the length of + * \param length Pointer to location to receive result + * \return DOM_NO_ERR. + */ +dom_exception dom_implementation_list_get_length( + struct dom_implementation_list *list, unsigned long *length) +{ + unsigned long count = 0; + struct dom_implementation_list_item *i; + + for (i = list->head; i; i = i->next) + count++; + + *length = count; + + return DOM_NO_ERR; +} + +/** + * Retrieve an item by index from a DOM implementation list + * + * \param list The list to retrieve the item from + * \param index The list index to retrieve + * \param impl Pointer to location to receive result + * \return DOM_NO_ERR. + * + * ::index is a zero-based index into ::list. + * ::index lies in the range [0, length-1] + * + * The returned implementation will have had its reference count increased. + * The client should unref the implementation once it has finished with it. + */ +dom_exception dom_implementation_list_item( + struct dom_implementation_list *list, unsigned long index, + struct dom_implementation **impl) +{ + unsigned long idx = 0; + struct dom_implementation_list_item *i; + + for (i = list->head; i; i = i->next) { + if (idx == index) + break; + + idx++; + } + + if (i == NULL) { + *impl = NULL; + } else { + dom_implementation_ref(i->impl); + *impl = i->impl; + } + + return DOM_NO_ERR; +} -- cgit v1.2.3