Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch tdomNodeType Excluding Merge-Ins

This is equivalent to a diff from 12ce2296e4 to 7148e12240

2014-01-10
01:11
Improved speed of operations in node token mode notable. This is achieved by introducing a Tcl_Obj type tdomNodeType. Tcl_Objs of type tdomNodeType are created without string representation, saving malloc costs until string representation is needed (which typically isn't needed). Additionally, DOM node identification from token is faster with tdomNodeType Tcl_Objs. check-in: 8f70a39a92 user: rolf tags: trunk
2014-01-01
22:08
Enhanced bench suite. Closed-Leaf check-in: 7148e12240 user: rolf tags: tdomNodeType
04:03
Made tcldom_returnNodeOjb static. check-in: 40b95f4a60 user: rolf tags: tdomNodeType
2013-12-29
01:29
Update from trunk. check-in: 6b6f0a48b7 user: rolf tags: tdomNodeType
01:25
Minor test suite correction and addition. check-in: 12ce2296e4 user: rolf tags: trunk
2013-12-27
21:56
More #ifdefery, to handle tip 388 changes to tcl.h. check-in: ebe56a3001 user: rolf tags: trunk

Changes to generic/tcldom.c.

   355    355   \---------------------------------------------------------------------------*/
   356    356   
   357    357   typedef struct XsltMsgCBInfo {
   358    358       Tcl_Interp * interp;
   359    359       Tcl_Obj    * msgcmd;
   360    360   } XsltMsgCBInfo;
   361    361   
          362  +
          363  +static void UpdateStringOfTdomNode(Tcl_Obj *objPtr);
          364  +static int  SetTdomNodeFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
          365  +
          366  +const Tcl_ObjType tdomNodeType = {
          367  +    "tdom-node",
          368  +    NULL,
          369  +    NULL,
          370  +    UpdateStringOfTdomNode,
          371  +    SetTdomNodeFromAny
          372  +};
          373  +
   362    374   /*----------------------------------------------------------------------------
   363    375   |   Prototypes for procedures defined later in this file:
   364    376   |
   365    377   \---------------------------------------------------------------------------*/
   366    378   
   367    379   static Tcl_VarTraceProc  tcldom_docTrace;
   368         -static Tcl_VarTraceProc  tcldom_nodeTrace;
   369    380   
   370    381   static Tcl_CmdDeleteProc tcldom_docCmdDeleteProc;
   371         -static Tcl_CmdDeleteProc tcldom_nodeCmdDeleteProc;
   372    382   
   373    383   #ifdef TCL_THREADS
   374    384   
   375    385   static int tcldom_EvalLocked(Tcl_Interp* interp, Tcl_Obj** objv,
   376    386                                domDocument* doc, int flag);
   377    387   
   378    388   static int tcldom_RegisterDocShared(domDocument* doc);
................................................................................
   481    491       }
   482    492   
   483    493       tcldom_deleteDoc(dinfo->interp, doc);
   484    494   
   485    495       FREE((void*)dinfo);
   486    496   }
   487    497   
   488         -
   489         -/*----------------------------------------------------------------------------
   490         -|   tcldom_nodeCmdDeleteProc
   491         -|
   492         -\---------------------------------------------------------------------------*/
   493         -static
   494         -void tcldom_nodeCmdDeleteProc (
   495         -    ClientData  clientData
   496         -)
   497         -{
   498         -    domDeleteInfo *dinfo = (domDeleteInfo *)clientData;
   499         -    char          *var   = dinfo->traceVarName;
   500         -
   501         -    DBG(fprintf (stderr, "--> tcldom_nodeCmdDeleteProc node %p\n", 
   502         -                 dinfo->node));
   503         -
   504         -    if (var) {
   505         -         DBG(fprintf(stderr, "--> tcldom_nodeCmdDeleteProc calls "
   506         -                    "Tcl_UntraceVar for \"%s\"\n", var));
   507         -        Tcl_UntraceVar(dinfo->interp, var, 
   508         -                       TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
   509         -                       tcldom_nodeTrace, clientData);
   510         -        FREE(var);
   511         -        dinfo->traceVarName = NULL;
   512         -    }
   513         -    FREE((void*)dinfo);
   514         -}
   515         -
   516         -
   517    498   /*----------------------------------------------------------------------------
   518    499   |   tcldom_docTrace
   519    500   |
   520    501   \---------------------------------------------------------------------------*/
   521    502   static
   522    503   char * tcldom_docTrace (
   523    504       ClientData    clientData,
................................................................................
   544    525           DBG(fprintf(stderr, "--> tcldom_docTrace delete doc %p\n", doc));
   545    526           Tcl_DeleteCommand(interp, objCmdName);
   546    527       }
   547    528   
   548    529       return NULL;
   549    530   }
   550    531   
   551         -
   552         -/*----------------------------------------------------------------------------
   553         -|   tcldom_nodeTrace
   554         -|
   555         -\---------------------------------------------------------------------------*/
   556         -static
   557         -char * tcldom_nodeTrace (
   558         -    ClientData    clientData,
   559         -    Tcl_Interp   *interp,
   560         -    CONST84 char *name1,
   561         -    CONST84 char *name2,
   562         -    int           flags
   563         -)
   564         -{
   565         -    domDeleteInfo *dinfo = (domDeleteInfo*)clientData;
   566         -    domNode       *node = dinfo->node;
   567         -    char           objCmdName[80];
   568         -
   569         -    DBG(fprintf(stderr, "--> tcldom_nodeTrace %x %p\n", flags, node));
   570         -
   571         -    if (flags & TCL_INTERP_DESTROYED) {
   572         -        return NULL;
   573         -    }
   574         -    if (flags & TCL_TRACE_WRITES) {
   575         -        return "var is read-only";
   576         -    }
   577         -    if (flags & TCL_TRACE_UNSETS) {
   578         -        NODE_CMD(objCmdName, node);
   579         -        DBG(fprintf(stderr, "--> tcldom_nodeTrace delete node %p\n", node));
   580         -        Tcl_UntraceVar(interp, name1, TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
   581         -                       tcldom_nodeTrace, clientData);
   582         -        Tcl_DeleteCommand(interp, objCmdName);
   583         -        node->nodeFlags &= ~VISIBLE_IN_TCL;
   584         -    }
   585         -
   586         -    return NULL;
   587         -}
   588         -
          532  +/*----------------------------------------------------------------------------
          533  +|   UpdateStringOfTdomNode
          534  +|
          535  +\---------------------------------------------------------------------------*/
          536  +static void
          537  +UpdateStringOfTdomNode(
          538  +    Tcl_Obj *objPtr)
          539  +{
          540  +    char nodeName[80];
          541  +    int  len;
          542  +    
          543  +    NODE_CMD(nodeName, objPtr->internalRep.otherValuePtr);
          544  +    len = strlen(nodeName);
          545  +    objPtr->bytes = (ckalloc((unsigned char) len+1));
          546  +    memcpy(objPtr->bytes, nodeName, len+1);
          547  +    objPtr->length = len;
          548  +}
          549  +
          550  +/*----------------------------------------------------------------------------
          551  +|   SetTdomNodeFromAny
          552  +|
          553  +\---------------------------------------------------------------------------*/
          554  +static int
          555  +SetTdomNodeFromAny(
          556  +    Tcl_Interp *interp,		/* Tcl interpreter or NULL */
          557  +    Tcl_Obj *objPtr)		/* Pointer to the object to parse */
          558  +{
          559  +    Tcl_CmdInfo  cmdInfo;
          560  +    domNode     *node = NULL;
          561  +    char        *nodeName;
          562  +    
          563  +    if (objPtr->typePtr == &tdomNodeType) {
          564  +        return TCL_OK;
          565  +    }
          566  +
          567  +    nodeName = Tcl_GetString(objPtr);
          568  +    if (strncmp(nodeName, "domNode", 7)) {
          569  +        if (interp) {
          570  +            SetResult("parameter not a domNode!");
          571  +            return TCL_ERROR;
          572  +        }
          573  +    }
          574  +    if (sscanf(&nodeName[7], "%p", &node) != 1) {
          575  +        if (!Tcl_GetCommandInfo(interp, nodeName, &cmdInfo)) {
          576  +            if (interp) {
          577  +                SetResult("parameter not a domNode!");
          578  +                return TCL_ERROR;
          579  +            }
          580  +        }
          581  +        if (   (cmdInfo.isNativeObjectProc == 0)
          582  +            || (cmdInfo.objProc != (Tcl_ObjCmdProc*)tcldom_NodeObjCmd)) {
          583  +            if (interp) {
          584  +                SetResult("parameter not a domNode object command");
          585  +                return TCL_ERROR;
          586  +            }
          587  +        }
          588  +        node = (domNode*)cmdInfo.objClientData;
          589  +    }
          590  +    if (objPtr->typePtr && objPtr->typePtr->freeIntRepProc) {
          591  +        objPtr->typePtr->freeIntRepProc(objPtr);
          592  +    }
          593  +    objPtr->internalRep.otherValuePtr = node;
          594  +    objPtr->typePtr = &tdomNodeType;
          595  +    
          596  +    return TCL_OK;
          597  +}
   589    598   
   590    599   /*----------------------------------------------------------------------------
   591    600   |   tcldom_createNodeObj
   592    601   |
   593    602   \---------------------------------------------------------------------------*/
   594    603   void tcldom_createNodeObj (
   595    604       Tcl_Interp * interp,
................................................................................
   609    618                                (ClientData)        node,
   610    619                                (Tcl_CmdDeleteProc*)NULL);
   611    620           node->nodeFlags |= VISIBLE_IN_TCL;
   612    621       }
   613    622   }
   614    623   
   615    624   /*----------------------------------------------------------------------------
   616         -|   tcldom_returnNodeObj
          625  +|   tcldom_setInterpAndReturnVar
   617    626   |
   618    627   \---------------------------------------------------------------------------*/
   619    628   static
   620         -int tcldom_returnNodeObj (
          629  +int tcldom_setInterpAndReturnVar (
   621    630       Tcl_Interp *interp,
   622    631       domNode    *node,
   623    632       int         setVariable,
   624    633       Tcl_Obj    *var_name
   625    634   )
   626    635   {
   627         -    char            objCmdName[80], *objVar;
   628         -    domDeleteInfo * dinfo;
   629         -    Tcl_CmdInfo     cmdInfo;
   630         -
          636  +    char     objCmdName[80], *objVar;
          637  +    Tcl_Obj *resultObj;
          638  +    
   631    639       GetTcldomTSD()
   632    640   
   633    641       if (node == NULL) {
   634    642           if (setVariable) {
   635    643               objVar = Tcl_GetString(var_name);
   636         -            Tcl_UnsetVar(interp, objVar, 0);
   637    644               Tcl_SetVar(interp, objVar, "", 0);
   638    645           }
   639    646           SetResult("");
   640    647           return TCL_OK;
   641    648       }
   642         -    tcldom_createNodeObj(interp, node, objCmdName);
   643         -    if (TSD(dontCreateObjCommands)) {
          649  +    if (TSD(dontCreateObjCommands) == 0) {
          650  +        tcldom_createNodeObj(interp, node, objCmdName);
   644    651           if (setVariable) {
   645    652               objVar = Tcl_GetString(var_name);
   646         -            Tcl_SetVar(interp, objVar, objCmdName, 0);
          653  +            Tcl_SetVar  (interp, objVar, objCmdName, 0);
   647    654           }
          655  +        SetResult(objCmdName);
   648    656       } else {
          657  +        resultObj = Tcl_NewObj();
          658  +        resultObj->bytes = NULL;
          659  +        resultObj->length = 0;
          660  +        resultObj->internalRep.otherValuePtr = node;
          661  +        resultObj->typePtr = &tdomNodeType;
          662  +        Tcl_SetObjResult (interp, resultObj);
   649    663           if (setVariable) {
          664  +            NODE_CMD(objCmdName, node);
   650    665               objVar = Tcl_GetString(var_name);
   651         -            Tcl_UnsetVar(interp, objVar, 0);
   652    666               Tcl_SetVar  (interp, objVar, objCmdName, 0);
   653         -            Tcl_GetCommandInfo(interp, objCmdName, &cmdInfo);
   654         -            if (0) {
   655         -                dinfo = (domDeleteInfo*)MALLOC(sizeof(domDeleteInfo));
   656         -                dinfo->interp       = interp;
   657         -                dinfo->node         = node;
   658         -                dinfo->traceVarName = NULL;
   659         -                Tcl_TraceVar(interp, objVar, 
   660         -                             TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
   661         -                             (Tcl_VarTraceProc*)tcldom_nodeTrace,
   662         -                             (ClientData)dinfo);
   663         -                dinfo->traceVarName = tdomstrdup(objVar);
   664         -
   665         -                /* Patch node object command to remove above trace 
   666         -                   on teardown */
   667         -                cmdInfo.deleteData = (ClientData)dinfo;
   668         -                cmdInfo.deleteProc = tcldom_nodeCmdDeleteProc;
   669         -                Tcl_SetCommandInfo(interp, objCmdName, &cmdInfo);
   670         -            }
   671         -        }
   672         -    }
   673         -
   674         -    SetResult(objCmdName);
   675         -    return TCL_OK;
          667  +        }
          668  +    }
          669  +    return TCL_OK;
          670  +}
          671  +
          672  +/*----------------------------------------------------------------------------
          673  +|   tcldom_returnNodeObj
          674  +|
          675  +\---------------------------------------------------------------------------*/
          676  +static
          677  +Tcl_Obj *tcldom_returnNodeObj (
          678  +    Tcl_Interp *interp,
          679  +    domNode    *node)
          680  +{
          681  +    char     objCmdName[80];
          682  +    Tcl_Obj *resultObj;
          683  +    
          684  +    GetTcldomTSD()
          685  +
          686  +    resultObj = Tcl_NewObj();
          687  +    if (node == NULL) {
          688  +        return resultObj;
          689  +    }
          690  +    if (TSD(dontCreateObjCommands) == 0) {
          691  +        tcldom_createNodeObj(interp, node, objCmdName);
          692  +    }
          693  +    resultObj->bytes = NULL;
          694  +    resultObj->length = 0;
          695  +    resultObj->internalRep.otherValuePtr = node;
          696  +    resultObj->typePtr = &tdomNodeType;
          697  +    return resultObj;
   676    698   }
   677    699   
   678    700   /*----------------------------------------------------------------------------
   679    701   |   tcldom_returnDocumentObj
   680    702   |
   681    703   \---------------------------------------------------------------------------*/
   682    704   int tcldom_returnDocumentObj (
................................................................................
   757    779       domNode    *node,
   758    780       int         nsIndex,
   759    781       const char *uri
   760    782   )
   761    783   {
   762    784       int         result;
   763    785       domNode    *child;
   764         -    char        prefix[MAX_PREFIX_LEN], objCmdName[80];
          786  +    char        prefix[MAX_PREFIX_LEN];
   765    787       const char *localName;
   766    788       Tcl_Obj    *namePtr, *resultPtr;
   767    789   
   768    790       /* nsIndex == -1 ==> DOM 1 no NS i.e getElementsByTagName
   769    791          nsIndex != -1 are the NS aware cases
   770    792          nsIndex == -2 ==> more than one namespace in the document with the 
   771    793                            requested namespace, we have to strcmp the URI
................................................................................
   792    814               if (nsIndex == -1) {
   793    815                   localName = node->nodeName;
   794    816               } else {
   795    817                   domSplitQName(node->nodeName, prefix, &localName);
   796    818               }
   797    819               if (Tcl_StringMatch(localName, namePattern)) {
   798    820                   resultPtr = Tcl_GetObjResult(interp);
   799         -                tcldom_createNodeObj(interp, node, objCmdName);
   800         -                namePtr = Tcl_NewStringObj(objCmdName, -1);
          821  +                namePtr = tcldom_returnNodeObj(interp, node);
   801    822                   result = Tcl_ListObjAppendElement(interp, resultPtr, namePtr);
   802    823                   if (result != TCL_OK) {
   803    824                       Tcl_DecrRefCount(namePtr);
   804    825                       return result;
   805    826                   }
   806    827               }
   807    828           }
................................................................................
   869    890       domNode    * node,
   870    891       void       * clientData
   871    892   )
   872    893   {
   873    894       Tcl_Interp * interp = (Tcl_Interp*)clientData;
   874    895       Tcl_Obj    * resultPtr = Tcl_GetObjResult(interp);
   875    896       Tcl_Obj    * namePtr;
   876         -    char         objCmdName[80];
   877    897       int          result;
   878    898   
   879    899   
   880         -    tcldom_createNodeObj(interp, node, objCmdName);
   881         -    namePtr = Tcl_NewStringObj(objCmdName, -1);
          900  +    namePtr = tcldom_returnNodeObj(interp, node);
   882    901       result  = Tcl_ListObjAppendElement(interp, resultPtr, namePtr);
   883    902       if (result != TCL_OK) {
   884    903           Tcl_DecrRefCount(namePtr);
   885    904       }
   886    905       return result;
   887    906   }
   888    907   
................................................................................
   987   1006       }
   988   1007       if (result != 0) {
   989   1008           return TCL_ERROR;
   990   1009       }
   991   1010       return TCL_OK;
   992   1011   }
   993   1012   
         1013  +
         1014  +/*----------------------------------------------------------------------------
         1015  +|   tcldom_getNodeFromObj
         1016  +|
         1017  +\---------------------------------------------------------------------------*/
         1018  +domNode * tcldom_getNodeFromObj (
         1019  +    Tcl_Interp  *interp,
         1020  +    Tcl_Obj     *nodeObj
         1021  +)
         1022  +{
         1023  +    Tcl_CmdInfo  cmdInfo;
         1024  +    domNode     *node = NULL;
         1025  +    char        *nodeName;
         1026  +    
         1027  +    GetTcldomTSD()
         1028  +
         1029  +    if (nodeObj->typePtr == &tdomNodeType) {
         1030  +        return (domNode*)nodeObj->internalRep.otherValuePtr;
         1031  +    }
         1032  +    
         1033  +    if (TSD(dontCreateObjCommands)) {
         1034  +        if (SetTdomNodeFromAny (interp, nodeObj) == TCL_OK) {
         1035  +            return (domNode*)nodeObj->internalRep.otherValuePtr;
         1036  +        }
         1037  +        return NULL;
         1038  +    }
         1039  +    
         1040  +    nodeName = Tcl_GetString(nodeObj);
         1041  +    if (strncmp(nodeName, "domNode", 7)) {
         1042  +        SetResult("parameter not a domNode!");
         1043  +        return NULL;
         1044  +    }
         1045  +    if (sscanf(&nodeName[7], "%p", &node) != 1) {
         1046  +        if (!Tcl_GetCommandInfo(interp, nodeName, &cmdInfo)) {
         1047  +            SetResult("parameter not a domNode!");
         1048  +            return NULL;
         1049  +        }
         1050  +        if (   (cmdInfo.isNativeObjectProc == 0)
         1051  +            || (cmdInfo.objProc != (Tcl_ObjCmdProc*)tcldom_NodeObjCmd)) {
         1052  +            SetResult("parameter not a domNode object command!");
         1053  +            return NULL;
         1054  +        }
         1055  +        node = (domNode*)cmdInfo.objClientData;
         1056  +    }
         1057  +
         1058  +    return node;
         1059  +}
   994   1060   
   995   1061   /*----------------------------------------------------------------------------
   996   1062   |   tcldom_getNodeFromName
   997   1063   |
   998   1064   \---------------------------------------------------------------------------*/
   999   1065   domNode * tcldom_getNodeFromName (
  1000   1066       Tcl_Interp  *interp,
................................................................................
  1157   1223       nodeToAppend = doc->rootNode->firstChild;
  1158   1224       while (nodeToAppend) {
  1159   1225           domAppendChild(node, nodeToAppend);
  1160   1226           nodeToAppend = nodeToAppend->nextSibling;
  1161   1227       }
  1162   1228       domFreeDocument(doc, NULL, NULL);
  1163   1229   
  1164         -    return tcldom_returnNodeObj(interp, node, 0, NULL);
         1230  +    return tcldom_setInterpAndReturnVar(interp, node, 0, NULL);
  1165   1231   #endif
  1166   1232   }
  1167   1233   
  1168   1234   
  1169   1235   /*----------------------------------------------------------------------------
  1170   1236   |   tcldom_xpathResultSet
  1171   1237   |
................................................................................
  1176   1242       xpathResultSet  *rs,
  1177   1243       Tcl_Obj         *type,
  1178   1244       Tcl_Obj         *value
  1179   1245   )
  1180   1246   {
  1181   1247       int          rc, i;
  1182   1248       Tcl_Obj     *namePtr, *objv[2];
  1183         -    char         objCmdName[80];
  1184   1249       domAttrNode *attr;
  1185   1250       domNodeType  startType;
  1186   1251       int          mixedNodeSet;
  1187   1252   
  1188   1253       switch (rs->type) {
  1189   1254           case EmptyResult:
  1190   1255                Tcl_SetStringObj(type, "empty", -1);
................................................................................
  1235   1300                    if (rs->nodes[i]->nodeType == ATTRIBUTE_NODE) {
  1236   1301                        attr = (domAttrNode*)rs->nodes[i];
  1237   1302                        objv[0] = Tcl_NewStringObj(attr->nodeName, -1);
  1238   1303                        objv[1] = Tcl_NewStringObj(attr->nodeValue,
  1239   1304                                                   attr->valueLength);
  1240   1305                        namePtr = Tcl_NewListObj(2, objv);
  1241   1306                    } else {
  1242         -                     tcldom_createNodeObj(interp, rs->nodes[i], objCmdName);
  1243         -                     namePtr = Tcl_NewStringObj(objCmdName, -1);
         1307  +                     namePtr = tcldom_returnNodeObj(interp, rs->nodes[i]);
  1244   1308                    }
  1245   1309                    rc = Tcl_ListObjAppendElement(interp, value, namePtr);
  1246   1310                    if (rc != TCL_OK) {
  1247   1311                        Tcl_DecrRefCount(namePtr);
  1248   1312                        return rc;
  1249   1313                    }
  1250   1314                }
................................................................................
  1279   1343       xpathResultSets *args,
  1280   1344       xpathResultSet  *result,
  1281   1345       char           **errMsg
  1282   1346   )
  1283   1347   {
  1284   1348       Tcl_Interp  *interp = (Tcl_Interp*) clientData;
  1285   1349       char         tclxpathFuncName[200], objCmdName[80];
  1286         -    char         *errStr, *typeStr, *nodeName;
         1350  +    char         *errStr, *typeStr;
  1287   1351       Tcl_Obj     *resultPtr, *objv[MAX_REWRITE_ARGS], *type, *value, *nodeObj,
  1288   1352                   *tmpObj;
  1289   1353       Tcl_CmdInfo  cmdInfo;
  1290   1354       int          objc, rc, i, errStrLen, listLen, intValue, res;
  1291   1355       double       doubleValue;
  1292   1356       domNode     *node;
  1293   1357   
................................................................................
  1321   1385           tmpObj = Tcl_NewListObj(0, NULL);
  1322   1386           Tcl_ListObjAppendElement(interp, tmpObj, 
  1323   1387                                    Tcl_NewStringObj(objCmdName, -1));
  1324   1388           Tcl_ListObjAppendElement(
  1325   1389               interp, tmpObj,
  1326   1390               Tcl_NewStringObj(((domAttrNode*)ctxNode)->nodeName, -1));
  1327   1391       } else {
  1328         -        tcldom_createNodeObj(interp, ctxNode, objCmdName);
  1329         -        tmpObj = Tcl_NewStringObj(objCmdName, -1);
         1392  +        tmpObj = tcldom_returnNodeObj(interp, ctxNode);
  1330   1393       }
  1331   1394       objv[objc] = tmpObj;
  1332   1395       Tcl_IncrRefCount(objv[objc++]);
  1333   1396   
  1334   1397       objv[objc] = Tcl_NewIntObj(position);
  1335   1398       Tcl_IncrRefCount(objv[objc++]);
  1336   1399   
................................................................................
  1392   1455                   if (rc != TCL_OK) {
  1393   1456                       *errMsg = tdomstrdup("value not a node list!");
  1394   1457                       res = XPATH_EVAL_ERR;
  1395   1458                       goto funcCallCleanup;
  1396   1459                   }
  1397   1460                   for (i=0; i < listLen; i++) {
  1398   1461                       rc = Tcl_ListObjIndex(interp, value, i, &nodeObj);
  1399         -                    nodeName = Tcl_GetString(nodeObj);
  1400         -                    node = tcldom_getNodeFromName(interp, nodeName, &errStr);
         1462  +                    node = tcldom_getNodeFromObj(interp, nodeObj);
  1401   1463                       if (node == NULL) {
  1402         -                        *errMsg = tdomstrdup(errStr);
         1464  +                        *errMsg = tdomstrdup(Tcl_GetStringResult(interp));
  1403   1465                           res = XPATH_EVAL_ERR;
  1404   1466                           goto funcCallCleanup;
  1405   1467                       }
  1406   1468                       rsAddNode(result, node);
  1407   1469                   }
  1408   1470                   sortByDocOrder(result);
  1409   1471               } else
................................................................................
  1959   2021               return rc;
  1960   2022           }
  1961   2023           if ((rc = tcldom_appendFromTclList(interp, newnode, childObj))
  1962   2024               != TCL_OK) {
  1963   2025               return rc;
  1964   2026           }
  1965   2027       }
  1966         -    return tcldom_returnNodeObj(interp, node, 0, NULL);
         2028  +    return tcldom_setInterpAndReturnVar(interp, node, 0, NULL);
  1967   2029   }
  1968   2030   
  1969   2031   
  1970   2032   /*----------------------------------------------------------------------------
  1971   2033   |   tcldom_treeAsTclList
  1972   2034   |
  1973   2035   \---------------------------------------------------------------------------*/
................................................................................
  3321   3383       domDocument *doc,
  3322   3384       Tcl_Interp  *interp,
  3323   3385       int          objc,
  3324   3386       Tcl_Obj     *CONST objv[] 
  3325   3387       )
  3326   3388   {
  3327   3389       int      len, i, hnew;
  3328         -    char    *errMsg;
  3329   3390       Tcl_HashEntry *h;
  3330   3391       Tcl_Obj *objPtr;
  3331   3392       domNode     *node;
  3332   3393       
  3333   3394       CheckArgs (4,4,0, "<domDoc> renameNode nodeList name");
  3334   3395       if (Tcl_ListObjLength (interp, objv[2], &len) != TCL_OK) {
  3335   3396           SetResult ("The first argument to the renameNode method"
................................................................................
  3336   3397                      " must be a list of element nodes.");
  3337   3398           return TCL_ERROR;
  3338   3399       }
  3339   3400       h = Tcl_CreateHashEntry(&HASHTAB(doc,tdom_tagNames), 
  3340   3401                               Tcl_GetString(objv[3]), &hnew);
  3341   3402       for (i = 0; i < len; i++) {
  3342   3403           Tcl_ListObjIndex (interp, objv[2], i, &objPtr);
  3343         -        node = tcldom_getNodeFromName (interp, Tcl_GetString (objPtr),
  3344         -                                       &errMsg);
         3404  +        node = tcldom_getNodeFromObj (interp, objPtr);
  3345   3405           if (node == NULL) {
  3346         -            SetResult (errMsg);
  3347         -            if (errMsg) FREE (errMsg);
  3348   3406               return TCL_ERROR;
  3349   3407           }
  3350   3408           node->nodeName = (char *)&(h->key);
  3351   3409       }
  3352   3410       return TCL_OK;
  3353   3411   }
  3354   3412   
................................................................................
  3661   3719   {
  3662   3720       GetTcldomTSD()
  3663   3721   
  3664   3722       domNode     *node, *child, *refChild, *oldChild, *refNode;
  3665   3723       domNS       *ns;
  3666   3724       domAttrNode *attrs;
  3667   3725       domException exception;
  3668         -    char         tmp[200], objCmdName[80], prefix[MAX_PREFIX_LEN],
  3669         -                *method, *nodeName, *str, *attr_name, *attr_val, *filter,
  3670         -                *errMsg;
         3726  +    char         tmp[200], prefix[MAX_PREFIX_LEN], *method, *nodeName,
         3727  +                 *str, *attr_name, *attr_val, *filter;
  3671   3728       const char  *localName, *uri, *nsStr;
  3672   3729       int          result, length, methodIndex, i, line, column;
  3673   3730       int          nsIndex, bool, hnew, legacy;
  3674   3731       Tcl_Obj     *namePtr, *resultPtr;
  3675   3732       Tcl_Obj     *mobjv[MAX_REWRITE_ARGS];
  3676   3733       Tcl_CmdInfo  cmdInfo;
  3677   3734       Tcl_HashEntry *h;
................................................................................
  3729   3786           if (objc < 3) {
  3730   3787               SetResult(node_usage);
  3731   3788               return TCL_ERROR;
  3732   3789           }
  3733   3790           if (TSD(domCreateCmdMode) == DOM_CREATECMDMODE_AUTO) {
  3734   3791               TSD(dontCreateObjCommands) = 1;
  3735   3792           }
  3736         -        nodeName = Tcl_GetString(objv[1]);
  3737         -        node = tcldom_getNodeFromName(interp, nodeName, &errMsg);
         3793  +        node = tcldom_getNodeFromObj(interp, objv[1]);
  3738   3794           if (node == NULL) {
  3739         -            SetResult(errMsg);
  3740   3795               return TCL_ERROR;
  3741   3796           }
  3742   3797           objc--;
  3743   3798           objv++;
  3744   3799       }
  3745   3800       if (objc < 2) {
  3746   3801           SetResult(node_usage);
................................................................................
  3868   3923           case m_selectNodes:
  3869   3924               return tcldom_selectNodes (interp, node, --objc, ++objv);
  3870   3925   
  3871   3926           case m_find:
  3872   3927               CheckArgs(4,5,2,"attrName attrVal ?nodeObjVar?");
  3873   3928               attr_name = Tcl_GetStringFromObj(objv[2], NULL);
  3874   3929               attr_val  = Tcl_GetStringFromObj(objv[3], &length);
  3875         -            return tcldom_returnNodeObj
         3930  +            return tcldom_setInterpAndReturnVar
  3876   3931                   (interp, tcldom_find(node, attr_name, attr_val, length),
  3877   3932                    (objc == 5), (objc == 5) ? objv[4] : NULL);
  3878   3933   
  3879   3934           case m_child:
  3880   3935               CheckArgs(3,6,2,"instance|all ?type? ?attr value?");
  3881   3936               return tcldom_xpointerSearch(interp, XP_CHILD, node, objc, objv);
  3882   3937   
................................................................................
  3897   3952               return tcldom_xpointerSearch(interp, XP_PSIBLING, node,objc,objv);
  3898   3953   
  3899   3954           case m_root:
  3900   3955               CheckArgs(2,3,2,"?nodeObjVar?");
  3901   3956               while (node->parentNode) {
  3902   3957                   node = node->parentNode;
  3903   3958               }
  3904         -            return tcldom_returnNodeObj(interp, node, (objc == 3),
         3959  +            return tcldom_setInterpAndReturnVar(interp, node, (objc == 3),
  3905   3960                                           (objc == 3) ? objv[2] : NULL);
  3906   3961   
  3907   3962           case m_text:
  3908   3963               CheckArgs(2,2,2,"");
  3909   3964               if (node->nodeType != ELEMENT_NODE) {
  3910   3965                   SetResult("NOT_AN_ELEMENT");
  3911   3966                   return TCL_ERROR;
................................................................................
  4040   4095               for ( i = 2;  i < objc; ) {
  4041   4096                   attr_name = Tcl_GetString(objv[i++]);
  4042   4097                   CheckName (interp, attr_name, "attribute", 0);
  4043   4098                   attr_val  = Tcl_GetString(objv[i++]);
  4044   4099                   CheckText (interp, attr_val, "attribute");
  4045   4100                   domSetAttribute(node, attr_name, attr_val);
  4046   4101               }
  4047         -            return tcldom_returnNodeObj(interp, node, 0, NULL);
         4102  +            return tcldom_setInterpAndReturnVar(interp, node, 0, NULL);
  4048   4103   
  4049   4104           case m_setAttributeNS:
  4050   4105               if (node->nodeType != ELEMENT_NODE) {
  4051   4106                   SetResult("NOT_AN_ELEMENT : there are no attributes");
  4052   4107                   return TCL_ERROR;
  4053   4108               }
  4054   4109               if ((objc < 5) || (((objc - 2) % 3) != 0)) {
................................................................................
  4070   4125                           SetResult("For all prefixed attributes with prefixes "
  4071   4126                                     "other than 'xml' or 'xmlns' "
  4072   4127                                     "you have to provide a namespace URI");
  4073   4128                       }
  4074   4129                       return TCL_ERROR;
  4075   4130                   }
  4076   4131               }
  4077         -            return tcldom_returnNodeObj(interp, node, 0, NULL);
         4132  +            return tcldom_setInterpAndReturnVar(interp, node, 0, NULL);
  4078   4133   
  4079   4134           case m_hasAttribute:
  4080   4135               CheckArgs(3,3,2,"attrName");
  4081   4136               if (node->nodeType != ELEMENT_NODE) {		
  4082   4137                   SetResult("NOT_AN_ELEMENT : there are no attributes");
  4083   4138                   return TCL_ERROR;
  4084   4139               }
................................................................................
  4128   4183               result = domRemoveAttribute(node, attr_name);
  4129   4184               if (result) {
  4130   4185                   SetResult("can't remove attribute '");
  4131   4186                   AppendResult(attr_name);
  4132   4187                   AppendResult("'");
  4133   4188                   return TCL_ERROR;
  4134   4189               }
  4135         -            return tcldom_returnNodeObj(interp, node, 0, NULL);
         4190  +            return tcldom_setInterpAndReturnVar(interp, node, 0, NULL);
  4136   4191   
  4137   4192           case m_removeAttributeNS:
  4138   4193               CheckArgs(4,4,2,"uri attrName");
  4139   4194               if (node->nodeType != ELEMENT_NODE) {		
  4140   4195                   SetResult("NOT_AN_ELEMENT : there are no attributes");
  4141   4196                   return TCL_ERROR;
  4142   4197               }
................................................................................
  4145   4200               result = domRemoveAttributeNS(node, uri, localName);
  4146   4201               if (result < 0) {
  4147   4202                   SetResult("can't remove attribute with localName '");
  4148   4203                   AppendResult(localName);
  4149   4204                   AppendResult("'");
  4150   4205                   return TCL_ERROR;
  4151   4206               }
  4152         -            return tcldom_returnNodeObj(interp, node, 0, NULL);
         4207  +            return tcldom_setInterpAndReturnVar(interp, node, 0, NULL);
  4153   4208   
  4154   4209           case m_nextSibling:
  4155   4210               CheckArgs(2,3,2,"?nodeObjVar?");
  4156         -            return tcldom_returnNodeObj(interp, node->nextSibling,
         4211  +            return tcldom_setInterpAndReturnVar(interp, node->nextSibling,
  4157   4212                                           (objc == 3), 
  4158   4213                                           (objc == 3) ? objv[2] : NULL);
  4159   4214           case m_previousSibling:
  4160   4215               CheckArgs(2,3,2,"?nodeObjVar?");
  4161         -            return tcldom_returnNodeObj(interp, node->previousSibling,
         4216  +            return tcldom_setInterpAndReturnVar(interp, node->previousSibling,
  4162   4217                                           (objc == 3),
  4163   4218                                           (objc == 3) ? objv[2] : NULL);
  4164   4219           case m_firstChild:
  4165   4220               CheckArgs(2,3,2,"?nodeObjVar?");
  4166   4221               if (node->nodeType == ELEMENT_NODE) {
  4167         -                return tcldom_returnNodeObj(interp, node->firstChild,
         4222  +                return tcldom_setInterpAndReturnVar(interp, node->firstChild,
  4168   4223                                               (objc == 3),
  4169   4224                                               (objc == 3) ? objv[2] : NULL);
  4170   4225               }
  4171         -            return tcldom_returnNodeObj(interp, NULL, (objc == 3),
         4226  +            return tcldom_setInterpAndReturnVar(interp, NULL, (objc == 3),
  4172   4227                                           (objc == 3) ? objv[2] : NULL);
  4173   4228           case m_lastChild:
  4174   4229               CheckArgs(2,3,2,"?nodeObjVar?");
  4175   4230               if (node->nodeType == ELEMENT_NODE) {
  4176         -                return tcldom_returnNodeObj(interp, node->lastChild,
         4231  +                return tcldom_setInterpAndReturnVar(interp, node->lastChild,
  4177   4232                                               (objc == 3),
  4178   4233                                               (objc == 3) ? objv[2] : NULL);
  4179   4234               }
  4180         -            return tcldom_returnNodeObj(interp, NULL, (objc == 3),
         4235  +            return tcldom_setInterpAndReturnVar(interp, NULL, (objc == 3),
  4181   4236                                           (objc == 3) ? objv[2] : NULL);
  4182   4237           case m_parentNode:
  4183   4238               CheckArgs(2,3,2,"?nodeObjVar?");
  4184         -            return tcldom_returnNodeObj(interp, node->parentNode, (objc == 3),
         4239  +            return tcldom_setInterpAndReturnVar(interp, node->parentNode, (objc == 3),
  4185   4240                                           (objc == 3) ? objv[2] : NULL);
  4186   4241           case m_appendFromList:
  4187   4242               CheckArgs(3,3,2,"list");
  4188   4243               return tcldom_appendFromTclList(interp, node, objv[2]);
  4189   4244   
  4190   4245           case m_appendFromScript:
  4191   4246               CheckArgs(3,3,2,"script");
  4192   4247               if (nodecmd_appendFromScript(interp, node, objv[2]) != TCL_OK) {
  4193   4248                   return TCL_ERROR;
  4194   4249               }
  4195         -            return tcldom_returnNodeObj(interp, node, 0, NULL);
         4250  +            return tcldom_setInterpAndReturnVar(interp, node, 0, NULL);
  4196   4251   
  4197   4252           case m_insertBeforeFromScript:
  4198   4253               CheckArgs(4,4,2, "script refChild");
  4199         -            nodeName = Tcl_GetString (objv[3]);
  4200         -            if (nodeName[0] == '\0') {
  4201         -                refChild = NULL;
         4254  +            if (objv[3]->typePtr == &tdomNodeType) {
         4255  +                refChild = objv[3]->internalRep.otherValuePtr;
  4202   4256               } else {
  4203         -                refChild = tcldom_getNodeFromName (interp, nodeName, &errMsg);
  4204         -                if (refChild == NULL) {
  4205         -                    SetResult ( errMsg );
  4206         -                    return TCL_ERROR;
         4257  +                nodeName = Tcl_GetString (objv[3]);
         4258  +                if (nodeName[0] == '\0') {
         4259  +                    refChild = NULL;
         4260  +                } else {
         4261  +                    refChild = tcldom_getNodeFromObj (interp, objv[3]);
         4262  +                    if (refChild == NULL) {
         4263  +                        return TCL_ERROR;
         4264  +                    }
  4207   4265                   }
  4208   4266               }
  4209   4267               if (nodecmd_insertBeforeFromScript(interp, node, objv[2], refChild)
  4210   4268                   != TCL_OK) {
  4211   4269                   return TCL_ERROR;
  4212   4270               }
  4213         -            return tcldom_returnNodeObj (interp, node, 0, NULL);
         4271  +            return tcldom_setInterpAndReturnVar (interp, node, 0, NULL);
  4214   4272               
  4215   4273           case m_appendXML:
  4216   4274               CheckArgs(3,3,2,"xmlString");
  4217   4275               return tcldom_appendXML(interp, node, objv[2]);
  4218   4276   
  4219   4277           case m_appendChild:
  4220   4278               CheckArgs(3,3,2,"nodeToAppend");
  4221         -            nodeName = Tcl_GetString(objv[2]);
  4222         -            child = tcldom_getNodeFromName(interp, nodeName, &errMsg);
         4279  +            child = tcldom_getNodeFromObj(interp, objv[2]);
  4223   4280               if (child == NULL) {
  4224         -                SetResult(errMsg);
  4225   4281                   return TCL_ERROR;
  4226   4282               }
  4227   4283               exception = domAppendChild (node, child);
  4228   4284               if (exception != OK) {
  4229   4285                   SetResult(domException2String(exception));
  4230   4286                   return TCL_ERROR;
  4231   4287               }
  4232         -            return tcldom_returnNodeObj(interp, child, 0, NULL);
         4288  +            return tcldom_setInterpAndReturnVar(interp, child, 0, NULL);
  4233   4289   
  4234   4290           case m_cloneNode:
  4235   4291               CheckArgs(2,3,2,"?-deep?");
  4236   4292               if (objc == 3) {
  4237   4293                   if (!strcmp(Tcl_GetString(objv[2]), "-deep")) {
  4238         -                    return tcldom_returnNodeObj(interp, domCloneNode(node, 1),
         4294  +                    return tcldom_setInterpAndReturnVar(interp, domCloneNode(node, 1),
  4239   4295                                                   0, NULL);
  4240   4296                   }
  4241   4297                   SetResult("unknown option! Options: ?-deep? ");
  4242   4298                   return TCL_ERROR;
  4243   4299               }
  4244         -            return tcldom_returnNodeObj(interp, domCloneNode(node, 0), 0, NULL);
         4300  +            return tcldom_setInterpAndReturnVar(interp, domCloneNode(node, 0), 0, NULL);
  4245   4301   
  4246   4302           case m_removeChild:
  4247   4303               CheckArgs(3,3,2,"childToRemove");
  4248         -            nodeName = Tcl_GetString(objv[2]);
  4249         -            child = tcldom_getNodeFromName(interp, nodeName, &errMsg);
         4304  +            child = tcldom_getNodeFromObj(interp, objv[2]);
  4250   4305               if (child == NULL) {
  4251         -                SetResult(errMsg);
  4252   4306                   return TCL_ERROR;
  4253   4307               }
  4254   4308               exception = domRemoveChild (node, child);
  4255   4309               if (exception != OK) {
  4256   4310                   SetResult (domException2String (exception));
  4257   4311                   return TCL_ERROR;
  4258   4312               }
  4259         -            return tcldom_returnNodeObj(interp, child, 0, NULL);
         4313  +            return tcldom_setInterpAndReturnVar(interp, child, 0, NULL);
  4260   4314   
  4261   4315           case m_insertBefore:
  4262   4316               CheckArgs(4,4,2,"childToInsert refChild");
  4263         -            nodeName = Tcl_GetString(objv[2]);
  4264         -            child = tcldom_getNodeFromName(interp, nodeName, &errMsg);
         4317  +            child = tcldom_getNodeFromObj(interp, objv[2]);
  4265   4318               if (child == NULL) {
  4266         -                SetResult(errMsg);
  4267   4319                   return TCL_ERROR;
  4268   4320               }
  4269   4321   
  4270         -            nodeName = Tcl_GetString (objv[3]);
  4271         -            if (nodeName[0] == '\0') {
  4272         -                refChild = NULL;
         4322  +            if (objv[3]->typePtr == &tdomNodeType) {
         4323  +                refChild = objv[3]->internalRep.otherValuePtr;
  4273   4324               } else {
  4274         -                refChild = tcldom_getNodeFromName (interp, nodeName, &errMsg);
  4275         -                if (refChild == NULL) {
  4276         -                    SetResult ( errMsg );
  4277         -                    return TCL_ERROR;
         4325  +                nodeName = Tcl_GetString (objv[3]);
         4326  +                if (nodeName[0] == '\0') {
         4327  +                    refChild = NULL;
         4328  +                } else {
         4329  +                    refChild = tcldom_getNodeFromObj (interp, objv[3]);
         4330  +                    if (refChild == NULL) {
         4331  +                        return TCL_ERROR;
         4332  +                    }
  4278   4333                   }
  4279   4334               }
  4280   4335               exception = domInsertBefore(node, child, refChild);
  4281   4336               if (exception != OK) {
  4282   4337                   SetResult(domException2String(exception));
  4283   4338                   return TCL_ERROR;
  4284   4339               }
  4285         -            return tcldom_returnNodeObj(interp, child, 0, NULL);
         4340  +            return tcldom_setInterpAndReturnVar(interp, child, 0, NULL);
  4286   4341   
  4287   4342           case m_replaceChild:
  4288   4343               CheckArgs(4,4,2,"new old");
  4289         -            nodeName = Tcl_GetString(objv[2]);
  4290         -            child = tcldom_getNodeFromName(interp, nodeName, &errMsg);
         4344  +            child = tcldom_getNodeFromObj(interp, objv[2]);
  4291   4345               if (child == NULL) {
  4292         -                SetResult(errMsg);
  4293   4346                   return TCL_ERROR;
  4294   4347               }
  4295         -
  4296         -            nodeName = Tcl_GetString(objv[3]);
  4297         -            oldChild = tcldom_getNodeFromName(interp, nodeName, &errMsg);
         4348  +            oldChild = tcldom_getNodeFromObj(interp, objv[3]);
  4298   4349               if (oldChild == NULL) {
  4299         -                SetResult(errMsg);
  4300   4350                   return TCL_ERROR;
  4301   4351               }
  4302   4352               exception = domReplaceChild(node, child, oldChild);
  4303   4353               if (exception != OK) {
  4304   4354                   SetResult(domException2String(exception));
  4305   4355                   return TCL_ERROR;
  4306   4356               }
  4307         -            return tcldom_returnNodeObj(interp, oldChild, 0, NULL);
         4357  +            return tcldom_setInterpAndReturnVar(interp, oldChild, 0, NULL);
  4308   4358   
  4309   4359           case m_hasChildNodes:
  4310   4360               CheckArgs(2,2,2,"");
  4311   4361               if (node->nodeType == ELEMENT_NODE) {
  4312   4362                   SetIntResult(node->firstChild ? 1 : 0);
  4313   4363               } else {
  4314   4364                   SetIntResult(0);
................................................................................
  4317   4367   
  4318   4368           case m_childNodes:
  4319   4369               CheckArgs(2,2,2,"");
  4320   4370               resultPtr = Tcl_GetObjResult(interp);
  4321   4371               if (node->nodeType == ELEMENT_NODE) {
  4322   4372                   child = node->firstChild;
  4323   4373                   while (child != NULL) {
  4324         -                    tcldom_createNodeObj(interp, child, objCmdName);
  4325         -                    namePtr = Tcl_NewStringObj(objCmdName, -1);
         4374  +                    namePtr = tcldom_returnNodeObj(interp, child);
  4326   4375                       result  = Tcl_ListObjAppendElement(interp, resultPtr,
  4327   4376                                                          namePtr);
  4328   4377                       if (result != TCL_OK) {
  4329   4378                           Tcl_DecrRefCount(namePtr);
  4330   4379                           return result;
  4331   4380                       }
  4332   4381                       child = child->nextSibling;
................................................................................
  4386   4435           case m_getElementById:
  4387   4436               CheckArgs(3,3,2,"id");
  4388   4437               if (node->ownerDocument->ids) {
  4389   4438                   str = Tcl_GetString(objv[2]);
  4390   4439                   h = Tcl_FindHashEntry(node->ownerDocument->ids, str);
  4391   4440                   if (h) {
  4392   4441                       domNode *node = Tcl_GetHashValue(h);
  4393         -                    return tcldom_returnNodeObj(interp, node, 0, NULL);
         4442  +                    return tcldom_setInterpAndReturnVar(interp, node, 0, NULL);
  4394   4443                   }
  4395   4444               }
  4396   4445               SetResult("");
  4397   4446               return TCL_OK;
  4398   4447   
  4399   4448           case m_nodeName:
  4400   4449               CheckArgs(2,2,2,"");
................................................................................
  4619   4668                       node->nodeFlags &= (~DISABLE_OUTPUT_ESCAPING);
  4620   4669                   }
  4621   4670               }
  4622   4671               break;
  4623   4672   
  4624   4673           case m_precedes:
  4625   4674               CheckArgs(3,3,2, "node");
  4626         -            nodeName = Tcl_GetString(objv[2]);
  4627         -            refNode = tcldom_getNodeFromName(interp, nodeName, &errMsg);
         4675  +            refNode = tcldom_getNodeFromObj(interp, objv[2]);
  4628   4676               if (refNode == NULL) {
  4629         -                SetResult(errMsg);
  4630   4677                   return TCL_ERROR;
  4631   4678               }
  4632   4679               if (node->ownerDocument != refNode->ownerDocument) {
  4633   4680                   SetResult("Cannot compare the relative order of nodes "
  4634   4681                             "out of different documents.");
  4635   4682                   return TCL_ERROR;
  4636   4683               }
................................................................................
  4676   4723                                        node->ownerDocument, LOCK_WRITE);
  4677   4724           case m_readlock:
  4678   4725               CheckArgs(3,3,2,"script");
  4679   4726               return tcldom_EvalLocked(interp, (Tcl_Obj**)objv, 
  4680   4727                                        node->ownerDocument, LOCK_READ);
  4681   4728           )
  4682   4729       }
  4683         -    return TCL_OK;
  4684         -}
         4730  +    return TCL_OK;}
         4731  +
  4685   4732   
  4686   4733   
  4687   4734   /*----------------------------------------------------------------------------
  4688   4735   |   tcldom_DocObjCmd
  4689   4736   |
  4690   4737   \---------------------------------------------------------------------------*/
  4691   4738   int tcldom_DocObjCmd (
................................................................................
  4824   4871       |
  4825   4872       \---------------------------------------------------------------------*/
  4826   4873   
  4827   4874       switch ((enum docMethod) methodIndex ) {
  4828   4875   
  4829   4876           case m_documentElement:
  4830   4877               CheckArgs(2,3,2,"");
  4831         -            return tcldom_returnNodeObj(interp, doc->documentElement,
         4878  +            return tcldom_setInterpAndReturnVar(interp, doc->documentElement,
  4832   4879                                           (objc == 3), 
  4833   4880                                           (objc == 3) ? objv[2] : NULL);
  4834   4881           case m_getElementsByTagName:
  4835   4882               CheckArgs(3,3,2,"elementName");
  4836   4883               return tcldom_getElementsByTagName(interp, Tcl_GetString(objv[2]),
  4837   4884                                                  doc->documentElement, -1, NULL);
  4838   4885           case m_getElementsByTagNameNS:
................................................................................
  4869   4916                                                  doc->documentElement, nsIndex,
  4870   4917                                                  uri);
  4871   4918           case m_createElement:
  4872   4919               CheckArgs(3,4,2,"elementName ?newObjVar?");
  4873   4920               tag = Tcl_GetString(objv[2]);
  4874   4921               CheckName (interp, tag, "tag", 0);
  4875   4922               n = domNewElementNode(doc, tag, ELEMENT_NODE);
  4876         -            return tcldom_returnNodeObj(interp, n, (objc == 4),
         4923  +            return tcldom_setInterpAndReturnVar(interp, n, (objc == 4),
  4877   4924                                           (objc == 4) ? objv[3] : NULL);
  4878   4925   
  4879   4926           case m_createElementNS:
  4880   4927               CheckArgs(4,5,2,"elementName uri ?newObjVar?");
  4881   4928               uri = Tcl_GetString(objv[2]);
  4882   4929               tag = Tcl_GetString(objv[3]);
  4883   4930               CheckName (interp, tag, "full qualified tag", 1);
  4884   4931               n = domNewElementNodeNS(doc, tag, uri, ELEMENT_NODE);
  4885         -            return tcldom_returnNodeObj(interp, n, (objc == 5),
         4932  +            return tcldom_setInterpAndReturnVar(interp, n, (objc == 5),
  4886   4933                                           (objc == 5) ? objv[4] : NULL);
  4887   4934   
  4888   4935           case m_createTextNode:
  4889   4936               CheckArgs(3,4,2,"data ?newObjVar?");
  4890   4937               data = Tcl_GetStringFromObj(objv[2], &data_length);
  4891   4938               CheckText (interp, data, "text");
  4892   4939               n = (domNode*)domNewTextNode(doc, data, data_length, TEXT_NODE);
  4893         -            return tcldom_returnNodeObj(interp, n, (objc == 4),
         4940  +            return tcldom_setInterpAndReturnVar(interp, n, (objc == 4),
  4894   4941                                           (objc == 4) ? objv[3] : NULL);
  4895   4942   
  4896   4943           case m_createCDATASection:
  4897   4944               CheckArgs(3,4,2,"data ?newObjVar?");
  4898   4945               data = Tcl_GetStringFromObj(objv[2], &data_length);
  4899   4946               CheckCDATA (interp, data);
  4900   4947               n = (domNode*)domNewTextNode(doc, data, data_length, 
  4901   4948                                            CDATA_SECTION_NODE);
  4902         -            return tcldom_returnNodeObj(interp, n, (objc == 4),
         4949  +            return tcldom_setInterpAndReturnVar(interp, n, (objc == 4),
  4903   4950                                           (objc == 4) ? objv[3] : NULL);
  4904   4951   
  4905   4952           case m_createComment:
  4906   4953               CheckArgs(3,4,2,"data ?newObjVar?");
  4907   4954               data = Tcl_GetStringFromObj(objv[2], &data_length);
  4908   4955               CheckComment(interp, data);
  4909   4956               n = (domNode*)domNewTextNode(doc, data, data_length, COMMENT_NODE);
  4910         -            return tcldom_returnNodeObj(interp, n, (objc == 4),
         4957  +            return tcldom_setInterpAndReturnVar(interp, n, (objc == 4),
  4911   4958                                           (objc == 4) ? objv[3] : NULL);
  4912   4959   
  4913   4960           case m_createProcessingInstruction:
  4914   4961               CheckArgs(4,5,2,"target data ?newObjVar?");
  4915   4962               target = Tcl_GetStringFromObj(objv[2], &target_length);
  4916   4963               CheckPIName (interp, target);
  4917   4964               data   = Tcl_GetStringFromObj(objv[3], &data_length);
  4918   4965               CheckPIValue (interp, data);
  4919   4966               n = (domNode*)domNewProcessingInstructionNode(doc, target, 
  4920   4967                                                             target_length, data, 
  4921   4968                                                             data_length);
  4922         -            return tcldom_returnNodeObj(interp, n, (objc == 5),
         4969  +            return tcldom_setInterpAndReturnVar(interp, n, (objc == 5),
  4923   4970                                           (objc == 5) ? objv[4] : NULL);
  4924   4971   
  4925   4972           case m_delete:
  4926   4973               CheckArgs(2,2,2,"");
  4927   4974               if (clientData != NULL) {
  4928   4975                   Tcl_DeleteCommand(interp, Tcl_GetString (objv[0]));
  4929   4976               } else {

Added tests/dom.bench.

            1  +# -*- tcl -*-
            2  +# Tcl Benchmark File
            3  +#
            4  +# This file contains a number of benchmarks for the dom methods.
            5  +# This allow developers to monitor/gauge/track package performance.
            6  +#
            7  +# (c) 2013 Rolf Ade <rolf@pointsman.de>
            8  +
            9  +
           10  +# ### ### ### ######### ######### ######### ###########################
           11  +## Setting up the environment ...
           12  +
           13  +package require tdom 
           14  +
           15  +# ### ### ### ######### ######### ######### ###########################
           16  +## Benchmarks.
           17  +
           18  +dom createNodeCmd elementNode e1
           19  +
           20  +foreach nrOf {1 10 100 1000} {
           21  +
           22  +    bench -desc "getElementsByTagName: $nrOf returned nodes" -pre {
           23  +        dom createDocument root doc
           24  +        $doc documentElement root
           25  +        $root appendFromScript {
           26  +            for {set x 0} {$x < $nrOf} {incr x} {
           27  +                e1
           28  +            }
           29  +        }
           30  +    } -body {
           31  +        $doc getElementsByTagName e1
           32  +    } -post {
           33  +        $doc delete
           34  +    }
           35  +
           36  +}
           37  +
           38  +foreach nrOf {1 10 100 1000} {
           39  +
           40  +    bench -desc "getElementsByTagName: $nrOf returned node tokens" -pre {
           41  +        dom createDocument root doc
           42  +        $doc documentElement root
           43  +        $root appendFromScript {
           44  +            for {set x 0} {$x < $nrOf} {incr x} {
           45  +                e1
           46  +            }
           47  +        }
           48  +        dom setObjectCommands token
           49  +    } -body {
           50  +        $doc getElementsByTagName e1
           51  +    } -post {
           52  +        dom setObjectCommands automatic
           53  +        $doc delete
           54  +    }
           55  +
           56  +}
           57  +
           58  +proc cloneImitated {source target} {
           59  +    foreach att [$source attributes] {
           60  +        $target setAttribute $att [$source @$att]
           61  +    }
           62  +    set targetDoc [$target ownerDocument]
           63  +    foreach child [$source childNodes] {
           64  +        switch [$child nodeType] {
           65  +            "ELEMENT_NODE" {
           66  +                set targetChild [$targetDoc createElement [$child nodeName]]
           67  +            }
           68  +            "TEXT_NODE" {
           69  +                set targetChild [$targetDoc createTextNode [$child nodeValue]]
           70  +            }
           71  +            "CDATA_SECTION_NODE" {
           72  +                set targetChild [$targetDoc createCDATASection \
           73  +                                     [$child nodeValue]]
           74  +            }
           75  +            "PROCESSING_INSTRUCTION_NODE" {
           76  +                set targetChild [$targetDoc createProcessingInstruction \
           77  +                                     [$child nodeName] [$child nodeValue]]
           78  +            }
           79  +            "COMMENT_NODE" {
           80  +                set targetChild [$targetDoc createComment [$child nodeValue]]
           81  +            }
           82  +            default {
           83  +                error "Unexpected node type [$child nodeType]"
           84  +            }
           85  +        }
           86  +        $target appendChild $targetChild
           87  +        cloneImitated $child $targetChild
           88  +    }
           89  +}
           90  +
           91  +proc cloneImitated2 {source target} {
           92  +    foreach att [$source attributes] {
           93  +        $target setAttribute $att [$source @$att]
           94  +    }
           95  +    set targetDoc [$target ownerDocument]
           96  +    foreach child [$source childNodes] {
           97  +        switch [$child nodeType] {
           98  +            "ELEMENT_NODE" {
           99  +                $targetDoc createElement [$child nodeName] targetChild
          100  +            }
          101  +            "TEXT_NODE" {
          102  +                $targetDoc createTextNode [$child nodeValue] targetChild
          103  +            }
          104  +            "CDATA_SECTION_NODE" {
          105  +                $targetDoc createCDATASection [$child nodeValue] targetChild
          106  +            }
          107  +            "PROCESSING_INSTRUCTION_NODE" {
          108  +                $targetDoc createProcessingInstruction [$child nodeName] \
          109  +                    targetChild
          110  +            }
          111  +            "COMMENT_NODE" {
          112  +                $targetDoc createComment [$child nodeValue] targetChild
          113  +            }
          114  +            default {
          115  +                error "Unexpected node type [$child nodeType]"
          116  +            }
          117  +        }
          118  +        $target appendChild $targetChild
          119  +        cloneImitated2 $child $targetChild
          120  +    }
          121  +}
          122  +
          123  +proc cloneImitatedToken {source target} {
          124  +    foreach att [domNode $source attributes] {
          125  +        domNode $target setAttribute $att [domNode $source @$att]
          126  +    }
          127  +    set targetDoc [domNode $target ownerDocument]
          128  +    foreach child [domNode $source childNodes] {
          129  +        switch [domNode $child nodeType] {
          130  +            "ELEMENT_NODE" {
          131  +                set targetChild [$targetDoc createElement \
          132  +                                     [domNode $child nodeName]]
          133  +            }
          134  +            "TEXT_NODE" {
          135  +                set targetChild [$targetDoc createTextNode \
          136  +                                     [domNode $child nodeValue]]
          137  +            }
          138  +            "CDATA_SECTION_NODE" {
          139  +                set targetChild [$targetDoc createCDATASection \
          140  +                                     [domNode $child nodeValue]]
          141  +            }
          142  +            "PROCESSING_INSTRUCTION_NODE" {
          143  +                set targetChild [$targetDoc createProcessingInstruction \
          144  +                                     [domNode $child nodeName] \
          145  +                                     [domNode $child nodeValue]]
          146  +            }
          147  +            "COMMENT_NODE" {
          148  +                set targetChild [$targetDoc createComment \
          149  +                                     [domNode $child nodeValue]]
          150  +            }
          151  +            default {
          152  +                error "Unexpected node type [domNode $child nodeType]"
          153  +            }
          154  +        }
          155  +        domNode $target appendChild $targetChild
          156  +        cloneImitatedToken $child $targetChild
          157  +    }
          158  +}
          159  +
          160  +bench -desc "clone dom tree without clone method - cmds" -pre {
          161  +    set fd [open [file join [file dir [info script]] ../tests/data/mondial-europe.xml]]
          162  +    fconfigure $fd -encoding utf-8
          163  +    set doc [dom parse -channel $fd]
          164  +    close $fd
          165  +    set root [$doc documentElement]
          166  +    set clone [dom createDocument [$root nodeName]]
          167  +    set cloneRoot [$clone documentElement]
          168  +} -iters 5 -body {
          169  +    cloneImitated $root $cloneRoot
          170  +} -post {
          171  +    $doc delete
          172  +    $clone delete
          173  +}
          174  +
          175  +bench -desc "clone dom tree without clone method - cmds 2" -pre {
          176  +    set fd [open [file join [file dir [info script]] ../tests/data/mondial-europe.xml]]
          177  +    fconfigure $fd -encoding utf-8
          178  +    set doc [dom parse -channel $fd]
          179  +    close $fd
          180  +    set root [$doc documentElement]
          181  +    set clone [dom createDocument [$root nodeName]]
          182  +    set cloneRoot [$clone documentElement]
          183  +} -iters 5 -body {
          184  +    cloneImitated2 $root $cloneRoot
          185  +} -post {
          186  +    $doc delete
          187  +    $clone delete
          188  +}
          189  +
          190  +bench -desc "clone dom tree without clone method - token" -pre {
          191  +    set fd [open [file join [file dir [info script]] ../tests/data/mondial-europe.xml]]
          192  +    fconfigure $fd -encoding utf-8
          193  +    set doc [dom parse -channel $fd]
          194  +    close $fd
          195  +    set root [$doc documentElement]
          196  +    set clone [dom createDocument [$root nodeName]]
          197  +    set cloneRoot [$clone documentElement]
          198  +    dom setObjectCommands token
          199  +} -iters 5 -body {
          200  +    cloneImitatedToken $root $cloneRoot
          201  +} -post {
          202  +    $doc delete
          203  +    $clone delete
          204  +    dom setObjectCommands automatic
          205  +}

Changes to tests/domNode.bench.

   202    202       } -body {
   203    203           $doc selectNodes -cache 1 count(/root/e1)
   204    204       } -post {
   205    205           $doc delete
   206    206       }
   207    207   
   208    208   }
          209  +
          210  +foreach nrOf {1 10 100 1000} {
          211  +
          212  +    bench -desc "getElementsByTagName: $nrOf returned nodes" -pre {
          213  +        dom createDocument root doc
          214  +        $doc documentElement root
          215  +        $root appendFromScript {
          216  +            for {set x 0} {$x < $nrOf} {incr x} {
          217  +                e1
          218  +            }
          219  +        }
          220  +    } -body {
          221  +        $doc getElementsByTagName e1
          222  +    } -post {
          223  +        $doc delete
          224  +    }
          225  +
          226  +}
          227  +
          228  +foreach nrOf {1 10 100 1000} {
          229  +
          230  +    bench -desc "getElementsByTagName: $nrOf returned node tokens" -pre {
          231  +        dom createDocument root doc
          232  +        $doc documentElement root
          233  +        $root appendFromScript {
          234  +            for {set x 0} {$x < $nrOf} {incr x} {
          235  +                e1
          236  +            }
          237  +        }
          238  +        dom setObjectCommands token
          239  +    } -body {
          240  +        $doc getElementsByTagName e1
          241  +    } -post {
          242  +        dom setObjectCommands automatic
          243  +        $doc delete
          244  +    }
          245  +
          246  +}
          247  +
          248  +
          249  +bench -desc "firstChild node cmd" -pre {
          250  +    dom parse <root><e/></root> doc
          251  +    $doc documentElement root
          252  +} -body {
          253  +    $root firstChild
          254  +} -post {
          255  +    $doc delete
          256  +}
          257  +
          258  +bench -desc "firstChild node token" -pre {
          259  +    dom parse <root><e/></root> doc
          260  +    $doc documentElement root
          261  +    dom setObjectCommands token
          262  +} -body {
          263  +    $root firstChild
          264  +} -post {
          265  +    $doc delete
          266  +    dom setObjectCommands automatic
          267  +}
          268  +
          269  +bench -desc "firstChild node token from node token" -pre {
          270  +    dom parse <root><e/></root> doc
          271  +    dom setObjectCommands token
          272  +    $doc documentElement root
          273  +} -body {
          274  +    domNode $root firstChild
          275  +} -post {
          276  +    $doc delete
          277  +    dom setObjectCommands automatic
          278  +}
   209    279   
   210    280   dom parse <root/> doc
   211    281   $doc documentElement root
   212    282   
   213    283   bench -desc "Check for text-only element - xpath - empty"  -body {
   214    284       for {set x 0} {$x < 100} {incr x} {
   215    285           $doc selectNodes -cache 1 {count(node()) = 1 and node() = text()}