diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2019-01-03 16:54:16 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2019-01-03 16:54:16 (GMT) |
commit | c0573da8973e0ae8650d787d639a9acf9ab4a1ac (patch) | |
tree | ae0daad36caaacde226aa18a75415b247b89148b /tclxml.c | |
download | blt-c0573da8973e0ae8650d787d639a9acf9ab4a1ac.zip blt-c0573da8973e0ae8650d787d639a9acf9ab4a1ac.tar.gz blt-c0573da8973e0ae8650d787d639a9acf9ab4a1ac.tar.bz2 |
Squashed 'tclxml/' content from commit 22ffbb5a
git-subtree-dir: tclxml
git-subtree-split: 22ffbb5a3e984efb993e8b58cdf7a11ffddd1836
Diffstat (limited to 'tclxml.c')
-rwxr-xr-x | tclxml.c | 3708 |
1 files changed, 3708 insertions, 0 deletions
diff --git a/tclxml.c b/tclxml.c new file mode 100755 index 0000000..adc2e0f --- /dev/null +++ b/tclxml.c @@ -0,0 +1,3708 @@ +/* + * tclxml.c -- + * + * Entry point for XML parsers, DOM and XSLT. + * + * Copyright (c) 2005-2007 Steve Ball, explain + * http://www.explain.com.au/ + * Copyright (c) 1998-2004 Steve Ball, Zveno Pty Ltd + * + * See the file "LICENSE" for information on usage and + * redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * $Id: tclxml.c,v 1.2 2009/03/03 22:55:36 joye Exp $ + * + */ + +#include <tclxml/tclxml.h> +#include <tclxml-libxml2/tclxml-libxml2.h> +#include <tcldom-libxml2/tcldom-libxml2.h> +#include <tclxslt/tclxslt.h> +#include <string.h> + +#define TCL_DOES_STUBS \ + (TCL_MAJOR_VERSION > 8 || TCL_MAJOR_VERSION == 8 && (TCL_MINOR_VERSION > 1 || \ + (TCL_MINOR_VERSION == 1 && TCL_RELEASE_LEVEL == TCL_FINAL_RELEASE))) +#ifdef USE_TCLXML_STUBS +#ifndef TCLXML_DOES_STUBS +# define TCLXML_DOES_STUBS TCL_DOES_STUBS +#endif /* USE_TCLXML_STUBS */ +#endif /* TCL_DOES_STUBS */ + +/* + * The structure below is used to manage package options. + */ + +typedef struct ThreadSpecificData { + int initialized; + + TclXML_ParserClassInfo *defaultParser; /* Current default parser */ + Tcl_HashTable *registeredParsers; /* All known parser classes */ + + /* + * Retain a pointer to the whitespace variable + */ + + Tcl_Obj *whitespaceRE; + + /* + * Counter to generate unique command names + */ + + int uniqueCounter; + + /* + * Callback for external entity resolution + */ + + Tcl_Obj *externalentitycmd; + Tcl_Interp *interp; +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; + +/* This string is a backup. Value should be defined in xml package. */ +static char whitespace[] = " \t\r\n"; + +/* + * Configuration option tables + */ + +static CONST84 char *globalConfigureSwitches[] = { + "-externalentitycommand", + (char *) NULL +}; +enum globalConfigureSwitches { + TCLXML_GLOBAL_EXTERNALENTITYCOMMAND +}; + +static CONST84 char *instanceConfigureSwitches[] = { + "-final", + "-validate", + "-baseurl", + "-baseuri", + "-encoding", + "-elementstartcommand", + "-elementendcommand", + "-characterdatacommand", + "-processinginstructioncommand", + "-defaultcommand", + "-unparsedentitydeclcommand", + "-notationdeclcommand", + "-externalentitycommand", + "-unknownencodingcommand", + "-commentcommand", + "-notstandalonecommand", + "-startcdatasectioncommand", + "-endcdatasectioncommand", + "-defaultexpandinternalentities", + "-elementdeclcommand", + "-attlistdeclcommand", + "-startdoctypedeclcommand", + "-enddoctypedeclcommand", + "-paramentityparsing", + "-ignorewhitespace", + "-reportempty", + "-entitydeclcommand", /* added to avoid exception */ + "-parameterentitydeclcommand", /* added to avoid exception */ + "-doctypecommand", /* added to avoid exception */ + "-entityreferencecommand", /* added to avoid exception */ + "-xmldeclcommand", /* added to avoid exception */ + (char *) NULL + }; +enum instanceConfigureSwitches { + TCLXML_FINAL, TCLXML_VALIDATE, TCLXML_BASEURL, TCLXML_BASEURI, + TCLXML_ENCODING, + TCLXML_ELEMENTSTARTCMD, TCLXML_ELEMENTENDCMD, + TCLXML_DATACMD, TCLXML_PICMD, + TCLXML_DEFAULTCMD, + TCLXML_UNPARSEDENTITYCMD, TCLXML_NOTATIONCMD, + TCLXML_EXTERNALENTITYCMD, TCLXML_UNKNOWNENCODINGCMD, + TCLXML_COMMENTCMD, TCLXML_NOTSTANDALONECMD, + TCLXML_STARTCDATASECTIONCMD, TCLXML_ENDCDATASECTIONCMD, + TCLXML_DEFAULTEXPANDINTERNALENTITIES, + TCLXML_ELEMENTDECLCMD, TCLXML_ATTLISTDECLCMD, + TCLXML_STARTDOCTYPEDECLCMD, TCLXML_ENDDOCTYPEDECLCMD, + TCLXML_PARAMENTITYPARSING, + TCLXML_NOWHITESPACE, + TCLXML_REPORTEMPTY, + TCLXML_ENTITYDECLCMD, + TCLXML_PARAMENTITYDECLCMD, + TCLXML_DOCTYPECMD, + TCLXML_ENTITYREFCMD, + TCLXML_XMLDECLCMD +}; + +/* + * Prototypes for procedures defined later in this file: + */ + +static void TclXMLInstanceDeleteCmd _ANSI_ARGS_((ClientData clientData)); +static int TclXMLDestroyParserInstance _ANSI_ARGS_((TclXML_Info *xmlinfo)); +static int TclXMLInstanceCmd _ANSI_ARGS_((ClientData dummy, + Tcl_Interp *interp, int objc, struct Tcl_Obj *CONST objv[])); +static int TclXMLCreateParserCmd _ANSI_ARGS_((ClientData dummy, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); +static int TclXMLParserClassCmd _ANSI_ARGS_((ClientData dummy, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); +static int TclXMLResetParser _ANSI_ARGS_((Tcl_Interp *interp, TclXML_Info *xmlinfo)); +static int TclXMLConfigureCmd _ANSI_ARGS_((ClientData dummy, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); +static Tcl_Obj* FindUniqueCmdName _ANSI_ARGS_((Tcl_Interp *interp)); +static int TclXMLInstanceConfigure _ANSI_ARGS_((Tcl_Interp *interp, + TclXML_Info *xmlinfo, int objc, Tcl_Obj *CONST objv[])); +static int TclXMLCget _ANSI_ARGS_((Tcl_Interp *interp, + TclXML_Info *xmlinfo, int objc, Tcl_Obj *CONST objv[])); +static int TclXMLConfigureParserInstance _ANSI_ARGS_(( + TclXML_Info *xmlinfo, Tcl_Obj *option, Tcl_Obj *value)); +static int TclXMLGet _ANSI_ARGS_((Tcl_Interp *interp, + TclXML_Info *xmlinfo, int objc, Tcl_Obj *CONST objv[])); +static int TclXMLParse _ANSI_ARGS_((Tcl_Interp *interp, + TclXML_Info *xmlinfo, char *data, int len)); +static void TclXMLDispatchPCDATA _ANSI_ARGS_((TclXML_Info *xmlinfo)); + +#if (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0) + +/* + *---------------------------------------------------------------------------- + * + * Tcl_GetString -- + * + * Compatibility routine for Tcl 8.0 + * + * Results: + * String representation of object.. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static char * +Tcl_GetString (obj) + Tcl_Obj *obj; /* Object to retrieve string from. */ +{ + char *s; + int i; + + s = Tcl_GetStringFromObj(obj, &i); + return s; +} +#endif /* TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0 */ + +/* + *---------------------------------------------------------------------------- + * + * Tclxml_Init -- + * + * Initialisation routine for loadable module. + * Also calls the initialisation routines for TclDOM and TclXSLT, + * as these were originally separate modules. + * + * Results: + * None. + * + * Side effects: + * Creates commands in the interpreter, + * loads xml, dom and xslt packages. + * + *---------------------------------------------------------------------------- + */ + +int +Tclxml_Init (interp) + Tcl_Interp *interp; /* Interpreter to initialise. */ +{ + ThreadSpecificData *tsdPtr; + +#ifdef USE_TCL_STUBS + if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { + return TCL_ERROR; + } +#endif + + tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + tsdPtr->initialized = 1; + tsdPtr->defaultParser = NULL; + tsdPtr->uniqueCounter = 0; + + /* + tsdPtr->whitespaceRE = Tcl_GetVar2Ex(interp, "::xml::Wsp", NULL, TCL_GLOBAL_ONLY); + if (tsdPtr->whitespaceRE == NULL) { + tsdPtr->whitespaceRE = Tcl_SetVar2Ex(interp, "::xml::Wsp", NULL, Tcl_NewStringObj(whitespace, -1), TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG); + if (tsdPtr->whitespaceRE == NULL) { + return TCL_ERROR; + } + } + Tcl_IncrRefCount(tsdPtr->whitespaceRE); + */ + + tsdPtr->registeredParsers = (Tcl_HashTable *) Tcl_Alloc(sizeof(Tcl_HashTable)); + Tcl_InitHashTable(tsdPtr->registeredParsers, TCL_STRING_KEYS); + + tsdPtr->externalentitycmd = NULL; + tsdPtr->interp = interp; + + Tcl_CreateObjCommand(interp, "xml::configure", TclXMLConfigureCmd, NULL, NULL); + Tcl_CreateObjCommand(interp, "xml::parser", TclXMLCreateParserCmd, NULL, NULL); + Tcl_CreateObjCommand(interp, "xml::parserclass", TclXMLParserClassCmd, NULL, NULL); + + if (Tclxml_libxml2_Init(interp) != TCL_OK) { + return TCL_ERROR; + } + + /* + if (Tcldom_libxml2_Init(interp) != TCL_OK) { + return TCL_ERROR; + } + + if (Tclxslt_libxslt_Init(interp) != TCL_OK) { + return TCL_ERROR; + } + */ + + #if TCLXML_DOES_STUBS + { + extern TclxmlStubs tclxmlStubs; + if (Tcl_PkgProvideEx(interp, "xml::c", TCLXML_VERSION, + (ClientData) &tclxmlStubs) != TCL_OK) { + return TCL_ERROR; + } + } + #else + if (Tcl_PkgProvide(interp, "xml::c", TCLXML_VERSION) != TCL_OK) { + return TCL_ERROR; + } + #endif + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------------- + * + * Tclxml_SafeInit -- + * + * Initialisation routine for loadable module in a safe interpreter. + * + * Results: + * None. + * + * Side effects: + * Creates commands in the interpreter, + * loads xml package. + * + *---------------------------------------------------------------------------- + */ + +int +Tclxml_SafeInit (interp) + Tcl_Interp *interp; /* Interpreter to initialise. */ +{ + return Tclxml_Init(interp); +} + +/* + *---------------------------------------------------------------------------- + * + * TclXMLConfigureCmd -- + * + * Command for xml::configure command. + * + * Results: + * Depends on method. + * + * Side effects: + * Depends on method. + * + *---------------------------------------------------------------------------- + */ + +static int +TclXMLConfigureCmd(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + int index; + + if (objc < 3) { + Tcl_SetResult(interp, "must specify option", NULL); + return TCL_ERROR; + } else if (objc == 3) { + /* TODO: retrieve option's value */ + return TCL_OK; + } else if (objc % 2 == 1) { + Tcl_SetResult(interp, "value for option missing", NULL); + return TCL_ERROR; + } + + for (objc -= 2, objv += 2; objc; objc -= 2, objv += 2) { + if (Tcl_GetIndexFromObj(interp, objv[0], globalConfigureSwitches, + "switch", 0, &index) != TCL_OK) { + return TCL_ERROR; + } + switch ((enum globalConfigureSwitches) index) { + case TCLXML_GLOBAL_EXTERNALENTITYCOMMAND: + tsdPtr->externalentitycmd = objv[1]; + Tcl_IncrRefCount(tsdPtr->externalentitycmd); + break; + + default: + return TCL_ERROR; + } + } + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXMLParserClassCmd -- + * + * Command for xml::parserclass command. + * + * Results: + * Depends on method. + * + * Side effects: + * Depends on method. + * + *---------------------------------------------------------------------------- + */ + +static int +TclXMLParserClassCmd(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + TclXML_ParserClassInfo *classinfo; + int method, index; + Tcl_Obj *listPtr; + Tcl_HashEntry *entryPtr; + Tcl_HashSearch search; + + static CONST84 char *methods[] = { + "create", "destroy", "info", + NULL + }; + enum methods { + TCLXML_CREATE, TCLXML_DESTROY, TCLXML_INFO + }; + static CONST84 char *createOptions[] = { + "-createcommand", "-createentityparsercommand", + "-parsecommand", "-configurecommand", + "-deletecommand", "-resetcommand", + NULL + }; + enum createOptions { + TCLXML_CREATEPROC, TCLXML_CREATE_ENTITY_PARSER, + TCLXML_PARSEPROC, TCLXML_CONFIGUREPROC, + TCLXML_DELETEPROC, TCLXML_RESETPROC + }; + static CONST84 char *infoMethods[] = { + "names", "default", + NULL + }; + enum infoMethods { + TCLXML_INFO_NAMES, TCLXML_INFO_DEFAULT + }; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "method ?args?"); + return TCL_ERROR; + } + + if (Tcl_GetIndexFromObj(interp, objv[1], methods, + "method", 0, &method) != TCL_OK) { + return TCL_ERROR; + } + + switch ((enum methods) method) { + case TCLXML_CREATE: + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "create name ?args?"); + return TCL_ERROR; + } + + classinfo = (TclXML_ParserClassInfo *) Tcl_Alloc(sizeof(TclXML_ParserClassInfo)); + classinfo->name = objv[2]; + Tcl_IncrRefCount(classinfo->name); + classinfo->create = NULL; + classinfo->createCmd = NULL; + classinfo->createEntity = NULL; + classinfo->createEntityCmd = NULL; + classinfo->parse = NULL; + classinfo->parseCmd = NULL; + classinfo->configure = NULL; + classinfo->configureCmd = NULL; + classinfo->reset = NULL; + classinfo->resetCmd = NULL; + classinfo->destroy = NULL; + classinfo->destroyCmd = NULL; + + objv += 3; + objc -= 3; + while (objc > 1) { + if (Tcl_GetIndexFromObj(interp, objv[0], createOptions, + "options", 0, &index) != TCL_OK) { + return TCL_ERROR; + } + Tcl_IncrRefCount(objv[1]); + switch ((enum createOptions) index) { + + case TCLXML_CREATEPROC: + + classinfo->createCmd = objv[1]; + break; + + case TCLXML_CREATE_ENTITY_PARSER: + + classinfo->createEntityCmd = objv[1]; + break; + + case TCLXML_PARSEPROC: + + classinfo->parseCmd = objv[1]; + break; + + case TCLXML_CONFIGUREPROC: + + classinfo->configureCmd = objv[1]; + break; + + case TCLXML_RESETPROC: + + classinfo->resetCmd = objv[1]; + break; + + case TCLXML_DELETEPROC: + + classinfo->destroyCmd = objv[1]; + break; + + default: + Tcl_AppendResult(interp, "unknown option \"", Tcl_GetStringFromObj(objv[0], NULL), "\"", NULL); + Tcl_DecrRefCount(objv[1]); + Tcl_DecrRefCount(classinfo->name); + Tcl_Free((char *)classinfo); + return TCL_ERROR; + } + + objc -= 2; + objv += 2; + + } + + if (TclXML_RegisterXMLParser(interp, classinfo) != TCL_OK) { + Tcl_Free((char *)classinfo); + return TCL_ERROR; + } + break; + + case TCLXML_DESTROY: + /* Not yet implemented */ + break; + + case TCLXML_INFO: + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "method"); + return TCL_ERROR; + } + + if (Tcl_GetIndexFromObj(interp, objv[2], infoMethods, + "method", 0, &index) != TCL_OK) { + return TCL_ERROR; + } + switch ((enum infoMethods) index) { + case TCLXML_INFO_NAMES: + + listPtr = Tcl_NewListObj(0, NULL); + entryPtr = Tcl_FirstHashEntry(tsdPtr->registeredParsers, &search); + while (entryPtr != NULL) { + Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj(Tcl_GetHashKey(tsdPtr->registeredParsers, entryPtr), -1)); + entryPtr = Tcl_NextHashEntry(&search); + } + + Tcl_SetObjResult(interp, listPtr); + + break; + + case TCLXML_INFO_DEFAULT: + + if (!tsdPtr->defaultParser) { + Tcl_SetResult(interp, "", NULL); + } else { + Tcl_SetObjResult(interp, tsdPtr->defaultParser->name); + } + + break; + + default: + Tcl_SetResult(interp, "unknown method", NULL); + return TCL_ERROR; + } + break; + + default: + Tcl_SetResult(interp, "unknown method", NULL); + return TCL_ERROR; + } + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXML_RegisterXMLParser -- + * + * Adds a new XML parser. + * + * Results: + * Standard Tcl return code. + * + * Side effects: + * New parser is available for use in parser instances. + * + *---------------------------------------------------------------------------- + */ + +int +TclXML_RegisterXMLParser(interp, classinfo) + Tcl_Interp *interp; + TclXML_ParserClassInfo *classinfo; +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + int new; + Tcl_HashEntry *entryPtr; + + entryPtr = Tcl_CreateHashEntry(tsdPtr->registeredParsers, Tcl_GetStringFromObj(classinfo->name, NULL), &new); + if (!new) { + Tcl_Obj *ptr = Tcl_NewStringObj("parser class \"", -1); + Tcl_AppendObjToObj(ptr, classinfo->name); + Tcl_AppendObjToObj(ptr, Tcl_NewStringObj("\" already registered", -1)); + + Tcl_ResetResult(interp); + Tcl_SetObjResult(interp, ptr); + return TCL_ERROR; + } + + Tcl_SetHashValue(entryPtr, (ClientData) classinfo); + + /* + * Set default parser - last wins + */ + + tsdPtr->defaultParser = classinfo; + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXMLCreateParserCmd -- + * + * Creation command for xml::parser command. + * + * Results: + * The name of the newly created parser instance. + * + * Side effects: + * This creates a parser instance. + * + *---------------------------------------------------------------------------- + */ + +static int +TclXMLCreateParserCmd(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + TclXML_Info *xmlinfo; + int found, i, index, poption; + + static CONST84 char *switches[] = { + "-parser", + (char *) NULL + }; + enum switches { + TCLXML_PARSER + }; + + if (tsdPtr == NULL) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("TclXML package improperly initialised", -1)); + return TCL_ERROR; + } + if (!tsdPtr->defaultParser) { + Tcl_SetResult(interp, "no parsers available", NULL); + return TCL_ERROR; + } + + /* + * Create the data structures for this parser. + */ + + if (!(xmlinfo = (TclXML_Info *) Tcl_Alloc(sizeof(TclXML_Info)))) { + Tcl_SetResult(interp, "unable to create parser", NULL); + return TCL_ERROR; + } + xmlinfo->interp = interp; + xmlinfo->clientData = NULL; + xmlinfo->base = NULL; + xmlinfo->encoding = Tcl_NewStringObj("utf-8", -1); + + /* + * Find unique command name + */ + if (objc < 2) { + xmlinfo->name = FindUniqueCmdName(interp); + } else { + xmlinfo->name = objv[1]; + if (*(Tcl_GetStringFromObj(xmlinfo->name, NULL)) != '-') { + Tcl_IncrRefCount(xmlinfo->name); + objv++; + objc--; + } else { + xmlinfo->name = FindUniqueCmdName(interp); + } + } + + xmlinfo->validate = 0; + xmlinfo->elementstartcommand = NULL; + xmlinfo->elementstart = NULL; + xmlinfo->elementstartdata = 0; + xmlinfo->elementendcommand = NULL; + xmlinfo->elementend = NULL; + xmlinfo->elementenddata = 0; + xmlinfo->datacommand = NULL; + xmlinfo->cdatacb = NULL; + xmlinfo->cdatacbdata = 0; + xmlinfo->picommand = NULL; + xmlinfo->pi = NULL; + xmlinfo->pidata = 0; + xmlinfo->defaultcommand = NULL; + xmlinfo->defaultcb = NULL; + xmlinfo->defaultdata = 0; + xmlinfo->unparsedcommand = NULL; + xmlinfo->unparsed = NULL; + xmlinfo->unparseddata = 0; + xmlinfo->notationcommand = NULL; + xmlinfo->notation = NULL; + xmlinfo->notationdata = 0; + xmlinfo->entitycommand = NULL; + xmlinfo->entity = NULL; + xmlinfo->entitydata = 0; + xmlinfo->unknownencodingcommand = NULL; + xmlinfo->unknownencoding = NULL; + xmlinfo->unknownencodingdata = 0; + /* ericm@scriptics.com */ + xmlinfo->commentCommand = NULL; + xmlinfo->comment = NULL; + xmlinfo->commentdata = 0; + xmlinfo->notStandaloneCommand = NULL; + xmlinfo->notStandalone = NULL; + xmlinfo->notstandalonedata = 0; + xmlinfo->elementDeclCommand = NULL; + xmlinfo->elementDecl = NULL; + xmlinfo->elementdecldata = 0; + xmlinfo->attlistDeclCommand = NULL; + xmlinfo->attlistDecl = NULL; + xmlinfo->attlistdecldata = 0; + xmlinfo->startDoctypeDeclCommand = NULL; + xmlinfo->startDoctypeDecl = NULL; + xmlinfo->startdoctypedecldata = 0; + xmlinfo->endDoctypeDeclCommand = NULL; + xmlinfo->endDoctypeDecl = NULL; + xmlinfo->enddoctypedecldata = 0; +#ifdef TCLXML_CDATASECTIONS + xmlinfo->startCDATASectionCommand = NULL; + xmlinfo->startCDATASection = NULL; + xmlinfo->startcdatasectiondata = 0; + xmlinfo->endCdataSectionCommand = NULL; + xmlinfo->endCdataSection = NULL; + xmlinfo->endcdatasectiondata = 0; +#endif + + /* + * Options may include an explicit desired parser class + * + * SF TclXML Bug 513909 ... + * Start search at first argument! If there was a parser name + * specified we already skipped over it. + * + * Changing the search. Do not stop at the first occurence of + * "-parser". There can be more than one instance of the option in + * the argument list and it is the last instance that counts. + */ + + found = 0; + i = 1; + poption = -1; + + while (i < objc) { + Tcl_ResetResult (interp); + if (Tcl_GetIndexFromObj(interp, objv[i], switches, "option", 0, &index) == TCL_OK) { + poption = i; + found = 1; + } + i += 2; + } + Tcl_ResetResult (interp); + + if (found) { + Tcl_HashEntry *pentry; + + if (poption == (objc - 1)) { + Tcl_SetResult(interp, "no value for option", NULL); + goto error; + } + + /* + * Use given parser class + */ + + pentry = Tcl_FindHashEntry(tsdPtr->registeredParsers, + Tcl_GetStringFromObj(objv[poption + 1], + NULL)); + if (pentry != NULL) { + xmlinfo->parserClass = Tcl_GetHashValue(pentry); + } else { + Tcl_AppendResult(interp, "no such parser class \"", + Tcl_GetStringFromObj(objv[poption + 1], NULL), + "\"", NULL); + goto error; + } + + } else { + /* + * Use default parser + */ + xmlinfo->parserClass = tsdPtr->defaultParser; + } + + if (TclXMLResetParser(interp, xmlinfo) != TCL_OK) { + /* this may leak memory... + Tcl_Free((char *)xmlinfo); + */ + return TCL_ERROR; + } + + /* + * Register a Tcl command for this parser instance. + */ + + Tcl_CreateObjCommand(interp, Tcl_GetStringFromObj(xmlinfo->name, NULL), + TclXMLInstanceCmd, (ClientData) xmlinfo, TclXMLInstanceDeleteCmd); + + /* + * Handle configuration options + * + * SF TclXML Bug 513909 ... + * Note: If the caller used "-parser" to specify a parser class we + * have to take care that it and its argument are *not* seen by + * "TclXMLInstanceConfigure" because this option is not allowed + * during general configuration. + */ + + if (objc > 1) { + if (found) { + /* + * The options contained at least one instance of "-parser + * class". We now go through the whole list of arguments and + * build a new list which contains only the non-"-parser" + * switches. The 'ResetResult' takes care of clearing the + * interpreter result before "Tcl_GetIndexFromObj" tries to + * use it again. + */ + + int res; + int cfgc = 0; + Tcl_Obj** cfgv = (Tcl_Obj**) Tcl_Alloc (objc * sizeof (Tcl_Obj*)); + + i = 1; + while (i < objc) { + Tcl_ResetResult (interp); + if (Tcl_GetIndexFromObj(interp, objv[i], switches, "option", 0, &index) == TCL_OK) { + /* Ignore "-parser" during copying */ + i += 2; + continue; + } + + cfgv [cfgc] = objv [i]; i++ ; cfgc++ ; /* copy option ... */ + cfgv [cfgc] = objv [i]; i++ ; cfgc++ ; /* ... and value */ + } + Tcl_ResetResult (interp); + + res = TclXMLInstanceConfigure(interp, xmlinfo, cfgc, cfgv); + Tcl_Free ((char*) cfgv); + if (res == TCL_ERROR) { + return TCL_ERROR; + } + } else { + /* + * The options contained no "-parser class" specification. We + * can propagate it unchanged. + */ + + if (TclXMLInstanceConfigure(interp, xmlinfo, objc - 1, objv + 1) == TCL_ERROR) { + return TCL_ERROR; + } + } + } + + Tcl_SetObjResult(interp, xmlinfo->name); + return TCL_OK; + + error: +/* this may leak memory + Tcl_Free((char*)xmlinfo); +*/ + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------------- + * + * FindUniqueCmdName -- + * + * Generate new command name in caller's namespace. + * + * Results: + * Returns newly allocated Tcl object containing name. + * + * Side effects: + * Allocates Tcl object. + * + *---------------------------------------------------------------------------- + */ + +static Tcl_Obj * +FindUniqueCmdName(interp) + Tcl_Interp *interp; +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + Tcl_Obj *name; + Tcl_CmdInfo cmdinfo; + char s[20]; + + name = Tcl_NewObj(); + Tcl_IncrRefCount(name); + + do { + sprintf(s, "xmlparser%d", tsdPtr->uniqueCounter++); + Tcl_SetStringObj(name, s, -1); + } while (Tcl_GetCommandInfo(interp, Tcl_GetStringFromObj(name, NULL), &cmdinfo)); + + return name; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXMLResetParser -- + * + * (Re-)Initialise the parser instance structure. + * + * Results: + * Parser made ready for parsing. + * + * Side effects: + * Destroys and creates a parser instance. + * Modifies TclXML_Info fields. + * + *---------------------------------------------------------------------------- + */ + +static int +TclXMLResetParser(interp, xmlinfo) + Tcl_Interp *interp; + TclXML_Info *xmlinfo; +{ + TclXML_ParserClassInfo *classInfo = (TclXML_ParserClassInfo *) xmlinfo->parserClass; + + if (xmlinfo->base) { + Tcl_DecrRefCount(xmlinfo->base); + xmlinfo->base = NULL; + } + + xmlinfo->final = 1; + xmlinfo->status = TCL_OK; + xmlinfo->result = NULL; + xmlinfo->continueCount = 0; + xmlinfo->context = NULL; + + xmlinfo->cdata = NULL; + xmlinfo->nowhitespace = 0; + + xmlinfo->reportempty = 0; + xmlinfo->expandinternalentities = 1; + xmlinfo->paramentities = 1; + + if (classInfo->reset) { + if ((*classInfo->reset)((ClientData) xmlinfo) != TCL_OK) { + return TCL_ERROR; + } + } else if (classInfo->resetCmd) { + Tcl_Obj *cmdPtr = Tcl_DuplicateObj(classInfo->resetCmd); + int result; + + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) interp); + Tcl_ListObjAppendElement(interp, cmdPtr, xmlinfo->name); + + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) interp); + + if (result != TCL_OK) { + Tcl_Free((char*)xmlinfo); + return TCL_ERROR; + } + } else if (classInfo->create) { + + /* + * Otherwise destroy and then create a fresh parser instance + */ + + /* + * Destroy the old parser instance, if it exists + * Could probably just reset it, but this approach + * is pretty much guaranteed to work. + */ + + if (TclXMLDestroyParserInstance(xmlinfo) != TCL_OK) { + return TCL_ERROR; + } + + /* + * Directly invoke the create routine + */ + if ((xmlinfo->clientData = (*classInfo->create)(interp, xmlinfo)) == NULL) { + Tcl_Free((char*)xmlinfo); + return TCL_ERROR; + } + } else if (classInfo->createCmd) { + Tcl_Obj *cmdPtr = Tcl_DuplicateObj(classInfo->createCmd); + int result, i; + + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) interp); + Tcl_ListObjAppendElement(interp, cmdPtr, xmlinfo->name); + + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) interp); + + if (result != TCL_OK) { + Tcl_Free((char*)xmlinfo); + return TCL_ERROR; + } else { + + /* + * Return result is parser instance argument + */ + + xmlinfo->clientData = (ClientData) Tcl_GetObjResult(interp); + Tcl_IncrRefCount((Tcl_Obj *) xmlinfo->clientData); + + /* + * Add all of the currently configured callbacks to the + * creation command line. Destroying the parser instance + * just clobbered all of these settings. + */ + + cmdPtr = Tcl_DuplicateObj(classInfo->configureCmd); + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) interp); + Tcl_ListObjAppendElement(interp, cmdPtr, xmlinfo->name); + + for (i = 0; instanceConfigureSwitches[i]; i++) { + Tcl_Obj *objPtr = Tcl_NewStringObj(instanceConfigureSwitches[i], -1); + Tcl_ListObjAppendElement(interp, cmdPtr, objPtr); + TclXMLCget(interp, xmlinfo, 1, &objPtr); + Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_GetObjResult(interp)); + } + + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) interp); + + if (result != TCL_OK) { + Tcl_Free((char *)xmlinfo); + return TCL_ERROR; + } + + } + + } else { + Tcl_SetResult(interp, "bad parser class data", NULL); + Tcl_Free((char*)xmlinfo); + return TCL_ERROR; + } + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TclXMLCreateEntityParser -- + * + * Create an entity parser, based on the original + * parser referred to by parent. + * + * Results: + * New entity parser created and initialized. + * + * Side effects: + * The TclXML_Info struct pointed to by external is modified. + * + *---------------------------------------------------------------------- + */ + +static int +TclXMLCreateEntityParser(interp, external, parent) + Tcl_Interp *interp; + TclXML_Info *external; + TclXML_Info *parent; +{ + TclXML_ParserClassInfo *extClassInfo; + + external->parserClass = parent->parserClass; + extClassInfo = (TclXML_ParserClassInfo *) external->parserClass; + + if (!extClassInfo->createEntity || !extClassInfo->createEntityCmd) { + Tcl_SetResult(interp, "cannot create entity parser", NULL); + return TCL_ERROR; + } + + if (parent->elementstartcommand) { + Tcl_IncrRefCount(parent->elementstartcommand); + } + if (parent->elementendcommand) { + Tcl_IncrRefCount(parent->elementendcommand); + } + if (parent->datacommand) { + Tcl_IncrRefCount(parent->datacommand); + } + if (parent->picommand) { + Tcl_IncrRefCount(parent->picommand); + } + if (parent->defaultcommand) { + Tcl_IncrRefCount(parent->defaultcommand); + } + if (parent->unparsedcommand) { + Tcl_IncrRefCount(parent->unparsedcommand); + } + if (parent->notationcommand) { + Tcl_IncrRefCount(parent->notationcommand); + } + if (parent->entitycommand) { + Tcl_IncrRefCount(parent->entitycommand); + } + if (parent->unknownencodingcommand) { + Tcl_IncrRefCount(parent->unknownencodingcommand); + } + if (parent->commentCommand) { + Tcl_IncrRefCount(parent->commentCommand); + } + if (parent->notStandaloneCommand) { + Tcl_IncrRefCount(parent->notStandaloneCommand); + } +#ifdef TCLXML_CDATASECTIONS + if (parent->startCdataSectionCommand) { + Tcl_IncrRefCount(parent->startCdataSectionCommand); + } + if (parent->endCdataSectionCommand) { + Tcl_IncrRefCount(parent->endCdataSectionCommand); + } +#endif + if (parent->elementDeclCommand) { + Tcl_IncrRefCount(parent->elementDeclCommand); + } + if (parent->attlistDeclCommand) { + Tcl_IncrRefCount(parent->attlistDeclCommand); + } + if (parent->startDoctypeDeclCommand) { + Tcl_IncrRefCount(parent->startDoctypeDeclCommand); + } + if (parent->endDoctypeDeclCommand) { + Tcl_IncrRefCount(parent->endDoctypeDeclCommand); + } + + external->elementstartcommand = parent->elementstartcommand; + external->elementstart = parent->elementstart; + external->elementendcommand = parent->elementendcommand; + external->elementend = parent->elementend; + external->datacommand = parent->datacommand; + external->cdatacb = parent->cdatacb; + external->picommand = parent->picommand; + external->pi = parent->pi; + external->defaultcommand = parent->defaultcommand; + external->defaultcb = parent->defaultcb; + external->unparsedcommand = parent->unparsedcommand; + external->unparsed = parent->unparsed; + external->notationcommand = parent->notationcommand; + external->notation = parent->notation; + external->entitycommand = parent->entitycommand; + external->entity = parent->entity; + external->unknownencodingcommand = parent->unknownencodingcommand; + external->unknownencoding = parent->unknownencoding; + external->commentCommand = parent->commentCommand; + external->comment = parent->comment; + external->notStandaloneCommand = parent->notStandaloneCommand; + external->notStandalone = parent->notStandalone; + external->elementDeclCommand = parent->elementDeclCommand; + external->elementDecl = parent->elementDecl; + external->attlistDeclCommand = parent->attlistDeclCommand; + external->attlistDecl = parent->attlistDecl; + external->startDoctypeDeclCommand = parent->startDoctypeDeclCommand; + external->startDoctypeDecl = parent->startDoctypeDecl; + external->endDoctypeDeclCommand = parent->endDoctypeDeclCommand; + external->endDoctypeDecl = parent->endDoctypeDecl; +#ifdef TCLXML_CDATASECTIONS + external->startCdataSectionCommand = parent->startCdataSectionCommand; + external->startCdataSection = parent->startCdataSection; + external->endCdataSectionCommand = parent->endCdataSectionCommand; + external->endCdataSection = parent->endCdataSection; +#endif + + external->final = 1; + external->validate = parent->validate; + external->status = TCL_OK; + external->result = NULL; + external->continueCount = 0; + external->context = NULL; + external->cdata = NULL; + external->nowhitespace = parent->nowhitespace; + if (parent->encoding) { + external->encoding = Tcl_DuplicateObj(parent->encoding); + } else { + external->encoding = Tcl_NewStringObj("utf-8", -1); + } + + if (extClassInfo->createEntity) { + /* + * Directly invoke the create routine + */ + if ((external->clientData = (*extClassInfo->createEntity)(interp, (ClientData) external)) == NULL) { + Tcl_Free((char*)external); + return TCL_ERROR; + } + } else if (extClassInfo->createEntityCmd) { + int result; + + result = Tcl_GlobalEvalObj(interp, extClassInfo->createEntityCmd); + if (result != TCL_OK) { + Tcl_Free((char*)external); + return TCL_ERROR; + } else { + + /* + * Return result is parser instance argument + */ + + external->clientData = (ClientData) Tcl_GetObjResult(interp); + Tcl_IncrRefCount((Tcl_Obj *) external->clientData); + + } + } + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXMLDestroyParserInstance -- + * + * Destroys the parser instance. + * + * Results: + * None. + * + * Side effects: + * Depends on class destroy proc. + * + *---------------------------------------------------------------------------- + */ + +static int +TclXMLDestroyParserInstance(xmlinfo) + TclXML_Info *xmlinfo; +{ + TclXML_ParserClassInfo *classInfo = (TclXML_ParserClassInfo *) xmlinfo->parserClass; + + if (xmlinfo->clientData) { + if (classInfo->destroy) { + if ((*classInfo->destroy)(xmlinfo->clientData) != TCL_OK) { + if (xmlinfo->encoding) { + Tcl_DecrRefCount(xmlinfo->encoding); + } + Tcl_Free((char *)xmlinfo); + return TCL_ERROR; + } + } else if (classInfo->destroyCmd) { + Tcl_Obj *cmdPtr = Tcl_DuplicateObj(classInfo->destroyCmd); + int result; + + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, (Tcl_Obj *) xmlinfo->clientData); + + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + + if (result != TCL_OK) { + if (xmlinfo->encoding) { + Tcl_DecrRefCount(xmlinfo->encoding); + } + Tcl_Free((char *)xmlinfo); + return TCL_ERROR; + } + + Tcl_DecrRefCount((Tcl_Obj *) xmlinfo->clientData); + + } + + xmlinfo->clientData = NULL; + + } + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXMLFreeParser -- + * + * Destroy the parser instance structure. + * + * Results: + * None. + * + * Side effects: + * Frees any memory allocated for the XML parser instance. + * + *---------------------------------------------------------------------------- + */ + +static void +TclXMLFreeParser(xmlinfo) + TclXML_Info *xmlinfo; +{ + if (TclXMLDestroyParserInstance(xmlinfo) == TCL_OK) { + if (xmlinfo->encoding) { + Tcl_DecrRefCount(xmlinfo->encoding); + } + Tcl_Free((char*)xmlinfo); + } +} + +/* + *---------------------------------------------------------------------------- + * + * TclXMLInstanceCmd -- + * + * Implements instance command for XML parsers. + * + * Results: + * Depends on the method. + * + * Side effects: + * Depends on the method. + * + *---------------------------------------------------------------------------- + */ + +static int +TclXMLInstanceCmd (clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +{ + TclXML_Info *xmlinfo = (TclXML_Info *) clientData; + TclXML_Info *child; + char *encoding, *data; + int len, index, result = TCL_OK; + Tcl_Obj *childNamePtr; + static CONST84 char *options[] = { + "configure", "cget", "entityparser", "free", "get", "parse", "reset", NULL + }; + enum options { + TCLXML_CONFIGURE, TCLXML_CGET, TCLXML_ENTITYPARSER, TCLXML_FREE, TCLXML_GET, + TCLXML_PARSE, TCLXML_RESET + }; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "method ?args?"); + return TCL_ERROR; + } + + if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + + switch ((enum options) index) { + case TCLXML_CONFIGURE: + + result = TclXMLInstanceConfigure(interp, xmlinfo, objc - 2, objv + 2); + break; + + case TCLXML_CGET: + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "cget option"); + return TCL_ERROR; + } + + result = TclXMLCget(interp, xmlinfo, objc - 2, objv + 2); + break; + + case TCLXML_ENTITYPARSER: + /* ericm@scriptics.com, 1999.9.13 */ + + /* check for args - Pat Thoyts */ + if (objc == 2) { + childNamePtr = FindUniqueCmdName(interp); + } else if (objc == 3) { + childNamePtr = objv[2]; + } else { + Tcl_WrongNumArgs(interp, 1, objv, "entityparser ?args?"); + return TCL_ERROR; + } + + /* + * Create the data structures for this parser. + */ + if (!(child = (TclXML_Info *) Tcl_Alloc(sizeof(TclXML_Info)))) { + Tcl_Free((char*)child); + Tcl_SetResult(interp, "unable to create parser", NULL); + return TCL_ERROR; + } + + child->interp = interp; + Tcl_IncrRefCount(childNamePtr); + child->name = childNamePtr; + + /* Actually create the parser instance */ + if (TclXMLCreateEntityParser(interp, child, + xmlinfo) != TCL_OK) { + Tcl_DecrRefCount(childNamePtr); + Tcl_Free((char*)child); + return TCL_ERROR; + } + + /* Register a Tcl command for this parser instance */ + Tcl_CreateObjCommand(interp, Tcl_GetString(child->name), + TclXMLInstanceCmd, (ClientData) child, TclXMLInstanceDeleteCmd); + + Tcl_SetObjResult(interp, child->name); + result = TCL_OK; + break; + + case TCLXML_FREE: + + /* ericm@scriptics.com, 1999.9.13 */ + Tcl_DeleteCommand(interp, Tcl_GetString(xmlinfo->name)); + result = TCL_OK; + break; + + case TCLXML_GET: + + /* ericm@scriptics.com, 1999.6.28 */ + result = TclXMLGet(interp, xmlinfo, objc - 2, objv + 2); + break; + + case TCLXML_PARSE: + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "data"); + return TCL_ERROR; + } + + if (xmlinfo->encoding) { + encoding = Tcl_GetStringFromObj(xmlinfo->encoding, NULL); + } else { + encoding = "utf-8"; + } + if (strlen(encoding) == 0 || strcmp(encoding, "utf-8") == 0) { + data = Tcl_GetStringFromObj(objv[2], &len); + } else { + data = (char *) Tcl_GetByteArrayFromObj(objv[2], &len); + } + + result = TclXMLParse(interp, xmlinfo, data, len); + + break; + + case TCLXML_RESET: + + if (objc > 2) { + Tcl_WrongNumArgs(interp, 1, objv, ""); + return TCL_ERROR; + } + + TclXMLResetParser(interp, xmlinfo); + break; + + default: + + Tcl_SetResult(interp, "unknown method", NULL); + return TCL_ERROR; + } + + return result; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXMLParse -- + * + * Invoke parser class' parse proc and check return result. + * + * Results: + * TCL_OK if no errors, TCL_ERROR otherwise. + * + * Side effects: + * Sets interpreter result as appropriate. + * + *---------------------------------------------------------------------------- + */ + +static int +TclXMLParse (interp, xmlinfo, data, len) + Tcl_Interp *interp; + TclXML_Info *xmlinfo; + char *data; + int len; +{ + int result; + TclXML_ParserClassInfo *classInfo = (TclXML_ParserClassInfo *) xmlinfo->parserClass; + + xmlinfo->status = TCL_OK; + if (xmlinfo->result != NULL) { + Tcl_DecrRefCount(xmlinfo->result); + } + xmlinfo->result = NULL; + + if (classInfo->parse) { + if ((*classInfo->parse)(xmlinfo->clientData, data, len, xmlinfo->final) != TCL_OK) { + return TCL_ERROR; + } + } else if (classInfo->parseCmd) { + Tcl_Obj *cmdPtr = Tcl_DuplicateObj(classInfo->parseCmd); + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + + if (xmlinfo->clientData) { + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, (Tcl_Obj *) xmlinfo->clientData); + } else if (xmlinfo->name) { + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, xmlinfo->name); + } + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, Tcl_NewStringObj(data, len)); + + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + + if (result != TCL_OK) { + return TCL_ERROR; + } + + } else { + Tcl_SetResult(interp, "XML parser cannot parse", NULL); + return TCL_ERROR; + } + + switch (xmlinfo->status) { + case TCL_OK: + case TCL_BREAK: + case TCL_CONTINUE: + TclXMLDispatchPCDATA(xmlinfo); + Tcl_ResetResult(interp); + return TCL_OK; + + case TCL_ERROR: + Tcl_SetObjResult(interp, xmlinfo->result); + return TCL_ERROR; + + default: + /* + * Propagate application-specific error condition. + * Patch by Marshall Rose <mrose@dbc.mtview.ca.us> + */ + Tcl_SetObjResult(interp, xmlinfo->result); + return xmlinfo->status; + } +} + +/* + *---------------------------------------------------------------------------- + * + * TclXMLInstanceConfigure -- + * + * Configures a XML parser instance. + * + * Results: + * Depends on the method. + * + * Side effects: + * Depends on the method. + * + *---------------------------------------------------------------------------- + */ + +static int +TclXMLInstanceConfigure (interp, xmlinfo, objc, objv) + Tcl_Interp *interp; + TclXML_Info *xmlinfo; + int objc; + Tcl_Obj *CONST objv[]; +{ + int index, bool, doParse = 0, result; + TclXML_ParserClassInfo *classinfo = (TclXML_ParserClassInfo *) xmlinfo->parserClass; + + while (objc > 1) { + /* + * Firstly, pass the option to the parser's own + * configuration management routine. + * It may pass back an error or break code to + * stop us from further processing the options. + */ + + if (classinfo->configure) { + result = (*classinfo->configure)(xmlinfo->clientData, objv[0], objv[1]); + if (result == TCL_BREAK) { + objc -= 2; + objv += 2; + continue; + } + if (result != TCL_OK) { + return TCL_ERROR; + } + } else if (classinfo->configureCmd) { + Tcl_Obj *cmdPtr = Tcl_DuplicateObj(classinfo->configureCmd); + + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) interp); + + if (xmlinfo->clientData) { + Tcl_ListObjAppendElement(interp, cmdPtr, (Tcl_Obj *) xmlinfo->clientData); + } else if (xmlinfo->name) { + Tcl_ListObjAppendElement(interp, cmdPtr, xmlinfo->name); + } + + Tcl_ListObjAppendElement(interp, cmdPtr, objv[0]); + Tcl_ListObjAppendElement(interp, cmdPtr, objv[1]); + + result = Tcl_GlobalEvalObj(interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) interp); + + if (result == TCL_BREAK) { + objc -= 2; + objv += 2; + continue; + } else if (result != TCL_OK) { + return TCL_ERROR; + } + } + + Tcl_ResetResult (interp); + + if (Tcl_GetIndexFromObj(interp, objv[0], instanceConfigureSwitches, + "switch", 0, &index) != TCL_OK) { + return TCL_ERROR; + } + switch ((enum instanceConfigureSwitches) index) { + case TCLXML_FINAL: /* -final */ + + if (Tcl_GetBooleanFromObj(interp, objv[1], &bool) != TCL_OK) { + return TCL_ERROR; + } + + if (bool && !xmlinfo->final) { + doParse = 1; + + } else if (!bool && xmlinfo->final) { + /* + * Reset the parser for new input + */ + + TclXMLResetParser(interp, xmlinfo); + doParse = 0; + } + xmlinfo->final = bool; + break; + + case TCLXML_ENCODING: /* -encoding */ + if (xmlinfo->encoding) { + Tcl_DecrRefCount(xmlinfo->encoding); + } + xmlinfo->encoding = objv[1]; + Tcl_IncrRefCount(xmlinfo->encoding); + break; + + case TCLXML_VALIDATE: /* -validate */ + if (Tcl_GetBooleanFromObj(interp, objv[1], &bool) != TCL_OK) { + return TCL_ERROR; + } + /* + * If the parser is in the middle of parsing a document, + * this will be ignored. Perhaps an error should be returned? + */ + xmlinfo->validate = bool; + break; + + case TCLXML_BASEURL: /* -baseurl, -baseuri */ + case TCLXML_BASEURI: + if (xmlinfo->base != NULL) { + Tcl_DecrRefCount(xmlinfo->base); + } + + xmlinfo->base = objv[1]; + Tcl_IncrRefCount(xmlinfo->base); + break; + + case TCLXML_DEFAULTEXPANDINTERNALENTITIES: /* -defaultexpandinternalentities */ + /* ericm@scriptics */ + if (Tcl_GetBooleanFromObj(interp, objv[1], &bool) != TCL_OK) { + return TCL_ERROR; + } + xmlinfo->expandinternalentities = bool; + break; + + case TCLXML_PARAMENTITYPARSING: + /* ericm@scriptics */ + case TCLXML_NOWHITESPACE: + case TCLXML_REPORTEMPTY: + /* + * All of these get passed through to the instance's + * configure procedure. + */ + + if (TclXMLConfigureParserInstance(xmlinfo, objv[0], objv[1]) != TCL_OK) { + return TCL_ERROR; + } + break; + + case TCLXML_ELEMENTSTARTCMD: /* -elementstartcommand */ + + if (xmlinfo->elementstartcommand != NULL) { + Tcl_DecrRefCount(xmlinfo->elementstartcommand); + } + xmlinfo->elementstart = NULL; + + xmlinfo->elementstartcommand = objv[1]; + Tcl_IncrRefCount(xmlinfo->elementstartcommand); + break; + + case TCLXML_ELEMENTENDCMD: /* -elementendcommand */ + + if (xmlinfo->elementendcommand != NULL) { + Tcl_DecrRefCount(xmlinfo->elementendcommand); + } + xmlinfo->elementend = NULL; + + xmlinfo->elementendcommand = objv[1]; + Tcl_IncrRefCount(xmlinfo->elementendcommand); + break; + + case TCLXML_DATACMD: /* -characterdatacommand */ + + if (xmlinfo->datacommand != NULL) { + Tcl_DecrRefCount(xmlinfo->datacommand); + } + xmlinfo->cdatacb = NULL; + + xmlinfo->datacommand = objv[1]; + Tcl_IncrRefCount(xmlinfo->datacommand); + break; + + case TCLXML_PICMD: /* -processinginstructioncommand */ + + if (xmlinfo->picommand != NULL) { + Tcl_DecrRefCount(xmlinfo->picommand); + } + xmlinfo->pi = NULL; + + xmlinfo->picommand = objv[1]; + Tcl_IncrRefCount(xmlinfo->picommand); + break; + + case TCLXML_DEFAULTCMD: /* -defaultcommand */ + + if (xmlinfo->defaultcommand != NULL) { + Tcl_DecrRefCount(xmlinfo->defaultcommand); + } + xmlinfo->defaultcb = NULL; + + xmlinfo->defaultcommand = objv[1]; + Tcl_IncrRefCount(xmlinfo->defaultcommand); + break; + + case TCLXML_UNPARSEDENTITYCMD: /* -unparsedentitydeclcommand */ + + if (xmlinfo->unparsedcommand != NULL) { + Tcl_DecrRefCount(xmlinfo->unparsedcommand); + } + xmlinfo->unparsed = NULL; + + xmlinfo->unparsedcommand = objv[1]; + Tcl_IncrRefCount(xmlinfo->unparsedcommand); + break; + + case TCLXML_NOTATIONCMD: /* -notationdeclcommand */ + + if (xmlinfo->notationcommand != NULL) { + Tcl_DecrRefCount(xmlinfo->notationcommand); + } + xmlinfo->notation = NULL; + + xmlinfo->notationcommand = objv[1]; + Tcl_IncrRefCount(xmlinfo->notationcommand); + break; + + case TCLXML_EXTERNALENTITYCMD: /* -externalentitycommand */ + + if (xmlinfo->entitycommand != NULL) { + Tcl_DecrRefCount(xmlinfo->entitycommand); + } + xmlinfo->entity = NULL; + + xmlinfo->entitycommand = objv[1]; + Tcl_IncrRefCount(xmlinfo->entitycommand); + break; + + case TCLXML_UNKNOWNENCODINGCMD: /* -unknownencodingcommand */ + + /* Not implemented */ + break; + + if (xmlinfo->unknownencodingcommand != NULL) { + Tcl_DecrRefCount(xmlinfo->unknownencodingcommand); + } + xmlinfo->unknownencoding = NULL; + + xmlinfo->unknownencodingcommand = objv[1]; + Tcl_IncrRefCount(xmlinfo->unknownencodingcommand); + break; + + case TCLXML_COMMENTCMD: /* -commentcommand */ + /* ericm@scriptics.com */ + if (xmlinfo->commentCommand != NULL) { + Tcl_DecrRefCount(xmlinfo->commentCommand); + } + xmlinfo->comment = NULL; + + xmlinfo->commentCommand = objv[1]; + Tcl_IncrRefCount(xmlinfo->commentCommand); + break; + + case TCLXML_NOTSTANDALONECMD: /* -notstandalonecommand */ + /* ericm@scriptics.com */ + if (xmlinfo->notStandaloneCommand != NULL) { + Tcl_DecrRefCount(xmlinfo->notStandaloneCommand); + } + xmlinfo->notStandalone = NULL; + + xmlinfo->notStandaloneCommand = objv[1]; + Tcl_IncrRefCount(xmlinfo->notStandaloneCommand); + break; + +#ifdef TCLXML_CDATASECTIONS + case TCLXML_STARTCDATASECTIONCMD: /* -startcdatasectioncommand */ + /* ericm@scriptics */ + if (xmlinfo->startCdataSectionCommand != NULL) { + Tcl_DecrRefCount(xmlinfo->startCdataSectionCommand); + } + xmlinfo->startCDATASection = NULL; + + xmlinfo->startCdataSectionCommand = objv[1]; + Tcl_IncrRefCount(xmlinfo->startCdataSectionCommand); + break; + + case TCLXML_ENDCDATASECTIONCMD: /* -endcdatasectioncommand */ + /* ericm@scriptics */ + if (xmlinfo->endCdataSectionCommand != NULL) { + Tcl_DecrRefCount(xmlinfo->endCdataSectionCommand); + } + xmlinfo->endCDATASection = NULL; + + xmlinfo->endCdataSectionCommand = objv[1]; + Tcl_IncrRefCount(xmlinfo->endCdataSectionCommand); + break; +#endif + + case TCLXML_ELEMENTDECLCMD: /* -elementdeclcommand */ + /* ericm@scriptics.com */ + if (xmlinfo->elementDeclCommand != NULL) { + Tcl_DecrRefCount(xmlinfo->elementDeclCommand); + } + xmlinfo->elementDecl = NULL; + + xmlinfo->elementDeclCommand = objv[1]; + Tcl_IncrRefCount(xmlinfo->elementDeclCommand); + break; + + case TCLXML_ATTLISTDECLCMD: /* -attlistdeclcommand */ + /* ericm@scriptics.com */ + if (xmlinfo->attlistDeclCommand != NULL) { + Tcl_DecrRefCount(xmlinfo->attlistDeclCommand); + } + xmlinfo->attlistDecl = NULL; + + xmlinfo->attlistDeclCommand = objv[1]; + Tcl_IncrRefCount(xmlinfo->attlistDeclCommand); + break; + + case TCLXML_STARTDOCTYPEDECLCMD: /* -startdoctypedeclcommand */ + /* ericm@scriptics.com */ + if (xmlinfo->startDoctypeDeclCommand != NULL) { + Tcl_DecrRefCount(xmlinfo->startDoctypeDeclCommand); + } + xmlinfo->startDoctypeDecl = NULL; + + xmlinfo->startDoctypeDeclCommand = objv[1]; + Tcl_IncrRefCount(xmlinfo->startDoctypeDeclCommand); + break; + + case TCLXML_ENDDOCTYPEDECLCMD: /* -enddoctypedeclcommand */ + /* ericm@scriptics.com */ + if (xmlinfo->endDoctypeDeclCommand != NULL) { + Tcl_DecrRefCount(xmlinfo->endDoctypeDeclCommand); + } + xmlinfo->endDoctypeDecl = NULL; + + xmlinfo->endDoctypeDeclCommand = objv[1]; + Tcl_IncrRefCount(xmlinfo->endDoctypeDeclCommand); + break; + + case TCLXML_ENTITYDECLCMD: /* -entitydeclcommand */ + case TCLXML_PARAMENTITYDECLCMD: /* -parameterentitydeclcommand */ + case TCLXML_DOCTYPECMD: /* -doctypecommand */ + case TCLXML_ENTITYREFCMD: /* -entityreferencecommand */ + case TCLXML_XMLDECLCMD: /* -xmldeclcommand */ + /* commands used by tcldom, but not here yet */ + break; + + default: + return TCL_ERROR; + break; + } + + objv += 2; + objc -= 2; + + } + + if (doParse) { + return TclXMLParse(interp, xmlinfo, "", 0); + } else { + return TCL_OK; + } + +} + +/* + *---------------------------------------------------------------------------- + * + * TclXMLCget -- + * + * Returns setting of configuration option. + * + * Results: + * Option value. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int +TclXMLCget (interp, xmlinfo, objc, objv) + Tcl_Interp *interp; + TclXML_Info *xmlinfo; + int objc; + Tcl_Obj *CONST objv[]; +{ + int index; + + if (Tcl_GetIndexFromObj(interp, objv[0], instanceConfigureSwitches, "switch", 0, &index) != TCL_OK) { + return TCL_ERROR; + } + + Tcl_SetObjResult(interp, Tcl_NewObj()); + + switch ((enum instanceConfigureSwitches) index) { + case TCLXML_FINAL: + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(xmlinfo->final)); + break; + case TCLXML_VALIDATE: + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(xmlinfo->validate)); + break; + case TCLXML_DEFAULTEXPANDINTERNALENTITIES: + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(xmlinfo->expandinternalentities)); + break; + case TCLXML_REPORTEMPTY: + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(xmlinfo->reportempty)); + break; + case TCLXML_PARAMENTITYPARSING: + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(xmlinfo->paramentities)); + break; + case TCLXML_NOWHITESPACE: + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(xmlinfo->nowhitespace)); + break; + case TCLXML_BASEURL: + case TCLXML_BASEURI: + if (xmlinfo->base) { + Tcl_SetObjResult(interp, xmlinfo->base); + } + break; + case TCLXML_ENCODING: + if (xmlinfo->encoding) { + Tcl_SetObjResult(interp, xmlinfo->encoding); + } + break; + case TCLXML_ELEMENTSTARTCMD: + if (xmlinfo->elementstartcommand) { + Tcl_SetObjResult(interp, xmlinfo->elementstartcommand); + } + break; + case TCLXML_ELEMENTENDCMD: + if (xmlinfo->elementendcommand) { + Tcl_SetObjResult(interp, xmlinfo->elementendcommand); + } + break; + case TCLXML_DATACMD: + if (xmlinfo->datacommand) { + Tcl_SetObjResult(interp, xmlinfo->datacommand); + } + break; + case TCLXML_PICMD: + if (xmlinfo->picommand) { + Tcl_SetObjResult(interp, xmlinfo->picommand); + } + break; + case TCLXML_DEFAULTCMD: + if (xmlinfo->defaultcommand) { + Tcl_SetObjResult(interp, xmlinfo->defaultcommand); + } + break; + case TCLXML_UNPARSEDENTITYCMD: + if (xmlinfo->unparsedcommand) { + Tcl_SetObjResult(interp, xmlinfo->unparsedcommand); + } + break; + case TCLXML_NOTATIONCMD: + if (xmlinfo->notationcommand) { + Tcl_SetObjResult(interp, xmlinfo->notationcommand); + } + break; + case TCLXML_EXTERNALENTITYCMD: + if (xmlinfo->entitycommand) { + Tcl_SetObjResult(interp, xmlinfo->entitycommand); + } + break; + case TCLXML_UNKNOWNENCODINGCMD: + if (xmlinfo->unknownencodingcommand) { + Tcl_SetObjResult(interp, xmlinfo->unknownencodingcommand); + } + break; + case TCLXML_COMMENTCMD: + if (xmlinfo->commentCommand) { + Tcl_SetObjResult(interp, xmlinfo->commentCommand); + } + break; + case TCLXML_NOTSTANDALONECMD: + if (xmlinfo->notStandaloneCommand) { + Tcl_SetObjResult(interp, xmlinfo->notStandaloneCommand); + } + break; +#ifdef TCLXML_CDATASECTIONS + case TCLXML_STARTCDATASECTIONCMD: + if (xmlinfo->startCdataSectionCommand) { + Tcl_SetObjResult(interp, xmlinfo->startCdataSectionCommand); + } + break; + case TCLXML_ENDCDATASECTIONCMD: + if (xmlinfo->endCdataSectionCommand) { + Tcl_SetObjResult(interp, xmlinfo->endCdataSectionCommand); + } + break; +#else + case TCLXML_STARTCDATASECTIONCMD: + case TCLXML_ENDCDATASECTIONCMD: + break; +#endif + case TCLXML_ELEMENTDECLCMD: + if (xmlinfo->elementDeclCommand) { + Tcl_SetObjResult(interp, xmlinfo->elementDeclCommand); + } + break; + case TCLXML_ATTLISTDECLCMD: + if (xmlinfo->attlistDeclCommand) { + Tcl_SetObjResult(interp, xmlinfo->attlistDeclCommand); + } + break; + case TCLXML_STARTDOCTYPEDECLCMD: + if (xmlinfo->startDoctypeDeclCommand) { + Tcl_SetObjResult(interp, xmlinfo->startDoctypeDeclCommand); + } + break; + case TCLXML_ENDDOCTYPEDECLCMD: + if (xmlinfo->endDoctypeDeclCommand) { + Tcl_SetObjResult(interp, xmlinfo->endDoctypeDeclCommand); + } + break; + + case TCLXML_ENTITYDECLCMD: + case TCLXML_PARAMENTITYDECLCMD: + case TCLXML_DOCTYPECMD: + case TCLXML_ENTITYREFCMD: + case TCLXML_XMLDECLCMD: + /* These are not (yet) supported) */ + break; + } + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXMLConfigureParserInstance -- + * + * Set an option in a parser instance. + * + * Results: + * Standard Tcl result. + * + * Side effects: + * Depends on parser class. + * + *---------------------------------------------------------------------------- + */ + +static int +TclXMLConfigureParserInstance (xmlinfo, option, value) + TclXML_Info *xmlinfo; + Tcl_Obj *option; + Tcl_Obj *value; +{ + TclXML_ParserClassInfo *classInfo = (TclXML_ParserClassInfo *) xmlinfo->parserClass; + + if (classInfo->configure) { + if ((*classInfo->configure)(xmlinfo->clientData, option, value) != TCL_OK) { + return TCL_ERROR; + } + } else if (classInfo->configureCmd) { + Tcl_Obj *cmdPtr = Tcl_DuplicateObj(classInfo->configureCmd); + int result; + + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + + /* SF Bug 514045. + */ + + if (xmlinfo->clientData) { + Tcl_ListObjAppendElement(NULL, cmdPtr, (Tcl_Obj *) xmlinfo->clientData); + } else if (xmlinfo->name) { + Tcl_ListObjAppendElement(NULL, cmdPtr, xmlinfo->name); + } + + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, option); + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, value); + + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + + if (result != TCL_OK) { + return TCL_ERROR; + } + } else { + Tcl_SetResult(xmlinfo->interp, "no configure procedure for parser", NULL); + return TCL_ERROR; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXMLGet -- + * + * Returns runtime parser information, depending on option + * ericm@scriptics.com, 1999.6.28 + * + * Results: + * Option value. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int +TclXMLGet (interp, xmlinfo, objc, objv) + Tcl_Interp *interp; + TclXML_Info *xmlinfo; + int objc; + Tcl_Obj *CONST objv[]; +{ + TclXML_ParserClassInfo *classInfo = (TclXML_ParserClassInfo *) xmlinfo->parserClass; + + if (classInfo->get) { + return (*classInfo->get)(xmlinfo->clientData, objc, objv); + } else if (classInfo->getCmd) { + Tcl_Obj *cmdPtr = Tcl_DuplicateObj(classInfo->getCmd); + int i, result; + + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + + for (i = 0; i < objc; i++) { + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, objv[i]); + } + + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + + return result; + } else { + Tcl_SetResult(interp, "parser has no get procedure", NULL); + return TCL_ERROR; + } +} + +/* + *---------------------------------------------------------------------------- + * + * TclXMLHandlerResult -- + * + * Manage the result of the application callback. + * + * Results: + * None. + * + * Side Effects: + * Further invocation of callback scripts may be inhibited. + * + *---------------------------------------------------------------------------- + */ + +static void +TclXMLHandlerResult(xmlinfo, result) + TclXML_Info *xmlinfo; + int result; +{ + switch (result) { + case TCL_OK: + xmlinfo->status = TCL_OK; + break; + + case TCL_CONTINUE: + /* + * Skip callbacks until the matching end element event + * occurs for the currently open element. + * Keep a reference count to handle nested + * elements. + */ + xmlinfo->status = TCL_CONTINUE; + xmlinfo->continueCount = 0; + break; + + case TCL_BREAK: + /* + * Skip all further callbacks, but return OK. + */ + xmlinfo->status = TCL_BREAK; + break; + + case TCL_ERROR: + default: + /* + * Skip all further callbacks, and return error. + */ + xmlinfo->status = TCL_ERROR; + xmlinfo->result = Tcl_GetObjResult(xmlinfo->interp); + Tcl_IncrRefCount(xmlinfo->result); + break; + } +} + +/* + *---------------------------------------------------------------------------- + * + * TclXML_ElementStartHandler -- + * + * Called by parser instance for each start tag. + * + * Results: + * None. + * + * Side Effects: + * Callback script is invoked. + * + *---------------------------------------------------------------------------- + */ + +void +TclXML_ElementStartHandler(userData, name, nsuri, atts, nsDecls) + void *userData; + Tcl_Obj *name; + Tcl_Obj *nsuri; + Tcl_Obj *atts; + Tcl_Obj *nsDecls; +{ + TclXML_Info *xmlinfo = (TclXML_Info *) userData; + int result = TCL_OK; + + TclXMLDispatchPCDATA(xmlinfo); + + if (xmlinfo->status == TCL_CONTINUE) { + + /* + * We're currently skipping elements looking for the + * close of the continued element. + */ + + xmlinfo->continueCount++; + return; + } + + if ((xmlinfo->elementstartcommand == NULL && + xmlinfo->elementstart == NULL) || + xmlinfo->status != TCL_OK) { + return; + } + + if (xmlinfo->elementstart) { + result = (xmlinfo->elementstart)(xmlinfo->interp, xmlinfo->elementstartdata, name, nsuri, atts, nsDecls); + } else if (xmlinfo->elementstartcommand) { + Tcl_Obj *cmdPtr; + + /* + * Take a copy of the callback script so that arguments may be appended. + */ + + cmdPtr = Tcl_DuplicateObj(xmlinfo->elementstartcommand); + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, name); + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, atts); + if (nsuri) { + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, Tcl_NewStringObj("-namespace", -1)); + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, nsuri); + } + if (nsDecls) { + int len; + if ((Tcl_ListObjLength(xmlinfo->interp, nsDecls, &len) == TCL_OK) && (len > 0)) { + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, Tcl_NewStringObj("-namespacedecls", -1)); + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, nsDecls); + } + } + + /* + * It would be desirable to be able to terminate parsing + * if the return result is TCL_ERROR or TCL_BREAK. + */ + + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + } + + TclXMLHandlerResult(xmlinfo, result); +} + +/* + *---------------------------------------------------------------------------- + * + * TclXML_ElementEndHandler -- + * + * Called by parser instance for each end tag. + * + * Results: + * None. + * + * Side Effects: + * Callback script is invoked. + * + *---------------------------------------------------------------------------- + */ + +void +TclXML_ElementEndHandler(userData, name) + void *userData; + Tcl_Obj *name; +{ + TclXML_Info *xmlinfo = (TclXML_Info *) userData; + int result = TCL_OK;; + + TclXMLDispatchPCDATA(xmlinfo); + + if (xmlinfo->status == TCL_CONTINUE) { + /* + * We're currently skipping elements looking for the + * end of the currently open element. + */ + + if (!--(xmlinfo->continueCount)) { + xmlinfo->status = TCL_OK; + } else { + return; + } + } + + if ((xmlinfo->elementend == NULL && + xmlinfo->elementendcommand == NULL) || + xmlinfo->status != TCL_OK) { + return; + } + + if (xmlinfo->elementend) { + result = (xmlinfo->elementend)(xmlinfo->interp, xmlinfo->elementenddata, name); + } else if (xmlinfo->elementendcommand) { + Tcl_Obj *cmdPtr; + + /* + * Take a copy of the callback script so that arguments may be appended. + */ + + cmdPtr = Tcl_DuplicateObj(xmlinfo->elementendcommand); + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, name); + + /* + * It would be desirable to be able to terminate parsing + * if the return result is TCL_ERROR or TCL_BREAK. + */ + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + } + + TclXMLHandlerResult(xmlinfo, result); + + return; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXML_CharacterDataHandler -- + * + * Called by parser instance for character data. + * + * Results: + * None. + * + * Side Effects: + * Character data is accumulated in a string object + * + *---------------------------------------------------------------------------- + */ + +void +TclXML_CharacterDataHandler(userData, s) + void *userData; + Tcl_Obj *s; +{ + TclXML_Info *xmlinfo = (TclXML_Info *) userData; + if (xmlinfo->cdata == NULL) { + xmlinfo->cdata = s; + Tcl_IncrRefCount(xmlinfo->cdata); + } else { + Tcl_AppendObjToObj(xmlinfo->cdata, s); + } +} + +/* + *---------------------------------------------------------------------------- + * + * TclXMLDispatchPCDATA -- + * + * Called to check whether any accumulated character data + * exists, and if so invoke the callback. + * + * Results: + * None. + * + * Side Effects: + * Callback script evaluated. + * + *---------------------------------------------------------------------------- + */ + +static void +TclXMLDispatchPCDATA(xmlinfo) + TclXML_Info *xmlinfo; +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + int result = TCL_OK; + + if (xmlinfo->cdata == NULL || + (xmlinfo->datacommand == NULL && xmlinfo->cdatacb == NULL) || + xmlinfo->status != TCL_OK) { + return; + } + + /* + * Optionally ignore white-space-only PCDATA + */ + + if (xmlinfo->nowhitespace) { + if (!Tcl_RegExpMatchObj(xmlinfo->interp, xmlinfo->cdata, tsdPtr->whitespaceRE)) { + goto finish; + } + } + + if (xmlinfo->cdatacb) { + result = (xmlinfo->cdatacb)(xmlinfo->interp, xmlinfo->cdatacbdata, xmlinfo->cdata); + } else if (xmlinfo->datacommand) { + Tcl_Obj *cmdPtr; + + /* + * Take a copy of the callback script so that arguments may be appended. + */ + + cmdPtr = Tcl_DuplicateObj(xmlinfo->datacommand); + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + + if (Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, xmlinfo->cdata) != TCL_OK) { + xmlinfo->status = TCL_ERROR; + return; + } + + /* + * It would be desirable to be able to terminate parsing + * if the return result is TCL_ERROR or TCL_BREAK. + */ + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + } + + TclXMLHandlerResult(xmlinfo, result); + + finish: + Tcl_DecrRefCount(xmlinfo->cdata); + xmlinfo->cdata = NULL; + + return; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXML_ProcessingInstructionHandler -- + * + * Called by parser instance for processing instructions. + * + * Results: + * None. + * + * Side Effects: + * Callback script is invoked. + * + *---------------------------------------------------------------------------- + */ + +void +TclXML_ProcessingInstructionHandler(userData, target, data) + void *userData; + Tcl_Obj *target; + Tcl_Obj *data; +{ + TclXML_Info *xmlinfo = (TclXML_Info *) userData; + int result = TCL_OK; + + TclXMLDispatchPCDATA(xmlinfo); + + if ((xmlinfo->picommand == NULL && xmlinfo->pi == NULL) || + xmlinfo->status != TCL_OK) { + return; + } + + if (xmlinfo->pi) { + result = (xmlinfo->pi)(xmlinfo->interp, xmlinfo->pidata, target, data); + } else if (xmlinfo->picommand) { + Tcl_Obj *cmdPtr; + + /* + * Take a copy of the callback script so that arguments may be appended. + */ + + cmdPtr = Tcl_DuplicateObj(xmlinfo->picommand); + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, target); + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, data); + + /* + * It would be desirable to be able to terminate parsing + * if the return result is TCL_ERROR or TCL_BREAK. + */ + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + } + + TclXMLHandlerResult(xmlinfo, result); + + return; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXML_DefaultHandler -- + * + * Called by parser instance for processing data which has no other handler. + * + * Results: + * None. + * + * Side Effects: + * Callback script is invoked. + * + *---------------------------------------------------------------------------- + */ + +void +TclXML_DefaultHandler(userData, s) + void *userData; + Tcl_Obj *s; +{ + TclXML_Info *xmlinfo = (TclXML_Info *) userData; + int result = TCL_OK; + + TclXMLDispatchPCDATA(xmlinfo); + + if ((xmlinfo->defaultcommand == NULL && xmlinfo->defaultcb == NULL) || + xmlinfo->status != TCL_OK) { + return; + } + + if (xmlinfo->defaultcb) { + result = (xmlinfo->defaultcb)(xmlinfo->interp, xmlinfo->defaultdata, s); + } else if (xmlinfo->defaultcommand) { + Tcl_Obj *cmdPtr; + + /* + * Take a copy of the callback script so that arguments may be appended. + */ + + cmdPtr = Tcl_DuplicateObj(xmlinfo->defaultcommand); + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, s); + + /* + * It would be desirable to be able to terminate parsing + * if the return result is TCL_ERROR or TCL_BREAK. + */ + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + } + + TclXMLHandlerResult(xmlinfo, result); + + return; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXML_UnparsedDeclHandler -- + * + * Called by parser instance for processing an unparsed entity references. + * + * Results: + * None. + * + * Side Effects: + * Callback script is invoked. + * + *---------------------------------------------------------------------------- + */ + +void +TclXML_UnparsedDeclHandler(userData, entityName, base, systemId, publicId, notationName) + void *userData; + Tcl_Obj *entityName; + Tcl_Obj *base; + Tcl_Obj *systemId; + Tcl_Obj *publicId; + Tcl_Obj *notationName; +{ + TclXML_Info *xmlinfo = (TclXML_Info *) userData; + int result = TCL_OK; + + TclXMLDispatchPCDATA(xmlinfo); + + if ((xmlinfo->unparsedcommand == NULL && xmlinfo->unparsed == NULL) || + xmlinfo->status != TCL_OK) { + return; + } + + if (xmlinfo->unparsed) { + result = (xmlinfo->unparsed)(xmlinfo->interp, xmlinfo->unparseddata, entityName, base, systemId, publicId, notationName); + } else if (xmlinfo->unparsedcommand) { + Tcl_Obj *cmdPtr; + + /* + * Take a copy of the callback script so that arguments may be appended. + */ + + cmdPtr = Tcl_DuplicateObj(xmlinfo->unparsedcommand); + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, entityName); + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, base); + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, systemId); + if (publicId == NULL) { + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, Tcl_NewObj()); + } else { + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, publicId); + } + if (notationName == NULL) { + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, Tcl_NewObj()); + } else { + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, notationName); + } + + /* + * It would be desirable to be able to terminate parsing + * if the return result is TCL_ERROR or TCL_BREAK. + */ + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + } + + TclXMLHandlerResult(xmlinfo, result); + + return; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXML_NotationDeclHandler -- + * + * Called by parser instance for processing a notation declaration. + * + * Results: + * None. + * + * Side Effects: + * Callback script is invoked. + * + *---------------------------------------------------------------------------- + */ + +void +TclXML_NotationDeclHandler(userData, notationName, base, systemId, publicId) + void *userData; + Tcl_Obj *notationName; + Tcl_Obj *base; + Tcl_Obj *systemId; + Tcl_Obj *publicId; +{ + TclXML_Info *xmlinfo = (TclXML_Info *) userData; + int result = TCL_OK; + + TclXMLDispatchPCDATA(xmlinfo); + + if ((xmlinfo->notationcommand == NULL && xmlinfo->notation == NULL) || + xmlinfo->status != TCL_OK) { + return; + } + + if (xmlinfo->notation) { + result = (xmlinfo->notation)(xmlinfo->interp, xmlinfo->notationdata, notationName, base, systemId, publicId); + } else if (xmlinfo->notationcommand) { + Tcl_Obj *cmdPtr; + + /* + * Take a copy of the callback script so that arguments may be appended. + */ + + cmdPtr = Tcl_DuplicateObj(xmlinfo->notationcommand); + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, notationName); + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, base); + if (systemId == NULL) { + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, Tcl_NewObj()); + } else { + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, systemId); + } + if (publicId == NULL) { + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, Tcl_NewObj()); + } else { + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, publicId); + } + + /* + * It would be desirable to be able to terminate parsing + * if the return result is TCL_ERROR or TCL_BREAK. + */ + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + } + + TclXMLHandlerResult(xmlinfo, result); + + return; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXML_UnknownEncodingHandler -- + * + * Called by parser instance for processing a reference to a character in an + * unknown encoding. + * + * Results: + * None. + * + * Side Effects: + * Callback script is invoked. + * + *---------------------------------------------------------------------------- + */ + +int +TclXML_UnknownEncodingHandler(encodingHandlerData, name, info) + void *encodingHandlerData; + Tcl_Obj *name; + void *info; +{ + TclXML_Info *xmlinfo = (TclXML_Info *) encodingHandlerData; + int result = TCL_OK; + + TclXMLDispatchPCDATA(xmlinfo); + + Tcl_SetResult(xmlinfo->interp, "not implemented", NULL); + return 0; + + if ((xmlinfo->unknownencodingcommand == NULL && xmlinfo->unknownencoding == NULL) || + xmlinfo->status != TCL_OK) { + return 0; + } + + if (xmlinfo->unknownencoding) { + result = (xmlinfo->unknownencoding)(xmlinfo->interp, xmlinfo->unknownencodingdata, name, info); + } else if (xmlinfo->unknownencodingcommand) { + Tcl_Obj *cmdPtr; + + /* + * Take a copy of the callback script so that arguments may be appended. + */ + + cmdPtr = Tcl_DuplicateObj(xmlinfo->unknownencodingcommand); + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + + /* + * Setup the arguments + */ + + /* + * It would be desirable to be able to terminate parsing + * if the return result is TCL_ERROR or TCL_BREAK. + */ + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + } + + TclXMLHandlerResult(xmlinfo, result); + + return 0; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXML_ExternalEntityRefHandler -- + * + * Called by parser instance for processing external entity references. + * May also be called outside the context of a parser for XInclude + * or XSLT import/include. + * + * Results: + * Returns success code. + * + * Side Effects: + * Callback script is invoked. + * + *---------------------------------------------------------------------------- + */ + +int +TclXML_ExternalEntityRefHandler(userData, openEntityNames, base, + systemId, publicId) + ClientData userData; /* NULL if not in parser context, current interp gets result */ + Tcl_Obj *openEntityNames; + Tcl_Obj *base; + Tcl_Obj *systemId; + Tcl_Obj *publicId; +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + TclXML_Info *xmlinfo = (TclXML_Info *) userData; + int result = TCL_OK; + Tcl_Obj *oldContext; + + if (xmlinfo != NULL) { + TclXMLDispatchPCDATA(xmlinfo); + + if (xmlinfo->entitycommand == NULL && xmlinfo->entity == NULL) { + if (Tcl_IsSafe(xmlinfo->interp)) { + return TCL_BREAK; + } else { + return TCL_CONTINUE; + } + } + if (xmlinfo->status != TCL_OK) { + return xmlinfo->status; + } + oldContext = xmlinfo->context; + xmlinfo->context = openEntityNames; + + if (xmlinfo->entity) { + result = (xmlinfo->entity)(xmlinfo->interp, xmlinfo->entitydata, xmlinfo->name, base, systemId, publicId); + } else if (xmlinfo->entitycommand) { + Tcl_Obj *cmdPtr; + + /* + * Take a copy of the callback script so that arguments may be appended. + */ + + cmdPtr = Tcl_DuplicateObj(xmlinfo->entitycommand); + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, xmlinfo->name); + + if (base) { + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, base); + } else { + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, Tcl_NewObj()); + } + + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, systemId); + + if (publicId) { + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, publicId); + } else { + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, Tcl_NewObj()); + } + + /* + * It would be desirable to be able to terminate parsing + * if the return result is TCL_ERROR or TCL_BREAK. + */ + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + } + + /* + * Return results have a different meaning for external entities, + * so don't retain the result for later use. + * TclXMLHandlerResult(xmlinfo, result); + */ + xmlinfo->context = oldContext; + + } else { + /* + * No parser context + */ + + if (tsdPtr->externalentitycmd) { + Tcl_Obj *cmdPtr; + + /* + * Take a copy of the callback script so that arguments may be appended. + */ + + cmdPtr = Tcl_DuplicateObj(tsdPtr->externalentitycmd); + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) tsdPtr->interp); + + if (base) { + Tcl_ListObjAppendElement(tsdPtr->interp, cmdPtr, base); + } else { + Tcl_ListObjAppendElement(tsdPtr->interp, cmdPtr, Tcl_NewObj()); + } + + Tcl_ListObjAppendElement(tsdPtr->interp, cmdPtr, systemId); + + if (publicId) { + Tcl_ListObjAppendElement(tsdPtr->interp, cmdPtr, publicId); + } else { + Tcl_ListObjAppendElement(tsdPtr->interp, cmdPtr, Tcl_NewObj()); + } + + /* + * It would be desirable to be able to terminate parsing + * if the return result is TCL_ERROR or TCL_BREAK. + */ + result = Tcl_GlobalEvalObj(tsdPtr->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) tsdPtr->interp); + } else if (Tcl_IsSafe(tsdPtr->interp)) { + return TCL_BREAK; + } else { + return TCL_CONTINUE; + } + } + + return result; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXML_CommentHandler -- + * + * Called by parser instance to handle comments encountered while parsing + * Added by ericm@scriptics.com, 1999.6.25. + * + * Results: + * None. + * + * Side Effects: + * Callback script is invoked. + * + *---------------------------------------------------------------------------- + */ +void +TclXML_CommentHandler(userData, data) + void *userData; + Tcl_Obj *data; +{ + TclXML_Info *xmlinfo = (TclXML_Info *) userData; + int result = TCL_OK; + + TclXMLDispatchPCDATA(xmlinfo); + + if (xmlinfo->status == TCL_CONTINUE) { + /* Currently skipping elements, looking for the close of the + * continued element. Comments don't have an end tag, so + * don't increment xmlinfo->continueCount + */ + return; + } + + if ((xmlinfo->commentCommand == NULL && xmlinfo->comment == NULL) || + xmlinfo->status != TCL_OK) { + return; + } + + if (xmlinfo->comment) { + result = (xmlinfo->comment)(xmlinfo->interp, xmlinfo->commentdata, data); + } else if (xmlinfo->commentCommand) { + Tcl_Obj *cmdPtr; + + cmdPtr = Tcl_DuplicateObj(xmlinfo->commentCommand); + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, data); + + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + } + + TclXMLHandlerResult(xmlinfo, result); + + return; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXML_NotStandaloneHandler -- + * + * Called by parser instance to handle "not standalone" documents (ie, documents + * that have an external subset or a reference to a parameter entity, + * but do not have standalone="yes") + * Added by ericm@scriptics.com, 1999.6.25. + * + * Results: + * None. + * + * Side Effects: + * Callback script is invoked. + * + *---------------------------------------------------------------------------- + */ + +int +TclXML_NotStandaloneHandler(userData) + void *userData; +{ + TclXML_Info *xmlinfo = (TclXML_Info *) userData; + int result = TCL_OK; + + TclXMLDispatchPCDATA(xmlinfo); + + if (xmlinfo->status != TCL_OK) { + return 0; + } else if (xmlinfo->notStandaloneCommand == NULL && xmlinfo->notStandalone == NULL) { + return 1; + } + + if (xmlinfo->notStandalone) { + result = (xmlinfo->notStandalone)(xmlinfo->interp, xmlinfo->notstandalonedata); + } else if (xmlinfo->notStandaloneCommand) { + Tcl_Obj *cmdPtr; + + cmdPtr = Tcl_DuplicateObj(xmlinfo->notStandaloneCommand); + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + } + + TclXMLHandlerResult(xmlinfo, result); + + return 1; +} + +/* + *---------------------------------------------------------------------- + * + * TclXML_ElementDeclHandler -- + * + * Called by expat to handle <!ELEMENT declarations. + * + * Results: + * None. + * + * Side effects: + * Callback script is invoked. + * + *---------------------------------------------------------------------- + */ + +void +TclXML_ElementDeclHandler(userData, name, contentspec) + void *userData; + Tcl_Obj *name; + Tcl_Obj *contentspec; +{ + TclXML_Info *xmlinfo = (TclXML_Info *) userData; + int result = TCL_OK; + + TclXMLDispatchPCDATA(xmlinfo); + + if ((xmlinfo->elementDeclCommand == NULL && xmlinfo->elementDecl == NULL) || + xmlinfo->status != TCL_OK) { + return; + } + + if (xmlinfo->elementDecl) { + result = (xmlinfo->elementDecl)(xmlinfo->interp, xmlinfo->elementdecldata, name, contentspec); + } else if (xmlinfo->elementDeclCommand) { + Tcl_Obj *cmdPtr; + + cmdPtr = Tcl_DuplicateObj(xmlinfo->elementDeclCommand); + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, name); + + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, contentspec); + + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + } + + TclXMLHandlerResult(xmlinfo, result); + + return; +} + +/* + *---------------------------------------------------------------------- + * + * TclXML_AttlistDeclHandler -- + * + * Called by parser instance to handle <!ATTLIST declarations. + * + * Results: + * None. + * + * Side effects: + * Callback script is invoked. + * + *---------------------------------------------------------------------- + */ + +void +TclXML_AttlistDeclHandler(userData, name, attributes) + void *userData; + Tcl_Obj *name; + Tcl_Obj *attributes; +{ + TclXML_Info *xmlinfo = (TclXML_Info *) userData; + int result = TCL_OK; + + TclXMLDispatchPCDATA(xmlinfo); + + if ((xmlinfo->attlistDeclCommand == NULL && xmlinfo->attlistDecl == NULL) || + xmlinfo->status != TCL_OK) { + return; + } + + if (xmlinfo->attlistDecl) { + result = (xmlinfo->attlistDecl)(xmlinfo->interp, xmlinfo->attlistdecldata, name, attributes); + } else if (xmlinfo->attlistDeclCommand) { + Tcl_Obj *cmdPtr; + + cmdPtr = Tcl_DuplicateObj(xmlinfo->attlistDeclCommand); + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, name); + + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, attributes); + + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + } + + TclXMLHandlerResult(xmlinfo, result); + + return; +} + +/* + *---------------------------------------------------------------------- + * + * TclXML_StartDoctypeDeclHandler -- + * + * Called by parser instance to handle the start of <!DOCTYPE declarations. + * + * Results: + * None. + * + * Side effects: + * Callback script is invoked. + * + *---------------------------------------------------------------------- + */ + +void +TclXML_StartDoctypeDeclHandler(userData, name) + void *userData; + Tcl_Obj *name; +{ + TclXML_Info *xmlinfo = (TclXML_Info *) userData; + int result = TCL_OK; + + TclXMLDispatchPCDATA(xmlinfo); + + if ((xmlinfo->startDoctypeDeclCommand == NULL && xmlinfo->startDoctypeDecl == NULL) || + xmlinfo->status != TCL_OK) { + return; + } + + if (xmlinfo->startDoctypeDecl) { + result = (xmlinfo->startDoctypeDecl)(xmlinfo->interp, xmlinfo->startdoctypedecldata, name); + } else if (xmlinfo->startDoctypeDeclCommand) { + Tcl_Obj *cmdPtr; + + cmdPtr = Tcl_DuplicateObj(xmlinfo->startDoctypeDeclCommand); + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + + Tcl_ListObjAppendElement(xmlinfo->interp, cmdPtr, name); + + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + } + + TclXMLHandlerResult(xmlinfo, result); + + return; +} + +/* + *---------------------------------------------------------------------- + * + * TclXML_EndDoctypeDeclHandler -- + * + * Called by parser instance to handle the end of <!DOCTYPE declarations. + * + * Results: + * None. + * + * Side effects: + * Callback script is invoked. + * + *---------------------------------------------------------------------- + */ + +void +TclXML_EndDoctypeDeclHandler(userData) + void *userData; +{ + TclXML_Info *xmlinfo = (TclXML_Info *) userData; + int result = TCL_OK; + + TclXMLDispatchPCDATA(xmlinfo); + + if ((xmlinfo->endDoctypeDeclCommand == NULL && xmlinfo->endDoctypeDecl == NULL) || + xmlinfo->status != TCL_OK) { + return; + } + + if (xmlinfo->endDoctypeDecl) { + result = (xmlinfo->endDoctypeDecl)(xmlinfo->interp, xmlinfo->enddoctypedecldata); + } else if (xmlinfo->endDoctypeDeclCommand) { + Tcl_Obj *cmdPtr; + + cmdPtr = Tcl_DuplicateObj(xmlinfo->endDoctypeDeclCommand); + Tcl_IncrRefCount(cmdPtr); + Tcl_Preserve((ClientData) xmlinfo->interp); + + result = Tcl_GlobalEvalObj(xmlinfo->interp, cmdPtr); + + Tcl_DecrRefCount(cmdPtr); + Tcl_Release((ClientData) xmlinfo->interp); + } + + TclXMLHandlerResult(xmlinfo, result); + + return; +} + +/* + *---------------------------------------------------------------------------- + * + * TclXMLInstanceDeleteCmd -- + * + * Called when a parser instance is deleted. + * + * Results: + * None. + * + * Side Effects: + * Memory structures are freed. + * + *---------------------------------------------------------------------------- + */ + +static void +TclXMLInstanceDeleteCmd(clientData) + ClientData clientData; +{ + TclXML_Info *xmlinfo = (TclXML_Info *) clientData; + + Tcl_DecrRefCount(xmlinfo->name); + + if (xmlinfo->cdata) { + Tcl_DecrRefCount(xmlinfo->cdata); + xmlinfo->cdata = NULL; + } + + if (xmlinfo->elementstartcommand) { + Tcl_DecrRefCount(xmlinfo->elementstartcommand); + } + if (xmlinfo->elementendcommand) { + Tcl_DecrRefCount(xmlinfo->elementendcommand); + } + if (xmlinfo->datacommand) { + Tcl_DecrRefCount(xmlinfo->datacommand); + } + if (xmlinfo->picommand) { + Tcl_DecrRefCount(xmlinfo->picommand); + } + if (xmlinfo->entitycommand) { + Tcl_DecrRefCount(xmlinfo->entitycommand); + } + + if (xmlinfo->unknownencodingcommand) { + Tcl_DecrRefCount(xmlinfo->unknownencodingcommand); + } + + if (xmlinfo->commentCommand) { + Tcl_DecrRefCount(xmlinfo->commentCommand); + } + + if (xmlinfo->notStandaloneCommand) { + Tcl_DecrRefCount(xmlinfo->notStandaloneCommand); + } + + if (xmlinfo->elementDeclCommand) { + Tcl_DecrRefCount(xmlinfo->elementDeclCommand); + } + + if (xmlinfo->attlistDeclCommand) { + Tcl_DecrRefCount(xmlinfo->attlistDeclCommand); + } + + if (xmlinfo->startDoctypeDeclCommand) { + Tcl_DecrRefCount(xmlinfo->startDoctypeDeclCommand); + } + + if (xmlinfo->endDoctypeDeclCommand) { + Tcl_DecrRefCount(xmlinfo->endDoctypeDeclCommand); + } + + TclXMLFreeParser(xmlinfo); +} + +/* + *---------------------------------------------------------------------------- + * + * TclXML_Register*Cmd -- + * + * Configures a direct callback handler. + * + * Results: + * None. + * + * Side Effects: + * Parser data structure modified. + * + *---------------------------------------------------------------------------- + */ + +int +TclXML_RegisterElementStartProc(interp, parser, clientData, callback) + Tcl_Interp *interp; + TclXML_Info *parser; + ClientData clientData; + TclXML_ElementStartProc *callback; +{ + parser->elementstart = callback; + parser->elementstartdata = clientData; + + if (parser->elementstartcommand) { + Tcl_DecrRefCount(parser->elementstartcommand); + parser->elementstartcommand = NULL; + } + + return TCL_OK; +} + +int +TclXML_RegisterElementEndProc(interp, parser, clientData, callback) + Tcl_Interp *interp; + TclXML_Info *parser; + ClientData clientData; + TclXML_ElementEndProc *callback; +{ + parser->elementend = callback; + parser->elementenddata = clientData; + + if (parser->elementendcommand) { + Tcl_DecrRefCount(parser->elementendcommand); + parser->elementendcommand = NULL; + } + + return TCL_OK; +} + +int +TclXML_RegisterCharacterDataProc(interp, parser, clientData, callback) + Tcl_Interp *interp; + TclXML_Info *parser; + ClientData clientData; + TclXML_CharacterDataProc *callback; +{ + parser->cdatacb = callback; + parser->cdatacbdata = clientData; + + if (parser->datacommand) { + Tcl_DecrRefCount(parser->datacommand); + parser->datacommand = NULL; + } + + return TCL_OK; +} + +int +TclXML_RegisterPIProc(interp, parser, clientData, callback) + Tcl_Interp *interp; + TclXML_Info *parser; + ClientData clientData; + TclXML_PIProc *callback; +{ + parser->pi = callback; + parser->pidata = clientData; + + if (parser->picommand) { + Tcl_DecrRefCount(parser->picommand); + parser->picommand = NULL; + } + + return TCL_OK; +} + +int +TclXML_RegisterDefaultProc(interp, parser, clientData, callback) + Tcl_Interp *interp; + TclXML_Info *parser; + ClientData clientData; + TclXML_DefaultProc *callback; +{ + parser->defaultcb = callback; + parser->defaultdata = clientData; + + if (parser->defaultcommand) { + Tcl_DecrRefCount(parser->defaultcommand); + parser->defaultcommand = NULL; + } + + return TCL_OK; +} + +int +TclXML_RegisterUnparsedProc(interp, parser, clientData, callback) + Tcl_Interp *interp; + TclXML_Info *parser; + ClientData clientData; + TclXML_UnparsedProc *callback; +{ + parser->unparsed = callback; + parser->unparseddata = clientData; + + if (parser->unparsedcommand) { + Tcl_DecrRefCount(parser->unparsedcommand); + parser->unparsedcommand = NULL; + } + + return TCL_OK; +} + +int +TclXML_RegisterNotationDeclProc(interp, parser, clientData, callback) + Tcl_Interp *interp; + TclXML_Info *parser; + ClientData clientData; + TclXML_NotationDeclProc *callback; +{ + parser->notation = callback; + parser->notationdata = clientData; + + if (parser->notationcommand) { + Tcl_DecrRefCount(parser->notationcommand); + parser->notationcommand = NULL; + } + + return TCL_OK; +} + +int +TclXML_RegisterEntityProc(interp, parser, clientData, callback) + Tcl_Interp *interp; + TclXML_Info *parser; + ClientData clientData; + TclXML_EntityProc *callback; +{ + parser->entity = callback; + parser->entitydata = clientData; + + if (parser->entitycommand) { + Tcl_DecrRefCount(parser->entitycommand); + parser->entitycommand = NULL; + } + + return TCL_OK; +} + +int +TclXML_RegisterUnknownEncodingProc(interp, parser, clientData, callback) + Tcl_Interp *interp; + TclXML_Info *parser; + ClientData clientData; + TclXML_UnknownEncodingProc *callback; +{ + parser->unknownencoding = callback; + parser->unknownencodingdata = clientData; + + if (parser->unknownencodingcommand) { + Tcl_DecrRefCount(parser->unknownencodingcommand); + parser->unknownencodingcommand = NULL; + } + + return TCL_OK; +} + +int +TclXML_RegisterCommentProc(interp, parser, clientData, callback) + Tcl_Interp *interp; + TclXML_Info *parser; + ClientData clientData; + TclXML_CommentProc *callback; +{ + parser->comment = callback; + parser->commentdata = clientData; + + if (parser->commentCommand) { + Tcl_DecrRefCount(parser->commentCommand); + parser->commentCommand = NULL; + } + + return TCL_OK; +} + +int +TclXML_RegisterNotStandaloneProc(interp, parser, clientData, callback) + Tcl_Interp *interp; + TclXML_Info *parser; + ClientData clientData; + TclXML_NotStandaloneProc *callback; +{ + parser->notStandalone = callback; + parser->notstandalonedata = clientData; + + if (parser->notStandaloneCommand) { + Tcl_DecrRefCount(parser->notStandaloneCommand); + parser->notStandaloneCommand = NULL; + } + + return TCL_OK; +} + +int +TclXML_RegisterElementDeclProc(interp, parser, clientData, callback) + Tcl_Interp *interp; + TclXML_Info *parser; + ClientData clientData; + TclXML_ElementDeclProc *callback; +{ + parser->elementDecl = callback; + parser->elementdecldata = clientData; + + if (parser->elementDeclCommand) { + Tcl_DecrRefCount(parser->elementDeclCommand); + parser->elementDeclCommand = NULL; + } + + return TCL_OK; +} + +int +TclXML_RegisterAttListDeclProc(interp, parser, clientData, callback) + Tcl_Interp *interp; + TclXML_Info *parser; + ClientData clientData; + TclXML_AttlistDeclProc *callback; +{ + parser->attlistDecl = callback; + parser->attlistdecldata = clientData; + + if (parser->attlistDeclCommand) { + Tcl_DecrRefCount(parser->attlistDeclCommand); + parser->attlistDeclCommand = NULL; + } + + return TCL_OK; +} + +int +TclXML_RegisterStartDoctypeDeclProc(interp, parser, clientData, callback) + Tcl_Interp *interp; + TclXML_Info *parser; + ClientData clientData; + TclXML_StartDoctypeDeclProc *callback; +{ + parser->startDoctypeDecl = callback; + parser->startdoctypedecldata = clientData; + + if (parser->startDoctypeDeclCommand) { + Tcl_DecrRefCount(parser->startDoctypeDeclCommand); + parser->startDoctypeDeclCommand = NULL; + } + + return TCL_OK; +} + +int +TclXML_RegisterEndDoctypeDeclProc(interp, parser, clientData, callback) + Tcl_Interp *interp; + TclXML_Info *parser; + ClientData clientData; + TclXML_EndDoctypeDeclProc *callback; +{ + parser->endDoctypeDecl = callback; + parser->enddoctypedecldata = clientData; + + if (parser->endDoctypeDeclCommand) { + Tcl_DecrRefCount(parser->endDoctypeDeclCommand); + parser->endDoctypeDeclCommand = NULL; + } + + return TCL_OK; +} |