diff options
author | dgp <dgp@users.sourceforge.net> | 2006-02-01 17:48:04 (GMT) |
---|---|---|
committer | dgp <dgp@users.sourceforge.net> | 2006-02-01 17:48:04 (GMT) |
commit | 2e9bf45bc4d2510a07a538c48f8103957ede3aaf (patch) | |
tree | ded30cb2443dbed838e4a79ea4cf381328c34592 /generic | |
parent | 0fbd247a14d17e3925000c394aaa26523bd2fa12 (diff) | |
download | tcl-2e9bf45bc4d2510a07a538c48f8103957ede3aaf.zip tcl-2e9bf45bc4d2510a07a538c48f8103957ede3aaf.tar.gz tcl-2e9bf45bc4d2510a07a538c48f8103957ede3aaf.tar.bz2 |
TIP#250 IMPLEMENTATION
* doc/namespace.n: New command [namespace upvar]. [Patch 1275435]
* generic/tclInt.h:
* generic/tclNamesp.c:
* generic/tclVar.c:
* tests/namespace.test:
* tests/upvar.test:
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tclInt.h | 5 | ||||
-rw-r--r-- | generic/tclNamesp.c | 86 | ||||
-rw-r--r-- | generic/tclVar.c | 82 |
3 files changed, 149 insertions, 24 deletions
diff --git a/generic/tclInt.h b/generic/tclInt.h index 895eafd..cd224de 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclInt.h,v 1.264 2005/12/27 20:14:09 kennykb Exp $ + * RCS: @(#) $Id: tclInt.h,v 1.265 2006/02/01 17:48:10 dgp Exp $ */ #ifndef _TCLINT @@ -2118,6 +2118,9 @@ MODULE_SCOPE int TclMergeReturnOptions(Tcl_Interp *interp, int objc, MODULE_SCOPE int TclObjInvokeNamespace(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], Tcl_Namespace *nsPtr, int flags); +MODULE_SCOPE int TclPtrMakeUpvar (Tcl_Interp *interp, + Var *otherP1Ptr, CONST char *myName, + int myFlags, int index); MODULE_SCOPE int TclObjPrintf(Tcl_Interp *interp, Tcl_Obj *objPtr, CONST char *format, ...); MODULE_SCOPE int TclParseBackslash(CONST char *src, diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index 2debd69..55b6dc1 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -21,7 +21,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclNamesp.c,v 1.91 2006/01/11 17:34:53 dgp Exp $ + * RCS: @(#) $Id: tclNamesp.c,v 1.92 2006/02/01 17:48:11 dgp Exp $ */ #include "tclInt.h" @@ -228,6 +228,8 @@ static int NamespaceQualifiersCmd(ClientData dummy, Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]); static int NamespaceTailCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); +static int NamespaceUpvarCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); static int NamespaceWhichCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int SetNsNameFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr); @@ -2896,13 +2898,13 @@ Tcl_NamespaceObjCmd( "children", "code", "current", "delete", "ensemble", "eval", "exists", "export", "forget", "import", "inscope", "origin", "parent", "path", "qualifiers", - "tail", "which", NULL + "tail", "upvar", "which", NULL }; enum NSSubCmdIdx { NSChildrenIdx, NSCodeIdx, NSCurrentIdx, NSDeleteIdx, NSEnsembleIdx, NSEvalIdx, NSExistsIdx, NSExportIdx, NSForgetIdx, NSImportIdx, NSInscopeIdx, NSOriginIdx, NSParentIdx, NSPathIdx, NSQualifiersIdx, - NSTailIdx, NSWhichIdx + NSTailIdx, NSUpvarIdx, NSWhichIdx }; int index, result; @@ -2969,6 +2971,9 @@ Tcl_NamespaceObjCmd( break; case NSTailIdx: result = NamespaceTailCmd(clientData, interp, objc, objv); + break; + case NSUpvarIdx: + result = NamespaceUpvarCmd(clientData, interp, objc, objv); break; case NSWhichIdx: result = NamespaceWhichCmd(clientData, interp, objc, objv); @@ -4332,6 +4337,81 @@ NamespaceTailCmd( /* *---------------------------------------------------------------------- * + * NamespaceUpvarCmd -- + * + * Invoked to implement the "namespace upvar" command, that creates + * variables in the current scope linked to variables in another + * namespace. Handles the following syntax: + * + * namespace upvar ns otherVar myVar ?otherVar myVar ...? + * + * Results: + * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. + * + * Side effects: + * Creates new variables in the current scope, linked to the + * corresponding variables in the stipulated nmamespace. + * If anything goes wrong, the result is an error message. + * + *---------------------------------------------------------------------- + */ + +static int +NamespaceUpvarCmd(dummy, interp, objc, objv) + ClientData dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ +{ + Tcl_Namespace *nsPtr; + int result; + Var *otherPtr, *arrayPtr; + char *myName; + CallFrame frame, *framePtr = &frame; + + if (objc < 5 || !(objc & 1)) { + Tcl_WrongNumArgs(interp, 2, objv, "ns otherVar myVar ?otherVar myVar ...?"); + return TCL_ERROR; + } + + result = TclGetNamespaceFromObj(interp, objv[2], &nsPtr); + if (result != TCL_OK) { + return TCL_ERROR; + } + + objc -= 3; + objv += 3; + + for (; objc>0 ; objc-=2, objv+=2) { + /* + * Locate the other variable + */ + Tcl_PushCallFrame(interp, (Tcl_CallFrame *) framePtr, nsPtr, 0); + otherPtr = TclObjLookupVar(interp, objv[0], NULL, + (TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG), "access", + /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); + if (otherPtr == NULL) { + return TCL_ERROR; + } + Tcl_PopCallFrame(interp); + + /* + * Create the new variable and link it to otherPtr + */ + + myName = TclGetString(objv[1]); + result = TclPtrMakeUpvar(interp, otherPtr, myName, 0, -1); + if (result != TCL_OK) { + return TCL_ERROR; + } + } + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * * NamespaceWhichCmd -- * * Invoked to implement the "namespace which" command that returns the diff --git a/generic/tclVar.c b/generic/tclVar.c index 0bf98cf..6ae9d16 100644 --- a/generic/tclVar.c +++ b/generic/tclVar.c @@ -15,7 +15,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclVar.c,v 1.117 2005/11/27 02:33:49 das Exp $ + * RCS: @(#) $Id: tclVar.c,v 1.118 2006/02/01 17:48:11 dgp Exp $ */ #include "tclInt.h" @@ -3204,10 +3204,8 @@ ObjMakeUpvar( * scalar, this is its index. Otherwise, -1 */ { Interp *iPtr = (Interp *) interp; - Var *otherPtr, *varPtr, *arrayPtr; + Var *otherPtr, *arrayPtr; CallFrame *varFramePtr; - CONST char *errMsg; - CONST char *p; /* * Find "other" in "framePtr". If not looking up other in just the current @@ -3229,30 +3227,74 @@ ObjMakeUpvar( return TCL_ERROR; } - if (index >= 0) { - if (!(varFramePtr->isProcCallFrame & FRAME_IS_PROC)) { - Tcl_Panic("ObjMakeUpvar called with an index outside from a proc.\n"); - } - varPtr = &(varFramePtr->compiledLocals[index]); - } else { - /* - * Check that we are not trying to create a namespace var linked to a - * local variable in a procedure. If we allowed this, the local - * variable in the shorter-lived procedure frame could go away leaving - * the namespace var's reference invalid. - */ + /* + * Check that we are not trying to create a namespace var linked to a + * local variable in a procedure. If we allowed this, the local + * variable in the shorter-lived procedure frame could go away leaving + * the namespace var's reference invalid. + */ + if (index < 0) { if (((otherP2 ? arrayPtr->nsPtr : otherPtr->nsPtr) == NULL) - && ((myFlags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY)) - || (varFramePtr == NULL) - || !(varFramePtr->isProcCallFrame & FRAME_IS_PROC) - || (strstr(myName, "::") != NULL))) { + && ((myFlags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY)) + || (varFramePtr == NULL) + || !(varFramePtr->isProcCallFrame & FRAME_IS_PROC) + || (strstr(myName, "::") != NULL))) { Tcl_AppendResult((Tcl_Interp *) iPtr, "bad variable name \"", myName, "\": upvar won't create namespace variable that ", "refers to procedure variable", NULL); return TCL_ERROR; } + } + return TclPtrMakeUpvar(interp, otherPtr, myName, myFlags, index); +} + + +/* + *---------------------------------------------------------------------- + * + * TclPtrMakeUpvar -- + * + * This procedure does all of the work of the "global" and "upvar" + * commands. + * + * Results: + * A standard Tcl completion code. If an error occurs then an error + * message is left in iPtr->result. + * + * Side effects: + * The variable given by myName is linked to the variable in framePtr + * given by otherP1 and otherP2, so that references to myName are + * redirected to the other variable like a symbolic link. + * + *---------------------------------------------------------------------- + */ + +int +TclPtrMakeUpvar(interp, otherPtr, myName, myFlags, index) + Tcl_Interp *interp; /* Interpreter containing variables. Used for + * error messages, too. */ + Var *otherPtr; /* Pointer to the variable being linked-to */ + CONST char *myName; /* Name of variable which will refer to + * otherP1/otherP2. Must be a scalar. */ + int myFlags; /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY: + * indicates scope of myName. */ + int index; /* If the variable to be linked is an indexed + * scalar, this is its index. Otherwise, -1 */ +{ + Interp *iPtr = (Interp *) interp; + CallFrame *varFramePtr = iPtr->varFramePtr; + Var *varPtr; + CONST char *errMsg; + CONST char *p; + + if (index >= 0) { + if (!(varFramePtr->isProcCallFrame & FRAME_IS_PROC)) { + Tcl_Panic("ObjMakeUpvar called with an index outside from a proc.\n"); + } + varPtr = &(varFramePtr->compiledLocals[index]); + } else { /* * Do not permit the new variable to look like an array reference, as * it will not be reachable in that case [Bug 600812, TIP 184]. The |