os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclLink.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
/* 
sl@0
     2
 * tclLink.c --
sl@0
     3
 *
sl@0
     4
 *	This file implements linked variables (a C variable that is
sl@0
     5
 *	tied to a Tcl variable).  The idea of linked variables was
sl@0
     6
 *	first suggested by Andreas Stolcke and this implementation is
sl@0
     7
 *	based heavily on a prototype implementation provided by
sl@0
     8
 *	him.
sl@0
     9
 *
sl@0
    10
 * Copyright (c) 1993 The Regents of the University of California.
sl@0
    11
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
sl@0
    12
 * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.  
sl@0
    13
 *
sl@0
    14
 * See the file "license.terms" for information on usage and redistribution
sl@0
    15
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0
    16
 *
sl@0
    17
 * RCS: @(#) $Id: tclLink.c,v 1.8.2.2 2007/05/10 18:23:58 dgp Exp $
sl@0
    18
 */
sl@0
    19
sl@0
    20
#include "tclInt.h"
sl@0
    21
sl@0
    22
/*
sl@0
    23
 * For each linked variable there is a data structure of the following
sl@0
    24
 * type, which describes the link and is the clientData for the trace
sl@0
    25
 * set on the Tcl variable.
sl@0
    26
 */
sl@0
    27
sl@0
    28
typedef struct Link {
sl@0
    29
    Tcl_Interp *interp;		/* Interpreter containing Tcl variable. */
sl@0
    30
    Tcl_Obj *varName;		/* Name of variable (must be global).  This
sl@0
    31
				 * is needed during trace callbacks, since
sl@0
    32
				 * the actual variable may be aliased at
sl@0
    33
				 * that time via upvar. */
sl@0
    34
    char *addr;			/* Location of C variable. */
sl@0
    35
    int type;			/* Type of link (TCL_LINK_INT, etc.). */
sl@0
    36
    union {
sl@0
    37
	int i;
sl@0
    38
	double d;
sl@0
    39
	Tcl_WideInt w;
sl@0
    40
    } lastValue;		/* Last known value of C variable;  used to
sl@0
    41
				 * avoid string conversions. */
sl@0
    42
    int flags;			/* Miscellaneous one-bit values;  see below
sl@0
    43
				 * for definitions. */
sl@0
    44
} Link;
sl@0
    45
sl@0
    46
/*
sl@0
    47
 * Definitions for flag bits:
sl@0
    48
 * LINK_READ_ONLY -		1 means errors should be generated if Tcl
sl@0
    49
 *				script attempts to write variable.
sl@0
    50
 * LINK_BEING_UPDATED -		1 means that a call to Tcl_UpdateLinkedVar
sl@0
    51
 *				is in progress for this variable, so
sl@0
    52
 *				trace callbacks on the variable should
sl@0
    53
 *				be ignored.
sl@0
    54
 */
sl@0
    55
sl@0
    56
#define LINK_READ_ONLY		1
sl@0
    57
#define LINK_BEING_UPDATED	2
sl@0
    58
sl@0
    59
/*
sl@0
    60
 * Forward references to procedures defined later in this file:
sl@0
    61
 */
sl@0
    62
sl@0
    63
static char *		LinkTraceProc _ANSI_ARGS_((ClientData clientData,
sl@0
    64
			    Tcl_Interp *interp, CONST char *name1, 
sl@0
    65
                            CONST char *name2, int flags));
sl@0
    66
static Tcl_Obj *	ObjValue _ANSI_ARGS_((Link *linkPtr));
sl@0
    67

sl@0
    68
/*
sl@0
    69
 *----------------------------------------------------------------------
sl@0
    70
 *
sl@0
    71
 * Tcl_LinkVar --
sl@0
    72
 *
sl@0
    73
 *	Link a C variable to a Tcl variable so that changes to either
sl@0
    74
 *	one causes the other to change.
sl@0
    75
 *
sl@0
    76
 * Results:
sl@0
    77
 *	The return value is TCL_OK if everything went well or TCL_ERROR
sl@0
    78
 *	if an error occurred (the interp's result is also set after
sl@0
    79
 *	errors).
sl@0
    80
 *
sl@0
    81
 * Side effects:
sl@0
    82
 *	The value at *addr is linked to the Tcl variable "varName",
sl@0
    83
 *	using "type" to convert between string values for Tcl and
sl@0
    84
 *	binary values for *addr.
sl@0
    85
 *
sl@0
    86
 *----------------------------------------------------------------------
sl@0
    87
 */
sl@0
    88
sl@0
    89
EXPORT_C int
sl@0
    90
Tcl_LinkVar(interp, varName, addr, type)
sl@0
    91
    Tcl_Interp *interp;		/* Interpreter in which varName exists. */
sl@0
    92
    CONST char *varName;	/* Name of a global variable in interp. */
sl@0
    93
    char *addr;			/* Address of a C variable to be linked
sl@0
    94
				 * to varName. */
sl@0
    95
    int type;			/* Type of C variable: TCL_LINK_INT, etc. 
sl@0
    96
				 * Also may have TCL_LINK_READ_ONLY
sl@0
    97
				 * OR'ed in. */
sl@0
    98
{
sl@0
    99
    Tcl_Obj *objPtr, *resPtr;
sl@0
   100
    Link *linkPtr;
sl@0
   101
    int code;
sl@0
   102
sl@0
   103
    linkPtr = (Link *) ckalloc(sizeof(Link));
sl@0
   104
    linkPtr->interp = interp;
sl@0
   105
    linkPtr->varName = Tcl_NewStringObj(varName, -1);
sl@0
   106
    Tcl_IncrRefCount(linkPtr->varName);
sl@0
   107
    linkPtr->addr = addr;
sl@0
   108
    linkPtr->type = type & ~TCL_LINK_READ_ONLY;
sl@0
   109
    if (type & TCL_LINK_READ_ONLY) {
sl@0
   110
	linkPtr->flags = LINK_READ_ONLY;
sl@0
   111
    } else {
sl@0
   112
	linkPtr->flags = 0;
sl@0
   113
    }
sl@0
   114
    objPtr = ObjValue(linkPtr);
sl@0
   115
    Tcl_IncrRefCount(objPtr);
sl@0
   116
    resPtr = Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, objPtr,
sl@0
   117
	    TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG);
sl@0
   118
    Tcl_DecrRefCount(objPtr);
sl@0
   119
    if (resPtr == NULL) {
sl@0
   120
	Tcl_DecrRefCount(linkPtr->varName);
sl@0
   121
	ckfree((char *) linkPtr);
sl@0
   122
	return TCL_ERROR;
sl@0
   123
    }
sl@0
   124
    code = Tcl_TraceVar(interp, varName, TCL_GLOBAL_ONLY|TCL_TRACE_READS
sl@0
   125
	    |TCL_TRACE_WRITES|TCL_TRACE_UNSETS, LinkTraceProc,
sl@0
   126
	    (ClientData) linkPtr);
sl@0
   127
    if (code != TCL_OK) {
sl@0
   128
	Tcl_DecrRefCount(linkPtr->varName);
sl@0
   129
	ckfree((char *) linkPtr);
sl@0
   130
    }
sl@0
   131
    return code;
sl@0
   132
}
sl@0
   133

sl@0
   134
/*
sl@0
   135
 *----------------------------------------------------------------------
sl@0
   136
 *
sl@0
   137
 * Tcl_UnlinkVar --
sl@0
   138
 *
sl@0
   139
 *	Destroy the link between a Tcl variable and a C variable.
sl@0
   140
 *
sl@0
   141
 * Results:
sl@0
   142
 *	None.
sl@0
   143
 *
sl@0
   144
 * Side effects:
sl@0
   145
 *	If "varName" was previously linked to a C variable, the link
sl@0
   146
 *	is broken to make the variable independent.  If there was no
sl@0
   147
 *	previous link for "varName" then nothing happens.
sl@0
   148
 *
sl@0
   149
 *----------------------------------------------------------------------
sl@0
   150
 */
sl@0
   151
sl@0
   152
EXPORT_C void
sl@0
   153
Tcl_UnlinkVar(interp, varName)
sl@0
   154
    Tcl_Interp *interp;		/* Interpreter containing variable to unlink. */
sl@0
   155
    CONST char *varName;	/* Global variable in interp to unlink. */
sl@0
   156
{
sl@0
   157
    Link *linkPtr;
sl@0
   158
sl@0
   159
    linkPtr = (Link *) Tcl_VarTraceInfo(interp, varName, TCL_GLOBAL_ONLY,
sl@0
   160
	    LinkTraceProc, (ClientData) NULL);
sl@0
   161
    if (linkPtr == NULL) {
sl@0
   162
	return;
sl@0
   163
    }
sl@0
   164
    Tcl_UntraceVar(interp, varName,
sl@0
   165
	    TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
sl@0
   166
	    LinkTraceProc, (ClientData) linkPtr);
sl@0
   167
    Tcl_DecrRefCount(linkPtr->varName);
sl@0
   168
    ckfree((char *) linkPtr);
sl@0
   169
}
sl@0
   170

sl@0
   171
/*
sl@0
   172
 *----------------------------------------------------------------------
sl@0
   173
 *
sl@0
   174
 * Tcl_UpdateLinkedVar --
sl@0
   175
 *
sl@0
   176
 *	This procedure is invoked after a linked variable has been
sl@0
   177
 *	changed by C code.  It updates the Tcl variable so that
sl@0
   178
 *	traces on the variable will trigger.
sl@0
   179
 *
sl@0
   180
 * Results:
sl@0
   181
 *	None.
sl@0
   182
 *
sl@0
   183
 * Side effects:
sl@0
   184
 *	The Tcl variable "varName" is updated from its C value,
sl@0
   185
 *	causing traces on the variable to trigger.
sl@0
   186
 *
sl@0
   187
 *----------------------------------------------------------------------
sl@0
   188
 */
sl@0
   189
sl@0
   190
EXPORT_C void
sl@0
   191
Tcl_UpdateLinkedVar(interp, varName)
sl@0
   192
    Tcl_Interp *interp;		/* Interpreter containing variable. */
sl@0
   193
    CONST char *varName;	/* Name of global variable that is linked. */
sl@0
   194
{
sl@0
   195
    Link *linkPtr;
sl@0
   196
    int savedFlag;
sl@0
   197
    Tcl_Obj *objPtr;
sl@0
   198
sl@0
   199
    linkPtr = (Link *) Tcl_VarTraceInfo(interp, varName, TCL_GLOBAL_ONLY,
sl@0
   200
	    LinkTraceProc, (ClientData) NULL);
sl@0
   201
    if (linkPtr == NULL) {
sl@0
   202
	return;
sl@0
   203
    }
sl@0
   204
    savedFlag = linkPtr->flags & LINK_BEING_UPDATED;
sl@0
   205
    linkPtr->flags |= LINK_BEING_UPDATED;
sl@0
   206
    objPtr = ObjValue(linkPtr);
sl@0
   207
    Tcl_IncrRefCount(objPtr);
sl@0
   208
    Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, objPtr, TCL_GLOBAL_ONLY);
sl@0
   209
    Tcl_DecrRefCount(objPtr);
sl@0
   210
    linkPtr->flags = (linkPtr->flags & ~LINK_BEING_UPDATED) | savedFlag;
sl@0
   211
}
sl@0
   212

sl@0
   213
/*
sl@0
   214
 *----------------------------------------------------------------------
sl@0
   215
 *
sl@0
   216
 * LinkTraceProc --
sl@0
   217
 *
sl@0
   218
 *	This procedure is invoked when a linked Tcl variable is read,
sl@0
   219
 *	written, or unset from Tcl.  It's responsible for keeping the
sl@0
   220
 *	C variable in sync with the Tcl variable.
sl@0
   221
 *
sl@0
   222
 * Results:
sl@0
   223
 *	If all goes well, NULL is returned; otherwise an error message
sl@0
   224
 *	is returned.
sl@0
   225
 *
sl@0
   226
 * Side effects:
sl@0
   227
 *	The C variable may be updated to make it consistent with the
sl@0
   228
 *	Tcl variable, or the Tcl variable may be overwritten to reject
sl@0
   229
 *	a modification.
sl@0
   230
 *
sl@0
   231
 *----------------------------------------------------------------------
sl@0
   232
 */
sl@0
   233
sl@0
   234
static char *
sl@0
   235
LinkTraceProc(clientData, interp, name1, name2, flags)
sl@0
   236
    ClientData clientData;	/* Contains information about the link. */
sl@0
   237
    Tcl_Interp *interp;		/* Interpreter containing Tcl variable. */
sl@0
   238
    CONST char *name1;		/* First part of variable name. */
sl@0
   239
    CONST char *name2;		/* Second part of variable name. */
sl@0
   240
    int flags;			/* Miscellaneous additional information. */
sl@0
   241
{
sl@0
   242
    Link *linkPtr = (Link *) clientData;
sl@0
   243
    int changed, valueLength;
sl@0
   244
    CONST char *value;
sl@0
   245
    char **pp, *result;
sl@0
   246
    Tcl_Obj *objPtr, *valueObj, *tmpPtr;
sl@0
   247
sl@0
   248
    /*
sl@0
   249
     * If the variable is being unset, then just re-create it (with a
sl@0
   250
     * trace) unless the whole interpreter is going away.
sl@0
   251
     */
sl@0
   252
sl@0
   253
    if (flags & TCL_TRACE_UNSETS) {
sl@0
   254
	if (Tcl_InterpDeleted(interp)) {
sl@0
   255
	    Tcl_DecrRefCount(linkPtr->varName);
sl@0
   256
	    ckfree((char *) linkPtr);
sl@0
   257
	} else if (flags & TCL_TRACE_DESTROYED) {
sl@0
   258
	    tmpPtr = ObjValue(linkPtr);
sl@0
   259
	    Tcl_IncrRefCount(tmpPtr);
sl@0
   260
	    Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr,
sl@0
   261
		    TCL_GLOBAL_ONLY);
sl@0
   262
	    Tcl_DecrRefCount(tmpPtr);
sl@0
   263
	    Tcl_TraceVar(interp, Tcl_GetString(linkPtr->varName),
sl@0
   264
		    TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES
sl@0
   265
		    |TCL_TRACE_UNSETS, LinkTraceProc, (ClientData) linkPtr);
sl@0
   266
	}
sl@0
   267
	return NULL;
sl@0
   268
    }
sl@0
   269
sl@0
   270
    /*
sl@0
   271
     * If we were invoked because of a call to Tcl_UpdateLinkedVar, then
sl@0
   272
     * don't do anything at all.  In particular, we don't want to get
sl@0
   273
     * upset that the variable is being modified, even if it is
sl@0
   274
     * supposed to be read-only.
sl@0
   275
     */
sl@0
   276
sl@0
   277
    if (linkPtr->flags & LINK_BEING_UPDATED) {
sl@0
   278
	return NULL;
sl@0
   279
    }
sl@0
   280
sl@0
   281
    /*
sl@0
   282
     * For read accesses, update the Tcl variable if the C variable
sl@0
   283
     * has changed since the last time we updated the Tcl variable.
sl@0
   284
     */
sl@0
   285
sl@0
   286
    if (flags & TCL_TRACE_READS) {
sl@0
   287
	switch (linkPtr->type) {
sl@0
   288
	case TCL_LINK_INT:
sl@0
   289
	case TCL_LINK_BOOLEAN:
sl@0
   290
	    changed = *(int *)(linkPtr->addr) != linkPtr->lastValue.i;
sl@0
   291
	    break;
sl@0
   292
	case TCL_LINK_DOUBLE:
sl@0
   293
	    changed = *(double *)(linkPtr->addr) != linkPtr->lastValue.d;
sl@0
   294
	    break;
sl@0
   295
	case TCL_LINK_WIDE_INT:
sl@0
   296
	    changed = *(Tcl_WideInt *)(linkPtr->addr) != linkPtr->lastValue.w;
sl@0
   297
	    break;
sl@0
   298
	case TCL_LINK_STRING:
sl@0
   299
	    changed = 1;
sl@0
   300
	    break;
sl@0
   301
	default:
sl@0
   302
	    return "internal error: bad linked variable type";
sl@0
   303
	}
sl@0
   304
	if (changed) {
sl@0
   305
	    tmpPtr = ObjValue(linkPtr);
sl@0
   306
	    Tcl_IncrRefCount(tmpPtr);
sl@0
   307
	    Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr,
sl@0
   308
		    TCL_GLOBAL_ONLY);
sl@0
   309
	    Tcl_DecrRefCount(tmpPtr);
sl@0
   310
	}
sl@0
   311
	return NULL;
sl@0
   312
    }
sl@0
   313
sl@0
   314
    /*
sl@0
   315
     * For writes, first make sure that the variable is writable.  Then
sl@0
   316
     * convert the Tcl value to C if possible.  If the variable isn't
sl@0
   317
     * writable or can't be converted, then restore the varaible's old
sl@0
   318
     * value and return an error.  Another tricky thing: we have to save
sl@0
   319
     * and restore the interpreter's result, since the variable access
sl@0
   320
     * could occur when the result has been partially set.
sl@0
   321
     */
sl@0
   322
sl@0
   323
    if (linkPtr->flags & LINK_READ_ONLY) {
sl@0
   324
	tmpPtr = ObjValue(linkPtr);
sl@0
   325
	Tcl_IncrRefCount(tmpPtr);
sl@0
   326
	Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr,
sl@0
   327
		TCL_GLOBAL_ONLY);
sl@0
   328
	Tcl_DecrRefCount(tmpPtr);
sl@0
   329
	return "linked variable is read-only";
sl@0
   330
    }
sl@0
   331
    valueObj = Tcl_ObjGetVar2(interp, linkPtr->varName,NULL, TCL_GLOBAL_ONLY);
sl@0
   332
    if (valueObj == NULL) {
sl@0
   333
	/*
sl@0
   334
	 * This shouldn't ever happen.
sl@0
   335
	 */
sl@0
   336
	return "internal error: linked variable couldn't be read";
sl@0
   337
    }
sl@0
   338
sl@0
   339
    objPtr = Tcl_GetObjResult(interp);
sl@0
   340
    Tcl_IncrRefCount(objPtr);
sl@0
   341
    Tcl_ResetResult(interp);
sl@0
   342
    result = NULL;
sl@0
   343
sl@0
   344
    switch (linkPtr->type) {
sl@0
   345
    case TCL_LINK_INT:
sl@0
   346
	if (Tcl_GetIntFromObj(interp, valueObj, &linkPtr->lastValue.i)
sl@0
   347
		!= TCL_OK) {
sl@0
   348
	    Tcl_SetObjResult(interp, objPtr);
sl@0
   349
	    tmpPtr = ObjValue(linkPtr);
sl@0
   350
	    Tcl_IncrRefCount(tmpPtr);
sl@0
   351
	    Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr,
sl@0
   352
		    TCL_GLOBAL_ONLY);
sl@0
   353
	    Tcl_DecrRefCount(tmpPtr);
sl@0
   354
	    result = "variable must have integer value";
sl@0
   355
	    goto end;
sl@0
   356
	}
sl@0
   357
	*(int *)(linkPtr->addr) = linkPtr->lastValue.i;
sl@0
   358
	break;
sl@0
   359
sl@0
   360
    case TCL_LINK_WIDE_INT:
sl@0
   361
	if (Tcl_GetWideIntFromObj(interp, valueObj, &linkPtr->lastValue.w)
sl@0
   362
		!= TCL_OK) {
sl@0
   363
	    Tcl_SetObjResult(interp, objPtr);
sl@0
   364
	    tmpPtr = ObjValue(linkPtr);
sl@0
   365
	    Tcl_IncrRefCount(tmpPtr);
sl@0
   366
	    Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr,
sl@0
   367
		    TCL_GLOBAL_ONLY);
sl@0
   368
	    Tcl_DecrRefCount(tmpPtr);
sl@0
   369
	    result = "variable must have integer value";
sl@0
   370
	    goto end;
sl@0
   371
	}
sl@0
   372
	*(Tcl_WideInt *)(linkPtr->addr) = linkPtr->lastValue.w;
sl@0
   373
	break;
sl@0
   374
sl@0
   375
    case TCL_LINK_DOUBLE:
sl@0
   376
	if (Tcl_GetDoubleFromObj(interp, valueObj, &linkPtr->lastValue.d)
sl@0
   377
		!= TCL_OK) {
sl@0
   378
	    Tcl_SetObjResult(interp, objPtr);
sl@0
   379
	    tmpPtr = ObjValue(linkPtr);
sl@0
   380
	    Tcl_IncrRefCount(tmpPtr);
sl@0
   381
	    Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr,
sl@0
   382
		    TCL_GLOBAL_ONLY);
sl@0
   383
	    Tcl_DecrRefCount(tmpPtr);
sl@0
   384
	    result = "variable must have real value";
sl@0
   385
	    goto end;
sl@0
   386
	}
sl@0
   387
	*(double *)(linkPtr->addr) = linkPtr->lastValue.d;
sl@0
   388
	break;
sl@0
   389
sl@0
   390
    case TCL_LINK_BOOLEAN:
sl@0
   391
	if (Tcl_GetBooleanFromObj(interp, valueObj, &linkPtr->lastValue.i)
sl@0
   392
	    != TCL_OK) {
sl@0
   393
	    Tcl_SetObjResult(interp, objPtr);
sl@0
   394
	    tmpPtr = ObjValue(linkPtr);
sl@0
   395
	    Tcl_IncrRefCount(tmpPtr);
sl@0
   396
	    Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr,
sl@0
   397
		    TCL_GLOBAL_ONLY);
sl@0
   398
	    Tcl_DecrRefCount(tmpPtr);
sl@0
   399
	    result = "variable must have boolean value";
sl@0
   400
	    goto end;
sl@0
   401
	}
sl@0
   402
	*(int *)(linkPtr->addr) = linkPtr->lastValue.i;
sl@0
   403
	break;
sl@0
   404
sl@0
   405
    case TCL_LINK_STRING:
sl@0
   406
	value = Tcl_GetStringFromObj(valueObj, &valueLength);
sl@0
   407
	valueLength++;
sl@0
   408
	pp = (char **)(linkPtr->addr);
sl@0
   409
	if (*pp != NULL) {
sl@0
   410
	    ckfree(*pp);
sl@0
   411
	}
sl@0
   412
	*pp = (char *) ckalloc((unsigned) valueLength);
sl@0
   413
	memcpy(*pp, value, (unsigned) valueLength);
sl@0
   414
	break;
sl@0
   415
sl@0
   416
    default:
sl@0
   417
	return "internal error: bad linked variable type";
sl@0
   418
    }
sl@0
   419
    end:
sl@0
   420
    Tcl_DecrRefCount(objPtr);
sl@0
   421
    return result;
sl@0
   422
}
sl@0
   423

sl@0
   424
/*
sl@0
   425
 *----------------------------------------------------------------------
sl@0
   426
 *
sl@0
   427
 * ObjValue --
sl@0
   428
 *
sl@0
   429
 *	Converts the value of a C variable to a Tcl_Obj* for use in a
sl@0
   430
 *	Tcl variable to which it is linked.
sl@0
   431
 *
sl@0
   432
 * Results:
sl@0
   433
 *	The return value is a pointer to a Tcl_Obj that represents
sl@0
   434
 *	the value of the C variable given by linkPtr.
sl@0
   435
 *
sl@0
   436
 * Side effects:
sl@0
   437
 *	None.
sl@0
   438
 *
sl@0
   439
 *----------------------------------------------------------------------
sl@0
   440
 */
sl@0
   441
sl@0
   442
static Tcl_Obj *
sl@0
   443
ObjValue(linkPtr)
sl@0
   444
    Link *linkPtr;		/* Structure describing linked variable. */
sl@0
   445
{
sl@0
   446
    char *p;
sl@0
   447
sl@0
   448
    switch (linkPtr->type) {
sl@0
   449
    case TCL_LINK_INT:
sl@0
   450
	linkPtr->lastValue.i = *(int *)(linkPtr->addr);
sl@0
   451
	return Tcl_NewIntObj(linkPtr->lastValue.i);
sl@0
   452
    case TCL_LINK_WIDE_INT:
sl@0
   453
	linkPtr->lastValue.w = *(Tcl_WideInt *)(linkPtr->addr);
sl@0
   454
	return Tcl_NewWideIntObj(linkPtr->lastValue.w);
sl@0
   455
    case TCL_LINK_DOUBLE:
sl@0
   456
	linkPtr->lastValue.d = *(double *)(linkPtr->addr);
sl@0
   457
	return Tcl_NewDoubleObj(linkPtr->lastValue.d);
sl@0
   458
    case TCL_LINK_BOOLEAN:
sl@0
   459
	linkPtr->lastValue.i = *(int *)(linkPtr->addr);
sl@0
   460
	return Tcl_NewBooleanObj(linkPtr->lastValue.i != 0);
sl@0
   461
    case TCL_LINK_STRING:
sl@0
   462
	p = *(char **)(linkPtr->addr);
sl@0
   463
	if (p == NULL) {
sl@0
   464
	    return Tcl_NewStringObj("NULL", 4);
sl@0
   465
	}
sl@0
   466
	return Tcl_NewStringObj(p, -1);
sl@0
   467
sl@0
   468
    /*
sl@0
   469
     * This code only gets executed if the link type is unknown
sl@0
   470
     * (shouldn't ever happen).
sl@0
   471
     */
sl@0
   472
    default:
sl@0
   473
	return Tcl_NewStringObj("??", 2);
sl@0
   474
    }
sl@0
   475
}