summaryrefslogtreecommitdiffstats
path: root/tclxml/tclxslt-libxslt.c
diff options
context:
space:
mode:
Diffstat (limited to 'tclxml/tclxslt-libxslt.c')
-rw-r--r--tclxml/tclxslt-libxslt.c1872
1 files changed, 0 insertions, 1872 deletions
diff --git a/tclxml/tclxslt-libxslt.c b/tclxml/tclxslt-libxslt.c
deleted file mode 100644
index 73e0f61..0000000
--- a/tclxml/tclxslt-libxslt.c
+++ /dev/null
@@ -1,1872 +0,0 @@
-/*
- * tclxslt.c --
- *
- * Interface to Gnome libxslt.
- *
- * Copyright (c) 2005-2007 Explain
- * http://www.explain.com.au/
- * Copyright (c) 2001-2004 Zveno Pty Ltd
- * http://www.zveno.com/
- *
- * See the file "LICENSE" for information on usage and
- * redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * $Id: tclxslt-libxslt.c,v 1.2 2016/01/15 21:06:01 joye Exp $
- *
- */
-
-#include <tclxslt/tclxslt.h>
-#include <string.h>
-#include <libxslt/imports.h>
-#include <libxslt/security.h>
-
-#undef TCL_STORAGE_CLASS
-#define TCL_STORAGE_CLASS DLLEXPORT
-
-#ifdef __WIN32__
-/*# include "win/win32config.h"*/
-#endif
-
-/*
- * Manage stylesheet objects
- */
-
-typedef struct TclXSLT_Stylesheet {
- Tcl_Interp *interp;
- char *name;
- xsltStylesheetPtr stylesheet;
- Tcl_HashEntry *entryPtr;
-
- Tcl_Obj *resulturi;
- Tcl_Obj *profilechannelObj;
-
- Tcl_Obj *messagecommand;
-} TclXSLT_Stylesheet;
-
-/*
- * Extension management
- */
-
-typedef struct TclXSLT_Extension {
- Tcl_Interp *interp;
- Tcl_Obj *nsuri;
- Tcl_Obj *tclns;
- xsltTransformContextPtr xformCtxt;
-} TclXSLT_Extension;
-
-typedef struct ThreadSpecificData {
- int initialised;
- Tcl_Interp *interp;
- int ssheetCntr;
- Tcl_HashTable *stylesheets;
- Tcl_HashTable *extensions;
-} ThreadSpecificData;
-static Tcl_ThreadDataKey dataKey;
-
-/*
- * Prototypes for procedures defined later in this file:
- */
-
-/*
- * Forward declarations for private functions.
- */
-
-static void TclXSLTGenericError _ANSI_ARGS_((void *ctx, const char *msg, ...));
-
-static int TclXSLTCompileCommand _ANSI_ARGS_((ClientData dummy,
- Tcl_Interp *interp,
- int objc,
- Tcl_Obj *CONST objv[]));
-static int TclXSLTInstanceCommand _ANSI_ARGS_((ClientData ssheet,
- Tcl_Interp *interp,
- int objc,
- Tcl_Obj *CONST objv[]));
-static void TclXSLTDeleteStylesheet _ANSI_ARGS_((ClientData ssheet));
-static int TclXSLTExtensionCommand _ANSI_ARGS_((ClientData dummy,
- Tcl_Interp *interp,
- int objc,
- Tcl_Obj *CONST objv[]));
-
-static Tcl_Obj * GetParameters _ANSI_ARGS_((Tcl_Interp *interp,
- xsltStylesheetPtr stylesheet));
-static int TclXSLTTransform _ANSI_ARGS_((TclXSLT_Stylesheet *stylesheet,
- Tcl_Obj *source,
- int paramc,
- Tcl_Obj *CONST paramv[]));
-
-static void TclXSLT_RegisterAll _ANSI_ARGS_((TclXSLT_Extension *extinfo,
- const xmlChar *nsuri));
-
-/* static xsltExtInitFunction TclXSLTExtInit; */
-static void *TclXSLTExtInit _ANSI_ARGS_((xsltTransformContextPtr ctxt,
- const xmlChar *URI));
-/* static xsltExtShutdownFunction TclXSLTExtShutdown; */
-static void TclXSLTExtShutdown _ANSI_ARGS_((xsltTransformContextPtr ctxt,
- const xmlChar *URI,
- void *userdata));
-/* static xmlXPathEvalFunc TclXSLTExtFunction; */
-static void TclXSLTExtFunction _ANSI_ARGS_((xmlXPathParserContextPtr xpathCtxt,
- int nargs));
-/* static xsltPreComputeFunction TclXSLTExtElementPreComp; */
-static void TclXSLTExtElementPreComp _ANSI_ARGS_((xsltStylesheetPtr style,
- xmlNodePtr inst,
- xsltTransformFunction function));
-/* static xsltTransformFunction TclXSLTExtElementTransform; */
-static void TclXSLTExtElementTransform _ANSI_ARGS_((xsltTransformContextPtr ctxt,
- xmlNodePtr node,
- xmlNodePtr inst,
- xsltStylePreCompPtr comp));
-/* static xsltSecurityCheck TclXSLTSecurityReadFile; */
-static int TclXSLTSecurityReadFile _ANSI_ARGS_((xsltSecurityPrefsPtr sec,
- xsltTransformContextPtr ctxt,
- const char *value));
-/* static xsltSecurityCheck TclXSLTSecurityWriteFile; */
-static int TclXSLTSecurityWriteFile _ANSI_ARGS_((xsltSecurityPrefsPtr sec,
- xsltTransformContextPtr ctxt,
- const char *value));
-/* static xsltSecurityCheck TclXSLTSecurityCreateDirectory; */
-static int TclXSLTSecurityCreateDirectory _ANSI_ARGS_((xsltSecurityPrefsPtr sec,
- xsltTransformContextPtr ctxt,
- const char *value));
-/* static xsltSecurityCheck TclXSLTSecurityReadNetwork; */
-static int TclXSLTSecurityReadNetwork _ANSI_ARGS_((xsltSecurityPrefsPtr sec,
- xsltTransformContextPtr ctxt,
- const char *value));
-/* static xsltSecurityCheck TclXSLTSecurityWriteNetwork; */
-static int TclXSLTSecurityWriteNetwork _ANSI_ARGS_((xsltSecurityPrefsPtr sec,
- xsltTransformContextPtr ctxt,
- const char *value));
-
-static Tcl_Obj * TclXSLT_ConvertXPathObjToTclObj _ANSI_ARGS_((Tcl_Interp *interp,
- xmlXPathObjectPtr xpobj));
-static xmlXPathObjectPtr TclXSLT_ConvertTclObjToXPathObj _ANSI_ARGS_((Tcl_Interp *interp,
- Tcl_Obj *objPtr));
-
-/*
- * Error context for passing error result back to caller.
- */
-
-typedef struct GenericError_Info {
- Tcl_Interp *interp;
- TclXSLT_Stylesheet *stylesheet;
- int code;
- Tcl_Obj *msg;
-} GenericError_Info;
-
-/*
- * Switch tables
- */
-
-#ifndef CONST84
-#define CONST84 /* Before 8.4 no 'const' required */
-#endif
-
-static CONST84 char *instanceCommandMethods[] = {
- "cget",
- "configure",
- "get",
- "transform",
- (char *) NULL
-};
-enum instanceCommandMethods {
- TCLXSLT_CGET,
- TCLXSLT_CONFIGURE,
- TCLXSLT_GET,
- TCLXSLT_TRANSFORM
-};
-static CONST84 char *instanceCommandOptions[] = {
- "-messagecommand",
- "-method",
- "-indent",
- "-resulturi",
- "-profilechannel",
- "-encoding",
- "-omitxmldeclaration",
- (char *) NULL
-};
-enum instanceCommandOptions {
- TCLXSLT_OPTION_MESSAGECOMMAND,
- TCLXSLT_OPTION_METHOD,
- TCLXSLT_OPTION_INDENT,
- TCLXSLT_OPTION_RESULTURI,
- TCLXSLT_OPTION_PROFILECHANNEL,
- TCLXSLT_OPTION_ENCODING,
- TCLXSLT_OPTION_OMITXMLDECLARATION
-};
-
-static CONST84 char *instanceGetMethods[] = {
- "parameters",
- (char *) NULL
-};
-enum instanceGetMethods {
- TCLXSLT_GET_PARAMETERS
-};
-
-static CONST84 char *extensionCommandMethods[] = {
- "add",
- "remove",
- (char *) NULL
-};
-enum extensionCommandMethods {
- TCLXSLT_EXT_ADD,
- TCLXSLT_EXT_REMOVE
-};
-
-/*
- * libxml2 and libxslt are mostly thread-safe,
- * but there are issues with error callbacks.
- */
-
-TCL_DECLARE_MUTEX(libxslt)
-
-/*
- *----------------------------------------------------------------------------
- *
- * Tclxslt_libxslt_Init --
- *
- * Initialisation routine for loadable module
- *
- * Results:
- * None.
- *
- * Side effects:
- * Creates commands in the interpreter,
- *
- *----------------------------------------------------------------------------
- */
-
-int
-Tclxslt_libxslt_Init (interp)
- Tcl_Interp *interp; /* Interpreter to initialise */
-{
- ThreadSpecificData *tsdPtr;
- xsltSecurityPrefsPtr sec;
-
- tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- if (!tsdPtr->initialised) {
- tsdPtr->initialised = 1;
- tsdPtr->interp = interp;
- tsdPtr->ssheetCntr = 0;
- tsdPtr->stylesheets = (Tcl_HashTable *) Tcl_Alloc(sizeof(Tcl_HashTable));
- Tcl_InitHashTable(tsdPtr->stylesheets, TCL_ONE_WORD_KEYS);
- tsdPtr->extensions = (Tcl_HashTable *) Tcl_Alloc(sizeof(Tcl_HashTable));
- Tcl_InitHashTable(tsdPtr->extensions, TCL_STRING_KEYS);
- } /* only need to init the library once per process */
-
- Tcl_CreateObjCommand(interp, "xslt::compile", TclXSLTCompileCommand, NULL, NULL);
- Tcl_CreateObjCommand(interp, "xslt::extension", TclXSLTExtensionCommand, NULL, NULL);
-
- Tcl_MutexLock(&libxslt);
-#ifndef TCLXML_STATIC_TCLXSLT
- exsltRegisterAll();
-#endif /* TCLXML_STATIC_TCLXSLT */
-
- /*
- * Setup security preferences
- */
- sec = xsltNewSecurityPrefs();
- if (xsltSetSecurityPrefs(sec, XSLT_SECPREF_READ_FILE,
- TclXSLTSecurityReadFile)) {
- Tcl_SetResult(interp, "unable to set readfile security", NULL);
- return TCL_ERROR;
- }
- if (xsltSetSecurityPrefs(sec, XSLT_SECPREF_WRITE_FILE,
- TclXSLTSecurityWriteFile)) {
- Tcl_SetResult(interp, "unable to set writefile security", NULL);
- return TCL_ERROR;
- }
- if (xsltSetSecurityPrefs(sec, XSLT_SECPREF_CREATE_DIRECTORY,
- TclXSLTSecurityCreateDirectory)) {
- Tcl_SetResult(interp, "unable to set createdirectory security", NULL);
- return TCL_ERROR;
- }
- if (xsltSetSecurityPrefs(sec, XSLT_SECPREF_READ_NETWORK,
- TclXSLTSecurityReadNetwork)) {
- Tcl_SetResult(interp, "unable to set readnetwork security", NULL);
- return TCL_ERROR;
- }
- if (xsltSetSecurityPrefs(sec, XSLT_SECPREF_WRITE_NETWORK,
- TclXSLTSecurityWriteNetwork)) {
- Tcl_SetResult(interp, "unable to set writenetwork security", NULL);
- return TCL_ERROR;
- }
- /* xsltSetCtxtSecurityPrefs(sec, userCtxt); */
- xsltSetDefaultSecurityPrefs(sec);
-
- Tcl_MutexUnlock(&libxslt);
-
- Tcl_SetVar2Ex(interp, "::xslt::libxsltversion", NULL, Tcl_NewStringObj(xsltEngineVersion, -1), 0);
- Tcl_SetVar2Ex(interp, "::xslt::libexsltversion", NULL, Tcl_NewStringObj(exsltLibraryVersion, -1), 0);
-
- return TCL_OK;
-}
-
-/*
- * XSLT is not safe due to the document(), xsl:include and xsl:import functions/elements.
- * However, libxslt checks whether access is permitted to external resources.
- *
- * NOTE: need to make sure decision to allow access to resources is made by a trusted interpreter, not the untrusted slave. Even better, use a mechanism similar to TclXML/libxml2 to access external resources.
- */
-
-int
-Tclxslt_libxslt_SafeInit (interp)
- Tcl_Interp *interp; /* Interpreter to initialise */
-{
- return Tclxslt_libxslt_Init(interp);
-}
-
-/*
- *----------------------------------------------------------------------------
- *
- * TclXSLTCompileCommand --
- *
- * Class creation command for xslt stylesheet objects.
- *
- * Results:
- * Compiles the XSLT stylesheet.
- * Creates a Tcl command associated with that stylesheet.
- *
- * Side effects:
- * Memory allocated, stylesheet is compiled.
- *
- *----------------------------------------------------------------------------
- */
-
-static int
-TclXSLTCompileCommand(dummy, interp, objc, objv)
- ClientData dummy;
- Tcl_Interp *interp;
- int objc;
- Tcl_Obj *CONST objv[];
-{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- TclXSLT_Stylesheet *info;
- xmlDocPtr origDoc, doc;
- xsltStylesheetPtr ssheetPtr = NULL;
- void *oldxsltErrorCtx, *oldxmlErrorCtx;
- xmlGenericErrorFunc old_xsltGenericError, old_xmlGenericError;
- GenericError_Info *errorInfoPtr;
- Tcl_Obj *errObjPtr = NULL;
- int new;
-
- if (objc != 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "stylesheet-doc");
- return TCL_ERROR;
- }
-
- if (TclXML_libxml2_GetDocFromObj(interp, objv[1], &origDoc) != TCL_OK) {
- return TCL_ERROR;
- }
-
- Tcl_MutexLock(&libxslt);
- doc = xmlCopyDoc(origDoc, 1);
- /*
- * xmlCopyDoc doesn't copy some of the fields.
- */
- if (origDoc->URL) {
- doc->URL = (const xmlChar *) Tcl_Alloc(strlen((char *) origDoc->URL) + 1);
- strcpy((char *) doc->URL, (char *) origDoc->URL);
- }
-
- /*
- * Prepare for compiling stylesheet
- */
-
- TclXML_libxml2_ResetError(interp);
-
- errorInfoPtr = (GenericError_Info *) Tcl_Alloc(sizeof(GenericError_Info));
- errorInfoPtr->interp = interp;
- errorInfoPtr->stylesheet = NULL;
- errorInfoPtr->code = TCL_OK;
- errorInfoPtr->msg = NULL;
- xmlSetGenericErrorFunc((void *) errorInfoPtr,
- TclXSLTGenericError);
-
- /*
- * Save the previous error context so that it can
- * be restored upon completion of the operation.
- */
- old_xsltGenericError = xsltGenericError;
- oldxsltErrorCtx = xsltGenericErrorContext;
- old_xmlGenericError = xmlGenericError;
- oldxmlErrorCtx = xmlGenericErrorContext;
-
- xmlSetGenericErrorFunc((void *) errorInfoPtr,
- TclXSLTGenericError);
- xsltSetGenericErrorFunc((void *) errorInfoPtr, TclXSLTGenericError);
-
- /*
- * Compile stylesheet
- */
-
- ssheetPtr = xsltParseStylesheetDoc(doc);
-
- xmlSetGenericErrorFunc((void *) oldxmlErrorCtx, old_xmlGenericError);
- xsltSetGenericErrorFunc((void *) oldxsltErrorCtx, old_xsltGenericError);
-
- Tcl_MutexUnlock(&libxslt);
-
- errObjPtr = TclXML_libxml2_GetErrorObj(interp);
-
- if (ssheetPtr == NULL) {
- Tcl_SetResult(interp, "error compiling stylesheet", NULL);
- goto error;
- }
-
- if (ssheetPtr->errors > 0) {
- Tcl_SetResult(interp, "error compiling XSLT stylesheet", NULL);
- goto error;
- }
-
- if (errorInfoPtr->code != TCL_OK) {
- goto error;
- }
-
- /* TODO: notify app of any warnings */
-
- info = (TclXSLT_Stylesheet *) Tcl_Alloc(sizeof(TclXSLT_Stylesheet));
- info->interp = interp;
- info->name = Tcl_Alloc(20);
- sprintf(info->name, "style%d", tsdPtr->ssheetCntr++);
- info->stylesheet = ssheetPtr;
- info->messagecommand = NULL;
- info->resulturi = NULL;
- info->profilechannelObj = NULL;
-
- /*
- * Create reverse mapping of stylesheet to name of stylesheet command.
- */
- info->entryPtr = Tcl_CreateHashEntry(tsdPtr->stylesheets, (ClientData) ssheetPtr, &new);
- /* sanity check: new == 1 */
- Tcl_SetHashValue(info->entryPtr, (ClientData) info->name);
-
- Tcl_CreateObjCommand(interp, info->name, TclXSLTInstanceCommand, (ClientData) info, TclXSLTDeleteStylesheet);
-
- Tcl_SetObjResult(interp, Tcl_NewStringObj(info->name, -1));
-
- return TCL_OK;
-
-error:
-
- if (errObjPtr) {
- Tcl_SetObjResult(interp, errObjPtr);
- } else if (errorInfoPtr->msg) {
- Tcl_SetObjResult(interp, errorInfoPtr->msg);
- Tcl_DecrRefCount(errorInfoPtr->msg);
- }
- Tcl_Free((char *) errorInfoPtr);
-
- Tcl_MutexLock(&libxslt);
- if (ssheetPtr) {
- xsltFreeStylesheet(ssheetPtr);
- } else {
- xmlFreeDoc(doc);
- }
- Tcl_MutexUnlock(&libxslt);
-
- return TCL_ERROR;
-}
-
-/*
- *----------------------------------------------------------------------------
- *
- * TclXSLTDeleteStylesheet --
- *
- * Class destruction command for xslt stylesheet objects.
- *
- * Results:
- * Frees memory associated with a stylesheet.
- *
- * Side effects:
- * Memory deallocated.
- *
- *----------------------------------------------------------------------------
- */
-
-static void
-TclXSLTDeleteStylesheet(clientData)
- ClientData clientData;
-{
- TclXSLT_Stylesheet *ssheet = (TclXSLT_Stylesheet *) clientData;
-
- Tcl_DeleteHashEntry(ssheet->entryPtr);
-
- Tcl_Free(ssheet->name);
- if (ssheet->messagecommand) {
- Tcl_DecrRefCount(ssheet->messagecommand);
- }
- if (ssheet->resulturi) {
- Tcl_DecrRefCount(ssheet->resulturi);
- }
- if (ssheet->profilechannelObj) {
- Tcl_DecrRefCount(ssheet->profilechannelObj);
- }
- Tcl_MutexLock(&libxslt);
- xsltFreeStylesheet(ssheet->stylesheet); /* Also frees document */
- Tcl_MutexUnlock(&libxslt);
- Tcl_Free((char *) ssheet);
-}
-
-/*
- *----------------------------------------------------------------------------
- *
- * TclXSLTInstanceCommand --
- *
- * Handles the stylesheet object command.
- *
- * Results:
- * Depends on method.
- *
- * Side effects:
- * Depends on method.
- *
- *----------------------------------------------------------------------------
- */
-
-static int
-TclXSLTInstanceCommand(clientData, interp, objc, objv)
- ClientData clientData;
- Tcl_Interp *interp;
- int objc;
- Tcl_Obj *CONST objv[];
-{
- TclXSLT_Stylesheet *ssheet = (TclXSLT_Stylesheet *) clientData;
- int method, option, indent = 0, theOmitXMLDeclaration = 0;
- const xmlChar *theMethod, *theEncoding;
-
- if (objc < 3) {
- Tcl_WrongNumArgs(interp, 1, objv, "method ?args ...?");
- return TCL_ERROR;
- }
-
- if (Tcl_GetIndexFromObj(interp, objv[1], instanceCommandMethods,
- "method", 0, &method) != TCL_OK) {
- return TCL_ERROR;
- }
-
- switch ((enum instanceCommandMethods) method) {
- case TCLXSLT_CGET:
-
- if (objc != 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "option");
- return TCL_ERROR;
- }
-
- if (Tcl_GetIndexFromObj(interp, objv[2], instanceCommandOptions,
- "option", 0, &option) != TCL_OK) {
- return TCL_ERROR;
- }
-
- switch ((enum instanceCommandOptions) option) {
-
- case TCLXSLT_OPTION_METHOD:
- XSLT_GET_IMPORT_PTR(theMethod, ssheet->stylesheet, method);
- if (theMethod != NULL) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj((CONST char *) theMethod, -1));
- } /* theMethod == NULL means XML method; result should be empty.
- EXCEPTION: if the result document is of type XML_HTML_DOCUMENT_NODE
- then the method should be "html".
- */
- break;
-
- case TCLXSLT_OPTION_ENCODING:
- XSLT_GET_IMPORT_PTR(theEncoding, ssheet->stylesheet, encoding);
- if (theEncoding != NULL) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj((CONST char *) theEncoding, -1));
- } /* theEncoding == NULL means default (UTF-8) encoding; result should be empty.
- */
- break;
-
- case TCLXSLT_OPTION_OMITXMLDECLARATION:
- XSLT_GET_IMPORT_INT(theOmitXMLDeclaration, ssheet->stylesheet, omitXmlDeclaration);
- Tcl_SetObjResult(interp, Tcl_NewBooleanObj(theOmitXMLDeclaration == 1));
- break;
-
- case TCLXSLT_OPTION_INDENT:
- XSLT_GET_IMPORT_INT(indent, ssheet->stylesheet, indent);
- Tcl_SetObjResult(interp, Tcl_NewBooleanObj(indent));
- break;
-
- case TCLXSLT_OPTION_MESSAGECOMMAND:
- if (ssheet->messagecommand != NULL) {
- Tcl_SetObjResult(interp, ssheet->messagecommand);
- }
- break;
-
- case TCLXSLT_OPTION_RESULTURI:
- if (ssheet->resulturi != NULL) {
- Tcl_SetObjResult(interp, ssheet->resulturi);
- }
- break;
-
- case TCLXSLT_OPTION_PROFILECHANNEL:
- if (ssheet->profilechannelObj != NULL) {
- Tcl_SetObjResult(interp, ssheet->profilechannelObj);
- }
- break;
-
- default:
- Tcl_SetResult(interp, "unknown option", NULL);
- return TCL_ERROR;
- }
-
- break;
-
- case TCLXSLT_CONFIGURE:
-
- if (objc != 4) {
- Tcl_WrongNumArgs(interp, 2, objv, "option value");
- return TCL_ERROR;
- }
-
- if (Tcl_GetIndexFromObj(interp, objv[2], instanceCommandOptions,
- "option", 0, &option) != TCL_OK) {
- return TCL_ERROR;
- }
-
- switch ((enum instanceCommandOptions) option) {
-
- case TCLXSLT_OPTION_METHOD:
- case TCLXSLT_OPTION_INDENT:
- case TCLXSLT_OPTION_ENCODING:
- case TCLXSLT_OPTION_OMITXMLDECLARATION:
- Tcl_SetResult(interp, "read-only option", NULL);
- return TCL_ERROR;
- break;
-
- case TCLXSLT_OPTION_MESSAGECOMMAND:
- if (ssheet->messagecommand != NULL) {
- Tcl_DecrRefCount(ssheet->messagecommand);
- }
- ssheet->messagecommand = objv[3];
- Tcl_IncrRefCount(ssheet->messagecommand);
- break;
-
- case TCLXSLT_OPTION_RESULTURI:
- if (ssheet->resulturi != NULL) {
- Tcl_DecrRefCount(ssheet->resulturi);
- }
- ssheet->resulturi = objv[3];
- Tcl_IncrRefCount(ssheet->resulturi);
- break;
-
- case TCLXSLT_OPTION_PROFILECHANNEL:
- if (ssheet->profilechannelObj != NULL) {
- Tcl_DecrRefCount(ssheet->profilechannelObj);
- }
-#ifdef __WIN32__
- Tcl_SetResult(interp, "profiling not available", NULL);
- return TCL_ERROR;
-#else
- ssheet->profilechannelObj = objv[3];
- Tcl_IncrRefCount(ssheet->profilechannelObj);
-#endif
- break;
-
- default:
- Tcl_SetResult(interp, "unknown option", NULL);
- return TCL_ERROR;
- }
-
- break;
-
- case TCLXSLT_GET:
- if (objc != 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "name");
- return TCL_ERROR;
- }
-
- if (Tcl_GetIndexFromObj(interp, objv[2], instanceGetMethods,
- "name", 0, &option) != TCL_OK) {
- return TCL_ERROR;
- }
-
- switch ((enum instanceGetMethods) option) {
- case TCLXSLT_GET_PARAMETERS:
-
- Tcl_SetObjResult(interp, GetParameters(interp, ssheet->stylesheet));
- break;
-
- default:
- Tcl_SetResult(interp, "unknown name", NULL);
- return TCL_ERROR;
- }
-
- break;
-
- case TCLXSLT_TRANSFORM:
- if (objc < 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "source ?param value...?");
- return TCL_ERROR;
- }
-
- return TclXSLTTransform(ssheet, objv[2], objc - 3, &objv[3]);
-
- break;
-
- default:
- Tcl_SetResult(interp, "unknown method", NULL);
- return TCL_OK;
- }
-
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------------
- *
- * TclXSLTTransform --
- *
- * Performs an XSL transformation.
- *
- * Results:
- * Result document created.
- *
- * Side effects:
- * Memory allocated for result document.
- *
- *----------------------------------------------------------------------------
- */
-
-static int
-TclXSLTTransform(stylesheet, source, paramc, paramv)
- TclXSLT_Stylesheet *stylesheet;
- Tcl_Obj *source;
- int paramc;
- Tcl_Obj *CONST paramv[];
-{
- xmlDocPtr doc, result;
- char **params = NULL;
- int nbparams = 0, i;
- GenericError_Info *errorInfoPtr;
- void *oldxsltErrorCtx, *oldxmlErrorCtx;
- xmlGenericErrorFunc old_xsltGenericError, old_xmlGenericError;
- Tcl_Obj *resultObjPtr, *errObjPtr = NULL;
- char *resulturi = NULL;
- FILE *profile = NULL;
- xsltTransformContextPtr userCtxt = NULL;
-
- errorInfoPtr = (GenericError_Info *) Tcl_Alloc(sizeof(GenericError_Info));
- errorInfoPtr->interp = stylesheet->interp;
- errorInfoPtr->stylesheet = stylesheet;
- errorInfoPtr->code = TCL_OK;
- errorInfoPtr->msg = NULL;
-
- if (TclXML_libxml2_GetDocFromObj(stylesheet->interp, source, &doc) != TCL_OK) {
- goto error;
- }
-
- TclXML_libxml2_ResetError(stylesheet->interp);
-
- params = (char **) Tcl_Alloc(sizeof(char **) * (paramc + 1));
- for (i = 0; i < paramc; i++) {
- params[nbparams++] = Tcl_GetStringFromObj(paramv[i++], NULL);
- params[nbparams++] = Tcl_GetStringFromObj(paramv[i], NULL);
- }
- params[nbparams] = NULL;
-
- if (stylesheet->resulturi) {
- resulturi = Tcl_GetStringFromObj(stylesheet->resulturi, NULL);
- }
-#ifdef __WIN32__
- /* Tcl_GetOpenFile not available on Windows */
-#else
- if (stylesheet->profilechannelObj) {
- if (Tcl_GetOpenFile(stylesheet->interp,
- Tcl_GetStringFromObj(stylesheet->profilechannelObj, NULL),
- 1, 1,
- (ClientData *) &profile) != TCL_OK) {
- goto error;
- }
- }
-#endif
-
- /*
- * Perform the transformation
- */
-
- Tcl_MutexLock(&libxslt);
-
- /*
- * Save the previous error context so that it can
- * be restored upon completion of the transformation.
- * This is necessary because transformations may occur
- * recursively (usually due to extensions).
- */
- old_xsltGenericError = xsltGenericError;
- oldxsltErrorCtx = xsltGenericErrorContext;
- old_xmlGenericError = xmlGenericError;
- oldxmlErrorCtx = xmlGenericErrorContext;
-
- xmlSetGenericErrorFunc((void *) errorInfoPtr,
- TclXSLTGenericError);
- xsltSetGenericErrorFunc((void *) errorInfoPtr, TclXSLTGenericError);
-
- userCtxt = xsltNewTransformContext(stylesheet->stylesheet, doc);
- if (userCtxt == NULL) {
- xmlSetGenericErrorFunc((void *) oldxmlErrorCtx, old_xmlGenericError);
- xsltSetGenericErrorFunc((void *) oldxsltErrorCtx, old_xsltGenericError);
-
- Tcl_MutexUnlock(&libxslt);
- Tcl_SetResult(stylesheet->interp, "unable to create transformation context", NULL);
- goto error;
- }
-
- result = xsltApplyStylesheetUser(stylesheet->stylesheet,
- doc,
- (const char **)params,
- resulturi,
- profile,
- userCtxt);
-
- xsltFreeTransformContext(userCtxt);
-
- xmlSetGenericErrorFunc((void *) oldxmlErrorCtx, old_xmlGenericError);
- xsltSetGenericErrorFunc((void *) oldxsltErrorCtx, old_xsltGenericError);
-
- Tcl_MutexUnlock(&libxslt);
-
- errObjPtr = TclXML_libxml2_GetErrorObj(stylesheet->interp);
-
- if (result == NULL) {
- Tcl_Obj *resultPtr = Tcl_NewStringObj("no result document: ", -1);
-
- if (errObjPtr) {
- Tcl_AppendObjToObj(resultPtr, errObjPtr);
- Tcl_SetObjResult(stylesheet->interp, resultPtr);
- goto error;
- } else {
- if (errorInfoPtr->msg) {
- Tcl_AppendObjToObj(resultPtr, errorInfoPtr->msg);
- }
-
- Tcl_SetObjResult(stylesheet->interp, resultPtr);
- goto error;
- }
- }
-
- if ((errObjPtr || (errorInfoPtr->code != TCL_OK && errorInfoPtr->msg)) && stylesheet->messagecommand) {
-
- /* We have produced a result, but there may possibly
- * have been errors. Trouble is, there might also
- * have been some completely innocent messages.
- * -messageCommand is the only way to find out about these.
- */
-
- Tcl_Obj *cmdPtr = Tcl_DuplicateObj(stylesheet->messagecommand);
- if (errObjPtr) {
- if (Tcl_ListObjAppendElement(stylesheet->interp, cmdPtr, errObjPtr) != TCL_OK) {
- goto error;
- }
- } else {
- if (Tcl_ListObjAppendElement(stylesheet->interp, cmdPtr, errorInfoPtr->msg) != TCL_OK) {
- goto error;
- }
- }
- if (Tcl_GlobalEvalObj(stylesheet->interp, cmdPtr) != TCL_OK) {
- Tcl_Obj *resultPtr = Tcl_NewStringObj("message command failed: ", -1);
-
- Tcl_AppendObjToObj(resultPtr, Tcl_GetObjResult(stylesheet->interp));
- Tcl_SetObjResult(stylesheet->interp, resultPtr);
- goto error;
- }
-
- }
-
- resultObjPtr = TclDOM_libxml2_CreateObjFromDoc(stylesheet->interp, result);
- Tcl_SetObjResult(stylesheet->interp, resultObjPtr);
-
- if (errorInfoPtr->msg) {
- Tcl_DecrRefCount(errorInfoPtr->msg);
- }
- Tcl_Free((char *) errorInfoPtr);
- Tcl_Free((char *) params);
-
- return TCL_OK;
-
- error:
-
- if (errorInfoPtr->msg) {
- Tcl_DecrRefCount(errorInfoPtr->msg);
- }
- if (params) {
- Tcl_Free((char *) params);
- }
- Tcl_Free((char *) errorInfoPtr);
-
- return TCL_ERROR;
-}
-
-void
-ListObjAppendUniqueList(interp, tablePtr, listPtr, newElementsPtr)
- Tcl_Interp *interp;
- Tcl_HashTable *tablePtr;
- Tcl_Obj *listPtr;
- Tcl_Obj *newElementsPtr;
-{
- int len, idx;
- Tcl_Obj *elementPtr, *keyPtr, *namePtr, *nameURIPtr;
- Tcl_HashEntry *entryPtr;
-
- Tcl_ListObjLength(interp, newElementsPtr, &len);
- for (idx = 0; idx < len; idx++) {
- Tcl_ListObjIndex(interp, newElementsPtr, idx, &elementPtr);
- Tcl_ListObjIndex(interp, elementPtr, 0, &namePtr);
- Tcl_ListObjIndex(interp, elementPtr, 1, &nameURIPtr);
-
- keyPtr = Tcl_NewObj();
- Tcl_AppendStringsToObj(keyPtr,
- Tcl_GetStringFromObj(nameURIPtr, NULL),
- "^",
- Tcl_GetStringFromObj(namePtr, NULL),
- NULL);
- entryPtr = Tcl_FindHashEntry(tablePtr, (CONST char *) keyPtr);
- if (entryPtr == NULL) {
- Tcl_ListObjAppendElement(interp, listPtr, elementPtr);
- }
- Tcl_DecrRefCount(keyPtr);
- }
-}
-
-/*
- *----------------------------------------------------------------------------
- *
- * GetParameters --
- *
- * Retrieves the parameters for a stylesheet.
- *
- * Results:
- * Returns a Tcl list object.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-static Tcl_Obj *
-GetParameters(interp, stylesheet)
- Tcl_Interp *interp;
- xsltStylesheetPtr stylesheet;
-{
- Tcl_Obj *resultPtr, *objPtr, *keyPtr;
- xsltStackElemPtr varPtr;
- Tcl_HashTable entries; /* to keep track of parameter qnames */
- int new;
-
- if (stylesheet == NULL) {
- return NULL;
- }
-
- resultPtr = Tcl_NewListObj(0, NULL);
- Tcl_InitObjHashTable(&entries);
-
- for (varPtr = stylesheet->variables; varPtr; varPtr = varPtr->next) {
- Tcl_Obj *listPtr;
-
- if (strcmp((char *) varPtr->comp->inst->name, "param") == 0) {
- listPtr = Tcl_NewListObj(0, NULL);
- Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj((CONST char *) varPtr->name, -1));
- Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj((CONST char *) varPtr->nameURI, -1));
- Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj((CONST char *) varPtr->select, -1));
-
- Tcl_ListObjAppendElement(interp, resultPtr, listPtr);
-
- keyPtr = Tcl_NewStringObj((CONST char *) varPtr->nameURI, -1);
- Tcl_AppendStringsToObj(keyPtr, "^", varPtr->name, NULL);
- Tcl_CreateHashEntry(&entries, (CONST char *) keyPtr, &new);
- }
- }
-
- objPtr = GetParameters(interp, stylesheet->next);
- if (objPtr) {
- ListObjAppendUniqueList(interp, &entries, resultPtr, objPtr);
- }
- objPtr = GetParameters(interp, stylesheet->imports);
- if (objPtr) {
- ListObjAppendUniqueList(interp, &entries, resultPtr, objPtr);
- }
-
- Tcl_DeleteHashTable(&entries);
-
- return resultPtr;
-}
-
-/*
- *----------------------------------------------------------------------------
- *
- * TclXSLTGenericError --
- *
- * Handler for stylesheet errors.
- *
- * NB. Cannot distinguish between errors and use of xsl:message element.
- *
- * Results:
- * Stores error message.
- *
- * Side effects:
- * Transform will return error condition.
- *
- *----------------------------------------------------------------------------
- */
-
-static void
-TclXSLTGenericError (void *ctx, const char *msg, ...)
-{
- va_list args;
- char buf[2048];
- int len;
- GenericError_Info *errorInfoPtr = (GenericError_Info *) ctx;
-
- if (ctx < (void *) 0x1000) {
- fprintf(stderr, "TclXSLT: bad context\n");
- va_start(args,msg);
- vfprintf(stderr, msg, args);
- va_end(args);
- return;
- }
-
- va_start(args,msg);
- len = vsnprintf(buf, 2047, msg, args);
- va_end(args);
-
- if (!errorInfoPtr->interp) {
- return;
- }
-
- if (errorInfoPtr->stylesheet && errorInfoPtr->stylesheet->messagecommand) {
-
- Tcl_Obj *cmdPtr = Tcl_DuplicateObj(errorInfoPtr->stylesheet->messagecommand);
- if (Tcl_ListObjAppendElement(errorInfoPtr->interp, cmdPtr, Tcl_NewStringObj(buf, len)) != TCL_OK) {
- Tcl_BackgroundError(errorInfoPtr->interp);
- return;
- }
- if (Tcl_GlobalEvalObj(errorInfoPtr->interp, cmdPtr) != TCL_OK) {
- Tcl_BackgroundError(errorInfoPtr->interp);
- return;
- }
-
- } else {
-
- if (!errorInfoPtr->msg) {
- errorInfoPtr->msg = Tcl_NewObj();
- Tcl_IncrRefCount(errorInfoPtr->msg);
- }
-
- errorInfoPtr->code = TCL_ERROR;
-
- Tcl_AppendToObj(errorInfoPtr->msg, buf, len);
-
- }
-}
-
-/*
- *----------------------------------------------------------------------------
- *
- * TclXSLTExtensionCommand --
- *
- * Command for xslt::extension command.
- *
- * Results:
- * Depends on method.
- *
- * Side effects:
- * Depends on method
- *
- *----------------------------------------------------------------------------
- */
-
-static int
-TclXSLTExtensionCommand(dummy, interp, objc, objv)
- ClientData dummy;
- Tcl_Interp *interp;
- int objc;
- Tcl_Obj *CONST objv[];
-{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- int method, new;
- TclXSLT_Extension *extinfo;
- Tcl_HashEntry *entry;
-
- if (objc < 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "method ?args ...?");
- return TCL_ERROR;
- }
-
- if (Tcl_GetIndexFromObj(interp, objv[1], extensionCommandMethods,
- "method", 0, &method) != TCL_OK) {
- return TCL_ERROR;
- }
-
- switch ((enum extensionCommandMethods) method) {
-
- case TCLXSLT_EXT_ADD:
- if (objc != 4) {
- Tcl_WrongNumArgs(interp, 2, objv, "nsuri tcl-namespace");
- return TCL_ERROR;
- }
-
- Tcl_MutexLock(&libxslt);
-
- if (xsltRegisterExtModule((const xmlChar *) Tcl_GetStringFromObj(objv[2], NULL),
- TclXSLTExtInit,
- TclXSLTExtShutdown)) {
- Tcl_MutexUnlock(&libxslt);
- Tcl_SetResult(interp, "cannot register extension module", NULL);
- }
-
- Tcl_MutexUnlock(&libxslt);
-
- extinfo = (TclXSLT_Extension *) Tcl_Alloc(sizeof(TclXSLT_Extension));
- extinfo->interp = interp;
- extinfo->nsuri = objv[2];
- Tcl_IncrRefCount(objv[2]);
- extinfo->tclns = objv[3];
- Tcl_IncrRefCount(objv[3]);
-
- extinfo->xformCtxt = NULL;
-
- entry = Tcl_CreateHashEntry(tsdPtr->extensions, Tcl_GetStringFromObj(objv[2], NULL), &new);
-
- if (!new) {
- Tcl_SetResult(interp, "extension already exists", NULL);
- Tcl_Free((char *) extinfo);
- return TCL_ERROR;
- }
-
- Tcl_SetHashValue(entry, extinfo);
-
- TclXSLT_RegisterAll(extinfo, (const xmlChar *) Tcl_GetStringFromObj(objv[2], NULL));
-
- Tcl_ResetResult(interp);
-
- break;
-
- case TCLXSLT_EXT_REMOVE:
- if (objc != 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "nsuri");
- return TCL_ERROR;
- }
-
- /*
- * TODO: Remove previously registered elements and functions.
- */
-
- entry = Tcl_FindHashEntry(tsdPtr->extensions, Tcl_GetStringFromObj(objv[2], NULL));
- if (entry == NULL) {
- Tcl_SetResult(interp, "unknown XML Namespace URI", NULL);
- return TCL_ERROR;
- }
-
- extinfo = (TclXSLT_Extension *) Tcl_GetHashValue(entry);
- Tcl_DecrRefCount(extinfo->nsuri);
- Tcl_DecrRefCount(extinfo->tclns);
- Tcl_Free((char *) extinfo);
-
- Tcl_DeleteHashEntry(entry);
-
- break;
-
- default:
- Tcl_SetResult(interp, "unknown method", NULL);
- return TCL_ERROR;
- }
-
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------------
- *
- * TclXSLTExtInit --
- *
- * Load extensions into a transformation context.
- *
- * Results:
- * Returns pointer to extension data.
- * Elements and functions are pre-registered.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-static void *
-TclXSLTExtInit(ctxt, URI)
- xsltTransformContextPtr ctxt;
- const xmlChar *URI;
-{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- Tcl_HashEntry *entry;
- TclXSLT_Extension *extinfo;
-
- entry = Tcl_FindHashEntry(tsdPtr->extensions, (CONST char *) URI);
- if (entry == NULL) {
- /* Extension module was removed */
- return NULL;
- }
-
- extinfo = (TclXSLT_Extension *) Tcl_GetHashValue(entry);
- extinfo->xformCtxt = ctxt;
-
- return (void *) extinfo;
-}
-
-void
-TclXSLT_RegisterAll(extinfo, nsuri)
- TclXSLT_Extension *extinfo;
- const xmlChar *nsuri;
-{
- Tcl_Obj *cmdPtr, *objPtr;
- Tcl_Obj **reg;
- int ret, i, len;
-
- /*
- * Q: How to distinguish between extension elements and functions?
- * A: Use the formal parameters. If the command can accept
- * a variable argument list, then it is registered as a function.
- * Otherwise it will be registered as an extension (and expected
- * to accept certain arguments).
- */
-
- cmdPtr = Tcl_NewStringObj("::xslt::getprocs ", -1);
- Tcl_IncrRefCount(cmdPtr);
- Tcl_AppendObjToObj(cmdPtr, extinfo->tclns);
- ret = Tcl_EvalObjEx(extinfo->interp, cmdPtr, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT);
- objPtr = Tcl_GetObjResult(extinfo->interp);
- Tcl_IncrRefCount(objPtr);
- Tcl_DecrRefCount(cmdPtr);
-
- if (ret != TCL_OK || objPtr == NULL) {
- /*
- * Something went wrong, therefore nothing to register.
- */
- return;
- }
-
- ret = Tcl_ListObjGetElements(extinfo->interp, objPtr, &len, &reg);
- if (ret != TCL_OK || len != 2) {
- /*
- * Something went wrong, therefore nothing to register.
- */
- return;
- }
-
- /*
- * reg[0] contains extension elements
- * reg[1] contains extension functions
- */
-
- Tcl_MutexLock(&libxslt);
-
- /*
- * First register the extension elements.
- */
-
- ret = Tcl_ListObjLength(extinfo->interp, reg[0], &len);
- if (ret == TCL_OK && len > 0) {
- for (i = 0; i < len; i++) {
-
- if (Tcl_ListObjIndex(extinfo->interp, reg[0], i, &objPtr) != TCL_OK) {
- continue;
- }
-
- xsltRegisterExtModuleElement((const xmlChar *) Tcl_GetStringFromObj(objPtr, NULL),
- nsuri,
- (xsltPreComputeFunction) TclXSLTExtElementPreComp,
- (xsltTransformFunction) TclXSLTExtElementTransform);
- }
- }
-
- /*
- * Now register the extension functions.
- */
-
- ret = Tcl_ListObjLength(extinfo->interp, reg[1], &len);
- if (ret != TCL_OK || len == 0) {
- Tcl_MutexUnlock(&libxslt);
- return;
- }
-
- for (i = 0; i < len; i++) {
-
- if (Tcl_ListObjIndex(extinfo->interp, reg[1], i, &objPtr) != TCL_OK) {
- continue;
- }
-
- xsltRegisterExtModuleFunction((const xmlChar *) Tcl_GetStringFromObj(objPtr, NULL),
- nsuri,
- TclXSLTExtFunction);
- }
-
- Tcl_MutexUnlock(&libxslt);
-
- Tcl_DecrRefCount(objPtr);
-
- return;
-}
-
-/*
- *----------------------------------------------------------------------------
- *
- * TclXSLTExtElementPreComp --
- *
- * Compilation step for extension element.
- *
- * Results:
- * Not currently used.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-static void
-TclXSLTExtElementPreComp(style, inst, function)
- xsltStylesheetPtr style;
- xmlNodePtr inst;
- xsltTransformFunction function;
-{
- return;
-}
-
-/*
- *----------------------------------------------------------------------------
- *
- * TclXSLTExtElementTransform --
- *
- * Implements extension element.
- *
- * Results:
- * Returns string returned by Tcl command evaluation.
- *
- * Side effects:
- * Depends on Tcl command evaluated.
- *
- *----------------------------------------------------------------------------
- */
-
-static void
-TclXSLTExtElementTransform(ctxt, node, inst, comp)
- xsltTransformContextPtr ctxt; /* unused */
- xmlNodePtr node;
- xmlNodePtr inst;
- xsltStylePreCompPtr comp; /* unused */
-{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- TclXSLT_Extension *extinfo;
- Tcl_HashEntry *entry;
- Tcl_Obj *cmdPtr;
- int ret;
-
- if (inst == NULL) {
- return;
- }
-
- entry = Tcl_FindHashEntry(tsdPtr->extensions, (CONST char *) inst->ns->href);
- if (entry == NULL) {
- /*
- * Cannot find extension module.
- * Must have been removed.
- */
- return;
- }
-
- extinfo = (TclXSLT_Extension *) Tcl_GetHashValue(entry);
-
- /*
- * Start constructing the script by first defining the command.
- */
-
- cmdPtr = Tcl_DuplicateObj(extinfo->tclns);
- Tcl_AppendStringsToObj(cmdPtr, "::", inst->name, NULL);
-
- if (Tcl_ListObjAppendElement(extinfo->interp, cmdPtr, TclDOM_libxml2_CreateObjFromNode(extinfo->interp, node)) != TCL_OK) {
- Tcl_DecrRefCount(cmdPtr);
- return;
- }
-
- /*
- * Converting the stylesheet node to a TclDOM node may clobber the
- * _private pointer. It would be nice to find the equivalent node
- * in the original DOM tree, but it may not even exist anymore :-(
- *
- * TODO: make extension elements more effective, and allow
- * pre-computation.
- */
-
- /*
- * Now evaluate the complete command.
- * Can't propagqte a return error result to
- * XSLT, so flag background error instead.
- */
- ret = Tcl_EvalObjEx(extinfo->interp, cmdPtr, TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT);
- if (ret != TCL_OK) {
- Tcl_BackgroundError(extinfo->interp);
- }
-}
-
-/*
- *----------------------------------------------------------------------------
- *
- * TclXSLTExtFunction --
- *
- * Handles evaluation of an extension function.
- *
- * Results:
- * Returns string returned by Tcl command evaluation.
- *
- * Side effects:
- * Depends on Tcl command evaluated.
- *
- *----------------------------------------------------------------------------
- */
-
-static void
-TclXSLTExtFunction(xpathCtxt, nargs)
- xmlXPathParserContextPtr xpathCtxt;
- int nargs;
-{
- xsltTransformContextPtr xformCtxt;
- TclXSLT_Extension *extinfo;
- Tcl_Obj *cmdPtr, *resultPtr;
- xmlXPathObjectPtr obj;
- int ret;
-
- Tcl_MutexLock(&libxslt);
-
- xformCtxt = xsltXPathGetTransformContext(xpathCtxt);
-
- /*
- * In order to find the instance data we need the
- * XML Namespace URI of this function.
- */
-
- extinfo = (TclXSLT_Extension *) xsltGetExtData(xformCtxt,
- xpathCtxt->context->functionURI);
-
- /*
- * Start constructing the script by first defining the command.
- */
-
- cmdPtr = Tcl_DuplicateObj(extinfo->tclns);
- Tcl_IncrRefCount(cmdPtr);
- Tcl_AppendStringsToObj(cmdPtr, "::", xpathCtxt->context->function, NULL);
-
- /*
- * Each argument on the stack is converted to a Tcl_Obj
- * of an appropriate type and passed as an argument to the Tcl command.
- */
-
- while (nargs) {
- Tcl_Obj *objv[2];
-
- obj = (xmlXPathObjectPtr) valuePop(xpathCtxt);
- if (obj == NULL) {
- xmlXPathSetError(xpathCtxt, XPATH_INVALID_OPERAND);
- Tcl_DecrRefCount(cmdPtr);
- Tcl_MutexUnlock(&libxslt);
- return;
- }
-
- objv[0] = TclXSLT_ConvertXPathObjToTclObj(extinfo->interp, obj);
- objv[1] = NULL;
- if (Tcl_ListObjReplace(extinfo->interp, cmdPtr, 1, 0, 1, objv) != TCL_OK) {
- Tcl_BackgroundError(extinfo->interp);
- Tcl_DecrRefCount(objv[0]);
- Tcl_DecrRefCount(cmdPtr);
- Tcl_MutexUnlock(&libxslt);
- return;
- }
-
- /* When should this XPath object be freed?
- * Immediately before returning from the function call?
- * What if the application retains a pointer to it?
- * If the application destroys the contents, then memory
- * will leak because the XPath object is not freed.
- *
- * TODO: take a copy of the object's content and pass that
- * to the application callback. That would allow this object
- * to be freed and allow the application to manage the copy.
-
- xmlXPathFreeObject(obj);
- */
-
- nargs--;
- }
-
- ret = Tcl_EvalObjEx(extinfo->interp, cmdPtr, TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT);
- resultPtr = Tcl_GetObjResult(extinfo->interp);
- Tcl_DecrRefCount(cmdPtr);
- Tcl_IncrRefCount(resultPtr);
-
- if (ret == TCL_OK) {
- obj = TclXSLT_ConvertTclObjToXPathObj(extinfo->interp, resultPtr);
- valuePush(xpathCtxt, obj);
- } else {
- xmlGenericError(xmlGenericErrorContext,
- "%s", Tcl_GetStringFromObj(resultPtr, NULL));
- /* Need to define a new error code - this is the closest in meaning */
- xpathCtxt->error = XPATH_UNKNOWN_FUNC_ERROR;
- }
-
- Tcl_MutexUnlock(&libxslt);
-
- Tcl_DecrRefCount(resultPtr);
-
-}
-
-/*
- *----------------------------------------------------------------------------
- *
- * TclXSLT_ConvertTclObjToXPathObj --
- *
- * Convert a Tcl Object to an XPath object.
- * Data type is preserved, with nodesets being
- * mapped from a list of nodes.
- *
- * NB. Mutex is assumed to be locked when invoking this routine.
- *
- * Results:
- * XPath Object.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-static xmlXPathObjectPtr
-TclXSLT_ConvertTclObjToXPathObj(interp, objPtr)
- Tcl_Interp *interp;
- Tcl_Obj *objPtr;
-{
- xmlNodePtr nodePtr;
- xmlDocPtr docPtr;
-
- if (TclDOM_libxml2_GetNodeFromObj(interp, objPtr, &nodePtr) == TCL_OK) {
- return xmlXPathNewNodeSet(nodePtr);
- }
-
- if (TclXML_libxml2_GetDocFromObj(interp, objPtr, &docPtr) == TCL_OK) {
- return xmlXPathNewNodeSet((xmlNodePtr) docPtr);
-
- }
-
- if (objPtr->typePtr == Tcl_GetObjType("int") ||
- objPtr->typePtr == Tcl_GetObjType("double")) {
- double number;
-
- if (Tcl_GetDoubleFromObj(interp, objPtr, &number) == TCL_OK) {
- return xmlXPathNewFloat(number);
- } else {
- return NULL;
- }
- } else if (objPtr->typePtr == Tcl_GetObjType("boolean")) {
- int bool;
-
- if (Tcl_GetBooleanFromObj(interp, objPtr, &bool) == TCL_OK) {
- return xmlXPathNewBoolean(bool);
- } else {
- return NULL;
- }
- } else if (objPtr->typePtr == Tcl_GetObjType("list")) {
- /*
- * If each of the elements can be converted to a node,
- * then return a nodeset.
- */
-
- int i, len;
- Tcl_Obj **listPtr;
- xmlNodeSetPtr nset;
-
- Tcl_ListObjGetElements(interp, objPtr, &len, &listPtr);
- if (len == 0) {
- return xmlXPathNewNodeSet(NULL);
- }
-
- /*
- * First pass: check that the elements are all nodes.
- */
- for (i = 0; i < len; i++) {
- if (TclXML_libxml2_GetDocFromObj(interp, listPtr[i], &docPtr) == TCL_OK) {
- continue;
- }
- if (TclDOM_libxml2_GetNodeFromObj(interp, listPtr[i], &nodePtr) != TCL_OK) {
- return xmlXPathNewString((const xmlChar *) Tcl_GetStringFromObj(objPtr, NULL));
- }
- }
- /*
- * Now go ahead and create the nodeset (we already did the hard
- * work to create internal reps in pass 1).
- */
- if (TclXML_libxml2_GetDocFromObj(interp, listPtr[0], &docPtr) == TCL_OK) {
- nset = xmlXPathNodeSetCreate((xmlNodePtr) docPtr);
- } else {
- TclDOM_libxml2_GetNodeFromObj(interp, listPtr[0], &nodePtr);
- nset = xmlXPathNodeSetCreate(nodePtr);
- }
- for (i = 1; i < len; i++) {
- if (TclXML_libxml2_GetDocFromObj(interp, listPtr[i], &docPtr) == TCL_OK) {
- xmlXPathNodeSetAdd(nset, (xmlNodePtr) docPtr);
- } else {
- TclDOM_libxml2_GetNodeFromObj(interp, listPtr[i], &nodePtr);
- xmlXPathNodeSetAdd(nset, nodePtr);
- }
- }
- return xmlXPathWrapNodeSet(nset);
-
- } else {
- return xmlXPathNewString((const xmlChar *) Tcl_GetStringFromObj(objPtr, NULL));
- }
-}
-
-/*
- *----------------------------------------------------------------------------
- *
- * TclXSLT_ConvertXPathObjToTclObj --
- *
- * Convert an XPath object to a Tcl Object.
- * Data type is preserved, with nodesets being
- * mapped to a list of nodes.
- *
- * Results:
- * Tcl Object.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-static Tcl_Obj *
-TclXSLT_ConvertXPathObjToTclObj(interp, xpobj)
- Tcl_Interp *interp;
- xmlXPathObjectPtr xpobj;
-{
- Tcl_Obj *objPtr;
- int i;
-
- switch (xpobj->type) {
- case XPATH_XSLT_TREE:
- case XPATH_NODESET:
-
- objPtr = Tcl_NewListObj(0, NULL);
- if (xpobj->nodesetval) {
- for (i = 0; i < xpobj->nodesetval->nodeNr; i++) {
- Tcl_Obj *nodeObjPtr = NULL;
- if (xpobj->nodesetval->nodeTab[i] &&
- xpobj->nodesetval->nodeTab[i]->type == XML_DOCUMENT_NODE) {
- nodeObjPtr = TclXML_libxml2_CreateObjFromDoc((xmlDocPtr) xpobj->nodesetval->nodeTab[i]);
- } else if (xpobj->nodesetval->nodeTab[i]) {
- nodeObjPtr = TclDOM_libxml2_CreateObjFromNode(interp, xpobj->nodesetval->nodeTab[i]);
- }
- Tcl_ListObjAppendElement(interp, objPtr, nodeObjPtr);
- }
- }
-
- break;
-
- case XPATH_BOOLEAN:
- objPtr = Tcl_NewBooleanObj(xpobj->boolval);
- break;
-
- case XPATH_NUMBER:
- objPtr = Tcl_NewDoubleObj(xpobj->floatval);
- break;
-
- case XPATH_STRING:
- case XPATH_UNDEFINED:
- case XPATH_POINT:
- case XPATH_RANGE:
- case XPATH_LOCATIONSET:
- case XPATH_USERS:
- default:
- objPtr = Tcl_NewStringObj((CONST char *) xmlXPathCastToString(xpobj), -1);
-
- break;
- }
-
- return objPtr;
-}
-
-/*
- *----------------------------------------------------------------------------
- *
- * TclXSLTExtShutdown --
- *
- * Clean up.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-static void
-TclXSLTExtShutdown(ctxt, URI, userdata)
- xsltTransformContextPtr ctxt;
- const xmlChar *URI;
- void *userdata;
-{
- /* Nothing to do */
-}
-
-/*
- *----------------------------------------------------------------------------
- *
- * TclXSLTSecurity --
- * TclXSLTSecurityReadFile --
- * TclXSLTSecurityWriteFile --
- * TclXSLTSecurityCreateDirectory --
- * TclXSLTSecurityReadNetwork --
- * TclXSLTSecurityWriteNetwork --
- *
- * Check if external operations are permitted.
- *
- * Results:
- * Returns boolean value.
- *
- * Side effects:
- * Depends on callback.
- *
- *----------------------------------------------------------------------------
- */
-
-static int
-TclXSLTSecurity(name, method, value)
- Tcl_Obj *name;
- const char *method;
- const char *value;
-{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- Tcl_Interp *master;
- Tcl_Obj *cmdPtr, *pathPtr;
- int result, permitted;
-
- if (Tcl_IsSafe(tsdPtr->interp)) {
-
- /*
- * Invoke hidden command
- */
-
- master = Tcl_GetMaster(tsdPtr->interp);
-
- if (!Tcl_IsSafe(master)) {
- return 0;
- }
-
- if (Tcl_GetInterpPath(master, tsdPtr->interp) != TCL_OK) {
- return 0;
- }
- pathPtr = Tcl_GetObjResult(master);
-
- cmdPtr = Tcl_NewListObj(0, NULL);
- Tcl_IncrRefCount(cmdPtr);
- Tcl_ListObjAppendElement(master, cmdPtr, Tcl_NewStringObj("interp", -1));
- Tcl_ListObjAppendElement(master, cmdPtr, Tcl_NewStringObj("invokehidden", -1));
- Tcl_ListObjAppendElement(master, cmdPtr, pathPtr);
- Tcl_ListObjAppendElement(master, cmdPtr, Tcl_NewStringObj("-global", -1));
- Tcl_ListObjAppendElement(master, cmdPtr, Tcl_NewStringObj("::xslt::security", -1));
- Tcl_ListObjAppendElement(master, cmdPtr, name);
- Tcl_ListObjAppendElement(master, cmdPtr, Tcl_NewStringObj(method, -1));
- Tcl_ListObjAppendElement(master, cmdPtr, Tcl_NewStringObj(value, -1));
-
- result = Tcl_EvalObjEx(master, cmdPtr, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT);
-
- Tcl_DecrRefCount(cmdPtr);
- } else {
-
- /*
- * Invoke command normally
- */
-
- cmdPtr = Tcl_NewListObj(0, NULL);
- Tcl_IncrRefCount(cmdPtr);
- Tcl_ListObjAppendElement(tsdPtr->interp, cmdPtr, Tcl_NewStringObj("::xslt::security", -1));
- Tcl_ListObjAppendElement(tsdPtr->interp, cmdPtr, name);
- Tcl_ListObjAppendElement(tsdPtr->interp, cmdPtr, Tcl_NewStringObj(method, -1));
- Tcl_ListObjAppendElement(tsdPtr->interp, cmdPtr, Tcl_NewStringObj(value, -1));
-
- result = Tcl_EvalObjEx(tsdPtr->interp, cmdPtr, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT);
-
- Tcl_DecrRefCount(cmdPtr);
- }
-
- if (result == TCL_OK) {
- if (Tcl_GetBooleanFromObj(tsdPtr->interp, Tcl_GetObjResult(tsdPtr->interp), &permitted) == TCL_OK) {
- return permitted;
- } else if (Tcl_IsSafe(tsdPtr->interp)) {
- return 0;
- } else {
- return 1;
- }
- } else if (Tcl_IsSafe(tsdPtr->interp)) {
- return 0;
- } else {
- return 1;
- }
-}
-static Tcl_Obj *
-TclXSLTSecurityGetName(ctxt)
- xsltTransformContextPtr ctxt;
-{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- Tcl_HashEntry *entryPtr;
-
- if (ctxt) {
- entryPtr = Tcl_FindHashEntry(tsdPtr->stylesheets, (ClientData) ctxt->style);
- if (entryPtr) {
- return Tcl_NewStringObj((char *) Tcl_GetHashValue(entryPtr), -1);
- } else {
- return Tcl_NewObj();
- }
- } else {
- return Tcl_NewObj();
- }
-}
-static int
-TclXSLTSecurityReadFile(sec, ctxt, value)
- xsltSecurityPrefsPtr sec;
- xsltTransformContextPtr ctxt;
- const char *value;
-{
- return TclXSLTSecurity(TclXSLTSecurityGetName(ctxt), "readfile", value);
-}
-static int
-TclXSLTSecurityWriteFile(sec, ctxt, value)
- xsltSecurityPrefsPtr sec;
- xsltTransformContextPtr ctxt;
- const char *value;
-{
- return TclXSLTSecurity(TclXSLTSecurityGetName(ctxt), "writefile", value);
-}
-static int
-TclXSLTSecurityCreateDirectory(sec, ctxt, value)
- xsltSecurityPrefsPtr sec;
- xsltTransformContextPtr ctxt;
- const char *value;
-{
- return TclXSLTSecurity(TclXSLTSecurityGetName(ctxt), "createdirectory", value);
-}
-static int
-TclXSLTSecurityReadNetwork(sec, ctxt, value)
- xsltSecurityPrefsPtr sec;
- xsltTransformContextPtr ctxt;
- const char *value;
-{
- return TclXSLTSecurity(TclXSLTSecurityGetName(ctxt), "readnetwork", value);
-}
-static int
-TclXSLTSecurityWriteNetwork(sec, ctxt, value)
- xsltSecurityPrefsPtr sec;
- xsltTransformContextPtr ctxt;
- const char *value;
-{
- return TclXSLTSecurity(TclXSLTSecurityGetName(ctxt), "writenetwork", value);
-}