diff --git a/ChangeLog b/ChangeLog index 85f869a9..b7063548 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +Thu May 15 18:06:18 EDT 2003 Daniel Veillard <daniel@veillard.com> + + * build_glob.py global.data globals.c parser.c + include/libxml/globals.h: patch from St�phane Bidoul for setting + up threads global defaults. + * doc/libxml2-api.xml: this extends the API with new functions + * python/tests/Makefile.am python/tests/reader2.py + python/tests/thread2.py: integrated the associated testcase and + fixed the error string used in reader2 + Wed May 14 14:56:46 EDT 2003 Daniel Veillard <daniel@veillard.com> * configure.in libxml.spec.in python/Makefile.am: trying diff --git a/build_glob.py b/build_glob.py index dc42c245..8855ec79 100755 --- a/build_glob.py +++ b/build_glob.py @@ -16,10 +16,15 @@ class globvar: self.type=type self.name=name +def striplinesep(line): + while line and line[-1] in ('\r','\n'): + line = line[:-1] + return line + def writeline(file, line=None): if line: file.write(line) - file.write(os.linesep) + file.write("\n") if __name__ == "__main__": globals={} @@ -34,8 +39,7 @@ if __name__ == "__main__": # Automatically generated string # for line in global_hdr: - if line[-len(os.linesep):] == os.linesep: - line = line[:-len(os.linesep)] + line = striplinesep(line) if line == " * Automatically generated by build_glob.py.": break writeline(global_functions_hdr, line) @@ -46,8 +50,7 @@ if __name__ == "__main__": writeline(global_functions_hdr) for line in global_code: - if line[-len(os.linesep):] == os.linesep: - line = line[:-len(os.linesep)] + line = striplinesep(line) if line == " * Automatically generated by build_glob.py.": break writeline(global_functions_impl, line) @@ -61,36 +64,38 @@ if __name__ == "__main__": for line in global_data: if line[0]=='#': continue - if line[-len(os.linesep):] == os.linesep: - line = line[:-len(os.linesep)] + line = striplinesep(line) fields = string.split(line, ",") # Update the header file writeline(global_functions_hdr) global_functions_hdr.write("extern "+fields[0]+" *") - if len(fields) == 3: + if fields[2]: global_functions_hdr.write("(*") global_functions_hdr.write("__"+fields[1]+"(void)") - if len(fields) == 3: + if fields[2]: global_functions_hdr.write(")"+fields[2]) writeline(global_functions_hdr,";") writeline(global_functions_hdr, "#ifdef LIBXML_THREAD_ENABLED") writeline(global_functions_hdr,"#define "+fields[1]+" \\") writeline(global_functions_hdr,"(*(__"+fields[1]+"()))") writeline(global_functions_hdr,"#else") - if len(fields) == 3: + if fields[2]: writeline(global_functions_hdr,"LIBXML_DLL_IMPORT extern "+fields[0]+" "+fields[1]+fields[2]+";") else: writeline(global_functions_hdr,"LIBXML_DLL_IMPORT extern "+fields[0]+" "+fields[1]+";") writeline(global_functions_hdr,"#endif") + # set/get for per-thread global defaults + if fields[3]: + writeline(global_functions_hdr,fields[0]+" "+fields[1][:3]+"ThrDef"+fields[1][3:]+"("+fields[0]+" v);") # Update the implementation file writeline(global_functions_impl) # writeline(global_functions_impl, "extern "+fields[0]+" "+fields[1]+";") writeline(global_functions_impl, "#undef\t"+fields[1]) writeline(global_functions_impl, fields[0]+" *") - if len(fields) == 3: + if fields[2]: global_functions_impl.write("(*") global_functions_impl.write("__"+fields[1]+"(void)") - if len(fields) == 3: + if fields[2]: writeline(global_functions_impl, ")[]") writeline(global_functions_impl, " {") writeline(global_functions_impl, " if (IS_MAIN_THREAD)") @@ -98,6 +103,16 @@ if __name__ == "__main__": writeline(global_functions_impl, " else") writeline(global_functions_impl, "\treturn (&xmlGetGlobalState()->"+fields[1]+");") writeline(global_functions_impl, "}") + # set/get for per-thread global defaults + if fields[3]: + writeline(global_functions_impl,fields[0]+" "+fields[1][:3]+"ThrDef"+fields[1][3:]+"("+fields[0]+" v) {") + writeline(global_functions_impl," "+fields[0]+" ret;"); + writeline(global_functions_impl," xmlMutexLock(xmlThrDefMutex);") + writeline(global_functions_impl," ret = "+fields[1][:3]+fields[1][3:]+"ThrDef;") + writeline(global_functions_impl," "+fields[1][:3]+fields[1][3:]+"ThrDef = v;") + writeline(global_functions_impl," xmlMutexUnlock(xmlThrDefMutex);") + writeline(global_functions_impl," return ret;") + writeline(global_functions_impl,"}") # Terminate the header file with appropriate boilerplate writeline(global_functions_hdr) writeline(global_functions_hdr, "#ifdef __cplusplus") diff --git a/doc/libxml2-api.xml b/doc/libxml2-api.xml index a36a6e58..16ac1508 100644 --- a/doc/libxml2-api.xml +++ b/doc/libxml2-api.xml @@ -1514,6 +1514,7 @@ <exports symbol='oldXMLWDcompatibility'/> <exports symbol='xmlBufferAllocScheme'/> <exports symbol='xmlBufferAllocScheme'/> + <exports symbol='xmlCleanupGlobals'/> <exports symbol='xmlDefaultBufferSize'/> <exports symbol='xmlDefaultBufferSize'/> <exports symbol='xmlDefaultSAXHandler'/> @@ -1538,6 +1539,7 @@ <exports symbol='xmlGlobalStatePtr'/> <exports symbol='xmlIndentTreeOutput'/> <exports symbol='xmlIndentTreeOutput'/> + <exports symbol='xmlInitGlobals'/> <exports symbol='xmlInitializeGlobalState'/> <exports symbol='xmlKeepBlanksDefaultValue'/> <exports symbol='xmlKeepBlanksDefaultValue'/> @@ -1567,6 +1569,22 @@ <exports symbol='xmlSaveNoEmptyTags'/> <exports symbol='xmlSubstituteEntitiesDefaultValue'/> <exports symbol='xmlSubstituteEntitiesDefaultValue'/> + <exports symbol='xmlThrDefBufferAllocScheme'/> + <exports symbol='xmlThrDefDefaultBufferSize'/> + <exports symbol='xmlThrDefDeregisterNodeDefault'/> + <exports symbol='xmlThrDefDoValidityCheckingDefaultValue'/> + <exports symbol='xmlThrDefGetWarningsDefaultValue'/> + <exports symbol='xmlThrDefIndentTreeOutput'/> + <exports symbol='xmlThrDefKeepBlanksDefaultValue'/> + <exports symbol='xmlThrDefLineNumbersDefaultValue'/> + <exports symbol='xmlThrDefLoadExtDtdDefaultValue'/> + <exports symbol='xmlThrDefParserDebugEntities'/> + <exports symbol='xmlThrDefPedanticParserDefaultValue'/> + <exports symbol='xmlThrDefRegisterNodeDefault'/> + <exports symbol='xmlThrDefSaveNoEmptyTags'/> + <exports symbol='xmlThrDefSetGenericErrorFunc'/> + <exports symbol='xmlThrDefSubstituteEntitiesDefaultValue'/> + <exports symbol='xmlThrDefTreeIndentString'/> <exports symbol='xmlTreeIndentString'/> <exports symbol='xmlTreeIndentString'/> </file> @@ -5383,6 +5401,10 @@ actually an xmlCharEncoding'/> <info>Unregisters all aliases</info> <return type='void'/> </function> + <function name='xmlCleanupGlobals' file='globals'> + <info></info> + <return type='void'/> + </function> <function name='xmlCleanupInputCallbacks' file='xmlIO'> <info>clears the entire input callback table. this includes the compiled-in I/O.</info> <return type='void'/> @@ -6439,6 +6461,10 @@ actually an xmlCharEncoding'/> <info>Initialize the char encoding support, it registers the default encoding supported. NOTE: while public, this function usually doesn't need to be called in normal processing.</info> <return type='void'/> </function> + <function name='xmlInitGlobals' file='globals'> + <info></info> + <return type='void'/> + </function> <function name='xmlInitMemory' file='xmlmemory'> <info>Initialize the memory layer.</info> <return type='int' info='0 on success'/> @@ -9300,6 +9326,87 @@ actually an xmlCharEncoding'/> <return type='xmlChar *' info='the xml:lang value or NULL if none exists.'/> <arg name='reader' type='xmlTextReaderPtr' info='the xmlTextReaderPtr used'/> </function> + <function name='xmlThrDefBufferAllocScheme' file='globals'> + <info></info> + <return type='xmlBufferAllocationScheme' info=''/> + <arg name='v' type='xmlBufferAllocationScheme' info=''/> + </function> + <function name='xmlThrDefDefaultBufferSize' file='globals'> + <info></info> + <return type='int' info=''/> + <arg name='v' type='int' info=''/> + </function> + <function name='xmlThrDefDeregisterNodeDefault' file='globals'> + <info></info> + <return type='xmlDeregisterNodeFunc' info=''/> + <arg name='func' type='xmlDeregisterNodeFunc' info=''/> + </function> + <function name='xmlThrDefDoValidityCheckingDefaultValue' file='globals'> + <info></info> + <return type='int' info=''/> + <arg name='v' type='int' info=''/> + </function> + <function name='xmlThrDefGetWarningsDefaultValue' file='globals'> + <info></info> + <return type='int' info=''/> + <arg name='v' type='int' info=''/> + </function> + <function name='xmlThrDefIndentTreeOutput' file='globals'> + <info></info> + <return type='int' info=''/> + <arg name='v' type='int' info=''/> + </function> + <function name='xmlThrDefKeepBlanksDefaultValue' file='globals'> + <info></info> + <return type='int' info=''/> + <arg name='v' type='int' info=''/> + </function> + <function name='xmlThrDefLineNumbersDefaultValue' file='globals'> + <info></info> + <return type='int' info=''/> + <arg name='v' type='int' info=''/> + </function> + <function name='xmlThrDefLoadExtDtdDefaultValue' file='globals'> + <info></info> + <return type='int' info=''/> + <arg name='v' type='int' info=''/> + </function> + <function name='xmlThrDefParserDebugEntities' file='globals'> + <info></info> + <return type='int' info=''/> + <arg name='v' type='int' info=''/> + </function> + <function name='xmlThrDefPedanticParserDefaultValue' file='globals'> + <info></info> + <return type='int' info=''/> + <arg name='v' type='int' info=''/> + </function> + <function name='xmlThrDefRegisterNodeDefault' file='globals'> + <info></info> + <return type='xmlRegisterNodeFunc' info=''/> + <arg name='func' type='xmlRegisterNodeFunc' info=''/> + </function> + <function name='xmlThrDefSaveNoEmptyTags' file='globals'> + <info></info> + <return type='int' info=''/> + <arg name='v' type='int' info=''/> + </function> + <function name='xmlThrDefSetGenericErrorFunc' file='globals'> + <info></info> + <return type='void'/> + <arg name='ctx' type='void *' info=''/> + <arg name='handler' type='xmlGenericErrorFunc' info=''/> + </function> + <function name='xmlThrDefSubstituteEntitiesDefaultValue' file='globals'> + <info></info> + <return type='int' info=''/> + <arg name='v' type='int' info=''/> + </function> + <function name='xmlThrDefTreeIndentString' file='globals'> + <info></info> + <return type='const char *' info=''/> + <arg name='v' type='const char *' info=''/> + </function> <function name='xmlUCSIsAlphabeticPresentationForms' file='xmlunicode'> <info>Check whether the character is part of AlphabeticPresentationForms UCS Block</info> <return type='int' info='1 if true 0 otherwise'/> diff --git a/global.data b/global.data index 6b170dd4..1a8c8a7e 100644 --- a/global.data +++ b/global.data @@ -1,24 +1,25 @@ -int,oldXMLWDcompatibility -xmlBufferAllocationScheme,xmlBufferAllocScheme -int,xmlDefaultBufferSize -xmlSAXHandler,xmlDefaultSAXHandler -xmlSAXLocator,xmlDefaultSAXLocator -int,xmlDoValidityCheckingDefaultValue -xmlGenericErrorFunc,xmlGenericError -void *,xmlGenericErrorContext -int,xmlGetWarningsDefaultValue -int,xmlIndentTreeOutput -const char *,xmlTreeIndentString -int,xmlKeepBlanksDefaultValue -int,xmlLineNumbersDefaultValue -int,xmlLoadExtDtdDefaultValue -int,xmlParserDebugEntities -const char *,xmlParserVersion -int,xmlPedanticParserDefaultValue -int,xmlSaveNoEmptyTags -#const xmlChar,xmlStringComment,[] -#const xmlChar,xmlStringText,[] -#const xmlChar,xmlStringTextNoenc,[] -int,xmlSubstituteEntitiesDefaultValue -xmlRegisterNodeFunc,xmlRegisterNodeDefaultValue -xmlDeregisterNodeFunc,xmlDeregisterNodeDefaultValue +#type,name,array?,threadGlobalDefault accessor? +int,oldXMLWDcompatibility,, +xmlBufferAllocationScheme,xmlBufferAllocScheme,,1 +int,xmlDefaultBufferSize,,1 +xmlSAXHandler,xmlDefaultSAXHandler,, +xmlSAXLocator,xmlDefaultSAXLocator,, +int,xmlDoValidityCheckingDefaultValue,,1 +xmlGenericErrorFunc,xmlGenericError,, +void *,xmlGenericErrorContext,, +int,xmlGetWarningsDefaultValue,,1 +int,xmlIndentTreeOutput,,1 +const char *,xmlTreeIndentString,,1 +int,xmlKeepBlanksDefaultValue,,1 +int,xmlLineNumbersDefaultValue,,1 +int,xmlLoadExtDtdDefaultValue,,1 +int,xmlParserDebugEntities,,1 +const char *,xmlParserVersion,, +int,xmlPedanticParserDefaultValue,,1 +int,xmlSaveNoEmptyTags,,1 +#const xmlChar,xmlStringComment,[],1 +#const xmlChar,xmlStringText,[],1 +#const xmlChar,xmlStringTextNoenc,[],1 +int,xmlSubstituteEntitiesDefaultValue,,1 +xmlRegisterNodeFunc,xmlRegisterNodeDefaultValue,, +xmlDeregisterNodeFunc,xmlDeregisterNodeDefaultValue,, diff --git a/globals.c b/globals.c index 0fc54e27..ee6417bc 100644 --- a/globals.c +++ b/globals.c @@ -21,6 +21,7 @@ #include <libxml/globals.h> #include <libxml/xmlmemory.h> +#include <libxml/threads.h> /* #define DEBUG_GLOBALS */ @@ -33,6 +34,21 @@ #define IS_MAIN_THREAD 1 #endif +/* + * Mutex to protect "ForNewThreads" variables + */ +static xmlMutexPtr xmlThrDefMutex = NULL; + +void xmlInitGlobals() +{ + xmlThrDefMutex = xmlNewMutex(); +} + +void xmlCleanupGlobals() +{ + xmlFreeMutex(xmlThrDefMutex); +} + /************************************************************************ * * * All the user accessible global variables of the library * @@ -150,12 +166,14 @@ const char *xmlParserVersion = LIBXML_VERSION_STRING; * XML_BUFFER_ALLOC_EXACT */ xmlBufferAllocationScheme xmlBufferAllocScheme = XML_BUFFER_ALLOC_EXACT; +static xmlBufferAllocationScheme xmlBufferAllocSchemeThrDef = XML_BUFFER_ALLOC_EXACT; /** * xmlDefaultBufferSize: * * Global setting, default buffer size. Default value is BASE_BUFFER_SIZE */ int xmlDefaultBufferSize = BASE_BUFFER_SIZE; +static int xmlDefaultBufferSizeThrDef = BASE_BUFFER_SIZE; /* * Parser defaults @@ -175,6 +193,7 @@ int oldXMLWDcompatibility = 0; /* DEPRECATED */ * Disabled by default */ int xmlParserDebugEntities = 0; +static int xmlParserDebugEntitiesThrDef = 0; /** * xmlDoValidityCheckingDefaultValue: * @@ -182,6 +201,7 @@ int xmlParserDebugEntities = 0; * Disabled by default. */ int xmlDoValidityCheckingDefaultValue = 0; +static int xmlDoValidityCheckingDefaultValueThrDef = 0; /** * xmlGetWarningsDefaultValue: * @@ -189,6 +209,7 @@ int xmlDoValidityCheckingDefaultValue = 0; * Activated by default. */ int xmlGetWarningsDefaultValue = 1; +static int xmlGetWarningsDefaultValueThrDef = 1; /** * xmlLoadExtDtdDefaultValue: * @@ -197,6 +218,7 @@ int xmlGetWarningsDefaultValue = 1; * Disabled by default. */ int xmlLoadExtDtdDefaultValue = 0; +static int xmlLoadExtDtdDefaultValueThrDef = 0; /** * xmlPedanticParserDefaultValue: * @@ -204,6 +226,7 @@ int xmlLoadExtDtdDefaultValue = 0; * Disabled by default. */ int xmlPedanticParserDefaultValue = 0; +static int xmlPedanticParserDefaultValueThrDef = 0; /** * xmlLineNumbersDefaultValue: * @@ -213,6 +236,7 @@ int xmlPedanticParserDefaultValue = 0; * applicaton. */ int xmlLineNumbersDefaultValue = 0; +static int xmlLineNumbersDefaultValueThrDef = 0; /** * xmlKeepBlanksDefaultValue: * @@ -223,6 +247,7 @@ int xmlLineNumbersDefaultValue = 0; * for some applications since this was libxml1 default behaviour. */ int xmlKeepBlanksDefaultValue = 1; +static int xmlKeepBlanksDefaultValueThrDef = 1; /** * xmlSubstituteEntitiesDefaultValue: * @@ -233,9 +258,12 @@ int xmlKeepBlanksDefaultValue = 1; * engine does not handle entities references transparently. */ int xmlSubstituteEntitiesDefaultValue = 0; +static int xmlSubstituteEntitiesDefaultValueThrDef = 0; xmlRegisterNodeFunc xmlRegisterNodeDefaultValue = NULL; +static xmlRegisterNodeFunc xmlRegisterNodeDefaultValueThrDef = NULL; xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValue = NULL; +static xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValueThrDef = NULL; /* * Error handling @@ -252,12 +280,14 @@ void xmlGenericErrorDefaultFunc (void *ctx ATTRIBUTE_UNUSED, * Global setting: function used for generic error callbacks */ xmlGenericErrorFunc xmlGenericError = xmlGenericErrorDefaultFunc; +static xmlGenericErrorFunc xmlGenericErrorThrDef = xmlGenericErrorDefaultFunc; /** * xmlGenericErrorContext: * * Global setting passed to generic error callbacks */ void *xmlGenericErrorContext = NULL; +static void *xmlGenericErrorContextThrDef = NULL; /* * output defaults @@ -269,6 +299,7 @@ void *xmlGenericErrorContext = NULL; * Enabled by default */ int xmlIndentTreeOutput = 1; +static int xmlIndentTreeOutputThrDef = 1; /** * xmlTreeIndentString: @@ -276,6 +307,7 @@ int xmlIndentTreeOutput = 1; * The string used to do one-level indent. By default is equal to " " (two spaces) */ const char *xmlTreeIndentString = " "; +static const char *xmlTreeIndentStringThrDef = " "; /** * xmlSaveNoEmptyTags: @@ -286,6 +318,7 @@ const char *xmlTreeIndentString = " "; * Disabled by default */ int xmlSaveNoEmptyTags = 0; +int xmlSaveNoEmptyTagsThrDef = 0; /** * xmlDefaultSAXHandler: @@ -427,6 +460,7 @@ xmlInitializeGlobalState(xmlGlobalStatePtr gs) /* * Perform initialization as required by libxml */ + xmlMutexLock(xmlThrDefMutex); #ifdef LIBXML_DOCB_ENABLED initdocbDefaultSAXHandler(&gs->docbDefaultSAXHandler); @@ -434,17 +468,17 @@ xmlInitializeGlobalState(xmlGlobalStatePtr gs) #ifdef LIBXML_HTML_ENABLED inithtmlDefaultSAXHandler(&gs->htmlDefaultSAXHandler); #endif - initGenericErrorDefaultFunc(&gs->xmlGenericError); gs->oldXMLWDcompatibility = 0; - gs->xmlBufferAllocScheme = XML_BUFFER_ALLOC_EXACT; - gs->xmlDefaultBufferSize = BASE_BUFFER_SIZE; + gs->xmlBufferAllocScheme = xmlBufferAllocSchemeThrDef; + gs->xmlDefaultBufferSize = xmlDefaultBufferSizeThrDef; initxmlDefaultSAXHandler(&gs->xmlDefaultSAXHandler, 1); gs->xmlDefaultSAXLocator.getPublicId = getPublicId; gs->xmlDefaultSAXLocator.getSystemId = getSystemId; gs->xmlDefaultSAXLocator.getLineNumber = getLineNumber; gs->xmlDefaultSAXLocator.getColumnNumber = getColumnNumber; - gs->xmlDoValidityCheckingDefaultValue = 0; + gs->xmlDoValidityCheckingDefaultValue = + xmlDoValidityCheckingDefaultValueThrDef; #if defined(DEBUG_MEMORY_LOCATION) | defined(DEBUG_MEMORY) gs->xmlFree = (xmlFreeFunc) xmlMemFree; gs->xmlMalloc = (xmlMallocFunc) xmlMemMalloc; @@ -458,21 +492,36 @@ xmlInitializeGlobalState(xmlGlobalStatePtr gs) gs->xmlRealloc = (xmlReallocFunc) realloc; gs->xmlMemStrdup = (xmlStrdupFunc) xmlStrdup; #endif - gs->xmlGenericErrorContext = NULL; - gs->xmlGetWarningsDefaultValue = 1; - gs->xmlIndentTreeOutput = 1; - gs->xmlTreeIndentString = " "; - gs->xmlKeepBlanksDefaultValue = 1; - gs->xmlLineNumbersDefaultValue = 0; - gs->xmlLoadExtDtdDefaultValue = 0; - gs->xmlParserDebugEntities = 0; + gs->xmlGetWarningsDefaultValue = xmlGetWarningsDefaultValueThrDef; + gs->xmlIndentTreeOutput = xmlIndentTreeOutputThrDef; + gs->xmlTreeIndentString = xmlTreeIndentStringThrDef; + gs->xmlKeepBlanksDefaultValue = xmlKeepBlanksDefaultValueThrDef; + gs->xmlLineNumbersDefaultValue = xmlLineNumbersDefaultValueThrDef; + gs->xmlLoadExtDtdDefaultValue = xmlLoadExtDtdDefaultValueThrDef; + gs->xmlParserDebugEntities = xmlParserDebugEntitiesThrDef; gs->xmlParserVersion = LIBXML_VERSION_STRING; - gs->xmlPedanticParserDefaultValue = 0; - gs->xmlSaveNoEmptyTags = 0; - gs->xmlSubstituteEntitiesDefaultValue = 0; + gs->xmlPedanticParserDefaultValue = xmlPedanticParserDefaultValueThrDef; + gs->xmlSaveNoEmptyTags = xmlSaveNoEmptyTagsThrDef; + gs->xmlSubstituteEntitiesDefaultValue = + xmlSubstituteEntitiesDefaultValueThrDef; - gs->xmlRegisterNodeDefaultValue = NULL; - gs->xmlDeregisterNodeDefaultValue = NULL; + gs->xmlGenericError = xmlGenericErrorThrDef; + gs->xmlGenericErrorContext = xmlGenericErrorContextThrDef; + gs->xmlRegisterNodeDefaultValue = xmlRegisterNodeDefaultValueThrDef; + gs->xmlDeregisterNodeDefaultValue = xmlDeregisterNodeDefaultValueThrDef; + + xmlMutexUnlock(xmlThrDefMutex); +} + +void +xmlThrDefSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) { + xmlMutexLock(xmlThrDefMutex); + xmlGenericErrorContextThrDef = ctx; + if (handler != NULL) + xmlGenericErrorThrDef = handler; + else + xmlGenericErrorThrDef = xmlGenericErrorDefaultFunc; + xmlMutexUnlock(xmlThrDefMutex); } /** @@ -493,6 +542,21 @@ xmlRegisterNodeDefault(xmlRegisterNodeFunc func) return(old); } +xmlRegisterNodeFunc +xmlThrDefRegisterNodeDefault(xmlRegisterNodeFunc func) +{ + xmlRegisterNodeFunc old; + + xmlMutexLock(xmlThrDefMutex); + old = xmlRegisterNodeDefaultValueThrDef; + + __xmlRegisterCallbacks = 1; + xmlRegisterNodeDefaultValueThrDef = func; + xmlMutexUnlock(xmlThrDefMutex); + + return(old); +} + /** * xmlDeregisterNodeDefault: * @func: function pointer to the new DeregisterNodeFunc @@ -511,6 +575,21 @@ xmlDeregisterNodeDefault(xmlDeregisterNodeFunc func) return(old); } +xmlDeregisterNodeFunc +xmlThrDefDeregisterNodeDefault(xmlDeregisterNodeFunc func) +{ + xmlDeregisterNodeFunc old; + + xmlMutexLock(xmlThrDefMutex); + old = xmlDeregisterNodeDefaultValueThrDef; + + __xmlRegisterCallbacks = 1; + xmlDeregisterNodeDefaultValueThrDef = func; + xmlMutexUnlock(xmlThrDefMutex); + + return(old); +} + #ifdef LIBXML_DOCB_ENABLED #undef docbDefaultSAXHandler @@ -558,6 +637,14 @@ __xmlBufferAllocScheme(void) { else return (&xmlGetGlobalState()->xmlBufferAllocScheme); } +xmlBufferAllocationScheme xmlThrDefBufferAllocScheme(xmlBufferAllocationScheme v) { + xmlBufferAllocationScheme ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlBufferAllocSchemeThrDef; + xmlBufferAllocSchemeThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} #undef xmlDefaultBufferSize int * @@ -567,6 +654,14 @@ __xmlDefaultBufferSize(void) { else return (&xmlGetGlobalState()->xmlDefaultBufferSize); } +int xmlThrDefDefaultBufferSize(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlDefaultBufferSizeThrDef; + xmlDefaultBufferSizeThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} #undef xmlDefaultSAXHandler xmlSAXHandler * @@ -594,6 +689,14 @@ __xmlDoValidityCheckingDefaultValue(void) { else return (&xmlGetGlobalState()->xmlDoValidityCheckingDefaultValue); } +int xmlThrDefDoValidityCheckingDefaultValue(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlDoValidityCheckingDefaultValueThrDef; + xmlDoValidityCheckingDefaultValueThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} #undef xmlGenericError xmlGenericErrorFunc * @@ -621,6 +724,14 @@ __xmlGetWarningsDefaultValue(void) { else return (&xmlGetGlobalState()->xmlGetWarningsDefaultValue); } +int xmlThrDefGetWarningsDefaultValue(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlGetWarningsDefaultValueThrDef; + xmlGetWarningsDefaultValueThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} #undef xmlIndentTreeOutput int * @@ -630,6 +741,14 @@ __xmlIndentTreeOutput(void) { else return (&xmlGetGlobalState()->xmlIndentTreeOutput); } +int xmlThrDefIndentTreeOutput(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlIndentTreeOutputThrDef; + xmlIndentTreeOutputThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} #undef xmlTreeIndentString const char * * @@ -639,6 +758,14 @@ __xmlTreeIndentString(void) { else return (&xmlGetGlobalState()->xmlTreeIndentString); } +const char * xmlThrDefTreeIndentString(const char * v) { + const char * ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlTreeIndentStringThrDef; + xmlTreeIndentStringThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} #undef xmlKeepBlanksDefaultValue int * @@ -648,6 +775,14 @@ __xmlKeepBlanksDefaultValue(void) { else return (&xmlGetGlobalState()->xmlKeepBlanksDefaultValue); } +int xmlThrDefKeepBlanksDefaultValue(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlKeepBlanksDefaultValueThrDef; + xmlKeepBlanksDefaultValueThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} #undef xmlLineNumbersDefaultValue int * @@ -657,6 +792,14 @@ __xmlLineNumbersDefaultValue(void) { else return (&xmlGetGlobalState()->xmlLineNumbersDefaultValue); } +int xmlThrDefLineNumbersDefaultValue(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlLineNumbersDefaultValueThrDef; + xmlLineNumbersDefaultValueThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} #undef xmlLoadExtDtdDefaultValue int * @@ -666,6 +809,14 @@ __xmlLoadExtDtdDefaultValue(void) { else return (&xmlGetGlobalState()->xmlLoadExtDtdDefaultValue); } +int xmlThrDefLoadExtDtdDefaultValue(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlLoadExtDtdDefaultValueThrDef; + xmlLoadExtDtdDefaultValueThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} #undef xmlParserDebugEntities int * @@ -675,6 +826,14 @@ __xmlParserDebugEntities(void) { else return (&xmlGetGlobalState()->xmlParserDebugEntities); } +int xmlThrDefParserDebugEntities(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlParserDebugEntitiesThrDef; + xmlParserDebugEntitiesThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} #undef xmlParserVersion const char * * @@ -693,6 +852,14 @@ __xmlPedanticParserDefaultValue(void) { else return (&xmlGetGlobalState()->xmlPedanticParserDefaultValue); } +int xmlThrDefPedanticParserDefaultValue(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlPedanticParserDefaultValueThrDef; + xmlPedanticParserDefaultValueThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} #undef xmlSaveNoEmptyTags int * @@ -702,6 +869,14 @@ __xmlSaveNoEmptyTags(void) { else return (&xmlGetGlobalState()->xmlSaveNoEmptyTags); } +int xmlThrDefSaveNoEmptyTags(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlSaveNoEmptyTagsThrDef; + xmlSaveNoEmptyTagsThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} #undef xmlSubstituteEntitiesDefaultValue int * @@ -711,6 +886,14 @@ __xmlSubstituteEntitiesDefaultValue(void) { else return (&xmlGetGlobalState()->xmlSubstituteEntitiesDefaultValue); } +int xmlThrDefSubstituteEntitiesDefaultValue(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlSubstituteEntitiesDefaultValueThrDef; + xmlSubstituteEntitiesDefaultValueThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} #undef xmlRegisterNodeDefaultValue xmlRegisterNodeFunc * diff --git a/include/libxml/globals.h b/include/libxml/globals.h index 9a7e3d1b..3a832f6a 100644 --- a/include/libxml/globals.h +++ b/include/libxml/globals.h @@ -22,6 +22,9 @@ extern "C" { #endif +void xmlInitGlobals(void); +void xmlCleanupGlobals(void); + /* * Externally global symbols which need to be protected for backwards * compatibility support. @@ -112,8 +115,12 @@ extern "C" { void xmlInitializeGlobalState(xmlGlobalStatePtr gs); +void xmlThrDefSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler); + xmlRegisterNodeFunc xmlRegisterNodeDefault(xmlRegisterNodeFunc func); +xmlRegisterNodeFunc xmlThrDefRegisterNodeDefault(xmlRegisterNodeFunc func); xmlDeregisterNodeFunc xmlDeregisterNodeDefault(xmlDeregisterNodeFunc func); +xmlDeregisterNodeFunc xmlThrDefDeregisterNodeDefault(xmlDeregisterNodeFunc func); /* * In general the memory allocation entry points are not kept @@ -217,6 +224,7 @@ extern xmlBufferAllocationScheme *__xmlBufferAllocScheme(void); #else LIBXML_DLL_IMPORT extern xmlBufferAllocationScheme xmlBufferAllocScheme; #endif +xmlBufferAllocationScheme xmlThrDefBufferAllocScheme(xmlBufferAllocationScheme v); extern int *__xmlDefaultBufferSize(void); #ifdef LIBXML_THREAD_ENABLED @@ -225,6 +233,7 @@ extern int *__xmlDefaultBufferSize(void); #else LIBXML_DLL_IMPORT extern int xmlDefaultBufferSize; #endif +int xmlThrDefDefaultBufferSize(int v); extern xmlSAXHandler *__xmlDefaultSAXHandler(void); #ifdef LIBXML_THREAD_ENABLED @@ -249,6 +258,7 @@ extern int *__xmlDoValidityCheckingDefaultValue(void); #else LIBXML_DLL_IMPORT extern int xmlDoValidityCheckingDefaultValue; #endif +int xmlThrDefDoValidityCheckingDefaultValue(int v); extern xmlGenericErrorFunc *__xmlGenericError(void); #ifdef LIBXML_THREAD_ENABLED @@ -273,6 +283,7 @@ extern int *__xmlGetWarningsDefaultValue(void); #else LIBXML_DLL_IMPORT extern int xmlGetWarningsDefaultValue; #endif +int xmlThrDefGetWarningsDefaultValue(int v); extern int *__xmlIndentTreeOutput(void); #ifdef LIBXML_THREAD_ENABLED @@ -281,6 +292,7 @@ extern int *__xmlIndentTreeOutput(void); #else LIBXML_DLL_IMPORT extern int xmlIndentTreeOutput; #endif +int xmlThrDefIndentTreeOutput(int v); extern const char * *__xmlTreeIndentString(void); #ifdef LIBXML_THREAD_ENABLED @@ -289,6 +301,7 @@ extern const char * *__xmlTreeIndentString(void); #else LIBXML_DLL_IMPORT extern const char * xmlTreeIndentString; #endif +const char * xmlThrDefTreeIndentString(const char * v); extern int *__xmlKeepBlanksDefaultValue(void); #ifdef LIBXML_THREAD_ENABLED @@ -297,6 +310,7 @@ extern int *__xmlKeepBlanksDefaultValue(void); #else LIBXML_DLL_IMPORT extern int xmlKeepBlanksDefaultValue; #endif +int xmlThrDefKeepBlanksDefaultValue(int v); extern int *__xmlLineNumbersDefaultValue(void); #ifdef LIBXML_THREAD_ENABLED @@ -305,6 +319,7 @@ extern int *__xmlLineNumbersDefaultValue(void); #else LIBXML_DLL_IMPORT extern int xmlLineNumbersDefaultValue; #endif +int xmlThrDefLineNumbersDefaultValue(int v); extern int *__xmlLoadExtDtdDefaultValue(void); #ifdef LIBXML_THREAD_ENABLED @@ -313,6 +328,7 @@ extern int *__xmlLoadExtDtdDefaultValue(void); #else LIBXML_DLL_IMPORT extern int xmlLoadExtDtdDefaultValue; #endif +int xmlThrDefLoadExtDtdDefaultValue(int v); extern int *__xmlParserDebugEntities(void); #ifdef LIBXML_THREAD_ENABLED @@ -321,6 +337,7 @@ extern int *__xmlParserDebugEntities(void); #else LIBXML_DLL_IMPORT extern int xmlParserDebugEntities; #endif +int xmlThrDefParserDebugEntities(int v); extern const char * *__xmlParserVersion(void); #ifdef LIBXML_THREAD_ENABLED @@ -337,6 +354,7 @@ extern int *__xmlPedanticParserDefaultValue(void); #else LIBXML_DLL_IMPORT extern int xmlPedanticParserDefaultValue; #endif +int xmlThrDefPedanticParserDefaultValue(int v); extern int *__xmlSaveNoEmptyTags(void); #ifdef LIBXML_THREAD_ENABLED @@ -345,6 +363,7 @@ extern int *__xmlSaveNoEmptyTags(void); #else LIBXML_DLL_IMPORT extern int xmlSaveNoEmptyTags; #endif +int xmlThrDefSaveNoEmptyTags(int v); extern int *__xmlSubstituteEntitiesDefaultValue(void); #ifdef LIBXML_THREAD_ENABLED @@ -353,6 +372,7 @@ extern int *__xmlSubstituteEntitiesDefaultValue(void); #else LIBXML_DLL_IMPORT extern int xmlSubstituteEntitiesDefaultValue; #endif +int xmlThrDefSubstituteEntitiesDefaultValue(int v); extern xmlRegisterNodeFunc *__xmlRegisterNodeDefaultValue(void); #ifdef LIBXML_THREAD_ENABLED diff --git a/parser.c b/parser.c index faeda8d6..40ffd20d 100644 --- a/parser.c +++ b/parser.c @@ -11140,6 +11140,7 @@ xmlInitParser(void) { if ((xmlGenericError == xmlGenericErrorDefaultFunc) || (xmlGenericError == NULL)) initGenericErrorDefaultFunc(NULL); + xmlInitGlobals(); xmlInitThreads(); xmlInitMemory(); xmlInitCharEncodingHandlers(); @@ -11176,5 +11177,6 @@ xmlCleanupParser(void) { xmlCatalogCleanup(); #endif xmlCleanupThreads(); + xmlCleanupGlobals(); xmlParserInitialized = 0; } diff --git a/python/libxml.c b/python/libxml.c index a9435308..e3728359 100644 --- a/python/libxml.c +++ b/python/libxml.c @@ -1267,6 +1267,7 @@ libxml_xmlErrorInitialize(void) printf("libxml_xmlErrorInitialize() called\n"); #endif xmlSetGenericErrorFunc(NULL, libxml_xmlErrorFuncHandler); + xmlThrDefSetGenericErrorFunc(NULL, libxml_xmlErrorFuncHandler); } PyObject * @@ -1767,7 +1768,7 @@ libxml_xpathCallbacksInitialize(void) printf("libxml_xpathCallbacksInitialized called\n"); #endif - for (i = 0; i < 10; i++) { + for (i = 0; i < libxml_xpathCallbacksMax; i++) { libxml_xpathCallbacks[i].ctx = NULL; libxml_xpathCallbacks[i].name = NULL; libxml_xpathCallbacks[i].ns_uri = NULL; @@ -2620,6 +2621,8 @@ initlibxml2mod(void) if (initialized != 0) return; + /* XXX xmlInitParser does much more than this */ + xmlInitGlobals(); xmlRegisterDefaultOutputCallbacks(); xmlRegisterDefaultInputCallbacks(); m = Py_InitModule((char *) "libxml2mod", libxmlMethods); diff --git a/python/libxml2class.txt b/python/libxml2class.txt index e4587f88..b33c8733 100644 --- a/python/libxml2class.txt +++ b/python/libxml2class.txt @@ -63,6 +63,22 @@ cleanupPredefinedEntities() initializePredefinedEntities() predefinedEntity() +# functions from module globals +cleanupGlobals() +initGlobals() +thrDefDefaultBufferSize() +thrDefDoValidityCheckingDefaultValue() +thrDefGetWarningsDefaultValue() +thrDefIndentTreeOutput() +thrDefKeepBlanksDefaultValue() +thrDefLineNumbersDefaultValue() +thrDefLoadExtDtdDefaultValue() +thrDefParserDebugEntities() +thrDefPedanticParserDefaultValue() +thrDefSaveNoEmptyTags() +thrDefSubstituteEntitiesDefaultValue() +thrDefTreeIndentString() + # functions from module nanoftp nanoFTPCleanup() nanoFTPInit() diff --git a/python/tests/Makefile.am b/python/tests/Makefile.am index 0c16acf0..d4e91dd5 100644 --- a/python/tests/Makefile.am +++ b/python/tests/Makefile.am @@ -28,7 +28,8 @@ PYTESTS= \ reader6.py \ ctxterror.py\ readererr.py\ - relaxng.py + relaxng.py \ + thread2.py XMLS= \ tst.xml \ diff --git a/python/tests/reader2.py b/python/tests/reader2.py index f8ca2541..afc3586a 100755 --- a/python/tests/reader2.py +++ b/python/tests/reader2.py @@ -14,10 +14,10 @@ libxml2.debugMemory(1) err="" expect="""../../test/valid/rss.xml:172: validity error: Element rss does not carry attribute version </rss> - ^ + ^ ../../test/valid/xlink.xml:450: validity error: ID dt-arc already defined <p><termdef id="dt-arc" term="Arc">An <ter - ^ + ^ ../../test/valid/xlink.xml:530: validity error: attribute def line 199 references an unknown ID "dt-xlg" ^ diff --git a/python/tests/thread2.py b/python/tests/thread2.py new file mode 100755 index 00000000..c8ac5ed3 --- /dev/null +++ b/python/tests/thread2.py @@ -0,0 +1,96 @@ +#!/usr/bin/python -u +import string, sys, time +import thread +from threading import Thread, Lock + +import libxml2 + +THREADS_COUNT = 15 + +failed = 0 + +class ErrorHandler: + + def __init__(self): + self.errors = [] + self.lock = Lock() + + def handler(self,ctx,str): + self.lock.acquire() + self.errors.append(str) + self.lock.release() + +def getLineNumbersDefault(): + old = libxml2.lineNumbersDefault(0) + libxml2.lineNumbersDefault(old) + return old + +def test(expectedLineNumbersDefault): + time.sleep(1) + global failed + # check a per thread-global + if expectedLineNumbersDefault != getLineNumbersDefault(): + failed = 1 + print "FAILED to obtain correct value for " \ + "lineNumbersDefault in thread %d" % thread.get_ident() + # check ther global error handler + # (which is NOT per-thread in the python bindings) + try: + doc = libxml2.parseFile("bad.xml") + except: + pass + else: + assert "failed" + +# global error handler +eh = ErrorHandler() +libxml2.registerErrorHandler(eh.handler,"") + +# set on the main thread only +libxml2.lineNumbersDefault(1) +test(1) +ec = len(eh.errors) +if ec == 0: + print "FAILED: should have obtained errors" + sys.exit(1) + +ts = [] +for i in range(THREADS_COUNT): + # expect 0 for lineNumbersDefault because + # the new value has been set on the main thread only + ts.append(Thread(target=test,args=(0,))) +for t in ts: + t.start() +for t in ts: + t.join() + +if len(eh.errors) != ec+THREADS_COUNT*ec: + print "FAILED: did not obtain the correct number of errors" + sys.exit(1) + +# set lineNumbersDefault for future new threads +libxml2.thrDefLineNumbersDefaultValue(1) +ts = [] +for i in range(THREADS_COUNT): + # expect 1 for lineNumbersDefault + ts.append(Thread(target=test,args=(1,))) +for t in ts: + t.start() +for t in ts: + t.join() + +if len(eh.errors) != ec+THREADS_COUNT*ec*2: + print "FAILED: did not obtain the correct number of errors" + sys.exit(1) + +if failed: + print "FAILED" + sys.exit(1) + +# Memory debug specific +libxml2.cleanupParser() +if libxml2.debugMemory(1) == 0: + print "OK" +else: + print "Memory leak %d bytes" % (libxml2.debugMemory(1)) + libxml2.dumpMemory()