diff options
Diffstat (limited to 'generic/tclLink.c')
-rw-r--r-- | generic/tclLink.c | 238 |
1 files changed, 129 insertions, 109 deletions
diff --git a/generic/tclLink.c b/generic/tclLink.c index 6a4e49e..2735256 100644 --- a/generic/tclLink.c +++ b/generic/tclLink.c @@ -11,8 +11,6 @@ * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tclLink.c,v 1.16 2005/12/13 22:43:18 kennykb Exp $ */ #include "tclInt.h" @@ -67,8 +65,19 @@ typedef struct Link { */ static char * LinkTraceProc(ClientData clientData,Tcl_Interp *interp, - CONST char *name1, CONST char *name2, int flags); + const char *name1, const char *name2, int flags); static Tcl_Obj * ObjValue(Link *linkPtr); + +/* + * Convenience macro for accessing the value of the C variable pointed to by a + * link. Note that this macro produces something that may be regarded as an + * lvalue or rvalue; it may be assigned to as well as read. Also note that + * this macro assumes the name of the variable being accessed (linkPtr); this + * is not strictly a good thing, but it keeps the code much shorter and + * cleaner. + */ + +#define LinkedVar(type) (*(type *) linkPtr->addr) /* *---------------------------------------------------------------------- @@ -93,7 +102,7 @@ static Tcl_Obj * ObjValue(Link *linkPtr); int Tcl_LinkVar( Tcl_Interp *interp, /* Interpreter in which varName exists. */ - CONST char *varName, /* Name of a global variable in interp. */ + const char *varName, /* Name of a global variable in interp. */ char *addr, /* Address of a C variable to be linked to * varName. */ int type) /* Type of C variable: TCL_LINK_INT, etc. Also @@ -103,7 +112,15 @@ Tcl_LinkVar( Link *linkPtr; int code; - linkPtr = (Link *) ckalloc(sizeof(Link)); + linkPtr = (Link *) Tcl_VarTraceInfo2(interp, varName, NULL, + TCL_GLOBAL_ONLY, LinkTraceProc, (ClientData) NULL); + if (linkPtr != NULL) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "variable '%s' is already linked", varName)); + return TCL_ERROR; + } + + linkPtr = ckalloc(sizeof(Link)); linkPtr->interp = interp; linkPtr->varName = Tcl_NewStringObj(varName, -1); Tcl_IncrRefCount(linkPtr->varName); @@ -118,15 +135,15 @@ Tcl_LinkVar( if (Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, objPtr, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { Tcl_DecrRefCount(linkPtr->varName); - ckfree((char *) linkPtr); + ckfree(linkPtr); return TCL_ERROR; } - code = Tcl_TraceVar(interp, varName, TCL_GLOBAL_ONLY|TCL_TRACE_READS - |TCL_TRACE_WRITES|TCL_TRACE_UNSETS, LinkTraceProc, - (ClientData) linkPtr); + code = Tcl_TraceVar2(interp, varName, NULL, + TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, + LinkTraceProc, linkPtr); if (code != TCL_OK) { Tcl_DecrRefCount(linkPtr->varName); - ckfree((char *) linkPtr); + ckfree(linkPtr); } return code; } @@ -152,20 +169,19 @@ Tcl_LinkVar( void Tcl_UnlinkVar( Tcl_Interp *interp, /* Interpreter containing variable to unlink */ - CONST char *varName) /* Global variable in interp to unlink. */ + const char *varName) /* Global variable in interp to unlink. */ { - Link *linkPtr; + Link *linkPtr = (Link *) Tcl_VarTraceInfo2(interp, varName, NULL, + TCL_GLOBAL_ONLY, LinkTraceProc, NULL); - linkPtr = (Link *) Tcl_VarTraceInfo(interp, varName, TCL_GLOBAL_ONLY, - LinkTraceProc, (ClientData) NULL); if (linkPtr == NULL) { return; } - Tcl_UntraceVar(interp, varName, + Tcl_UntraceVar2(interp, varName, NULL, TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - LinkTraceProc, (ClientData) linkPtr); + LinkTraceProc, linkPtr); Tcl_DecrRefCount(linkPtr->varName); - ckfree((char *) linkPtr); + ckfree(linkPtr); } /* @@ -190,13 +206,12 @@ Tcl_UnlinkVar( void Tcl_UpdateLinkedVar( Tcl_Interp *interp, /* Interpreter containing variable. */ - CONST char *varName) /* Name of global variable that is linked. */ + const char *varName) /* Name of global variable that is linked. */ { - Link *linkPtr; + Link *linkPtr = (Link *) Tcl_VarTraceInfo2(interp, varName, NULL, + TCL_GLOBAL_ONLY, LinkTraceProc, NULL); int savedFlag; - linkPtr = (Link *) Tcl_VarTraceInfo(interp, varName, TCL_GLOBAL_ONLY, - LinkTraceProc, (ClientData) NULL); if (linkPtr == NULL) { return; } @@ -204,7 +219,14 @@ Tcl_UpdateLinkedVar( linkPtr->flags |= LINK_BEING_UPDATED; Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - linkPtr->flags = (linkPtr->flags & ~LINK_BEING_UPDATED) | savedFlag; + /* + * Callback may have unlinked the variable. [Bug 1740631] + */ + linkPtr = (Link *) Tcl_VarTraceInfo2(interp, varName, NULL, + TCL_GLOBAL_ONLY, LinkTraceProc, NULL); + if (linkPtr != NULL) { + linkPtr->flags = (linkPtr->flags & ~LINK_BEING_UPDATED) | savedFlag; + } } /* @@ -232,13 +254,13 @@ static char * LinkTraceProc( ClientData clientData, /* Contains information about the link. */ Tcl_Interp *interp, /* Interpreter containing Tcl variable. */ - CONST char *name1, /* First part of variable name. */ - CONST char *name2, /* Second part of variable name. */ + const char *name1, /* First part of variable name. */ + const char *name2, /* Second part of variable name. */ int flags) /* Miscellaneous additional information. */ { - Link *linkPtr = (Link *) clientData; + Link *linkPtr = clientData; int changed, valueLength; - CONST char *value; + const char *value; char **pp; Tcl_Obj *valueObj; int valueInt; @@ -251,15 +273,15 @@ LinkTraceProc( */ if (flags & TCL_TRACE_UNSETS) { - if (flags & TCL_INTERP_DESTROYED) { + if (Tcl_InterpDeleted(interp)) { Tcl_DecrRefCount(linkPtr->varName); - ckfree((char *) linkPtr); + ckfree(linkPtr); } else if (flags & TCL_TRACE_DESTROYED) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - Tcl_TraceVar(interp, Tcl_GetString(linkPtr->varName), + Tcl_TraceVar2(interp, Tcl_GetString(linkPtr->varName), NULL, TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES - |TCL_TRACE_UNSETS, LinkTraceProc, (ClientData) linkPtr); + |TCL_TRACE_UNSETS, LinkTraceProc, linkPtr); } return NULL; } @@ -283,51 +305,46 @@ LinkTraceProc( switch (linkPtr->type) { case TCL_LINK_INT: case TCL_LINK_BOOLEAN: - changed = *(int *)(linkPtr->addr) != linkPtr->lastValue.i; + changed = (LinkedVar(int) != linkPtr->lastValue.i); break; case TCL_LINK_DOUBLE: - changed = *(double *)(linkPtr->addr) != linkPtr->lastValue.d; + changed = (LinkedVar(double) != linkPtr->lastValue.d); break; case TCL_LINK_WIDE_INT: - changed = *(Tcl_WideInt *)(linkPtr->addr) != linkPtr->lastValue.w; + changed = (LinkedVar(Tcl_WideInt) != linkPtr->lastValue.w); break; case TCL_LINK_WIDE_UINT: - changed = *(Tcl_WideUInt *)(linkPtr->addr) != - linkPtr->lastValue.uw; + changed = (LinkedVar(Tcl_WideUInt) != linkPtr->lastValue.uw); break; case TCL_LINK_CHAR: - changed = *(char *)(linkPtr->addr) != linkPtr->lastValue.c; + changed = (LinkedVar(char) != linkPtr->lastValue.c); break; case TCL_LINK_UCHAR: - changed = *(unsigned char *)(linkPtr->addr) != - linkPtr->lastValue.uc; + changed = (LinkedVar(unsigned char) != linkPtr->lastValue.uc); break; case TCL_LINK_SHORT: - changed = *(short *)(linkPtr->addr) != linkPtr->lastValue.s; + changed = (LinkedVar(short) != linkPtr->lastValue.s); break; case TCL_LINK_USHORT: - changed = *(unsigned short *)(linkPtr->addr) != - linkPtr->lastValue.us; + changed = (LinkedVar(unsigned short) != linkPtr->lastValue.us); break; case TCL_LINK_UINT: - changed = *(unsigned int *)(linkPtr->addr) != - linkPtr->lastValue.ui; + changed = (LinkedVar(unsigned int) != linkPtr->lastValue.ui); break; case TCL_LINK_LONG: - changed = *(long *)(linkPtr->addr) != linkPtr->lastValue.l; + changed = (LinkedVar(long) != linkPtr->lastValue.l); break; case TCL_LINK_ULONG: - changed = *(unsigned long *)(linkPtr->addr) != - linkPtr->lastValue.ul; + changed = (LinkedVar(unsigned long) != linkPtr->lastValue.ul); break; case TCL_LINK_FLOAT: - changed = *(float *)(linkPtr->addr) != linkPtr->lastValue.f; + changed = (LinkedVar(float) != linkPtr->lastValue.f); break; case TCL_LINK_STRING: changed = 1; break; default: - return "internal error: bad linked variable type"; + return (char *) "internal error: bad linked variable type"; } if (changed) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), @@ -348,14 +365,15 @@ LinkTraceProc( if (linkPtr->flags & LINK_READ_ONLY) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return "linked variable is read-only"; + return (char *) "linked variable is read-only"; } valueObj = Tcl_ObjGetVar2(interp, linkPtr->varName,NULL, TCL_GLOBAL_ONLY); if (valueObj == NULL) { /* * This shouldn't ever happen. */ - return "internal error: linked variable couldn't be read"; + + return (char *) "internal error: linked variable couldn't be read"; } switch (linkPtr->type) { @@ -364,9 +382,9 @@ LinkTraceProc( != TCL_OK) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return "variable must have integer value"; + return (char *) "variable must have integer value"; } - *(int *)(linkPtr->addr) = linkPtr->lastValue.i; + LinkedVar(int) = linkPtr->lastValue.i; break; case TCL_LINK_WIDE_INT: @@ -374,36 +392,36 @@ LinkTraceProc( != TCL_OK) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return "variable must have integer value"; + return (char *) "variable must have integer value"; } - *(Tcl_WideInt *)(linkPtr->addr) = linkPtr->lastValue.w; + LinkedVar(Tcl_WideInt) = linkPtr->lastValue.w; break; case TCL_LINK_DOUBLE: if (Tcl_GetDoubleFromObj(NULL, valueObj, &linkPtr->lastValue.d) != TCL_OK) { #ifdef ACCEPT_NAN - if (valueObj->typePtr != &tclDoubleType) { + if (valueObj->typePtr != &tclDoubleType) { #endif - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), - TCL_GLOBAL_ONLY); - return "variable must have real value"; + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, + ObjValue(linkPtr), TCL_GLOBAL_ONLY); + return (char *) "variable must have real value"; #ifdef ACCEPT_NAN - } - linkPtr->lastValue.d = valueObj->internalRep.doubleValue; + } + linkPtr->lastValue.d = valueObj->internalRep.doubleValue; #endif } - *(double *)(linkPtr->addr) = linkPtr->lastValue.d; + LinkedVar(double) = linkPtr->lastValue.d; break; case TCL_LINK_BOOLEAN: if (Tcl_GetBooleanFromObj(NULL, valueObj, &linkPtr->lastValue.i) - != TCL_OK) { + != TCL_OK) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return "variable must have boolean value"; + return (char *) "variable must have boolean value"; } - *(int *)(linkPtr->addr) = linkPtr->lastValue.i; + LinkedVar(int) = linkPtr->lastValue.i; break; case TCL_LINK_CHAR: @@ -411,10 +429,10 @@ LinkTraceProc( || valueInt < SCHAR_MIN || valueInt > SCHAR_MAX) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return "variable must have char value"; + return (char *) "variable must have char value"; } linkPtr->lastValue.c = (char)valueInt; - *(char *)(linkPtr->addr) = linkPtr->lastValue.c; + LinkedVar(char) = linkPtr->lastValue.c; break; case TCL_LINK_UCHAR: @@ -422,10 +440,10 @@ LinkTraceProc( || valueInt < 0 || valueInt > UCHAR_MAX) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return "variable must have unsigned char value"; + return (char *) "variable must have unsigned char value"; } linkPtr->lastValue.uc = (unsigned char) valueInt; - *(unsigned char *)(linkPtr->addr) = linkPtr->lastValue.uc; + LinkedVar(unsigned char) = linkPtr->lastValue.uc; break; case TCL_LINK_SHORT: @@ -433,10 +451,10 @@ LinkTraceProc( || valueInt < SHRT_MIN || valueInt > SHRT_MAX) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return "variable must have short value"; + return (char *) "variable must have short value"; } linkPtr->lastValue.s = (short)valueInt; - *(short *)(linkPtr->addr) = linkPtr->lastValue.s; + LinkedVar(short) = linkPtr->lastValue.s; break; case TCL_LINK_USHORT: @@ -444,10 +462,10 @@ LinkTraceProc( || valueInt < 0 || valueInt > USHRT_MAX) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return "variable must have unsigned short value"; + return (char *) "variable must have unsigned short value"; } linkPtr->lastValue.us = (unsigned short)valueInt; - *(unsigned short *)(linkPtr->addr) = linkPtr->lastValue.us; + LinkedVar(unsigned short) = linkPtr->lastValue.us; break; case TCL_LINK_UINT: @@ -455,10 +473,10 @@ LinkTraceProc( || valueWide < 0 || valueWide > UINT_MAX) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return "variable must have unsigned int value"; + return (char *) "variable must have unsigned int value"; } linkPtr->lastValue.ui = (unsigned int)valueWide; - *(unsigned int *)(linkPtr->addr) = linkPtr->lastValue.ui; + LinkedVar(unsigned int) = linkPtr->lastValue.ui; break; case TCL_LINK_LONG: @@ -466,21 +484,21 @@ LinkTraceProc( || valueWide < LONG_MIN || valueWide > LONG_MAX) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return "variable must have long value"; + return (char *) "variable must have long value"; } linkPtr->lastValue.l = (long)valueWide; - *(long *)(linkPtr->addr) = linkPtr->lastValue.l; + LinkedVar(long) = linkPtr->lastValue.l; break; case TCL_LINK_ULONG: if (Tcl_GetWideIntFromObj(interp, valueObj, &valueWide) != TCL_OK - || valueWide < 0 || valueWide > ULONG_MAX) { + || valueWide < 0 || (Tcl_WideUInt) valueWide > ULONG_MAX) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return "variable must have unsigned long value"; + return (char *) "variable must have unsigned long value"; } linkPtr->lastValue.ul = (unsigned long)valueWide; - *(unsigned long *)(linkPtr->addr) = linkPtr->lastValue.ul; + LinkedVar(unsigned long) = linkPtr->lastValue.ul; break; case TCL_LINK_WIDE_UINT: @@ -490,36 +508,34 @@ LinkTraceProc( if (Tcl_GetWideIntFromObj(interp, valueObj, &valueWide) != TCL_OK) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return "variable must have unsigned wide int value"; + return (char *) "variable must have unsigned wide int value"; } linkPtr->lastValue.uw = (Tcl_WideUInt)valueWide; - *(Tcl_WideUInt *)(linkPtr->addr) = linkPtr->lastValue.uw; + LinkedVar(Tcl_WideUInt) = linkPtr->lastValue.uw; break; case TCL_LINK_FLOAT: if (Tcl_GetDoubleFromObj(interp, valueObj, &valueDouble) != TCL_OK - || valueDouble < FLT_MIN || valueDouble > FLT_MAX) { + || valueDouble < -FLT_MAX || valueDouble > FLT_MAX) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return "variable must have float value"; + return (char *) "variable must have float value"; } linkPtr->lastValue.f = (float)valueDouble; - *(float *)(linkPtr->addr) = linkPtr->lastValue.f; + LinkedVar(float) = linkPtr->lastValue.f; break; case TCL_LINK_STRING: value = Tcl_GetStringFromObj(valueObj, &valueLength); valueLength++; - pp = (char **)(linkPtr->addr); - if (*pp != NULL) { - ckfree(*pp); - } - *pp = (char *) ckalloc((unsigned) valueLength); + pp = (char **) linkPtr->addr; + + *pp = ckrealloc(*pp, valueLength); memcpy(*pp, value, (unsigned) valueLength); break; default: - return "internal error: bad linked variable type"; + return (char *) "internal error: bad linked variable type"; } return NULL; } @@ -547,54 +563,56 @@ ObjValue( Link *linkPtr) /* Structure describing linked variable. */ { char *p; + Tcl_Obj *resultObj; switch (linkPtr->type) { case TCL_LINK_INT: - linkPtr->lastValue.i = *(int *)(linkPtr->addr); + linkPtr->lastValue.i = LinkedVar(int); return Tcl_NewIntObj(linkPtr->lastValue.i); case TCL_LINK_WIDE_INT: - linkPtr->lastValue.w = *(Tcl_WideInt *)(linkPtr->addr); + linkPtr->lastValue.w = LinkedVar(Tcl_WideInt); return Tcl_NewWideIntObj(linkPtr->lastValue.w); case TCL_LINK_DOUBLE: - linkPtr->lastValue.d = *(double *)(linkPtr->addr); + linkPtr->lastValue.d = LinkedVar(double); return Tcl_NewDoubleObj(linkPtr->lastValue.d); case TCL_LINK_BOOLEAN: - linkPtr->lastValue.i = *(int *)(linkPtr->addr); + linkPtr->lastValue.i = LinkedVar(int); return Tcl_NewBooleanObj(linkPtr->lastValue.i != 0); case TCL_LINK_CHAR: - linkPtr->lastValue.c = *(char *)(linkPtr->addr); + linkPtr->lastValue.c = LinkedVar(char); return Tcl_NewIntObj(linkPtr->lastValue.c); case TCL_LINK_UCHAR: - linkPtr->lastValue.uc = *(unsigned char *)(linkPtr->addr); + linkPtr->lastValue.uc = LinkedVar(unsigned char); return Tcl_NewIntObj(linkPtr->lastValue.uc); case TCL_LINK_SHORT: - linkPtr->lastValue.s = *(short *)(linkPtr->addr); + linkPtr->lastValue.s = LinkedVar(short); return Tcl_NewIntObj(linkPtr->lastValue.s); case TCL_LINK_USHORT: - linkPtr->lastValue.us = *(unsigned short *)(linkPtr->addr); + linkPtr->lastValue.us = LinkedVar(unsigned short); return Tcl_NewIntObj(linkPtr->lastValue.us); case TCL_LINK_UINT: - linkPtr->lastValue.ui = *(unsigned int *)(linkPtr->addr); - return Tcl_NewWideIntObj((Tcl_WideInt)(linkPtr->lastValue.ui)); + linkPtr->lastValue.ui = LinkedVar(unsigned int); + return Tcl_NewWideIntObj((Tcl_WideInt) linkPtr->lastValue.ui); case TCL_LINK_LONG: - linkPtr->lastValue.l = *(long *)(linkPtr->addr); - return Tcl_NewWideIntObj(linkPtr->lastValue.l); + linkPtr->lastValue.l = LinkedVar(long); + return Tcl_NewWideIntObj((Tcl_WideInt) linkPtr->lastValue.l); case TCL_LINK_ULONG: - linkPtr->lastValue.ul = *(unsigned long *)(linkPtr->addr); - return Tcl_NewWideIntObj((Tcl_WideInt)(linkPtr->lastValue.ul)); + linkPtr->lastValue.ul = LinkedVar(unsigned long); + return Tcl_NewWideIntObj((Tcl_WideInt) linkPtr->lastValue.ul); case TCL_LINK_FLOAT: - linkPtr->lastValue.f = *(float *)(linkPtr->addr); + linkPtr->lastValue.f = LinkedVar(float); return Tcl_NewDoubleObj(linkPtr->lastValue.f); case TCL_LINK_WIDE_UINT: - linkPtr->lastValue.uw = *(Tcl_WideUInt *)(linkPtr->addr); + linkPtr->lastValue.uw = LinkedVar(Tcl_WideUInt); /* * FIXME: represent as a bignum. */ return Tcl_NewWideIntObj((Tcl_WideInt) linkPtr->lastValue.uw); case TCL_LINK_STRING: - p = *(char **)(linkPtr->addr); + p = LinkedVar(char *); if (p == NULL) { - return Tcl_NewStringObj("NULL", 4); + TclNewLiteralStringObj(resultObj, "NULL"); + return resultObj; } return Tcl_NewStringObj(p, -1); @@ -602,8 +620,10 @@ ObjValue( * This code only gets executed if the link type is unknown (shouldn't * ever happen). */ + default: - return Tcl_NewStringObj("??", 2); + TclNewLiteralStringObj(resultObj, "??"); + return resultObj; } } |