diff options
102 files changed, 1546 insertions, 273 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..75df82a --- /dev/null +++ b/.clang-format @@ -0,0 +1,120 @@ +--- +Language: Cpp +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterClass: true + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Linux +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: false +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 8 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^(<.*/)' + Priority: 3 + - Regex: '^(<(nsutils)/)' + Priority: 2 + - Regex: '"utils/' + Priority: 4 + - Regex: '"netsurf/' + Priority: 5 + - Regex: '.*' + Priority: 6 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: false +IndentPPDirectives: None +IndentWidth: 8 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 100 +PenaltyBreakBeforeFirstCallParameter: 50 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 19 +PointerAlignment: Right +ReflowComments: true +SortIncludes: false +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 8 +UseTab: Always +... + diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..17f2958 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,89 @@ +name: "Linux Build" + +on: [push] + +jobs: + linux: + name: '${{ matrix.os }}: ${{ matrix.compiler.vendor }}' + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-22.04 + - ubuntu-20.04 + compiler: + # The NetSurf build system can't find LLVM AR (it looks for it + # in /usr/lib instead of /usr/bin: + # `make: /usr/lib/llvm-ar: No such file or directory`). + # So we need to make it explicit for llvm. + - { vendor: gnu, CC: gcc, AR: ar } + - { vendor: llvm, CC: clang, AR: llvm-ar } + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 1 + + - name: apt-get install packages + run: sudo apt-get update -qq && + sudo apt-get install --no-install-recommends -y + bison + build-essential + check + clang + flex + git + gperf + llvm + pkg-config + libxml-perl + libxml-sax-perl + libxml-sax-base-perl + libxml-sax-expat-perl + libxml-parser-perl + libxml-libxml-perl + libxml-xpath-perl + libswitch-perl + + - name: Get env.sh + run: | + mkdir projects + wget -O projects/env.sh https://git.netsurf-browser.org/netsurf.git/plain/docs/env.sh + + - name: Build and install project deps + env: + CC: ${{ matrix.compiler.CC }} + AR: ${{ matrix.compiler.AR }} + TARGET: ${{ github.event.repository.name }} + run: | + export TARGET_WORKSPACE="$(pwd)/projects" + source projects/env.sh + ns-clone -d -s + ns-make-libs install + + - name: Build Library + env: + CC: ${{ matrix.compiler.CC }} + AR: ${{ matrix.compiler.AR }} + TARGET: ${{ github.event.repository.name }} + run: | + export TARGET_WORKSPACE="$(pwd)/projects" + source projects/env.sh + make -j"$(nproc)" + + - name: Unit Tests + # Planet saving measure: + # The tests take ages to convert from XML and we don't gain much by + # running them on every combination in the matrix. + # Another option might be to have the transformed C tests checked in. + if: ${{ matrix.compiler.vendor == 'gnu' && matrix.os == 'ubuntu-22.04' }} + env: + CC: ${{ matrix.compiler.CC }} + AR: ${{ matrix.compiler.AR }} + TARGET: ${{ github.event.repository.name }} + run: | + export TARGET_WORKSPACE="$(pwd)/projects" + source projects/env.sh + make test diff --git a/.github/workflows/static-analysis.yaml b/.github/workflows/static-analysis.yaml new file mode 100644 index 0000000..ec5171f --- /dev/null +++ b/.github/workflows/static-analysis.yaml @@ -0,0 +1,61 @@ +name: "Static Analysis" + +on: [push] + +jobs: + codeql: + name: codeql + runs-on: ubuntu-22.04 + + strategy: + fail-fast: false + matrix: + language: ['cpp'] + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + fetch-depth: 1 + + - name: apt-get install packages + run: sudo apt-get update -qq && + sudo apt-get install --no-install-recommends -y + bison + build-essential + check + clang + flex + git + gperf + llvm + pkg-config + + - name: Get env.sh + run: | + mkdir projects + wget -O projects/env.sh https://git.netsurf-browser.org/netsurf.git/plain/docs/env.sh + + - name: Build and install project deps + env: + TARGET: ${{ github.event.repository.name }} + run: | + export TARGET_WORKSPACE="$(pwd)/projects" + source projects/env.sh + ns-clone -d -s + ns-make-libs install + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + + - name: Build Library + run: | + export TARGET_WORKSPACE="$(pwd)/projects" + source projects/env.sh + make -j"$(nproc)" + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 @@ -6,7 +6,7 @@ # Component settings COMPONENT := dom -COMPONENT_VERSION := 0.4.1 +COMPONENT_VERSION := 0.4.2 # Default to a static library COMPONENT_TYPE ?= lib-static @@ -56,7 +56,7 @@ include $(NSBUILD)/Makefile.top # Extra installation rules Is := include/dom I := /$(INCLUDEDIR)/dom -INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/dom.h;$(Is)/functypes.h;$(Is)/inttypes.h +INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/dom.h;$(Is)/functypes.h;$(Is)/inttypes.h;$(Is)/walk.h Is := include/dom/core I := /$(INCLUDEDIR)/dom/core @@ -69,7 +69,7 @@ INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/entity_ref.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/element.h;$(Is)/exceptions.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/implementation.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/namednodemap.h;$(Is)/node.h -INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/nodelist.h;$(Is)/string.h +INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/nodelist.h;$(Is)/tokenlist.h;$(Is)/string.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/pi.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/text.h;$(Is)/typeinfo.h @@ -149,6 +149,8 @@ INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/html_isindex_element.h INSTALL_ITEMS := $(INSTALL_ITEMS) /$(LIBDIR)/pkgconfig:lib$(COMPONENT).pc.in INSTALL_ITEMS := $(INSTALL_ITEMS) /$(LIBDIR):$(OUTPUT) +REQUIRED_PKGS := $(REQUIRED_PKGS) libwapcaplet + ifeq ($(WITH_LIBXML_BINDING),yes) REQUIRED_PKGS := $(REQUIRED_PKGS) libxml-2.0 endif @@ -157,3 +159,6 @@ ifeq ($(WITH_HUBBUB_BINDING),yes) REQUIRED_PKGS := $(REQUIRED_PKGS) libhubbub endif +ifeq ($(WITH_EXPAT_BINDING),yes) + REQUIRED_LIBS := $(REQUIRED_LIBS) expat +endif diff --git a/Makefile.config b/Makefile.config index 04971d5..0aba3ff 100644 --- a/Makefile.config +++ b/Makefile.config @@ -3,6 +3,9 @@ # Build the libxml2 binding? # yes | no WITH_LIBXML_BINDING := no + +# Build the expat binding? +# yes | no WITH_EXPAT_BINDING := yes # Build the hubbub binding? diff --git a/bindings/xml/libxml_xmlparser.c b/bindings/xml/libxml_xmlparser.c index 02b8a34..cd7f8ad 100644 --- a/bindings/xml/libxml_xmlparser.c +++ b/bindings/xml/libxml_xmlparser.c @@ -6,6 +6,7 @@ */ #include <stdbool.h> +#include <stdlib.h> #include <string.h> #include <assert.h> @@ -36,21 +37,21 @@ static void xml_parser_end_element_ns(void *ctx, const xmlChar *localname, static dom_exception xml_parser_link_nodes(dom_xml_parser *parser, struct dom_node *dom, xmlNodePtr xml); -static void xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent, - xmlNodePtr child); -static void xml_parser_add_element_node(dom_xml_parser *parser, +static dom_exception xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); -static void xml_parser_add_text_node(dom_xml_parser *parser, +static dom_exception xml_parser_add_element_node(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); -static void xml_parser_add_cdata_section(dom_xml_parser *parser, +static dom_exception xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); -static void xml_parser_add_entity_reference(dom_xml_parser *parser, +static dom_exception xml_parser_add_cdata_section(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); -static void xml_parser_add_entity(dom_xml_parser *parser, +static dom_exception xml_parser_add_entity_reference(dom_xml_parser *parser, + struct dom_node *parent, xmlNodePtr child); +static dom_exception xml_parser_add_entity(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); -static void xml_parser_add_comment(dom_xml_parser *parser, +static dom_exception xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); -static void xml_parser_add_document_type(dom_xml_parser *parser, +static dom_exception xml_parser_add_document_type(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); static void xml_parser_internal_subset(void *ctx, const xmlChar *name, @@ -96,6 +97,8 @@ struct dom_xml_parser { dom_msg msg; /**< Informational message function */ void *mctx; /**< Pointer to client data */ + + dom_exception err; /**< Last DOM error, if any */ }; /** @@ -133,7 +136,7 @@ static xmlSAXHandler sax_handler = { ._private = NULL, .startElementNs = xml_parser_start_element_ns, .endElementNs = xml_parser_end_element_ns, - .serror = NULL + .serror = NULL, }; static void *dom_xml_alloc(void *ptr, size_t len, void *pw) @@ -231,6 +234,8 @@ dom_xml_parser *dom_xml_parser_create(const char *enc, const char *int_enc, parser->msg = msg; parser->mctx = mctx; + parser->err = DOM_NO_ERR; + return parser; } @@ -271,6 +276,10 @@ dom_xml_error dom_xml_parser_parse_chunk(dom_xml_parser *parser, return DOM_XML_EXTERNAL_ERR | err; } + if (parser->err != DOM_NO_ERR) { + return DOM_XML_DOM_ERR | parser->err; + } + return DOM_XML_OK; } @@ -293,6 +302,10 @@ dom_xml_error dom_xml_parser_completed(dom_xml_parser *parser) return DOM_XML_EXTERNAL_ERR | err; } + if (parser->err != DOM_NO_ERR) { + return DOM_XML_DOM_ERR | parser->err; + } + return DOM_XML_OK; } @@ -304,15 +317,27 @@ dom_xml_error dom_xml_parser_completed(dom_xml_parser *parser) void xml_parser_start_document(void *ctx) { dom_xml_parser *parser = (dom_xml_parser *) ctx; - dom_exception err; +#if LIBXML_VERSION >= 21200 + const xmlError *xmlerr; +#else + xmlErrorPtr xmlerr; +#endif + + if (parser->err != DOM_NO_ERR) + return; /* Invoke libxml2's default behaviour */ xmlSAX2StartDocument(parser->xml_ctx); + xmlerr = xmlCtxtGetLastError(parser->xml_ctx); + if (xmlerr != NULL && xmlerr->level >= XML_ERR_ERROR) { + return; + } /* Link nodes together */ - err = xml_parser_link_nodes(parser, (struct dom_node *) parser->doc, + parser->err = xml_parser_link_nodes(parser, + (struct dom_node *) parser->doc, (xmlNodePtr) parser->xml_ctx->myDoc); - if (err != DOM_NO_ERR) { + if (parser->err != DOM_NO_ERR) { parser->msg(DOM_MSG_WARNING, parser->mctx, "Not able to link document nodes"); } @@ -328,10 +353,21 @@ void xml_parser_end_document(void *ctx) dom_xml_parser *parser = (dom_xml_parser *) ctx; xmlNodePtr node; xmlNodePtr n; - dom_exception err; +#if LIBXML_VERSION >= 21200 + const xmlError *xmlerr; +#else + xmlErrorPtr xmlerr; +#endif + + if (parser->err != DOM_NO_ERR) + return; /* Invoke libxml2's default behaviour */ xmlSAX2EndDocument(parser->xml_ctx); + xmlerr = xmlCtxtGetLastError(parser->xml_ctx); + if (xmlerr != NULL && xmlerr->level >= XML_ERR_ERROR) { + return; + } /* If there is no document, we can't do anything */ if (parser->doc == NULL) { @@ -344,9 +380,13 @@ void xml_parser_end_document(void *ctx) * children which occur after the last Element node in the list */ /* Get XML node */ - err = dom_node_get_user_data((struct dom_node *) parser->doc, + parser->err = dom_node_get_user_data((struct dom_node *) parser->doc, parser->udkey, (void **) (void *) &node); - if (err != DOM_NO_ERR) { + + /* The return value from dom_node_get_user_data() is always + * DOM_NO_ERR, but the returned "node" will be NULL if no user + * data is found. */ + if (parser->err != DOM_NO_ERR || node == NULL) { parser->msg(DOM_MSG_WARNING, parser->mctx, "Failed finding XML node"); return; @@ -368,8 +408,10 @@ void xml_parser_end_document(void *ctx) /* Now, mirror nodes in the DOM */ for (; n != NULL; n = n->next) { - xml_parser_add_node(parser, + parser->err = xml_parser_add_node(parser, (struct dom_node *) node->_private, n); + if (parser->err != DOM_NO_ERR) + return; } } @@ -397,11 +439,23 @@ void xml_parser_start_element_ns(void *ctx, const xmlChar *localname, { dom_xml_parser *parser = (dom_xml_parser *) ctx; xmlNodePtr parent = parser->xml_ctx->node; +#if LIBXML_VERSION >= 21200 + const xmlError *xmlerr; +#else + xmlErrorPtr xmlerr; +#endif + + if (parser->err != DOM_NO_ERR) + return; /* Invoke libxml2's default behaviour */ xmlSAX2StartElementNs(parser->xml_ctx, localname, prefix, URI, nb_namespaces, namespaces, nb_attributes, nb_defaulted, attributes); + xmlerr = xmlCtxtGetLastError(parser->xml_ctx); + if (xmlerr != NULL && xmlerr->level >= XML_ERR_ERROR) { + return; + } /* If there is no document, we can't do anything */ if (parser->doc == NULL) { @@ -440,16 +494,18 @@ void xml_parser_start_element_ns(void *ctx, const xmlChar *localname, /* Now, mirror nodes in the DOM */ for (; n != parser->xml_ctx->node; n = n->next) { - xml_parser_add_node(parser, + parser->err = xml_parser_add_node(parser, (struct dom_node *) parent->_private, n); + if (parser->err != DOM_NO_ERR) + return; } } /* Mirror the created node and its attributes in the DOM */ - xml_parser_add_node(parser, (struct dom_node *) parent->_private, + parser->err = xml_parser_add_node(parser, + (struct dom_node *) parent->_private, parser->xml_ctx->node); - } /** @@ -466,9 +522,21 @@ void xml_parser_end_element_ns(void *ctx, const xmlChar *localname, dom_xml_parser *parser = (dom_xml_parser *) ctx; xmlNodePtr node = parser->xml_ctx->node; xmlNodePtr n; +#if LIBXML_VERSION >= 21200 + const xmlError *xmlerr; +#else + xmlErrorPtr xmlerr; +#endif + + if (parser->err != DOM_NO_ERR) + return; /* Invoke libxml2's default behaviour */ xmlSAX2EndElementNs(parser->xml_ctx, localname, prefix, URI); + xmlerr = xmlCtxtGetLastError(parser->xml_ctx); + if (xmlerr != NULL && xmlerr->level >= XML_ERR_ERROR) { + return; + } /* If there is no document, we can't do anything */ if (parser->doc == NULL) { @@ -503,8 +571,10 @@ void xml_parser_end_element_ns(void *ctx, const xmlChar *localname, /* Now, mirror nodes in the DOM */ for (; n != NULL; n = n->next) { - xml_parser_add_node(parser, + parser->err = xml_parser_add_node(parser, (struct dom_node *) node->_private, n); + if (parser->err != DOM_NO_ERR) + return; } } @@ -543,9 +613,10 @@ dom_exception xml_parser_link_nodes(dom_xml_parser *parser, * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent, - xmlNodePtr child) +dom_exception xml_parser_add_node(dom_xml_parser *parser, + struct dom_node *parent, xmlNodePtr child) { static const char *node_types[] = { "THIS_IS_NOT_A_NODE", @@ -574,31 +645,26 @@ void xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent, switch (child->type) { case XML_ELEMENT_NODE: - xml_parser_add_element_node(parser, parent, child); - break; + return xml_parser_add_element_node(parser, parent, child); case XML_TEXT_NODE: - xml_parser_add_text_node(parser, parent, child); - break; + return xml_parser_add_text_node(parser, parent, child); case XML_CDATA_SECTION_NODE: - xml_parser_add_cdata_section(parser, parent, child); - break; + return xml_parser_add_cdata_section(parser, parent, child); case XML_ENTITY_REF_NODE: - xml_parser_add_entity_reference(parser, parent, child); - break; + return xml_parser_add_entity_reference(parser, parent, child); case XML_COMMENT_NODE: - xml_parser_add_comment(parser, parent, child); - break; + return xml_parser_add_comment(parser, parent, child); case XML_DTD_NODE: - xml_parser_add_document_type(parser, parent, child); - break; - case XML_ENTITY_DECL: - xml_parser_add_entity(parser, parent, child); - break; + return xml_parser_add_document_type(parser, parent, child); + case XML_ENTITY_DECL: + return xml_parser_add_entity(parser, parent, child); default: parser->msg(DOM_MSG_NOTICE, parser->mctx, "Unsupported node type: %s", node_types[child->type]); } + + return DOM_NO_ERR; } /** @@ -607,8 +673,9 @@ void xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent, * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_element_node(dom_xml_parser *parser, +dom_exception xml_parser_add_element_node(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child) { struct dom_element *el, *ins_el = NULL; @@ -626,7 +693,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for tag name"); - return; + return err; } /* Create element node */ @@ -637,7 +704,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed creating element '%s'", child->name); - return; + return err; } /* No longer need tag name */ @@ -660,7 +727,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for namespace"); - return; + return err; } /* QName is "prefix:localname", @@ -680,7 +747,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, dom_string_unref(namespace); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for qname"); - return; + return err; } /* Create element node */ @@ -692,7 +759,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed creating element '%s'", qnamebuf); - return; + return err; } /* No longer need namespace / qname */ @@ -752,7 +819,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for namespace"); - return; + goto cleanup; } /* QName is "prefix:localname", @@ -772,7 +839,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, dom_string_unref(namespace); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for qname"); - return; + goto cleanup; } /* Create attribute */ @@ -784,7 +851,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed creating attribute \ '%s'", qnamebuf); - return; + goto cleanup; } /* No longer need namespace / qname */ @@ -794,8 +861,12 @@ void xml_parser_add_element_node(dom_xml_parser *parser, /* Clone subtree (attribute value) */ for (c = a->children; c != NULL; c = c->next) { - xml_parser_add_node(parser, + err = xml_parser_add_node(parser, (struct dom_node *) attr, c); + if (err != DOM_NO_ERR) { + dom_node_unref((struct dom_node *) attr); + goto cleanup; + } } /* Link nodes together */ @@ -861,14 +932,14 @@ void xml_parser_add_element_node(dom_xml_parser *parser, /* No longer interested in element node */ dom_node_unref((struct dom_node *) el); - return; + return DOM_NO_ERR; cleanup: /* No longer want node (any attributes attached to it * will be cleaned up with it) */ dom_node_unref((struct dom_node *) el); - return; + return err; } /** @@ -877,9 +948,10 @@ cleanup: * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, - xmlNodePtr child) +dom_exception xml_parser_add_text_node(dom_xml_parser *parser, + struct dom_node *parent, xmlNodePtr child) { struct dom_text *text, *ins_text = NULL; dom_string *data; @@ -891,7 +963,7 @@ void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for text node contents "); - return; + return err; } /* Create text node */ @@ -900,7 +972,7 @@ void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, dom_string_unref(data); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for text node"); - return; + return err; } /* No longer need data */ @@ -913,7 +985,7 @@ void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, dom_node_unref((struct dom_node *) text); parser->msg(DOM_MSG_ERROR, parser->mctx, "Failed attaching text node"); - return; + return err; } /* We're not interested in the inserted text node */ @@ -925,11 +997,13 @@ void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, child); if (err != DOM_NO_ERR) { dom_node_unref((struct dom_node *) text); - return; + return err; } /* No longer interested in text node */ dom_node_unref((struct dom_node *) text); + + return DOM_NO_ERR; } /** @@ -938,8 +1012,9 @@ void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_cdata_section(dom_xml_parser *parser, +dom_exception xml_parser_add_cdata_section(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child) { struct dom_cdata_section *cdata, *ins_cdata = NULL; @@ -952,7 +1027,7 @@ void xml_parser_add_cdata_section(dom_xml_parser *parser, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for cdata section contents"); - return; + return err; } /* Create cdata section */ @@ -961,7 +1036,7 @@ void xml_parser_add_cdata_section(dom_xml_parser *parser, dom_string_unref(data); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for cdata section"); - return; + return err; } /* No longer need data */ @@ -974,7 +1049,7 @@ void xml_parser_add_cdata_section(dom_xml_parser *parser, dom_node_unref((struct dom_node *) cdata); parser->msg(DOM_MSG_ERROR, parser->mctx, "Failed attaching cdata section"); - return; + return err; } /* We're not interested in the inserted cdata section */ @@ -986,11 +1061,13 @@ void xml_parser_add_cdata_section(dom_xml_parser *parser, child); if (err != DOM_NO_ERR) { dom_node_unref((struct dom_node *) cdata); - return; + return err; } /* No longer interested in cdata section */ dom_node_unref((struct dom_node *) cdata); + + return DOM_NO_ERR; } /** @@ -999,8 +1076,9 @@ void xml_parser_add_cdata_section(dom_xml_parser *parser, * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_entity_reference(dom_xml_parser *parser, +dom_exception xml_parser_add_entity_reference(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child) { struct dom_entity_reference *entity, *ins_entity = NULL; @@ -1014,7 +1092,7 @@ void xml_parser_add_entity_reference(dom_xml_parser *parser, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for entity reference name"); - return; + return err; } /* Create text node */ @@ -1024,7 +1102,7 @@ void xml_parser_add_entity_reference(dom_xml_parser *parser, dom_string_unref(name); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for entity reference"); - return; + return err; } /* No longer need name */ @@ -1032,7 +1110,10 @@ void xml_parser_add_entity_reference(dom_xml_parser *parser, /* Mirror subtree (reference value) */ for (c = child->children; c != NULL; c = c->next) { - xml_parser_add_node(parser, (struct dom_node *) entity, c); + err = xml_parser_add_node(parser, + (struct dom_node *) entity, c); + if (err != DOM_NO_ERR) + return err; } /* Append entity reference to parent */ @@ -1042,7 +1123,7 @@ void xml_parser_add_entity_reference(dom_xml_parser *parser, dom_node_unref((struct dom_node *) entity); parser->msg(DOM_MSG_ERROR, parser->mctx, "Failed attaching entity reference"); - return; + return err; } /* We're not interested in the inserted entity reference */ @@ -1054,19 +1135,33 @@ void xml_parser_add_entity_reference(dom_xml_parser *parser, child); if (err != DOM_NO_ERR) { dom_node_unref((struct dom_node *) entity); - return; + return err; } /* No longer interested in entity reference */ dom_node_unref((struct dom_node *) entity); + + return DOM_NO_ERR; } -static void xml_parser_add_entity(dom_xml_parser *parser, - struct dom_node *parent, xmlNodePtr child) +/** + * Add an entity to the DOM + * + * \param parser The parser context + * \param parent The parent DOM node + * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise + */ +dom_exception xml_parser_add_entity(dom_xml_parser *parser, + struct dom_node *parent, xmlNodePtr child) { - UNUSED(parser); - UNUSED(parent); - UNUSED(child); + UNUSED(parser); + UNUSED(parent); + UNUSED(child); + + /** \todo implement */ + + return DOM_NO_ERR; } /** @@ -1075,9 +1170,10 @@ static void xml_parser_add_entity(dom_xml_parser *parser, * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, - xmlNodePtr child) +dom_exception xml_parser_add_comment(dom_xml_parser *parser, + struct dom_node *parent, xmlNodePtr child) { struct dom_comment *comment, *ins_comment = NULL; dom_string *data; @@ -1089,7 +1185,7 @@ void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for comment data"); - return; + return err; } /* Create comment */ @@ -1098,7 +1194,7 @@ void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, dom_string_unref(data); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for comment node"); - return; + return err; } /* No longer need data */ @@ -1111,7 +1207,7 @@ void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, dom_node_unref((struct dom_node *) comment); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed attaching comment node"); - return; + return err; } /* We're not interested in the inserted comment */ @@ -1123,11 +1219,13 @@ void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, child); if (err != DOM_NO_ERR) { dom_node_unref((struct dom_node *) comment); - return; + return err; } /* No longer interested in comment */ dom_node_unref((struct dom_node *) comment); + + return DOM_NO_ERR; } /** @@ -1136,8 +1234,9 @@ void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_document_type(dom_xml_parser *parser, +dom_exception xml_parser_add_document_type(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child) { xmlDtdPtr dtd = (xmlDtdPtr) child; @@ -1163,7 +1262,7 @@ void xml_parser_add_document_type(dom_xml_parser *parser, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed to create document type"); - return; + return err; } /* Add doctype to document */ @@ -1173,7 +1272,7 @@ void xml_parser_add_document_type(dom_xml_parser *parser, dom_node_unref((struct dom_node *) doctype); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed attaching doctype"); - return; + return err; } /* Not interested in inserted node */ @@ -1185,11 +1284,13 @@ void xml_parser_add_document_type(dom_xml_parser *parser, child); if (err != DOM_NO_ERR) { dom_node_unref((struct dom_node *) doctype); - return; + return err; } /* No longer interested in doctype */ dom_node_unref((struct dom_node *) doctype); + + return DOM_NO_ERR; } /* ------------------------------------------------------------------------*/ diff --git a/bindings/xml/xmlerror.h b/bindings/xml/xmlerror.h index 51f2c8b..a6cb905 100644 --- a/bindings/xml/xmlerror.h +++ b/bindings/xml/xmlerror.h @@ -13,7 +13,9 @@ typedef enum { DOM_XML_NOMEM = 1, - DOM_XML_EXTERNAL_ERR = (1<<16), + DOM_XML_EXTERNAL_ERR = (1<<16), + + DOM_XML_DOM_ERR = (1<<24), } dom_xml_error; #endif diff --git a/examples/dom-structure-dump.c b/examples/dom-structure-dump.c index 4ce7670..189292d 100644 --- a/examples/dom-structure-dump.c +++ b/examples/dom-structure-dump.c @@ -44,6 +44,7 @@ #include <string.h> #include <dom/dom.h> +#include <dom/walk.h> #include <dom/bindings/hubbub/parser.h> @@ -181,6 +182,12 @@ bool dump_dom_element_attribute(dom_node *node, char *attribute) return true; } +static inline void dump_indent(int depth) +{ + for (int i = 0; i < depth; i++) { + printf(" "); + } +} /** * Print a line in a DOM structure dump for an element @@ -189,25 +196,13 @@ bool dump_dom_element_attribute(dom_node *node, char *attribute) * \param depth The node's depth * \return true on success, or false on error */ -bool dump_dom_element(dom_node *node, int depth) +bool dump_dom_element(dom_node *node, int depth, bool close) { dom_exception exc; dom_string *node_name = NULL; - dom_node_type type; - int i; const char *string; size_t length; - /* Only interested in element nodes */ - exc = dom_node_get_node_type(node, &type); - if (exc != DOM_NO_ERR) { - printf("Exception raised for node_get_node_type\n"); - return false; - } else if (type != DOM_ELEMENT_NODE) { - /* Nothing to print */ - return true; - } - /* Get element name */ exc = dom_node_get_node_name(node, &node_name); if (exc != DOM_NO_ERR) { @@ -215,48 +210,84 @@ bool dump_dom_element(dom_node *node, int depth) return false; } else if (node_name == NULL) { printf("Broken: root_name == NULL\n"); - return false; + return false; } /* Print ASCII tree structure for current node */ - if (depth > 0) { - for (i = 0; i < depth; i++) { - printf("| "); - } - printf("+-"); - } + dump_indent(depth); /* Get string data and print element name */ string = dom_string_data(node_name); length = dom_string_byte_length(node_name); - printf("[%.*s]", (int)length, string); - - if (length == 5 && strncmp(string, "title", 5) == 0) { - /* Title tag, gather the title */ - dom_string *str; - exc = dom_node_get_text_content(node, &str); - if (exc == DOM_NO_ERR && str != NULL) { - printf(" $%.*s$", (int)dom_string_byte_length(str), - dom_string_data(str)); - dom_string_unref(str); - } - } - /* Finished with the node_name dom_string */ + /* TODO: Some elements don't have close tags; only print close tags for + * those that do. */ + printf("<%s%.*s", close ? "/" : "", (int)length, string); + dom_string_unref(node_name); - /* Print the element's id & class, if it has them */ - if (dump_dom_element_attribute(node, "id") == false || - dump_dom_element_attribute(node, "class") == false) { - /* Error occured */ - printf("\n"); - return false; + if (!close) { + if (length == 5 && strncmp(string, "title", 5) == 0) { + /* Title tag, gather the title */ + dom_string *s; + exc = dom_node_get_text_content(node, &s); + if (exc == DOM_NO_ERR && s != NULL) { + printf(" $%.*s$", + (int)dom_string_byte_length(s), + dom_string_data(s)); + dom_string_unref(s); + } + } + + /* Print the element's id & class, if it has them */ + if (dump_dom_element_attribute(node, "id") == false || + dump_dom_element_attribute(node, "class") == false) { + /* Error occured */ + printf(">\n"); + return false; + } } - printf("\n"); + printf(">\n"); return true; } +/** + * Structure dump callback for DOM walker. + */ +enum dom_walk_cmd dump_dom_structure__cb( + enum dom_walk_stage stage, + dom_node_type type, + dom_node *node, + void *pw) +{ + int *depth = pw; + + switch (type) { + case DOM_ELEMENT_NODE: + switch (stage) { + case DOM_WALK_STAGE_ENTER: + (*depth)++; + if (!dump_dom_element(node, *depth, false)) { + return DOM_WALK_CMD_ABORT; + } + break; + + case DOM_WALK_STAGE_LEAVE: + if (!dump_dom_element(node, *depth, true)) { + return DOM_WALK_CMD_ABORT; + } + (*depth)--; + break; + } + break; + + default: + break; + } + + return DOM_WALK_CMD_CONTINUE; +} /** * Walk though a DOM (sub)tree, in depth first order, printing DOM structure. @@ -267,51 +298,34 @@ bool dump_dom_element(dom_node *node, int depth) bool dump_dom_structure(dom_node *node, int depth) { dom_exception exc; - dom_node *child; - /* Print this node's entry */ - if (dump_dom_element(node, depth) == false) { - /* There was an error; return */ + if (!dump_dom_element(node, depth, false)) { return false; } - /* Get the node's first child */ - exc = dom_node_get_first_child(node, &child); + exc = libdom_treewalk(DOM_WALK_ENABLE_ALL, + dump_dom_structure__cb, + node, &depth); if (exc != DOM_NO_ERR) { - printf("Exception raised for node_get_first_child\n"); return false; - } else if (child != NULL) { - /* node has children; decend to children's depth */ - depth++; - - /* Loop though all node's children */ - do { - dom_node *next_child; - - /* Visit node's descendents */ - if (dump_dom_structure(child, depth) == false) { - /* There was an error; return */ - dom_node_unref(child); - return false; - } - - /* Go to next sibling */ - exc = dom_node_get_next_sibling(child, &next_child); - if (exc != DOM_NO_ERR) { - printf("Exception raised for " - "node_get_next_sibling\n"); - dom_node_unref(child); - return false; - } + } - dom_node_unref(child); - child = next_child; - } while (child != NULL); /* No more children */ + if (!dump_dom_element(node, depth, true)) { + return false; } return true; } +/* LWC leak callback */ +void sd__fini_lwc_callback(lwc_string *str, void *pw) +{ + (void)(pw); + + fprintf(stderr, "Leaked string: %.*s\n", + (int)lwc_string_length(str), + lwc_string_data(str)); +} /** * Main entry point from OS. @@ -354,6 +368,8 @@ int main(int argc, char **argv) /* Finished with the dom_document */ dom_node_unref(doc); + dom_namespace_finalise(); + lwc_iterate_strings(sd__fini_lwc_callback, NULL); return EXIT_SUCCESS; } diff --git a/examples/makefile b/examples/example.mk index 47cc7ae..8e1da17 100644 --- a/examples/makefile +++ b/examples/example.mk @@ -1,3 +1,9 @@ +# From the top level: +# +# make -C examples -f example.mk clean +# make -C examples -f example.mk +# ./examples/dom-structure-dump examples/files/test.html + CC := gcc LD := gcc diff --git a/include/dom/core/node.h b/include/dom/core/node.h index 9600e6d..90026a1 100644 --- a/include/dom/core/node.h +++ b/include/dom/core/node.h @@ -77,7 +77,7 @@ typedef struct dom_node_internal dom_node_internal; * DOM node type */ typedef struct dom_node { - void *vtable; + const void *vtable; uint32_t refcnt; } dom_node; @@ -169,8 +169,8 @@ typedef struct dom_node_vtable { dom_exception (*dom_node_set_user_data)(dom_node_internal *node, dom_string *key, void *data, dom_user_data_handler handler, void **result); - dom_exception (*dom_node_get_user_data)(dom_node_internal *node, - dom_string *key, void **result); + dom_exception (*dom_node_get_user_data)(const dom_node_internal *node, + const dom_string *key, void **result); } dom_node_vtable; /* The ref/unref methods define */ @@ -567,8 +567,8 @@ static inline dom_exception dom_node_set_user_data(struct dom_node *node, (dom_node *) (n), (k), (void *) (d), \ (dom_user_data_handler) h, (void **) (r)) -static inline dom_exception dom_node_get_user_data(struct dom_node *node, - dom_string *key, void **result) +static inline dom_exception dom_node_get_user_data(const struct dom_node *node, + const dom_string *key, void **result) { return ((dom_node_vtable *) node->vtable)->dom_node_get_user_data( (dom_node_internal *) node, key, result); diff --git a/include/dom/core/tokenlist.h b/include/dom/core/tokenlist.h new file mode 100644 index 0000000..718d3a5 --- /dev/null +++ b/include/dom/core/tokenlist.h @@ -0,0 +1,43 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2022 Daniel Silverstone <dsilvers@netsurf-browser.org> + */ + +#ifndef dom_core_tokenlist_h_ +#define dom_core_tokenlist_h_ + +#include <dom/core/exceptions.h> + +struct dom_element; +struct dom_string; + +typedef struct dom_tokenlist dom_tokenlist; + +void dom_tokenlist_ref(struct dom_tokenlist *list); +void dom_tokenlist_unref(struct dom_tokenlist *list); + +dom_exception dom_tokenlist_create(struct dom_element *ele, struct dom_string *attr, dom_tokenlist **list); + +dom_exception dom_tokenlist_get_length(struct dom_tokenlist *list, + uint32_t *length); +dom_exception _dom_tokenlist_item(struct dom_tokenlist *list, + uint32_t index, struct dom_string **value); + +#define dom_tokenlist_item(l, i, n) _dom_tokenlist_item((dom_tokenlist *) (l), \ + (uint32_t) (i), (struct dom_string **) (n)) + +dom_exception dom_tokenlist_get_value(struct dom_tokenlist *list, + struct dom_string **value); + +dom_exception dom_tokenlist_set_value(struct dom_tokenlist *list, + struct dom_string *value); + +dom_exception dom_tokenlist_contains(struct dom_tokenlist *list, struct dom_string *value, bool *contains); + +dom_exception dom_tokenlist_add(struct dom_tokenlist *list, struct dom_string *value); + +dom_exception dom_tokenlist_remove(struct dom_tokenlist *list, struct dom_string *value); + +#endif diff --git a/include/dom/dom.h b/include/dom/dom.h index c10e5a6..00bf3d9 100644 --- a/include/dom/dom.h +++ b/include/dom/dom.h @@ -32,6 +32,7 @@ #include <dom/core/doc_fragment.h> #include <dom/core/entity_ref.h> #include <dom/core/nodelist.h> +#include <dom/core/tokenlist.h> #include <dom/core/string.h> #include <dom/core/text.h> #include <dom/core/pi.h> diff --git a/include/dom/html/html_elements.h b/include/dom/html/html_elements.h index 5b54bbe..6e954c5 100644 --- a/include/dom/html/html_elements.h +++ b/include/dom/html/html_elements.h @@ -12,6 +12,7 @@ DOM_HTML_ELEMENT_STRINGS_ENTRY(_UNKNOWN) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(A) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(ABBR) \ + DOM_HTML_ELEMENT_STRINGS_ENTRY(ACRONYM) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(ADDRESS) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(APPLET) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(AREA) \ @@ -23,6 +24,8 @@ DOM_HTML_ELEMENT_STRINGS_ENTRY(BASEFONT) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(BDI) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(BDO) \ + DOM_HTML_ELEMENT_STRINGS_ENTRY(BGSOUND) \ + DOM_HTML_ELEMENT_STRINGS_ENTRY(BIG) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(BLOCKQUOTE) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(BODY) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(BR) \ @@ -81,11 +84,14 @@ DOM_HTML_ELEMENT_STRINGS_ENTRY(MAIN) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(MAP) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(MARK) \ + DOM_HTML_ELEMENT_STRINGS_ENTRY(MARQUEE) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(MENU) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(MENUITEM) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(META) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(METER) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(NAV) \ + DOM_HTML_ELEMENT_STRINGS_ENTRY(NOBR) \ + DOM_HTML_ELEMENT_STRINGS_ENTRY(NOFRAMES) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(NOSCRIPT) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(OBJECT) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(OL) \ @@ -108,7 +114,9 @@ DOM_HTML_ELEMENT_STRINGS_ENTRY(SELECT) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(SMALL) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(SOURCE) \ + DOM_HTML_ELEMENT_STRINGS_ENTRY(SPACER) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(SPAN) \ + DOM_HTML_ELEMENT_STRINGS_ENTRY(STRIKE) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(STRONG) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(STYLE) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(SUB) \ @@ -126,6 +134,7 @@ DOM_HTML_ELEMENT_STRINGS_ENTRY(TITLE) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(TR) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(TRACK) \ + DOM_HTML_ELEMENT_STRINGS_ENTRY(TT) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(U) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(UL) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(VAR) \ diff --git a/include/dom/walk.h b/include/dom/walk.h new file mode 100644 index 0000000..5de3546 --- /dev/null +++ b/include/dom/walk.h @@ -0,0 +1,65 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2021 Michael Drake <tlsa@netsurf-browser.org> + */ + +/** \file + * This is an API for walking a loaded DOM. + */ + +#ifndef dom_walk_h_ +#define dom_walk_h_ + +enum dom_walk_stage { + DOM_WALK_STAGE_ENTER, + DOM_WALK_STAGE_LEAVE, +}; + +enum dom_walk_enable { + DOM_WALK_ENABLE_ENTER = (1 << DOM_WALK_STAGE_ENTER), + DOM_WALK_ENABLE_LEAVE = (1 << DOM_WALK_STAGE_LEAVE), + DOM_WALK_ENABLE_ALL = DOM_WALK_ENABLE_ENTER | DOM_WALK_ENABLE_LEAVE, +}; + +enum dom_walk_cmd { + DOM_WALK_CMD_CONTINUE, /**< Continue the tree walk. */ + DOM_WALK_CMD_ABORT, /**< Early termination of the tree walk. */ + DOM_WALK_CMD_SKIP, /**< Skip children (only for \ref DOM_WALK_ENABLE_ENTER). */ +}; + +/** + * DOM walking callback. + * + * Client callback for DOM walk. + * + * \param[in] stage Whether the \ref node is being entered or left. + * \param[in] node The node being walked. Client must take ref itself. + * \param[in] type The node type. + * \param[in] pw Client private data. + * \return Tree walking client command. + */ +typedef enum dom_walk_cmd (*dom_walk_cb)( + enum dom_walk_stage stage, + dom_node_type type, + dom_node *node, + void *pw); + + +/** + * Walk a DOM subtree. + * + * \param[in] mask Mask of stages to enable callback for. + * \param[in] cb The client callback function. + * \param[in] root Node to start walk from. + * \param[in] pw The client's private data. + * \return false for early termination of walk, true otherwise. + */ +dom_exception libdom_treewalk( + enum dom_walk_enable mask, + dom_walk_cb cb, + dom_node *root, + void *pw); + +#endif diff --git a/libdom.pc.in b/libdom.pc.in index 406ed9e..86a97bb 100644 --- a/libdom.pc.in +++ b/libdom.pc.in @@ -7,5 +7,5 @@ Name: libdom Description: W3C DOM implementation Version: VERSION REQUIRED -Libs: -L${libdir} -ldom -lexpat +Libs: -L${libdir} -ldom LIBRARIES Cflags: -I${includedir} diff --git a/src/core/Makefile b/src/core/Makefile index 41fd51f..5d9c969 100644 --- a/src/core/Makefile +++ b/src/core/Makefile @@ -6,6 +6,6 @@ DIR_SOURCES := \ text.c typeinfo.c comment.c \ namednodemap.c nodelist.c \ cdatasection.c document_type.c entity_ref.c pi.c \ - doc_fragment.c document.c + doc_fragment.c document.c tokenlist.c include $(NSBUILD)/Makefile.subdir diff --git a/src/core/attr.c b/src/core/attr.c index e18e2a7..8fcaac3 100644 --- a/src/core/attr.c +++ b/src/core/attr.c @@ -49,7 +49,7 @@ struct dom_attr { }; /* The vtable for dom_attr node */ -static struct dom_attr_vtable attr_vtable = { +static const struct dom_attr_vtable attr_vtable = { { { DOM_NODE_EVENT_TARGET_VTABLE, @@ -60,7 +60,7 @@ static struct dom_attr_vtable attr_vtable = { }; /* The protected vtable for dom_attr */ -static struct dom_node_protect_vtable attr_protect_vtable = { +static const struct dom_node_protect_vtable attr_protect_vtable = { DOM_ATTR_PROTECT_VTABLE }; diff --git a/src/core/cdatasection.c b/src/core/cdatasection.c index c6812e3..efba237 100644 --- a/src/core/cdatasection.c +++ b/src/core/cdatasection.c @@ -20,7 +20,7 @@ struct dom_cdata_section { dom_text base; /**< Base node */ }; -static struct dom_node_protect_vtable cdata_section_protect_vtable = { +static const struct dom_node_protect_vtable cdata_section_protect_vtable = { DOM_CDATA_SECTION_PROTECT_VTABLE }; diff --git a/src/core/characterdata.c b/src/core/characterdata.c index ea665b3..e6f5dbe 100644 --- a/src/core/characterdata.c +++ b/src/core/characterdata.c @@ -21,7 +21,7 @@ /* The virtual functions for dom_characterdata, we make this vtable * public to each child class */ -struct dom_characterdata_vtable characterdata_vtable = { +const struct dom_characterdata_vtable characterdata_vtable = { { { DOM_NODE_EVENT_TARGET_VTABLE diff --git a/src/core/characterdata.h b/src/core/characterdata.h index 0b0889c..c8f4db3 100644 --- a/src/core/characterdata.h +++ b/src/core/characterdata.h @@ -116,7 +116,7 @@ dom_exception _dom_characterdata_copy(dom_node_internal *old, _dom_characterdata_destroy, \ _dom_characterdata_copy -extern struct dom_characterdata_vtable characterdata_vtable; +extern const struct dom_characterdata_vtable characterdata_vtable; dom_exception _dom_characterdata_copy_internal(dom_characterdata *old, dom_characterdata *new); diff --git a/src/core/comment.c b/src/core/comment.c index 0697826..b36a1be 100644 --- a/src/core/comment.c +++ b/src/core/comment.c @@ -21,7 +21,7 @@ struct dom_comment { dom_characterdata base; /**< Base node */ }; -static struct dom_node_protect_vtable comment_protect_vtable = { +static const struct dom_node_protect_vtable comment_protect_vtable = { DOM_COMMENT_PROTECT_VTABLE }; diff --git a/src/core/doc_fragment.c b/src/core/doc_fragment.c index 96cc707..9e10a1a 100644 --- a/src/core/doc_fragment.c +++ b/src/core/doc_fragment.c @@ -22,14 +22,14 @@ struct dom_document_fragment { dom_node_internal base; /**< Base node */ }; -static struct dom_node_vtable df_vtable = { +static const struct dom_node_vtable df_vtable = { { DOM_NODE_EVENT_TARGET_VTABLE }, DOM_NODE_VTABLE }; -static struct dom_node_protect_vtable df_protect_vtable = { +static const struct dom_node_protect_vtable df_protect_vtable = { DOM_DF_PROTECT_VTABLE }; diff --git a/src/core/document.c b/src/core/document.c index 7c0bcdc..40d4cd9 100644 --- a/src/core/document.c +++ b/src/core/document.c @@ -42,7 +42,7 @@ struct dom_doc_nl { }; /* The virtual functions of this dom_document */ -static struct dom_document_vtable document_vtable = { +static const struct dom_document_vtable document_vtable = { { { DOM_NODE_EVENT_TARGET_VTABLE @@ -52,7 +52,7 @@ static struct dom_document_vtable document_vtable = { DOM_DOCUMENT_VTABLE }; -static struct dom_node_protect_vtable document_protect_vtable = { +static const struct dom_node_protect_vtable document_protect_vtable = { DOM_DOCUMENT_PROTECT_VTABLE }; diff --git a/src/core/document_type.c b/src/core/document_type.c index d7b1b99..a0fafdd 100644 --- a/src/core/document_type.c +++ b/src/core/document_type.c @@ -27,7 +27,7 @@ struct dom_document_type { dom_string *system_id; /**< Doctype system ID */ }; -static struct dom_document_type_vtable document_type_vtable = { +static const struct dom_document_type_vtable document_type_vtable = { { { DOM_NODE_EVENT_TARGET_VTABLE @@ -37,7 +37,7 @@ static struct dom_document_type_vtable document_type_vtable = { DOM_DOCUMENT_TYPE_VTABLE }; -static struct dom_node_protect_vtable dt_protect_vtable = { +static const struct dom_node_protect_vtable dt_protect_vtable = { DOM_DT_PROTECT_VTABLE }; diff --git a/src/core/element.c b/src/core/element.c index dbdd56b..05dc8c6 100644 --- a/src/core/element.c +++ b/src/core/element.c @@ -32,7 +32,7 @@ #include "utils/list.h" #include "events/mutation_event.h" -struct dom_element_vtable _dom_element_vtable = { +const struct dom_element_vtable _dom_element_vtable = { { { DOM_NODE_EVENT_TARGET_VTABLE @@ -42,7 +42,7 @@ struct dom_element_vtable _dom_element_vtable = { DOM_ELEMENT_VTABLE }; -static struct dom_element_protected_vtable element_protect_vtable = { +static const struct dom_element_protected_vtable element_protect_vtable = { { DOM_NODE_PROTECT_VTABLE_ELEMENT }, @@ -1232,9 +1232,11 @@ dom_exception _dom_element_has_class(struct dom_element *element, /** * Get a named ancestor node * + * The caller is responsible for unreffing the returned node. + * * \param element Element to consider * \param name Node name to look for - * \param ancestor Pointer to location to receive node pointer + * \param ancestor Pointer to location to receive node. * \return DOM_NO_ERR. */ dom_exception dom_element_named_ancestor_node(dom_element *element, @@ -1251,7 +1253,7 @@ dom_exception dom_element_named_ancestor_node(dom_element *element, assert(node->name != NULL); if (dom_string_caseless_lwc_isequal(node->name, name)) { - *ancestor = (dom_element *)node; + *ancestor = (dom_element *)dom_node_ref(node); break; } } @@ -1262,6 +1264,8 @@ dom_exception dom_element_named_ancestor_node(dom_element *element, /** * Get a named parent node * + * The caller is responsible for unreffing the returned node. + * * \param element Element to consider * \param name Node name to look for * \param parent Pointer to location to receive node pointer @@ -1281,7 +1285,7 @@ dom_exception dom_element_named_parent_node(dom_element *element, assert(node->name != NULL); if (dom_string_caseless_lwc_isequal(node->name, name)) { - *parent = (dom_element *)node; + *parent = (dom_element *)dom_node_ref(node); } break; } @@ -1292,6 +1296,8 @@ dom_exception dom_element_named_parent_node(dom_element *element, /** * Get a named parent node * + * The caller is responsible for unreffing the returned node. + * * \param element Element to consider * \param name Node name to look for * \param parent Pointer to location to receive node pointer @@ -1308,7 +1314,7 @@ dom_exception dom_element_parent_node(dom_element *element, if (node->type != DOM_ELEMENT_NODE) continue; - *parent = (dom_element *)node; + *parent = (dom_element *)dom_node_ref(node); break; } diff --git a/src/core/element.h b/src/core/element.h index c89ddc0..fb946b7 100644 --- a/src/core/element.h +++ b/src/core/element.h @@ -238,6 +238,6 @@ dom_exception _dom_element_copy_internal(dom_element *old, dom_exception _dom_element_get_id(struct dom_element *ele, dom_string **id); -extern struct dom_element_vtable _dom_element_vtable; +extern const struct dom_element_vtable _dom_element_vtable; #endif diff --git a/src/core/entity_ref.c b/src/core/entity_ref.c index aa32111..bc6fbab 100644 --- a/src/core/entity_ref.c +++ b/src/core/entity_ref.c @@ -20,14 +20,14 @@ struct dom_entity_reference { dom_node_internal base; /**< Base node */ }; -static struct dom_node_vtable er_vtable = { +static const struct dom_node_vtable er_vtable = { { DOM_NODE_EVENT_TARGET_VTABLE }, DOM_NODE_VTABLE }; -static struct dom_node_protect_vtable er_protect_vtable = { +static const struct dom_node_protect_vtable er_protect_vtable = { DOM_ER_PROTECT_VTABLE }; diff --git a/src/core/node.c b/src/core/node.c index b471725..1218742 100644 --- a/src/core/node.c +++ b/src/core/node.c @@ -55,14 +55,14 @@ static inline dom_exception _dom_node_detach_range(dom_node_internal *first, static inline void _dom_node_replace(dom_node_internal *old, dom_node_internal *replacement); -static struct dom_node_vtable node_vtable = { +static const struct dom_node_vtable node_vtable = { { DOM_NODE_EVENT_TARGET_VTABLE }, DOM_NODE_VTABLE }; -static struct dom_node_protect_vtable node_protect_vtable = { +static const struct dom_node_protect_vtable node_protect_vtable = { DOM_NODE_PROTECT_VTABLE }; @@ -1827,8 +1827,8 @@ dom_exception _dom_node_set_user_data(dom_node_internal *node, * \param result Pointer to location to receive result * \return DOM_NO_ERR. */ -dom_exception _dom_node_get_user_data(dom_node_internal *node, - dom_string *key, void **result) +dom_exception _dom_node_get_user_data(const dom_node_internal *node, + const dom_string *key, void **result) { struct dom_user_data *ud = NULL; diff --git a/src/core/node.h b/src/core/node.h index 87f3cb3..36cdd7d 100644 --- a/src/core/node.h +++ b/src/core/node.h @@ -53,7 +53,7 @@ typedef struct dom_node_protect_vtable { */ struct dom_node_internal { struct dom_node base; /**< The vtable base */ - void *vtable; /**< The protected vtable */ + const void *vtable; /**< The protected vtable */ dom_string *name; /**< Node name (this is the local part * of a QName in the cases where a @@ -182,8 +182,8 @@ dom_exception _dom_node_get_feature(dom_node_internal *node, dom_exception _dom_node_set_user_data(dom_node_internal *node, dom_string *key, void *data, dom_user_data_handler handler, void **result); -dom_exception _dom_node_get_user_data(dom_node_internal *node, - dom_string *key, void **result); +dom_exception _dom_node_get_user_data(const dom_node_internal *node, + const dom_string *key, void **result); #define DOM_NODE_EVENT_TARGET_VTABLE \ _dom_node_add_event_listener, \ diff --git a/src/core/pi.c b/src/core/pi.c index d12f109..3e69841 100644 --- a/src/core/pi.c +++ b/src/core/pi.c @@ -20,14 +20,14 @@ struct dom_processing_instruction { dom_node_internal base; /**< Base node */ }; -static struct dom_node_vtable pi_vtable = { +static const struct dom_node_vtable pi_vtable = { { DOM_NODE_EVENT_TARGET_VTABLE }, DOM_NODE_VTABLE }; -static struct dom_node_protect_vtable pi_protect_vtable = { +static const struct dom_node_protect_vtable pi_protect_vtable = { DOM_PI_PROTECT_VTABLE }; /** diff --git a/src/core/text.c b/src/core/text.c index b73e86d..f63fabe 100644 --- a/src/core/text.c +++ b/src/core/text.c @@ -20,7 +20,7 @@ #include "utils/utils.h" /* The virtual table for dom_text */ -struct dom_text_vtable text_vtable = { +const struct dom_text_vtable text_vtable = { { { { @@ -33,7 +33,7 @@ struct dom_text_vtable text_vtable = { DOM_TEXT_VTABLE }; -static struct dom_node_protect_vtable text_protect_vtable = { +static const struct dom_node_protect_vtable text_protect_vtable = { DOM_TEXT_PROTECT_VTABLE }; diff --git a/src/core/text.h b/src/core/text.h index 26424ce..3f5739b 100644 --- a/src/core/text.h +++ b/src/core/text.h @@ -66,7 +66,7 @@ dom_exception _dom_text_copy(dom_node_internal *old, dom_node_internal **copy); __dom_text_destroy, \ _dom_text_copy -extern struct dom_text_vtable text_vtable; +extern const struct dom_text_vtable text_vtable; dom_exception _dom_text_copy_internal(dom_text *old, dom_text *new); #define dom_text_copy_internal(o, n) \ diff --git a/src/core/tokenlist.c b/src/core/tokenlist.c new file mode 100644 index 0000000..cc93a8c --- /dev/null +++ b/src/core/tokenlist.c @@ -0,0 +1,547 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2022 Daniel Silverstone <dsilvers@digital-scurf.org> + */ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include <dom/core/element.h> +#include <dom/core/nodelist.h> +#include <dom/core/tokenlist.h> +#include <dom/core/string.h> +#include <dom/events/event.h> +#include <dom/events/event_target.h> +#include <dom/events/event_listener.h> +#include <dom/events/mutation_event.h> + +#include "core/element.h" +#include "core/document.h" + +#include "utils/utils.h" + +#define DOM_TOKENLIST_GROW_INCREMENT 4 + +struct dom_tokenlist { + uint32_t refcnt; + dom_element *ele; + dom_string *attr; + dom_event_listener *listener; + dom_string *last_set; + bool needs_parse; + /* Parsed content, for optimal access */ + dom_string **entries; + uint32_t len; + uint32_t alloc; +}; + +/* Handle a DOMAttrModified event which might be to do with our attribute */ + +static void _dom_tokenlist_handle_attrmodified(dom_event *evt, void *pw) +{ + dom_mutation_event *mutevt = (dom_mutation_event *)evt; + dom_tokenlist *list = (dom_tokenlist *)pw; + dom_exception exc; + dom_string *value; + + { + dom_event_target *target; + exc = dom_event_get_target(evt, &target); + if (exc != DOM_NO_ERR) + return; + dom_node_unref(target); + if (target != (dom_event_target *)list->ele) + return; + } + + { + dom_string *attr; + exc = dom_mutation_event_get_attr_name(mutevt, &attr); + if (exc != DOM_NO_ERR) + return; + if (!dom_string_isequal(attr, list->attr)) { + dom_string_unref(attr); + return; + } + dom_string_unref(attr); + } + + /* At this point we know that this is a mutation of our attribute on our + * node */ + + exc = dom_mutation_event_get_new_value(mutevt, &value); + if (exc != DOM_NO_ERR) + return; + + if (list->last_set != NULL && + dom_string_isequal(list->last_set, value)) { + /* We've just seen the mutation event for one of our own set + * operations */ + dom_string_unref(value); + return; + } + + /* Mark that we need to re-parse the tokenlist on the next request */ + list->needs_parse = true; + + dom_string_unref(value); +} + +static dom_exception _dom_tokenlist_make_room(dom_tokenlist *list) +{ + if (list->len == list->alloc) { + uint32_t new_alloc = list->alloc + DOM_TOKENLIST_GROW_INCREMENT; + dom_string **new_entries = realloc( + list->entries, new_alloc * sizeof(dom_string *)); + if (new_entries == NULL) + return DOM_NO_MEM_ERR; + list->alloc = new_alloc; + list->entries = new_entries; + } + + return DOM_NO_ERR; +} + +static dom_exception _dom_tokenlist_reparse(dom_tokenlist *list) +{ + dom_exception exc; + dom_string *value; + const char *pos; + uint32_t remaining, check; + uint32_t n_entries = 0; + dom_string *temp; + bool found; + + if (!list->needs_parse) + return DOM_NO_ERR; + + /* Clean down the current entries */ + while (list->len-- > 0) + dom_string_unref(list->entries[list->len]); + list->len = 0; + + /* Get the "new" attribute value */ + exc = dom_element_get_attribute(list->ele, list->attr, &value); + if (exc != DOM_NO_ERR) + return exc; + + /* If there is no value, we're an empty list and we're done */ + if (value == NULL) { + list->needs_parse = false; + return DOM_NO_ERR; + } + + /* OK, there's something here to do, so let's do it... */ + + /* Count number of entries */ + for (pos = dom_string_data(value), remaining = dom_string_length(value); + remaining > 0;) { + if (*pos != ' ') { + while (*pos != ' ' && remaining > 0) { + remaining--; + pos++; + } + n_entries++; + } else { + while (*pos == ' ' && remaining > 0) { + remaining--; + pos++; + } + } + } + + /* If there are no entries (all whitespace) just bail here */ + if (n_entries == 0) { + list->needs_parse = false; + dom_string_unref(value); + return DOM_NO_ERR; + } + + /* If we need more room, reallocate the buffer */ + if (list->alloc < n_entries) { + dom_string **new_alloc = realloc( + list->entries, n_entries * sizeof(dom_string *)); + if (new_alloc == NULL) { + dom_string_unref(value); + return DOM_NO_MEM_ERR; + } + list->entries = new_alloc; + list->alloc = n_entries; + } + + /* And now parse those entries into the buffer */ + for (pos = dom_string_data(value), + remaining = dom_string_length(value), + n_entries = 0; + remaining > 0;) { + if (*pos != ' ') { + const char *s = pos; + while (*pos != ' ' && remaining > 0) { + pos++; + remaining--; + } + exc = dom_string_create_interned((const uint8_t *)s, + pos - s, + &temp); + if (exc != DOM_NO_ERR) { + dom_string_unref(value); + return exc; + } + found = false; + for (check = 0; check < list->len; check++) { + if (dom_string_isequal(temp, + list->entries[check])) { + found = true; + break; + } + } + if (found == true) { + dom_string_unref(temp); + } else { + list->entries[list->len] = temp; + list->len++; + } + } else { + while (*pos == ' ' && remaining > 0) { + pos++; + remaining--; + } + } + } + + dom_string_unref(value); + list->needs_parse = false; + + return DOM_NO_ERR; +} + +static dom_exception _dom_tokenlist_reify(dom_tokenlist *list) +{ + dom_exception exc; + uint32_t nchars = 0, n; + char *buffer, *next; + dom_string *output; + + if (list->len == 0) { + if (list->last_set != NULL) { + dom_string_unref(list->last_set); + } + list->last_set = dom_string_ref( + list->ele->base.owner->_memo_empty); + return dom_element_set_attribute(list->ele, + list->attr, + list->last_set); + } + + for (n = 0; n < list->len; ++n) + nchars += dom_string_length(list->entries[n]); + + buffer = calloc(1, nchars + list->len); + if (buffer == NULL) + return DOM_NO_MEM_ERR; + + for (next = buffer, n = 0; n < list->len; ++n) { + uint32_t slen = dom_string_length(list->entries[n]); + memcpy(next, dom_string_data(list->entries[n]), slen); + next[slen] = ' '; + next += slen + 1; + } + + exc = dom_string_create_interned((const uint8_t *)buffer, + nchars + list->len - 1, + &output); + free(buffer); + if (exc != DOM_NO_ERR) + return exc; + + if (list->last_set != NULL) { + dom_string_unref(list->last_set); + } + list->last_set = output; + + return dom_element_set_attribute(list->ele, list->attr, list->last_set); +} + +/**********************************************************************************/ + +/** + * Create a tokenlist + * + * \param ele The element which owns the tokenlist attribute + * \param attr The name of the attribute we are treating as a tokenlist + * \param list The tokenlist output which is set on success + * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion + * + * The returned list will already be referenced, so the client need not + * do so explicitly. The client must unref the list once finished with it. + * + * This list will take its own references to ::ele and ::attr + */ +dom_exception +dom_tokenlist_create(dom_element *ele, dom_string *attr, dom_tokenlist **list) +{ + dom_tokenlist *l; + dom_exception exc; + + l = calloc(1, sizeof(dom_tokenlist)); + if (l == NULL) + return DOM_NO_MEM_ERR; + + l->refcnt = 1; + l->ele = (dom_element *)dom_node_ref(ele); + l->attr = dom_string_ref(attr); + l->needs_parse = true; + + exc = dom_event_listener_create(_dom_tokenlist_handle_attrmodified, + l, + &l->listener); + if (exc != DOM_NO_ERR) + goto fail; + + exc = dom_event_target_add_event_listener( + ele, + ele->base.owner->_memo_domattrmodified, + l->listener, + false); + + if (exc != DOM_NO_ERR) + goto fail; + + *list = l; + + return DOM_NO_ERR; + +fail: + if (l->listener != NULL) + dom_event_listener_unref(l->listener); + dom_node_unref(l->ele); + dom_string_unref(l->attr); + free(l); + return exc; +} + +/** + * Claim a ref on a tokenlist + * + * \param list The tokenlist to claim a ref on + */ +void dom_tokenlist_ref(dom_tokenlist *list) +{ + assert(list != NULL); + list->refcnt++; +} + +/** + * Release a ref on a tokenlist + * + * \param list The list to release the reference of + * + * If you release the last ref, this cleans up the tokenlist + */ +void dom_tokenlist_unref(dom_tokenlist *list) +{ + assert(list != NULL); + + if (--list->refcnt > 0) + return; + + if (list->alloc > 0) { + while (list->len-- > 0) + dom_string_unref(list->entries[list->len]); + free(list->entries); + } + + dom_event_target_remove_event_listener( + list->ele, + list->ele->base.owner->_memo_domattrmodified, + list->listener, + false); + + dom_event_listener_unref(list->listener); + + if (list->last_set != NULL) + dom_string_unref(list->last_set); + + dom_string_unref(list->attr); + dom_node_unref(list->ele); + + free(list); +} + +/** + * Get the length of the tokenlist + * + * \param list The list to get the length of + * \param length Length of the list outputs here + * \return DOM_NO_ERR on success, otherwise the failure code + */ +dom_exception dom_tokenlist_get_length(dom_tokenlist *list, uint32_t *length) +{ + dom_exception exc; + assert(list != NULL); + + exc = _dom_tokenlist_reparse(list); + if (exc != DOM_NO_ERR) + return exc; + + *length = list->len; + + return DOM_NO_ERR; +} + +/** + * Get a particular item from the tokenlist + * + * \param list The list to retrieve the item from + * \param index The index of the item to retrieve + * \param value The value of the item returns here + * \return DOM_NO_ERR on success, otherwise the failure code + */ +dom_exception +_dom_tokenlist_item(dom_tokenlist *list, uint32_t index, dom_string **value) +{ + dom_exception exc; + assert(list != NULL); + + exc = _dom_tokenlist_reparse(list); + if (exc != DOM_NO_ERR) + return exc; + + if (index >= list->len) { + *value = NULL; + return DOM_NO_ERR; + } + + *value = dom_string_ref(list->entries[index]); + return DOM_NO_ERR; +} + +/** + * Retrieve the value of the tokenlist as a string + * + * \param list The list to retrieve the value of + * \param value The value of the list returns here + * \return DOM_NO_ERR on success, otherwise the failure code + */ +dom_exception dom_tokenlist_get_value(dom_tokenlist *list, dom_string **value) +{ + assert(list != NULL); + + return dom_element_get_attribute(list->ele, list->attr, value); +} + +/** + * Set the value of the tokenlist as a string + * + * \param list The list to set the value of + * \param value The value to set + * \return DOM_NO_ERR on success, otherwise the failure code + * + */ +dom_exception dom_tokenlist_set_value(dom_tokenlist *list, dom_string *value) +{ + assert(list != NULL); + + return dom_element_set_attribute(list->ele, list->attr, value); +} + +/** + * Check if the given value is in the tokenlist + * + * \param list The list to scan for the given value + * \param value The value to look for in the token list + * \param contains This will be set based on whether or not the value is present + * \return DOM_NO_ERR on success, otherwise the failure code + */ +dom_exception +dom_tokenlist_contains(dom_tokenlist *list, dom_string *value, bool *contains) +{ + dom_exception exc; + uint32_t n; + + assert(list != NULL); + + exc = _dom_tokenlist_reparse(list); + if (exc != DOM_NO_ERR) + return exc; + + *contains = false; + + for (n = 0; n < list->len; n++) { + if (dom_string_isequal(value, list->entries[n])) { + *contains = true; + break; + } + } + + return DOM_NO_ERR; +} + +/** + * Add the given value to the tokenlist + * + * \param list The list to add to + * \param value The value to add + * \return DOM_NO_ERR on success, otherwise the failure code + */ +dom_exception dom_tokenlist_add(dom_tokenlist *list, dom_string *value) +{ + dom_exception exc; + bool present = false; + + assert(list != NULL); + + exc = dom_tokenlist_contains(list, value, &present); + if (exc != DOM_NO_ERR) + return exc; + + if (present == true) + return DOM_NO_ERR; + + exc = _dom_tokenlist_make_room(list); + if (exc != DOM_NO_ERR) + return exc; + + list->entries[list->len++] = dom_string_ref(value); + + exc = _dom_tokenlist_reify(list); + + return exc; +} + +/** + * Remove the given value from the tokenlist + * + * \param list The list to remove from + * \param value The value to remove + * \return DOM_NO_ERR on success, otherwise the failure code + */ +dom_exception dom_tokenlist_remove(dom_tokenlist *list, dom_string *value) +{ + dom_exception exc; + uint32_t n, m; + + assert(list != NULL); + + exc = _dom_tokenlist_reparse(list); + if (exc != DOM_NO_ERR) + return false; + + for (n = 0; n < list->len; ++n) { + if (dom_string_isequal(value, list->entries[n])) { + dom_string_unref(list->entries[n]); + for (m = n + 1; m < list->len; ++m) { + list->entries[m - 1] = list->entries[m]; + } + list->len--; + break; + } + } + + exc = _dom_tokenlist_reify(list); + + return exc; +} diff --git a/src/core/tokenlist.h b/src/core/tokenlist.h new file mode 100644 index 0000000..325d726 --- /dev/null +++ b/src/core/tokenlist.h @@ -0,0 +1,18 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org> + */ + +#ifndef dom_internal_core_tokenlist_h_ +#define dom_internal_core_tokenlist_h_ + +#include <stdbool.h> + +#include <dom/core/tokenlist.h> + +struct dom_element; +struct dom_string; + +#endif diff --git a/src/events/event.c b/src/events/event.c index 3fe9978..26b245e 100644 --- a/src/events/event.c +++ b/src/events/event.c @@ -18,7 +18,7 @@ static void _virtual_dom_event_destroy(dom_event *evt); -static struct dom_event_private_vtable _event_vtable = { +static const struct dom_event_private_vtable _event_vtable = { _virtual_dom_event_destroy }; diff --git a/src/events/event.h b/src/events/event.h index 857f20a..7cada7b 100644 --- a/src/events/event.h +++ b/src/events/event.h @@ -45,7 +45,7 @@ struct dom_event { uint32_t refcnt; /**< The reference count of this object */ - struct dom_event_private_vtable *vtable; + const struct dom_event_private_vtable *vtable; /**< The private virtual function table of Event */ bool in_dispatch; /**< Whether this event is in dispatch */ bool is_initialised; /**< Whether this event is initialised */ diff --git a/src/events/keyboard_event.c b/src/events/keyboard_event.c index d349355..d1fa1ca 100644 --- a/src/events/keyboard_event.c +++ b/src/events/keyboard_event.c @@ -15,7 +15,7 @@ static void _virtual_dom_keyboard_event_destroy(struct dom_event *evt); -static struct dom_event_private_vtable _event_vtable = { +static const struct dom_event_private_vtable _event_vtable = { _virtual_dom_keyboard_event_destroy }; diff --git a/src/events/mouse_event.c b/src/events/mouse_event.c index b3b2154..ac1d142 100644 --- a/src/events/mouse_event.c +++ b/src/events/mouse_event.c @@ -15,7 +15,7 @@ static void _virtual_dom_mouse_event_destroy(struct dom_event *evt); -static struct dom_event_private_vtable _event_vtable = { +static const struct dom_event_private_vtable _event_vtable = { _virtual_dom_mouse_event_destroy }; diff --git a/src/events/mouse_multi_wheel_event.c b/src/events/mouse_multi_wheel_event.c index bcbe8d5..a42085a 100644 --- a/src/events/mouse_multi_wheel_event.c +++ b/src/events/mouse_multi_wheel_event.c @@ -16,7 +16,7 @@ static void _virtual_dom_mouse_multi_wheel_event_destroy( struct dom_event *evt); -static struct dom_event_private_vtable _event_vtable = { +static const struct dom_event_private_vtable _event_vtable = { _virtual_dom_mouse_multi_wheel_event_destroy }; diff --git a/src/events/mouse_wheel_event.c b/src/events/mouse_wheel_event.c index d59eab1..5d6bdd6 100644 --- a/src/events/mouse_wheel_event.c +++ b/src/events/mouse_wheel_event.c @@ -15,7 +15,7 @@ static void _virtual_dom_mouse_wheel_event_destroy(struct dom_event *evt); -static struct dom_event_private_vtable _event_vtable = { +static const struct dom_event_private_vtable _event_vtable = { _virtual_dom_mouse_wheel_event_destroy }; diff --git a/src/events/mutation_event.c b/src/events/mutation_event.c index df92c5f..2c5ffdc 100644 --- a/src/events/mutation_event.c +++ b/src/events/mutation_event.c @@ -11,7 +11,7 @@ static void _virtual_dom_mutation_event_destroy(struct dom_event *evt); -static struct dom_event_private_vtable _event_vtable = { +static const struct dom_event_private_vtable _event_vtable = { _virtual_dom_mutation_event_destroy }; diff --git a/src/events/mutation_name_event.c b/src/events/mutation_name_event.c index e0ba82e..13a51b5 100644 --- a/src/events/mutation_name_event.c +++ b/src/events/mutation_name_event.c @@ -14,7 +14,7 @@ static void _virtual_dom_mutation_name_event_destroy(struct dom_event *evt); -static struct dom_event_private_vtable _event_vtable = { +static const struct dom_event_private_vtable _event_vtable = { _virtual_dom_mutation_name_event_destroy }; diff --git a/src/events/text_event.c b/src/events/text_event.c index 3437716..d0d2706 100644 --- a/src/events/text_event.c +++ b/src/events/text_event.c @@ -12,7 +12,7 @@ static void _virtual_dom_text_event_destroy(struct dom_event *evt); -static struct dom_event_private_vtable _event_vtable = { +static const struct dom_event_private_vtable _event_vtable = { _virtual_dom_text_event_destroy }; diff --git a/src/events/ui_event.c b/src/events/ui_event.c index 34ec84d..672f999 100644 --- a/src/events/ui_event.c +++ b/src/events/ui_event.c @@ -11,7 +11,7 @@ static void _virtual_dom_ui_event_destroy(struct dom_event *evt); -static struct dom_event_private_vtable _event_vtable = { +static const struct dom_event_private_vtable _event_vtable = { _virtual_dom_ui_event_destroy }; diff --git a/src/html/html_anchor_element.c b/src/html/html_anchor_element.c index 8d64c2b..88fd2ac 100644 --- a/src/html/html_anchor_element.c +++ b/src/html/html_anchor_element.c @@ -18,7 +18,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_ANCHOR_ELEMENT }, diff --git a/src/html/html_applet_element.c b/src/html/html_applet_element.c index 93ea1b5..f7f1afc 100644 --- a/src/html/html_applet_element.c +++ b/src/html/html_applet_element.c @@ -18,7 +18,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_APPLET_ELEMENT }, diff --git a/src/html/html_area_element.c b/src/html/html_area_element.c index 828b073..3da59d7 100644 --- a/src/html/html_area_element.c +++ b/src/html/html_area_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_AREA_ELEMENT }, diff --git a/src/html/html_base_element.c b/src/html/html_base_element.c index 0034f7c..f322f5b 100644 --- a/src/html/html_base_element.c +++ b/src/html/html_base_element.c @@ -13,7 +13,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_BASE_ELEMENT }, diff --git a/src/html/html_basefont_element.c b/src/html/html_basefont_element.c index ac1183d..b68ae03 100644 --- a/src/html/html_basefont_element.c +++ b/src/html/html_basefont_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_BASE_FONT_ELEMENT }, diff --git a/src/html/html_body_element.c b/src/html/html_body_element.c index 0fc4b13..4f52152 100644 --- a/src/html/html_body_element.c +++ b/src/html/html_body_element.c @@ -15,7 +15,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_BODY_ELEMENT }, diff --git a/src/html/html_br_element.c b/src/html/html_br_element.c index 74e3ea8..71778f6 100644 --- a/src/html/html_br_element.c +++ b/src/html/html_br_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_BR_ELEMENT }, diff --git a/src/html/html_button_element.c b/src/html/html_button_element.c index 04a17dd..52a3607 100644 --- a/src/html/html_button_element.c +++ b/src/html/html_button_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_BUTTON_ELEMENT }, diff --git a/src/html/html_canvas_element.c b/src/html/html_canvas_element.c index 2543e5b..71d4a53 100644 --- a/src/html/html_canvas_element.c +++ b/src/html/html_canvas_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_CANVAS_ELEMENT }, @@ -152,10 +152,22 @@ dom_exception dom_html_canvas_element_get_width(dom_html_canvas_element *canvas, dom_ulong *width) { - return dom_html_element_get_dom_ulong_property(&canvas->base, + dom_exception exc; + + exc = dom_html_element_get_dom_ulong_property(&canvas->base, "width", SLEN("width"), width); + + if (exc != DOM_NO_ERR) + return exc; + + if (*width == (dom_ulong)-1) { + /* width not set on the canvas, default is 300px */ + *width = 300; + } + + return DOM_NO_ERR; } dom_exception @@ -172,10 +184,22 @@ dom_exception dom_html_canvas_element_get_height(dom_html_canvas_element *canvas, dom_ulong *height) { - return dom_html_element_get_dom_ulong_property(&canvas->base, + dom_exception exc; + + exc = dom_html_element_get_dom_ulong_property(&canvas->base, "height", SLEN("height"), height); + + if (exc != DOM_NO_ERR) + return exc; + + if (*height == (dom_ulong)-1) { + /* height not set on the canvas, default is 150px */ + *height = 150; + } + + return DOM_NO_ERR; } dom_exception diff --git a/src/html/html_directory_element.c b/src/html/html_directory_element.c index 585af1c..19db7cd 100644 --- a/src/html/html_directory_element.c +++ b/src/html/html_directory_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_DIRECTORY_ELEMENT }, diff --git a/src/html/html_div_element.c b/src/html/html_div_element.c index b061246..c39af74 100644 --- a/src/html/html_div_element.c +++ b/src/html/html_div_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_DIV_ELEMENT }, diff --git a/src/html/html_dlist_element.c b/src/html/html_dlist_element.c index ab9d4c3..fb0ad56 100644 --- a/src/html/html_dlist_element.c +++ b/src/html/html_dlist_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_DL_ELEMENT }, diff --git a/src/html/html_document.c b/src/html/html_document.c index 5d06e80..cf3c25d 100644 --- a/src/html/html_document.c +++ b/src/html/html_document.c @@ -72,7 +72,7 @@ #include "utils/namespace.h" #include "utils/utils.h" -static struct dom_html_document_vtable html_document_vtable = { +static const struct dom_html_document_vtable html_document_vtable = { { { { @@ -85,7 +85,7 @@ static struct dom_html_document_vtable html_document_vtable = { DOM_HTML_DOCUMENT_VTABLE }; -static struct dom_node_protect_vtable html_document_protect_vtable = { +static const struct dom_node_protect_vtable html_document_protect_vtable = { DOM_HTML_DOCUMENT_PROTECT_VTABLE }; @@ -319,6 +319,8 @@ static inline dom_html_element_type _dom_html_document_get_element_type( RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_RP) else RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_RT) + else + RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_TT) break; case 3: RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_DIV) @@ -354,6 +356,8 @@ static inline dom_html_element_type _dom_html_document_get_element_type( RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_BDO) else RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_WBR) + else + RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_BIG) break; case 4: RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_META) @@ -395,6 +399,8 @@ static inline dom_html_element_type _dom_html_document_get_element_type( RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_BASE) else RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_TIME) + else + RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_NOBR) break; case 5: RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_INPUT) @@ -469,6 +475,10 @@ static inline dom_html_element_type _dom_html_document_get_element_type( RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_SOURCE) else RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_STRONG) + else + RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_SPACER) + else + RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_STRIKE) break; case 7: RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_CAPTION) @@ -486,6 +496,12 @@ static inline dom_html_element_type _dom_html_document_get_element_type( RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_SECTION) else RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_SUMMARY) + else + RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_ACRONYM) + else + RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_BGSOUND) + else + RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_MARQUEE) break; case 8: RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_TEXTAREA) @@ -509,6 +525,8 @@ static inline dom_html_element_type _dom_html_document_get_element_type( RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_PROGRESS) else RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_TEMPLATE) + else + RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_NOFRAMES) break; case 10: RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_BLOCKQUOTE) @@ -809,8 +827,10 @@ _dom_html_document_create_element_internal( case DOM_HTML_ELEMENT_TYPE_EM: case DOM_HTML_ELEMENT_TYPE_RP: case DOM_HTML_ELEMENT_TYPE_RT: + case DOM_HTML_ELEMENT_TYPE_TT: case DOM_HTML_ELEMENT_TYPE_BDI: case DOM_HTML_ELEMENT_TYPE_BDO: + case DOM_HTML_ELEMENT_TYPE_BIG: case DOM_HTML_ELEMENT_TYPE_DFN: case DOM_HTML_ELEMENT_TYPE_KBD: case DOM_HTML_ELEMENT_TYPE_NAV: @@ -823,6 +843,7 @@ _dom_html_document_create_element_internal( case DOM_HTML_ELEMENT_TYPE_CODE: case DOM_HTML_ELEMENT_TYPE_MAIN: case DOM_HTML_ELEMENT_TYPE_MARK: + case DOM_HTML_ELEMENT_TYPE_NOBR: case DOM_HTML_ELEMENT_TYPE_RUBY: case DOM_HTML_ELEMENT_TYPE_SAMP: case DOM_HTML_ELEMENT_TYPE_ASIDE: @@ -833,10 +854,16 @@ _dom_html_document_create_element_internal( case DOM_HTML_ELEMENT_TYPE_HEADER: case DOM_HTML_ELEMENT_TYPE_HGROUP: case DOM_HTML_ELEMENT_TYPE_STRONG: + case DOM_HTML_ELEMENT_TYPE_SPACER: + case DOM_HTML_ELEMENT_TYPE_STRIKE: + case DOM_HTML_ELEMENT_TYPE_ACRONYM: case DOM_HTML_ELEMENT_TYPE_ADDRESS: case DOM_HTML_ELEMENT_TYPE_ARTICLE: + case DOM_HTML_ELEMENT_TYPE_BGSOUND: + case DOM_HTML_ELEMENT_TYPE_MARQUEE: case DOM_HTML_ELEMENT_TYPE_SECTION: case DOM_HTML_ELEMENT_TYPE_SUMMARY: + case DOM_HTML_ELEMENT_TYPE_NOFRAMES: case DOM_HTML_ELEMENT_TYPE_NOSCRIPT: case DOM_HTML_ELEMENT_TYPE_FIGCAPTION: /* These have no specialisation: use HTMLElement */ diff --git a/src/html/html_element.c b/src/html/html_element.c index 5d3df37..c110455 100644 --- a/src/html/html_element.c +++ b/src/html/html_element.c @@ -18,7 +18,7 @@ #include "core/document.h" #include "utils/utils.h" -struct dom_html_element_vtable _dom_html_element_vtable = { +const struct dom_html_element_vtable _dom_html_element_vtable = { { { { @@ -31,7 +31,7 @@ struct dom_html_element_vtable _dom_html_element_vtable = { DOM_HTML_ELEMENT_VTABLE }; -static struct dom_element_protected_vtable _dom_html_element_protect_vtable = { +static const struct dom_element_protected_vtable _dom_html_element_protect_vtable = { { DOM_HTML_ELEMENT_PROTECT_VTABLE }, @@ -477,7 +477,7 @@ dom_exception dom_html_element_get_int32_t_property(dom_html_element *ele, char *s3 = _strndup(dom_string_data(s2), dom_string_byte_length(s2)); if (s3 != NULL) { - *value = strtoul(s3, NULL, 0); + *value = strtol(s3, NULL, 0); free(s3); } else { err = DOM_NO_MEM_ERR; @@ -518,7 +518,7 @@ dom_exception dom_html_element_set_int32_t_property(dom_html_element *ele, if (err != DOM_NO_ERR) goto fail; - if (snprintf(numbuffer, 32, "%u", value) == 32) + if (snprintf(numbuffer, 32, "%"PRIu32, value) == 32) numbuffer[31] = '\0'; err = dom_string_create((const uint8_t *) numbuffer, @@ -607,7 +607,7 @@ dom_exception dom_html_element_set_dom_ulong_property(dom_html_element *ele, if (err != DOM_NO_ERR) goto fail; - if (snprintf(numbuffer, 32, "%u", value) == 32) + if (snprintf(numbuffer, 32, "%"PRIu32, value) == 32) numbuffer[31] = '\0'; err = dom_string_create((const uint8_t *) numbuffer, diff --git a/src/html/html_element.h b/src/html/html_element.h index 0290569..87e1bbb 100644 --- a/src/html/html_element.h +++ b/src/html/html_element.h @@ -162,7 +162,7 @@ dom_exception _dom_html_element_copy_internal(dom_html_element *old, #define dom_html_element_copy_internal(o, n) _dom_html_element_copy_internal( \ (dom_html_element *) (o), (dom_html_element *) (n)) -extern struct dom_html_element_vtable _dom_html_element_vtable; +extern const struct dom_html_element_vtable _dom_html_element_vtable; #endif diff --git a/src/html/html_fieldset_element.c b/src/html/html_fieldset_element.c index fe44e74..2ab8dd0 100644 --- a/src/html/html_fieldset_element.c +++ b/src/html/html_fieldset_element.c @@ -17,7 +17,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_FIELDSET_ELEMENT }, diff --git a/src/html/html_font_element.c b/src/html/html_font_element.c index ecedfb0..38f8869 100644 --- a/src/html/html_font_element.c +++ b/src/html/html_font_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_FONT_ELEMENT }, diff --git a/src/html/html_form_element.c b/src/html/html_form_element.c index 1dd1992..5ba8365 100644 --- a/src/html/html_form_element.c +++ b/src/html/html_form_element.c @@ -22,7 +22,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_FORM_ELEMENT }, diff --git a/src/html/html_frame_element.c b/src/html/html_frame_element.c index fe6859c..321cff9 100644 --- a/src/html/html_frame_element.c +++ b/src/html/html_frame_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_FRAME_ELEMENT }, diff --git a/src/html/html_frameset_element.c b/src/html/html_frameset_element.c index be44d5d..84a52b0 100644 --- a/src/html/html_frameset_element.c +++ b/src/html/html_frameset_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_FRAME_SET_ELEMENT }, diff --git a/src/html/html_head_element.c b/src/html/html_head_element.c index ff02b1f..20f6aa8 100644 --- a/src/html/html_head_element.c +++ b/src/html/html_head_element.c @@ -13,7 +13,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_HEAD_ELEMENT }, diff --git a/src/html/html_heading_element.c b/src/html/html_heading_element.c index 8ab2c5a..21e36c6 100644 --- a/src/html/html_heading_element.c +++ b/src/html/html_heading_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_HEADING_ELEMENT }, diff --git a/src/html/html_hr_element.c b/src/html/html_hr_element.c index e6086f5..8ca9743 100644 --- a/src/html/html_hr_element.c +++ b/src/html/html_hr_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_HR_ELEMENT }, diff --git a/src/html/html_html_element.c b/src/html/html_html_element.c index 9cdcd5e..24f35e4 100644 --- a/src/html/html_html_element.c +++ b/src/html/html_html_element.c @@ -13,7 +13,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_HTML_ELEMENT }, diff --git a/src/html/html_iframe_element.c b/src/html/html_iframe_element.c index 4d7272b..96397d0 100644 --- a/src/html/html_iframe_element.c +++ b/src/html/html_iframe_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_IFRAME_ELEMENT }, diff --git a/src/html/html_image_element.c b/src/html/html_image_element.c index 3cdd15f..e5b9c7b 100644 --- a/src/html/html_image_element.c +++ b/src/html/html_image_element.c @@ -18,7 +18,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_IMAGE_ELEMENT }, diff --git a/src/html/html_input_element.c b/src/html/html_input_element.c index 079b55e..025ef5d 100644 --- a/src/html/html_input_element.c +++ b/src/html/html_input_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_INPUT_ELEMENT }, diff --git a/src/html/html_isindex_element.c b/src/html/html_isindex_element.c index 40cb99c..e793fae 100644 --- a/src/html/html_isindex_element.c +++ b/src/html/html_isindex_element.c @@ -16,7 +16,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_ISINDEX_ELEMENT }, diff --git a/src/html/html_label_element.c b/src/html/html_label_element.c index 777144a..c62adca 100644 --- a/src/html/html_label_element.c +++ b/src/html/html_label_element.c @@ -15,7 +15,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_LABEL_ELEMENT }, diff --git a/src/html/html_legend_element.c b/src/html/html_legend_element.c index efb712b..f4200c8 100644 --- a/src/html/html_legend_element.c +++ b/src/html/html_legend_element.c @@ -19,7 +19,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_LEGEND_ELEMENT }, diff --git a/src/html/html_li_element.c b/src/html/html_li_element.c index 84becf9..6856046 100644 --- a/src/html/html_li_element.c +++ b/src/html/html_li_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_LI_ELEMENT }, diff --git a/src/html/html_link_element.c b/src/html/html_link_element.c index 87fe980..4916883 100644 --- a/src/html/html_link_element.c +++ b/src/html/html_link_element.c @@ -15,7 +15,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_LINK_ELEMENT }, diff --git a/src/html/html_map_element.c b/src/html/html_map_element.c index 3b10222..865d9b6 100644 --- a/src/html/html_map_element.c +++ b/src/html/html_map_element.c @@ -19,7 +19,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_MAP_ELEMENT }, diff --git a/src/html/html_menu_element.c b/src/html/html_menu_element.c index 09eadb6..882f1f2 100644 --- a/src/html/html_menu_element.c +++ b/src/html/html_menu_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_MENU_ELEMENT }, diff --git a/src/html/html_meta_element.c b/src/html/html_meta_element.c index 4098daf..39fd9e1 100644 --- a/src/html/html_meta_element.c +++ b/src/html/html_meta_element.c @@ -13,7 +13,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_META_ELEMENT }, diff --git a/src/html/html_mod_element.c b/src/html/html_mod_element.c index 20cb042..4f3331c 100644 --- a/src/html/html_mod_element.c +++ b/src/html/html_mod_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_MOD_ELEMENT }, diff --git a/src/html/html_object_element.c b/src/html/html_object_element.c index b51e3a0..1359ede 100644 --- a/src/html/html_object_element.c +++ b/src/html/html_object_element.c @@ -20,7 +20,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_OBJECT_ELEMENT }, diff --git a/src/html/html_olist_element.c b/src/html/html_olist_element.c index c89d11f..415b656 100644 --- a/src/html/html_olist_element.c +++ b/src/html/html_olist_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_OLIST_ELEMENT }, diff --git a/src/html/html_opt_group_element.c b/src/html/html_opt_group_element.c index 6af0a29..a50e3de 100644 --- a/src/html/html_opt_group_element.c +++ b/src/html/html_opt_group_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_OPT_GROUP_ELEMENT }, diff --git a/src/html/html_paragraph_element.c b/src/html/html_paragraph_element.c index 2b2f420..3c8f384 100644 --- a/src/html/html_paragraph_element.c +++ b/src/html/html_paragraph_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_P_ELEMENT }, diff --git a/src/html/html_param_element.c b/src/html/html_param_element.c index c75e1ce..2c991ac 100644 --- a/src/html/html_param_element.c +++ b/src/html/html_param_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_PARAM_ELEMENT }, diff --git a/src/html/html_pre_element.c b/src/html/html_pre_element.c index 64c8c3d..7582fde 100644 --- a/src/html/html_pre_element.c +++ b/src/html/html_pre_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_PRE_ELEMENT }, diff --git a/src/html/html_quote_element.c b/src/html/html_quote_element.c index cf3e0c5..f1bc06f 100644 --- a/src/html/html_quote_element.c +++ b/src/html/html_quote_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_QUOTE_ELEMENT }, diff --git a/src/html/html_script_element.c b/src/html/html_script_element.c index e8dfb1d..9acbf29 100644 --- a/src/html/html_script_element.c +++ b/src/html/html_script_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_SCRIPT_ELEMENT }, diff --git a/src/html/html_select_element.c b/src/html/html_select_element.c index 0801d0a..8ba78f1 100644 --- a/src/html/html_select_element.c +++ b/src/html/html_select_element.c @@ -17,7 +17,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_SELECT_ELEMENT }, diff --git a/src/html/html_style_element.c b/src/html/html_style_element.c index ae845be..4e4974f 100644 --- a/src/html/html_style_element.c +++ b/src/html/html_style_element.c @@ -13,7 +13,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_STYLE_ELEMENT }, diff --git a/src/html/html_table_element.c b/src/html/html_table_element.c index f197d07..010a6cd 100644 --- a/src/html/html_table_element.c +++ b/src/html/html_table_element.c @@ -21,7 +21,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_TABLE_ELEMENT }, diff --git a/src/html/html_tablecaption_element.c b/src/html/html_tablecaption_element.c index cae229c..0e55e3a 100644 --- a/src/html/html_tablecaption_element.c +++ b/src/html/html_tablecaption_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_TABLE_CAPTION_ELEMENT }, diff --git a/src/html/html_tablecell_element.c b/src/html/html_tablecell_element.c index 7a1f968..2fc31c8 100644 --- a/src/html/html_tablecell_element.c +++ b/src/html/html_tablecell_element.c @@ -18,7 +18,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_TABLE_CELL_ELEMENT }, diff --git a/src/html/html_tablecol_element.c b/src/html/html_tablecol_element.c index 74169be..56bcd64 100644 --- a/src/html/html_tablecol_element.c +++ b/src/html/html_tablecol_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_TABLE_COL_ELEMENT }, diff --git a/src/html/html_tablerow_element.c b/src/html/html_tablerow_element.c index 569e70f..1a6069b 100644 --- a/src/html/html_tablerow_element.c +++ b/src/html/html_tablerow_element.c @@ -20,7 +20,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_TABLE_ROW_ELEMENT }, diff --git a/src/html/html_tablesection_element.c b/src/html/html_tablesection_element.c index f839758..dee5ae5 100644 --- a/src/html/html_tablesection_element.c +++ b/src/html/html_tablesection_element.c @@ -21,7 +21,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_TABLE_SECTION_ELEMENT }, diff --git a/src/html/html_text_area_element.c b/src/html/html_text_area_element.c index 5c63c3c..db351bc 100644 --- a/src/html/html_text_area_element.c +++ b/src/html/html_text_area_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_TEXT_AREA_ELEMENT }, diff --git a/src/html/html_title_element.c b/src/html/html_title_element.c index 440b9d5..f727dfa 100644 --- a/src/html/html_title_element.c +++ b/src/html/html_title_element.c @@ -17,7 +17,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_TITLE_ELEMENT }, diff --git a/src/html/html_ulist_element.c b/src/html/html_ulist_element.c index f2b87fb..48cb0c2 100644 --- a/src/html/html_ulist_element.c +++ b/src/html/html_ulist_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_U_LIST_ELEMENT }, diff --git a/src/utils/Makefile b/src/utils/Makefile index 4bb586f..f891b6e 100644 --- a/src/utils/Makefile +++ b/src/utils/Makefile @@ -1,4 +1,4 @@ # Sources -DIR_SOURCES := namespace.c hashtable.c character_valid.c validate.c +DIR_SOURCES := namespace.c hashtable.c character_valid.c validate.c walk.c include $(NSBUILD)/Makefile.subdir diff --git a/src/utils/walk.c b/src/utils/walk.c new file mode 100644 index 0000000..f103908 --- /dev/null +++ b/src/utils/walk.c @@ -0,0 +1,130 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2021 Michael Drake <tlsa@netsurf-browser.org> + */ + +/** \file + * This is an API for walking a loaded DOM. + */ + +#include <dom/dom.h> +#include <dom/walk.h> + +/** + * Wrapper for calling client callback. + * + * \param[in] mask Mask of stages to enable callback for. + * \param[in] stage Whether the \ref node is being entered or left. + * \param[in] node The node being walked. + * \param[in] cb The client callback function. + * \param[in] pw The client's private data. + * \param[out] cmd_out Walk instruction from client. + * \return false for early termination of walk, true otherwise. + */ +static inline dom_exception dom_walk__cb( + enum dom_walk_enable mask, + enum dom_walk_stage stage, + dom_node *node, + dom_walk_cb cb, + void *pw, + enum dom_walk_cmd *cmd_out) +{ + if ((1 << stage) & mask) { + dom_node_type type; + dom_exception exc; + + exc = dom_node_get_node_type(node, &type); + if (exc != DOM_NO_ERR) { + return exc; + } + + *cmd_out = cb(stage, type, node, pw); + } + + return DOM_NO_ERR; +} + +/* exported interface documented in include/dom/walk.h */ +dom_exception libdom_treewalk( + enum dom_walk_enable mask, + dom_walk_cb cb, + dom_node *root, + void *pw) +{ + dom_node *node; + dom_exception exc; + enum dom_walk_cmd cmd = DOM_WALK_CMD_CONTINUE; + + node = dom_node_ref(root); + + while (cmd != DOM_WALK_CMD_ABORT) { + dom_node *next = NULL; + + if (cmd != DOM_WALK_CMD_SKIP) { + exc = dom_node_get_first_child(node, &next); + if (exc != DOM_NO_ERR) { + dom_node_unref(node); + break; + } + } + + if (next != NULL) { + dom_node_unref(node); + node = next; + } else { + /* No children; siblings & ancestor's siblings */ + while (node != root) { + exc = dom_walk__cb(mask, DOM_WALK_STAGE_LEAVE, + node, cb, pw, &cmd); + if (exc != DOM_NO_ERR || + cmd == DOM_WALK_CMD_ABORT) { + dom_node_unref(node); + return exc; + } + + exc = dom_node_get_next_sibling(node, &next); + if (exc != DOM_NO_ERR) { + dom_node_unref(node); + node = NULL; + break; + } + + if (next != NULL) { + /* Found next sibling. */ + break; + } + + exc = dom_node_get_parent_node(node, &next); + if (exc != DOM_NO_ERR) { + dom_node_unref(node); + return exc; + } + + dom_node_unref(node); + node = next; + } + + if (node == root) { + break; + } + + dom_node_unref(node); + node = next; + } + + assert(node != NULL); + assert(node != root); + + exc = dom_walk__cb(mask, DOM_WALK_STAGE_ENTER, node, + cb, pw, &cmd); + if (exc != DOM_NO_ERR) { + return exc; + } + } + + dom_node_unref(node); + + return DOM_NO_ERR; +} diff --git a/test/testutils/utils.c b/test/testutils/utils.c index c876613..379b0ad 100644 --- a/test/testutils/utils.c +++ b/test/testutils/utils.c @@ -27,7 +27,7 @@ void mymsg(uint32_t severity, void *ctx, const char *msg, ...) va_start(l, msg); - fprintf(stderr, "%d: ", severity); + fprintf(stderr, "%"PRIu32": ", severity); vfprintf(stderr, msg, l); fprintf(stderr, "\n"); } |