summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2006-02-01 17:48:04 (GMT)
committerdgp <dgp@users.sourceforge.net>2006-02-01 17:48:04 (GMT)
commit2e9bf45bc4d2510a07a538c48f8103957ede3aaf (patch)
treeded30cb2443dbed838e4a79ea4cf381328c34592 /generic
parent0fbd247a14d17e3925000c394aaa26523bd2fa12 (diff)
downloadtcl-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.h5
-rw-r--r--generic/tclNamesp.c86
-rw-r--r--generic/tclVar.c82
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