os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclTestObj.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
 * tclTestObj.c --
sl@0
     3
 *
sl@0
     4
 *	This file contains C command procedures for the additional Tcl
sl@0
     5
 *	commands that are used for testing implementations of the Tcl object
sl@0
     6
 *	types. These commands are not normally included in Tcl
sl@0
     7
 *	applications; they're only used for testing.
sl@0
     8
 *
sl@0
     9
 * Copyright (c) 1995-1998 Sun Microsystems, Inc.
sl@0
    10
 * Copyright (c) 1999 by Scriptics Corporation.
sl@0
    11
 *
sl@0
    12
 * See the file "license.terms" for information on usage and redistribution
sl@0
    13
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0
    14
 *
sl@0
    15
 * RCS: @(#) $Id: tclTestObj.c,v 1.12 2002/12/04 13:09:24 vincentdarley Exp $
sl@0
    16
 */
sl@0
    17
sl@0
    18
#include "tclInt.h"
sl@0
    19
sl@0
    20
/*
sl@0
    21
 * An array of Tcl_Obj pointers used in the commands that operate on or get
sl@0
    22
 * the values of Tcl object-valued variables. varPtr[i] is the i-th
sl@0
    23
 * variable's Tcl_Obj *.
sl@0
    24
 */
sl@0
    25
sl@0
    26
#define NUMBER_OF_OBJECT_VARS 20
sl@0
    27
static Tcl_Obj *varPtr[NUMBER_OF_OBJECT_VARS];
sl@0
    28
sl@0
    29
/*
sl@0
    30
 * Forward declarations for procedures defined later in this file:
sl@0
    31
 */
sl@0
    32
sl@0
    33
static int		CheckIfVarUnset _ANSI_ARGS_((Tcl_Interp *interp,
sl@0
    34
			    int varIndex));
sl@0
    35
static int		GetVariableIndex _ANSI_ARGS_((Tcl_Interp *interp,
sl@0
    36
			    char *string, int *indexPtr));
sl@0
    37
static void		SetVarToObj _ANSI_ARGS_((int varIndex,
sl@0
    38
			    Tcl_Obj *objPtr));
sl@0
    39
int			TclObjTest_Init _ANSI_ARGS_((Tcl_Interp *interp));
sl@0
    40
static int		TestbooleanobjCmd _ANSI_ARGS_((ClientData dummy,
sl@0
    41
			    Tcl_Interp *interp, int objc,
sl@0
    42
			    Tcl_Obj *CONST objv[]));
sl@0
    43
static int		TestconvertobjCmd _ANSI_ARGS_((ClientData dummy,
sl@0
    44
			    Tcl_Interp *interp, int objc,
sl@0
    45
			    Tcl_Obj *CONST objv[]));
sl@0
    46
static int		TestdoubleobjCmd _ANSI_ARGS_((ClientData dummy,
sl@0
    47
			    Tcl_Interp *interp, int objc,
sl@0
    48
			    Tcl_Obj *CONST objv[]));
sl@0
    49
static int		TestindexobjCmd _ANSI_ARGS_((ClientData dummy,
sl@0
    50
			    Tcl_Interp *interp, int objc,
sl@0
    51
			    Tcl_Obj *CONST objv[]));
sl@0
    52
static int		TestintobjCmd _ANSI_ARGS_((ClientData dummy,
sl@0
    53
			    Tcl_Interp *interp, int objc,
sl@0
    54
			    Tcl_Obj *CONST objv[]));
sl@0
    55
static int		TestobjCmd _ANSI_ARGS_((ClientData dummy,
sl@0
    56
			    Tcl_Interp *interp, int objc,
sl@0
    57
			    Tcl_Obj *CONST objv[]));
sl@0
    58
static int		TeststringobjCmd _ANSI_ARGS_((ClientData dummy,
sl@0
    59
			    Tcl_Interp *interp, int objc,
sl@0
    60
			    Tcl_Obj *CONST objv[]));
sl@0
    61
sl@0
    62
typedef struct TestString {
sl@0
    63
    int numChars;
sl@0
    64
    size_t allocated;
sl@0
    65
    size_t uallocated;
sl@0
    66
    Tcl_UniChar unicode[2];
sl@0
    67
} TestString;
sl@0
    68
sl@0
    69

sl@0
    70
/*
sl@0
    71
 *----------------------------------------------------------------------
sl@0
    72
 *
sl@0
    73
 * TclObjTest_Init --
sl@0
    74
 *
sl@0
    75
 *	This procedure creates additional commands that are used to test the
sl@0
    76
 *	Tcl object support.
sl@0
    77
 *
sl@0
    78
 * Results:
sl@0
    79
 *	Returns a standard Tcl completion code, and leaves an error
sl@0
    80
 *	message in the interp's result if an error occurs.
sl@0
    81
 *
sl@0
    82
 * Side effects:
sl@0
    83
 *	Creates and registers several new testing commands.
sl@0
    84
 *
sl@0
    85
 *----------------------------------------------------------------------
sl@0
    86
 */
sl@0
    87
sl@0
    88
int
sl@0
    89
TclObjTest_Init(interp)
sl@0
    90
    Tcl_Interp *interp;
sl@0
    91
{
sl@0
    92
    register int i;
sl@0
    93
    
sl@0
    94
    for (i = 0;  i < NUMBER_OF_OBJECT_VARS;  i++) {
sl@0
    95
        varPtr[i] = NULL;
sl@0
    96
    }
sl@0
    97
	
sl@0
    98
    Tcl_CreateObjCommand(interp, "testbooleanobj", TestbooleanobjCmd,
sl@0
    99
	    (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
sl@0
   100
    Tcl_CreateObjCommand(interp, "testconvertobj", TestconvertobjCmd,
sl@0
   101
	    (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
sl@0
   102
    Tcl_CreateObjCommand(interp, "testdoubleobj", TestdoubleobjCmd,
sl@0
   103
	    (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
sl@0
   104
    Tcl_CreateObjCommand(interp, "testintobj", TestintobjCmd,
sl@0
   105
	    (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
sl@0
   106
    Tcl_CreateObjCommand(interp, "testindexobj", TestindexobjCmd,
sl@0
   107
	    (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
sl@0
   108
    Tcl_CreateObjCommand(interp, "testobj", TestobjCmd,
sl@0
   109
	    (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
sl@0
   110
    Tcl_CreateObjCommand(interp, "teststringobj", TeststringobjCmd,
sl@0
   111
	    (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
sl@0
   112
    return TCL_OK;
sl@0
   113
}
sl@0
   114

sl@0
   115
/*
sl@0
   116
 *----------------------------------------------------------------------
sl@0
   117
 *
sl@0
   118
 * TestbooleanobjCmd --
sl@0
   119
 *
sl@0
   120
 *	This procedure implements the "testbooleanobj" command.  It is used
sl@0
   121
 *	to test the boolean Tcl object type implementation.
sl@0
   122
 *
sl@0
   123
 * Results:
sl@0
   124
 *	A standard Tcl object result.
sl@0
   125
 *
sl@0
   126
 * Side effects:
sl@0
   127
 *	Creates and frees boolean objects, and also converts objects to
sl@0
   128
 *	have boolean type.
sl@0
   129
 *
sl@0
   130
 *----------------------------------------------------------------------
sl@0
   131
 */
sl@0
   132
sl@0
   133
static int
sl@0
   134
TestbooleanobjCmd(clientData, interp, objc, objv)
sl@0
   135
    ClientData clientData;	/* Not used. */
sl@0
   136
    Tcl_Interp *interp;		/* Current interpreter. */
sl@0
   137
    int objc;			/* Number of arguments. */
sl@0
   138
    Tcl_Obj *CONST objv[];	/* Argument objects. */
sl@0
   139
{
sl@0
   140
    int varIndex, boolValue;
sl@0
   141
    char *index, *subCmd;
sl@0
   142
sl@0
   143
    if (objc < 3) {
sl@0
   144
	wrongNumArgs:
sl@0
   145
	Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
sl@0
   146
	return TCL_ERROR;
sl@0
   147
    }
sl@0
   148
sl@0
   149
    index = Tcl_GetString(objv[2]);
sl@0
   150
    if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
sl@0
   151
	return TCL_ERROR;
sl@0
   152
    }
sl@0
   153
sl@0
   154
    subCmd = Tcl_GetString(objv[1]);
sl@0
   155
    if (strcmp(subCmd, "set") == 0) {
sl@0
   156
	if (objc != 4) {
sl@0
   157
	    goto wrongNumArgs;
sl@0
   158
	}
sl@0
   159
	if (Tcl_GetBooleanFromObj(interp, objv[3], &boolValue) != TCL_OK) {
sl@0
   160
	    return TCL_ERROR;
sl@0
   161
	}
sl@0
   162
sl@0
   163
	/*
sl@0
   164
	 * If the object currently bound to the variable with index varIndex
sl@0
   165
	 * has ref count 1 (i.e. the object is unshared) we can modify that
sl@0
   166
	 * object directly. Otherwise, if RC>1 (i.e. the object is shared),
sl@0
   167
	 * we must create a new object to modify/set and decrement the old
sl@0
   168
	 * formerly-shared object's ref count. This is "copy on write".
sl@0
   169
	 */
sl@0
   170
sl@0
   171
	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
sl@0
   172
	    Tcl_SetBooleanObj(varPtr[varIndex], boolValue);
sl@0
   173
	} else {
sl@0
   174
	    SetVarToObj(varIndex, Tcl_NewBooleanObj(boolValue));
sl@0
   175
	}
sl@0
   176
	Tcl_SetObjResult(interp, varPtr[varIndex]);
sl@0
   177
    } else if (strcmp(subCmd, "get") == 0) {
sl@0
   178
	if (objc != 3) {
sl@0
   179
	    goto wrongNumArgs;
sl@0
   180
	}
sl@0
   181
	if (CheckIfVarUnset(interp, varIndex)) {
sl@0
   182
	    return TCL_ERROR;
sl@0
   183
	}
sl@0
   184
	Tcl_SetObjResult(interp, varPtr[varIndex]);
sl@0
   185
    } else if (strcmp(subCmd, "not") == 0) {
sl@0
   186
	if (objc != 3) {
sl@0
   187
	    goto wrongNumArgs;
sl@0
   188
	}
sl@0
   189
	if (CheckIfVarUnset(interp, varIndex)) {
sl@0
   190
	    return TCL_ERROR;
sl@0
   191
	}
sl@0
   192
	if (Tcl_GetBooleanFromObj(interp, varPtr[varIndex],
sl@0
   193
				  &boolValue) != TCL_OK) {
sl@0
   194
	    return TCL_ERROR;
sl@0
   195
	}
sl@0
   196
	if (!Tcl_IsShared(varPtr[varIndex])) {
sl@0
   197
	    Tcl_SetBooleanObj(varPtr[varIndex], !boolValue);
sl@0
   198
	} else {
sl@0
   199
	    SetVarToObj(varIndex, Tcl_NewBooleanObj(!boolValue));
sl@0
   200
	}
sl@0
   201
	Tcl_SetObjResult(interp, varPtr[varIndex]);
sl@0
   202
    } else {
sl@0
   203
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
sl@0
   204
		"bad option \"", Tcl_GetString(objv[1]),
sl@0
   205
		"\": must be set, get, or not", (char *) NULL);
sl@0
   206
	return TCL_ERROR;
sl@0
   207
    }
sl@0
   208
    return TCL_OK;
sl@0
   209
}
sl@0
   210

sl@0
   211
/*
sl@0
   212
 *----------------------------------------------------------------------
sl@0
   213
 *
sl@0
   214
 * TestconvertobjCmd --
sl@0
   215
 *
sl@0
   216
 *	This procedure implements the "testconvertobj" command. It is used
sl@0
   217
 *	to test converting objects to new types.
sl@0
   218
 *
sl@0
   219
 * Results:
sl@0
   220
 *	A standard Tcl object result.
sl@0
   221
 *
sl@0
   222
 * Side effects:
sl@0
   223
 *	Converts objects to new types.
sl@0
   224
 *
sl@0
   225
 *----------------------------------------------------------------------
sl@0
   226
 */
sl@0
   227
sl@0
   228
static int
sl@0
   229
TestconvertobjCmd(clientData, interp, objc, objv)
sl@0
   230
    ClientData clientData;	/* Not used. */
sl@0
   231
    Tcl_Interp *interp;		/* Current interpreter. */
sl@0
   232
    int objc;			/* Number of arguments. */
sl@0
   233
    Tcl_Obj *CONST objv[];	/* Argument objects. */
sl@0
   234
{
sl@0
   235
    char *subCmd;
sl@0
   236
    char buf[20];
sl@0
   237
sl@0
   238
    if (objc < 3) {
sl@0
   239
	wrongNumArgs:
sl@0
   240
	Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
sl@0
   241
	return TCL_ERROR;
sl@0
   242
    }
sl@0
   243
sl@0
   244
    subCmd = Tcl_GetString(objv[1]);
sl@0
   245
    if (strcmp(subCmd, "double") == 0) {
sl@0
   246
	double d;
sl@0
   247
sl@0
   248
	if (objc != 3) {
sl@0
   249
	    goto wrongNumArgs;
sl@0
   250
	}
sl@0
   251
	if (Tcl_GetDoubleFromObj(interp, objv[2], &d) != TCL_OK) {
sl@0
   252
	    return TCL_ERROR;
sl@0
   253
	}
sl@0
   254
	sprintf(buf, "%f", d);
sl@0
   255
        Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1);
sl@0
   256
    } else {
sl@0
   257
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
sl@0
   258
		"bad option \"", Tcl_GetString(objv[1]),
sl@0
   259
		"\": must be double", (char *) NULL);
sl@0
   260
	return TCL_ERROR;
sl@0
   261
    }
sl@0
   262
    return TCL_OK;
sl@0
   263
}
sl@0
   264

sl@0
   265
/*
sl@0
   266
 *----------------------------------------------------------------------
sl@0
   267
 *
sl@0
   268
 * TestdoubleobjCmd --
sl@0
   269
 *
sl@0
   270
 *	This procedure implements the "testdoubleobj" command.  It is used
sl@0
   271
 *	to test the double-precision floating point Tcl object type
sl@0
   272
 *	implementation.
sl@0
   273
 *
sl@0
   274
 * Results:
sl@0
   275
 *	A standard Tcl object result.
sl@0
   276
 *
sl@0
   277
 * Side effects:
sl@0
   278
 *	Creates and frees double objects, and also converts objects to
sl@0
   279
 *	have double type.
sl@0
   280
 *
sl@0
   281
 *----------------------------------------------------------------------
sl@0
   282
 */
sl@0
   283
sl@0
   284
static int
sl@0
   285
TestdoubleobjCmd(clientData, interp, objc, objv)
sl@0
   286
    ClientData clientData;	/* Not used. */
sl@0
   287
    Tcl_Interp *interp;		/* Current interpreter. */
sl@0
   288
    int objc;			/* Number of arguments. */
sl@0
   289
    Tcl_Obj *CONST objv[];	/* Argument objects. */
sl@0
   290
{
sl@0
   291
    int varIndex;
sl@0
   292
    double doubleValue;
sl@0
   293
    char *index, *subCmd, *string;
sl@0
   294
	
sl@0
   295
    if (objc < 3) {
sl@0
   296
	wrongNumArgs:
sl@0
   297
	Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
sl@0
   298
	return TCL_ERROR;
sl@0
   299
    }
sl@0
   300
sl@0
   301
    index = Tcl_GetString(objv[2]);
sl@0
   302
    if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
sl@0
   303
	return TCL_ERROR;
sl@0
   304
    }
sl@0
   305
sl@0
   306
    subCmd = Tcl_GetString(objv[1]);
sl@0
   307
    if (strcmp(subCmd, "set") == 0) {
sl@0
   308
	if (objc != 4) {
sl@0
   309
	    goto wrongNumArgs;
sl@0
   310
	}
sl@0
   311
	string = Tcl_GetString(objv[3]);
sl@0
   312
	if (Tcl_GetDouble(interp, string, &doubleValue) != TCL_OK) {
sl@0
   313
	    return TCL_ERROR;
sl@0
   314
	}
sl@0
   315
sl@0
   316
	/*
sl@0
   317
	 * If the object currently bound to the variable with index varIndex
sl@0
   318
	 * has ref count 1 (i.e. the object is unshared) we can modify that
sl@0
   319
	 * object directly. Otherwise, if RC>1 (i.e. the object is shared),
sl@0
   320
	 * we must create a new object to modify/set and decrement the old
sl@0
   321
	 * formerly-shared object's ref count. This is "copy on write".
sl@0
   322
	 */
sl@0
   323
sl@0
   324
	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
sl@0
   325
	    Tcl_SetDoubleObj(varPtr[varIndex], doubleValue);
sl@0
   326
	} else {
sl@0
   327
	    SetVarToObj(varIndex, Tcl_NewDoubleObj(doubleValue));
sl@0
   328
	}
sl@0
   329
	Tcl_SetObjResult(interp, varPtr[varIndex]);
sl@0
   330
    } else if (strcmp(subCmd, "get") == 0) {
sl@0
   331
	if (objc != 3) {
sl@0
   332
	    goto wrongNumArgs;
sl@0
   333
	}
sl@0
   334
	if (CheckIfVarUnset(interp, varIndex)) {
sl@0
   335
	    return TCL_ERROR;
sl@0
   336
	}
sl@0
   337
	Tcl_SetObjResult(interp, varPtr[varIndex]);
sl@0
   338
    } else if (strcmp(subCmd, "mult10") == 0) {
sl@0
   339
	if (objc != 3) {
sl@0
   340
	    goto wrongNumArgs;
sl@0
   341
	}
sl@0
   342
	if (CheckIfVarUnset(interp, varIndex)) {
sl@0
   343
	    return TCL_ERROR;
sl@0
   344
	}
sl@0
   345
	if (Tcl_GetDoubleFromObj(interp, varPtr[varIndex],
sl@0
   346
				 &doubleValue) != TCL_OK) {
sl@0
   347
	    return TCL_ERROR;
sl@0
   348
	}
sl@0
   349
	if (!Tcl_IsShared(varPtr[varIndex])) {
sl@0
   350
	    Tcl_SetDoubleObj(varPtr[varIndex], (doubleValue * 10.0));
sl@0
   351
	} else {
sl@0
   352
	    SetVarToObj(varIndex, Tcl_NewDoubleObj( (doubleValue * 10.0) ));
sl@0
   353
	}
sl@0
   354
	Tcl_SetObjResult(interp, varPtr[varIndex]);
sl@0
   355
    } else if (strcmp(subCmd, "div10") == 0) {
sl@0
   356
	if (objc != 3) {
sl@0
   357
	    goto wrongNumArgs;
sl@0
   358
	}
sl@0
   359
	if (CheckIfVarUnset(interp, varIndex)) {
sl@0
   360
	    return TCL_ERROR;
sl@0
   361
	}
sl@0
   362
	if (Tcl_GetDoubleFromObj(interp, varPtr[varIndex],
sl@0
   363
				 &doubleValue) != TCL_OK) {
sl@0
   364
	    return TCL_ERROR;
sl@0
   365
	}
sl@0
   366
	if (!Tcl_IsShared(varPtr[varIndex])) {
sl@0
   367
	    Tcl_SetDoubleObj(varPtr[varIndex], (doubleValue / 10.0));
sl@0
   368
	} else {
sl@0
   369
	    SetVarToObj(varIndex, Tcl_NewDoubleObj( (doubleValue / 10.0) ));
sl@0
   370
	}
sl@0
   371
	Tcl_SetObjResult(interp, varPtr[varIndex]);
sl@0
   372
    } else {
sl@0
   373
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
sl@0
   374
		"bad option \"", Tcl_GetString(objv[1]),
sl@0
   375
		"\": must be set, get, mult10, or div10", (char *) NULL);
sl@0
   376
	return TCL_ERROR;
sl@0
   377
    }
sl@0
   378
    return TCL_OK;
sl@0
   379
}
sl@0
   380

sl@0
   381
/*
sl@0
   382
 *----------------------------------------------------------------------
sl@0
   383
 *
sl@0
   384
 * TestindexobjCmd --
sl@0
   385
 *
sl@0
   386
 *	This procedure implements the "testindexobj" command. It is used to
sl@0
   387
 *	test the index Tcl object type implementation.
sl@0
   388
 *
sl@0
   389
 * Results:
sl@0
   390
 *	A standard Tcl object result.
sl@0
   391
 *
sl@0
   392
 * Side effects:
sl@0
   393
 *	Creates and frees int objects, and also converts objects to
sl@0
   394
 *	have int type.
sl@0
   395
 *
sl@0
   396
 *----------------------------------------------------------------------
sl@0
   397
 */
sl@0
   398
sl@0
   399
static int
sl@0
   400
TestindexobjCmd(clientData, interp, objc, objv)
sl@0
   401
    ClientData clientData;	/* Not used. */
sl@0
   402
    Tcl_Interp *interp;		/* Current interpreter. */
sl@0
   403
    int objc;			/* Number of arguments. */
sl@0
   404
    Tcl_Obj *CONST objv[];	/* Argument objects. */
sl@0
   405
{
sl@0
   406
    int allowAbbrev, index, index2, setError, i, result;
sl@0
   407
    CONST char **argv;
sl@0
   408
    static CONST char *tablePtr[] = {"a", "b", "check", (char *) NULL};
sl@0
   409
    /*
sl@0
   410
     * Keep this structure declaration in sync with tclIndexObj.c
sl@0
   411
     */
sl@0
   412
    struct IndexRep {
sl@0
   413
	VOID *tablePtr;			/* Pointer to the table of strings */
sl@0
   414
	int offset;			/* Offset between table entries */
sl@0
   415
	int index;			/* Selected index into table. */
sl@0
   416
    };
sl@0
   417
    struct IndexRep *indexRep;
sl@0
   418
sl@0
   419
    if ((objc == 3) && (strcmp(Tcl_GetString(objv[1]),
sl@0
   420
	    "check") == 0)) {
sl@0
   421
	/*
sl@0
   422
	 * This code checks to be sure that the results of
sl@0
   423
	 * Tcl_GetIndexFromObj are properly cached in the object and
sl@0
   424
	 * returned on subsequent lookups.
sl@0
   425
	 */
sl@0
   426
sl@0
   427
	if (Tcl_GetIntFromObj(interp, objv[2], &index2) != TCL_OK) {
sl@0
   428
	    return TCL_ERROR;
sl@0
   429
	}
sl@0
   430
sl@0
   431
	Tcl_GetIndexFromObj((Tcl_Interp *) NULL, objv[1], tablePtr,
sl@0
   432
		"token", 0, &index);
sl@0
   433
	indexRep = (struct IndexRep *) objv[1]->internalRep.otherValuePtr;
sl@0
   434
	indexRep->index = index2;
sl@0
   435
	result = Tcl_GetIndexFromObj((Tcl_Interp *) NULL, objv[1],
sl@0
   436
		tablePtr, "token", 0, &index);
sl@0
   437
	if (result == TCL_OK) {
sl@0
   438
	    Tcl_SetIntObj(Tcl_GetObjResult(interp), index);
sl@0
   439
	}
sl@0
   440
	return result;
sl@0
   441
    }
sl@0
   442
sl@0
   443
    if (objc < 5) {
sl@0
   444
	Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args", -1);
sl@0
   445
	return TCL_ERROR;
sl@0
   446
    }
sl@0
   447
sl@0
   448
    if (Tcl_GetBooleanFromObj(interp, objv[1], &setError) != TCL_OK) {
sl@0
   449
	return TCL_ERROR;
sl@0
   450
    }
sl@0
   451
    if (Tcl_GetBooleanFromObj(interp, objv[2], &allowAbbrev) != TCL_OK) {
sl@0
   452
	return TCL_ERROR;
sl@0
   453
    }
sl@0
   454
sl@0
   455
    argv = (CONST char **) ckalloc((unsigned) ((objc-3) * sizeof(char *)));
sl@0
   456
    for (i = 4; i < objc; i++) {
sl@0
   457
	argv[i-4] = Tcl_GetString(objv[i]);
sl@0
   458
    }
sl@0
   459
    argv[objc-4] = NULL;
sl@0
   460
    
sl@0
   461
    /*
sl@0
   462
     * Tcl_GetIndexFromObj assumes that the table is statically-allocated
sl@0
   463
     * so that its address is different for each index object. If we
sl@0
   464
     * accidently allocate a table at the same address as that cached in
sl@0
   465
     * the index object, clear out the object's cached state.
sl@0
   466
     */
sl@0
   467
sl@0
   468
    if ( objv[3]->typePtr != NULL
sl@0
   469
	 && !strcmp( "index", objv[3]->typePtr->name ) ) {
sl@0
   470
	indexRep = (struct IndexRep *) objv[3]->internalRep.otherValuePtr;
sl@0
   471
	if (indexRep->tablePtr == (VOID *) argv) {
sl@0
   472
	    objv[3]->typePtr->freeIntRepProc(objv[3]);
sl@0
   473
	    objv[3]->typePtr = NULL;
sl@0
   474
	}
sl@0
   475
    }
sl@0
   476
sl@0
   477
    result = Tcl_GetIndexFromObj((setError? interp : NULL), objv[3],
sl@0
   478
	    argv, "token", (allowAbbrev? 0 : TCL_EXACT), &index);
sl@0
   479
    ckfree((char *) argv);
sl@0
   480
    if (result == TCL_OK) {
sl@0
   481
	Tcl_SetIntObj(Tcl_GetObjResult(interp), index);
sl@0
   482
    }
sl@0
   483
    return result;
sl@0
   484
}
sl@0
   485

sl@0
   486
/*
sl@0
   487
 *----------------------------------------------------------------------
sl@0
   488
 *
sl@0
   489
 * TestintobjCmd --
sl@0
   490
 *
sl@0
   491
 *	This procedure implements the "testintobj" command. It is used to
sl@0
   492
 *	test the int Tcl object type implementation.
sl@0
   493
 *
sl@0
   494
 * Results:
sl@0
   495
 *	A standard Tcl object result.
sl@0
   496
 *
sl@0
   497
 * Side effects:
sl@0
   498
 *	Creates and frees int objects, and also converts objects to
sl@0
   499
 *	have int type.
sl@0
   500
 *
sl@0
   501
 *----------------------------------------------------------------------
sl@0
   502
 */
sl@0
   503
sl@0
   504
static int
sl@0
   505
TestintobjCmd(clientData, interp, objc, objv)
sl@0
   506
    ClientData clientData;	/* Not used. */
sl@0
   507
    Tcl_Interp *interp;		/* Current interpreter. */
sl@0
   508
    int objc;			/* Number of arguments. */
sl@0
   509
    Tcl_Obj *CONST objv[];	/* Argument objects. */
sl@0
   510
{
sl@0
   511
    int intValue, varIndex, i;
sl@0
   512
    long longValue;
sl@0
   513
    char *index, *subCmd, *string;
sl@0
   514
	
sl@0
   515
    if (objc < 3) {
sl@0
   516
	wrongNumArgs:
sl@0
   517
	Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
sl@0
   518
	return TCL_ERROR;
sl@0
   519
    }
sl@0
   520
sl@0
   521
    index = Tcl_GetString(objv[2]);
sl@0
   522
    if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
sl@0
   523
	return TCL_ERROR;
sl@0
   524
    }
sl@0
   525
sl@0
   526
    subCmd = Tcl_GetString(objv[1]);
sl@0
   527
    if (strcmp(subCmd, "set") == 0) {
sl@0
   528
	if (objc != 4) {
sl@0
   529
	    goto wrongNumArgs;
sl@0
   530
	}
sl@0
   531
	string = Tcl_GetString(objv[3]);
sl@0
   532
	if (Tcl_GetInt(interp, string, &i) != TCL_OK) {
sl@0
   533
	    return TCL_ERROR;
sl@0
   534
	}
sl@0
   535
	intValue = i;
sl@0
   536
sl@0
   537
	/*
sl@0
   538
	 * If the object currently bound to the variable with index varIndex
sl@0
   539
	 * has ref count 1 (i.e. the object is unshared) we can modify that
sl@0
   540
	 * object directly. Otherwise, if RC>1 (i.e. the object is shared),
sl@0
   541
	 * we must create a new object to modify/set and decrement the old
sl@0
   542
	 * formerly-shared object's ref count. This is "copy on write".
sl@0
   543
	 */
sl@0
   544
sl@0
   545
	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
sl@0
   546
	    Tcl_SetIntObj(varPtr[varIndex], intValue);
sl@0
   547
	} else {
sl@0
   548
	    SetVarToObj(varIndex, Tcl_NewIntObj(intValue));
sl@0
   549
	}
sl@0
   550
	Tcl_SetObjResult(interp, varPtr[varIndex]);
sl@0
   551
    } else if (strcmp(subCmd, "set2") == 0) { /* doesn't set result */
sl@0
   552
	if (objc != 4) {
sl@0
   553
	    goto wrongNumArgs;
sl@0
   554
	}
sl@0
   555
	string = Tcl_GetString(objv[3]);
sl@0
   556
	if (Tcl_GetInt(interp, string, &i) != TCL_OK) {
sl@0
   557
	    return TCL_ERROR;
sl@0
   558
	}
sl@0
   559
	intValue = i;
sl@0
   560
	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
sl@0
   561
	    Tcl_SetIntObj(varPtr[varIndex], intValue);
sl@0
   562
	} else {
sl@0
   563
	    SetVarToObj(varIndex, Tcl_NewIntObj(intValue));
sl@0
   564
	}
sl@0
   565
    } else if (strcmp(subCmd, "setlong") == 0) {
sl@0
   566
	if (objc != 4) {
sl@0
   567
	    goto wrongNumArgs;
sl@0
   568
	}
sl@0
   569
	string = Tcl_GetString(objv[3]);
sl@0
   570
	if (Tcl_GetInt(interp, string, &i) != TCL_OK) {
sl@0
   571
	    return TCL_ERROR;
sl@0
   572
	}
sl@0
   573
	intValue = i;
sl@0
   574
	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
sl@0
   575
	    Tcl_SetLongObj(varPtr[varIndex], intValue);
sl@0
   576
	} else {
sl@0
   577
	    SetVarToObj(varIndex, Tcl_NewLongObj(intValue));
sl@0
   578
	}
sl@0
   579
	Tcl_SetObjResult(interp, varPtr[varIndex]);
sl@0
   580
    } else if (strcmp(subCmd, "setmaxlong") == 0) {
sl@0
   581
	long maxLong = LONG_MAX;
sl@0
   582
	if (objc != 3) {
sl@0
   583
	    goto wrongNumArgs;
sl@0
   584
	}
sl@0
   585
	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
sl@0
   586
	    Tcl_SetLongObj(varPtr[varIndex], maxLong);
sl@0
   587
	} else {
sl@0
   588
	    SetVarToObj(varIndex, Tcl_NewLongObj(maxLong));
sl@0
   589
	}
sl@0
   590
    } else if (strcmp(subCmd, "ismaxlong") == 0) {
sl@0
   591
	if (objc != 3) {
sl@0
   592
	    goto wrongNumArgs;
sl@0
   593
	}
sl@0
   594
	if (CheckIfVarUnset(interp, varIndex)) {
sl@0
   595
	    return TCL_ERROR;
sl@0
   596
	}
sl@0
   597
	if (Tcl_GetLongFromObj(interp, varPtr[varIndex], &longValue) != TCL_OK) {
sl@0
   598
	    return TCL_ERROR;
sl@0
   599
	}
sl@0
   600
	Tcl_AppendToObj(Tcl_GetObjResult(interp),
sl@0
   601
	        ((longValue == LONG_MAX)? "1" : "0"), -1);
sl@0
   602
    } else if (strcmp(subCmd, "get") == 0) {
sl@0
   603
	if (objc != 3) {
sl@0
   604
	    goto wrongNumArgs;
sl@0
   605
	}
sl@0
   606
	if (CheckIfVarUnset(interp, varIndex)) {
sl@0
   607
	    return TCL_ERROR;
sl@0
   608
	}
sl@0
   609
	Tcl_SetObjResult(interp, varPtr[varIndex]);
sl@0
   610
    } else if (strcmp(subCmd, "get2") == 0) {
sl@0
   611
	if (objc != 3) {
sl@0
   612
	    goto wrongNumArgs;
sl@0
   613
	}
sl@0
   614
	if (CheckIfVarUnset(interp, varIndex)) {
sl@0
   615
	    return TCL_ERROR;
sl@0
   616
	}
sl@0
   617
	string = Tcl_GetString(varPtr[varIndex]);
sl@0
   618
	Tcl_AppendToObj(Tcl_GetObjResult(interp), string, -1);
sl@0
   619
    } else if (strcmp(subCmd, "inttoobigtest") == 0) {
sl@0
   620
	/*
sl@0
   621
	 * If long ints have more bits than ints on this platform, verify
sl@0
   622
	 * that Tcl_GetIntFromObj returns an error if the long int held
sl@0
   623
	 * in an integer object's internal representation is too large
sl@0
   624
	 * to fit in an int.
sl@0
   625
	 */
sl@0
   626
	
sl@0
   627
	if (objc != 3) {
sl@0
   628
	    goto wrongNumArgs;
sl@0
   629
	}
sl@0
   630
#if (INT_MAX == LONG_MAX)   /* int is same size as long int */
sl@0
   631
	Tcl_AppendToObj(Tcl_GetObjResult(interp), "1", -1);
sl@0
   632
#else 
sl@0
   633
	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
sl@0
   634
	    Tcl_SetLongObj(varPtr[varIndex], LONG_MAX);
sl@0
   635
	} else {
sl@0
   636
	    SetVarToObj(varIndex, Tcl_NewLongObj(LONG_MAX));
sl@0
   637
	}
sl@0
   638
	if (Tcl_GetIntFromObj(interp, varPtr[varIndex], &i) != TCL_OK) {
sl@0
   639
	    Tcl_ResetResult(interp);
sl@0
   640
	    Tcl_AppendToObj(Tcl_GetObjResult(interp), "1", -1);
sl@0
   641
	    return TCL_OK;
sl@0
   642
	}
sl@0
   643
	Tcl_AppendToObj(Tcl_GetObjResult(interp), "0", -1);
sl@0
   644
#endif
sl@0
   645
    } else if (strcmp(subCmd, "mult10") == 0) {
sl@0
   646
	if (objc != 3) {
sl@0
   647
	    goto wrongNumArgs;
sl@0
   648
	}
sl@0
   649
	if (CheckIfVarUnset(interp, varIndex)) {
sl@0
   650
	    return TCL_ERROR;
sl@0
   651
	}
sl@0
   652
	if (Tcl_GetIntFromObj(interp, varPtr[varIndex],
sl@0
   653
			      &intValue) != TCL_OK) {
sl@0
   654
	    return TCL_ERROR;
sl@0
   655
	}
sl@0
   656
	if (!Tcl_IsShared(varPtr[varIndex])) {
sl@0
   657
	    Tcl_SetIntObj(varPtr[varIndex], (intValue * 10));
sl@0
   658
	} else {
sl@0
   659
	    SetVarToObj(varIndex, Tcl_NewIntObj( (intValue * 10) ));
sl@0
   660
	}
sl@0
   661
	Tcl_SetObjResult(interp, varPtr[varIndex]);
sl@0
   662
    } else if (strcmp(subCmd, "div10") == 0) {
sl@0
   663
	if (objc != 3) {
sl@0
   664
	    goto wrongNumArgs;
sl@0
   665
	}
sl@0
   666
	if (CheckIfVarUnset(interp, varIndex)) {
sl@0
   667
	    return TCL_ERROR;
sl@0
   668
	}
sl@0
   669
	if (Tcl_GetIntFromObj(interp, varPtr[varIndex],
sl@0
   670
			      &intValue) != TCL_OK) {
sl@0
   671
	    return TCL_ERROR;
sl@0
   672
	}
sl@0
   673
	if (!Tcl_IsShared(varPtr[varIndex])) {
sl@0
   674
	    Tcl_SetIntObj(varPtr[varIndex], (intValue / 10));
sl@0
   675
	} else {
sl@0
   676
	    SetVarToObj(varIndex, Tcl_NewIntObj( (intValue / 10) ));
sl@0
   677
	}
sl@0
   678
	Tcl_SetObjResult(interp, varPtr[varIndex]);
sl@0
   679
    } else {
sl@0
   680
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
sl@0
   681
		"bad option \"", Tcl_GetString(objv[1]),
sl@0
   682
		"\": must be set, get, get2, mult10, or div10",
sl@0
   683
		(char *) NULL);
sl@0
   684
	return TCL_ERROR;
sl@0
   685
    }
sl@0
   686
    return TCL_OK;
sl@0
   687
}
sl@0
   688

sl@0
   689
/*
sl@0
   690
 *----------------------------------------------------------------------
sl@0
   691
 *
sl@0
   692
 * TestobjCmd --
sl@0
   693
 *
sl@0
   694
 *	This procedure implements the "testobj" command. It is used to test
sl@0
   695
 *	the type-independent portions of the Tcl object type implementation.
sl@0
   696
 *
sl@0
   697
 * Results:
sl@0
   698
 *	A standard Tcl object result.
sl@0
   699
 *
sl@0
   700
 * Side effects:
sl@0
   701
 *	Creates and frees objects.
sl@0
   702
 *
sl@0
   703
 *----------------------------------------------------------------------
sl@0
   704
 */
sl@0
   705
sl@0
   706
static int
sl@0
   707
TestobjCmd(clientData, interp, objc, objv)
sl@0
   708
    ClientData clientData;	/* Not used. */
sl@0
   709
    Tcl_Interp *interp;		/* Current interpreter. */
sl@0
   710
    int objc;			/* Number of arguments. */
sl@0
   711
    Tcl_Obj *CONST objv[];	/* Argument objects. */
sl@0
   712
{
sl@0
   713
    int varIndex, destIndex, i;
sl@0
   714
    char *index, *subCmd, *string;
sl@0
   715
    Tcl_ObjType *targetType;
sl@0
   716
	
sl@0
   717
    if (objc < 2) {
sl@0
   718
	wrongNumArgs:
sl@0
   719
	Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
sl@0
   720
	return TCL_ERROR;
sl@0
   721
    }
sl@0
   722
sl@0
   723
    subCmd = Tcl_GetString(objv[1]);
sl@0
   724
    if (strcmp(subCmd, "assign") == 0) {
sl@0
   725
        if (objc != 4) {
sl@0
   726
            goto wrongNumArgs;
sl@0
   727
        }
sl@0
   728
        index = Tcl_GetString(objv[2]);
sl@0
   729
        if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
sl@0
   730
            return TCL_ERROR;
sl@0
   731
        }
sl@0
   732
        if (CheckIfVarUnset(interp, varIndex)) {
sl@0
   733
	    return TCL_ERROR;
sl@0
   734
	}
sl@0
   735
	string = Tcl_GetString(objv[3]);
sl@0
   736
        if (GetVariableIndex(interp, string, &destIndex) != TCL_OK) {
sl@0
   737
            return TCL_ERROR;
sl@0
   738
        }
sl@0
   739
        SetVarToObj(destIndex, varPtr[varIndex]);
sl@0
   740
	Tcl_SetObjResult(interp, varPtr[destIndex]);
sl@0
   741
     } else if (strcmp(subCmd, "convert") == 0) {
sl@0
   742
        char *typeName;
sl@0
   743
        if (objc != 4) {
sl@0
   744
            goto wrongNumArgs;
sl@0
   745
        }
sl@0
   746
        index = Tcl_GetString(objv[2]);
sl@0
   747
        if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
sl@0
   748
            return TCL_ERROR;
sl@0
   749
        }
sl@0
   750
        if (CheckIfVarUnset(interp, varIndex)) {
sl@0
   751
	    return TCL_ERROR;
sl@0
   752
	}
sl@0
   753
        typeName = Tcl_GetString(objv[3]);
sl@0
   754
        if ((targetType = Tcl_GetObjType(typeName)) == NULL) {
sl@0
   755
	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
sl@0
   756
		    "no type ", typeName, " found", (char *) NULL);
sl@0
   757
            return TCL_ERROR;
sl@0
   758
        }
sl@0
   759
        if (Tcl_ConvertToType(interp, varPtr[varIndex], targetType)
sl@0
   760
            != TCL_OK) {
sl@0
   761
            return TCL_ERROR;
sl@0
   762
        }
sl@0
   763
	Tcl_SetObjResult(interp, varPtr[varIndex]);
sl@0
   764
    } else if (strcmp(subCmd, "duplicate") == 0) {
sl@0
   765
        if (objc != 4) {
sl@0
   766
            goto wrongNumArgs;
sl@0
   767
        }
sl@0
   768
        index = Tcl_GetString(objv[2]);
sl@0
   769
        if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
sl@0
   770
            return TCL_ERROR;
sl@0
   771
        }
sl@0
   772
        if (CheckIfVarUnset(interp, varIndex)) {
sl@0
   773
	    return TCL_ERROR;
sl@0
   774
	}
sl@0
   775
	string = Tcl_GetString(objv[3]);
sl@0
   776
        if (GetVariableIndex(interp, string, &destIndex) != TCL_OK) {
sl@0
   777
            return TCL_ERROR;
sl@0
   778
        }
sl@0
   779
        SetVarToObj(destIndex, Tcl_DuplicateObj(varPtr[varIndex]));
sl@0
   780
	Tcl_SetObjResult(interp, varPtr[destIndex]);
sl@0
   781
    } else if (strcmp(subCmd, "freeallvars") == 0) {
sl@0
   782
        if (objc != 2) {
sl@0
   783
            goto wrongNumArgs;
sl@0
   784
        }
sl@0
   785
        for (i = 0;  i < NUMBER_OF_OBJECT_VARS;  i++) {
sl@0
   786
            if (varPtr[i] != NULL) {
sl@0
   787
                Tcl_DecrRefCount(varPtr[i]);
sl@0
   788
                varPtr[i] = NULL;
sl@0
   789
            }
sl@0
   790
        }
sl@0
   791
    } else if ( strcmp ( subCmd, "invalidateStringRep" ) == 0 ) {
sl@0
   792
	if ( objc != 3 ) {
sl@0
   793
	    goto wrongNumArgs;
sl@0
   794
	}
sl@0
   795
	index = Tcl_GetString( objv[2] );
sl@0
   796
	if ( GetVariableIndex( interp, index, &varIndex ) != TCL_OK ) {
sl@0
   797
	    return TCL_ERROR;
sl@0
   798
	}
sl@0
   799
        if (CheckIfVarUnset(interp, varIndex)) {
sl@0
   800
	    return TCL_ERROR;
sl@0
   801
	}
sl@0
   802
	Tcl_InvalidateStringRep( varPtr[varIndex] );
sl@0
   803
	Tcl_SetObjResult( interp, varPtr[varIndex] );
sl@0
   804
    } else if (strcmp(subCmd, "newobj") == 0) {
sl@0
   805
        if (objc != 3) {
sl@0
   806
            goto wrongNumArgs;
sl@0
   807
        }
sl@0
   808
        index = Tcl_GetString(objv[2]);
sl@0
   809
        if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
sl@0
   810
            return TCL_ERROR;
sl@0
   811
        }
sl@0
   812
        SetVarToObj(varIndex, Tcl_NewObj());
sl@0
   813
	Tcl_SetObjResult(interp, varPtr[varIndex]);
sl@0
   814
    } else if (strcmp(subCmd, "objtype") == 0) {
sl@0
   815
	char *typeName;
sl@0
   816
sl@0
   817
	/*
sl@0
   818
	 * return an object containing the name of the argument's type
sl@0
   819
	 * of internal rep.  If none exists, return "none".
sl@0
   820
	 */
sl@0
   821
	
sl@0
   822
        if (objc != 3) {
sl@0
   823
            goto wrongNumArgs;
sl@0
   824
        }
sl@0
   825
	if (objv[2]->typePtr == NULL) {
sl@0
   826
	    Tcl_SetObjResult(interp, Tcl_NewStringObj("none", -1));
sl@0
   827
	} else {
sl@0
   828
	    typeName = objv[2]->typePtr->name;
sl@0
   829
	    Tcl_SetObjResult(interp, Tcl_NewStringObj(typeName, -1));
sl@0
   830
	}
sl@0
   831
    } else if (strcmp(subCmd, "refcount") == 0) {
sl@0
   832
	char buf[TCL_INTEGER_SPACE];
sl@0
   833
sl@0
   834
        if (objc != 3) {
sl@0
   835
            goto wrongNumArgs;
sl@0
   836
        }
sl@0
   837
        index = Tcl_GetString(objv[2]);
sl@0
   838
        if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
sl@0
   839
            return TCL_ERROR;
sl@0
   840
        }
sl@0
   841
        if (CheckIfVarUnset(interp, varIndex)) {
sl@0
   842
	    return TCL_ERROR;
sl@0
   843
	}
sl@0
   844
	TclFormatInt(buf, varPtr[varIndex]->refCount);
sl@0
   845
        Tcl_SetResult(interp, buf, TCL_VOLATILE);
sl@0
   846
    } else if (strcmp(subCmd, "type") == 0) {
sl@0
   847
        if (objc != 3) {
sl@0
   848
            goto wrongNumArgs;
sl@0
   849
        }
sl@0
   850
        index = Tcl_GetString(objv[2]);
sl@0
   851
        if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
sl@0
   852
            return TCL_ERROR;
sl@0
   853
        }
sl@0
   854
        if (CheckIfVarUnset(interp, varIndex)) {
sl@0
   855
	    return TCL_ERROR;
sl@0
   856
	}
sl@0
   857
        if (varPtr[varIndex]->typePtr == NULL) { /* a string! */
sl@0
   858
	    Tcl_AppendToObj(Tcl_GetObjResult(interp), "string", -1);
sl@0
   859
        } else {
sl@0
   860
            Tcl_AppendToObj(Tcl_GetObjResult(interp),
sl@0
   861
                    varPtr[varIndex]->typePtr->name, -1);
sl@0
   862
        }
sl@0
   863
    } else if (strcmp(subCmd, "types") == 0) {
sl@0
   864
        if (objc != 2) {
sl@0
   865
            goto wrongNumArgs;
sl@0
   866
        }
sl@0
   867
	if (Tcl_AppendAllObjTypes(interp,
sl@0
   868
		Tcl_GetObjResult(interp)) != TCL_OK) {
sl@0
   869
	    return TCL_ERROR;
sl@0
   870
	}
sl@0
   871
    } else {
sl@0
   872
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
sl@0
   873
		"bad option \"",
sl@0
   874
		Tcl_GetString(objv[1]),
sl@0
   875
		"\": must be assign, convert, duplicate, freeallvars, ",
sl@0
   876
		"newobj, objcount, objtype, refcount, type, or types",
sl@0
   877
		(char *) NULL);
sl@0
   878
	return TCL_ERROR;
sl@0
   879
    }
sl@0
   880
    return TCL_OK;
sl@0
   881
}
sl@0
   882

sl@0
   883
/*
sl@0
   884
 *----------------------------------------------------------------------
sl@0
   885
 *
sl@0
   886
 * TeststringobjCmd --
sl@0
   887
 *
sl@0
   888
 *	This procedure implements the "teststringobj" command. It is used to
sl@0
   889
 *	test the string Tcl object type implementation.
sl@0
   890
 *
sl@0
   891
 * Results:
sl@0
   892
 *	A standard Tcl object result.
sl@0
   893
 *
sl@0
   894
 * Side effects:
sl@0
   895
 *	Creates and frees string objects, and also converts objects to
sl@0
   896
 *	have string type.
sl@0
   897
 *
sl@0
   898
 *----------------------------------------------------------------------
sl@0
   899
 */
sl@0
   900
sl@0
   901
static int
sl@0
   902
TeststringobjCmd(clientData, interp, objc, objv)
sl@0
   903
    ClientData clientData;	/* Not used. */
sl@0
   904
    Tcl_Interp *interp;		/* Current interpreter. */
sl@0
   905
    int objc;			/* Number of arguments. */
sl@0
   906
    Tcl_Obj *CONST objv[];	/* Argument objects. */
sl@0
   907
{
sl@0
   908
    int varIndex, option, i, length;
sl@0
   909
#define MAX_STRINGS 11
sl@0
   910
    char *index, *string, *strings[MAX_STRINGS+1];
sl@0
   911
    TestString *strPtr;
sl@0
   912
    static CONST char *options[] = {
sl@0
   913
	"append", "appendstrings", "get", "get2", "length", "length2",
sl@0
   914
	"set", "set2", "setlength", "ualloc", "getunicode", 
sl@0
   915
	(char *) NULL
sl@0
   916
    };
sl@0
   917
sl@0
   918
    if (objc < 3) {
sl@0
   919
	wrongNumArgs:
sl@0
   920
	Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
sl@0
   921
	return TCL_ERROR;
sl@0
   922
    }
sl@0
   923
sl@0
   924
    index = Tcl_GetString(objv[2]);
sl@0
   925
    if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
sl@0
   926
	return TCL_ERROR;
sl@0
   927
    }
sl@0
   928
sl@0
   929
    if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, &option)
sl@0
   930
	    != TCL_OK) {
sl@0
   931
	return TCL_ERROR;
sl@0
   932
    }
sl@0
   933
    switch (option) {
sl@0
   934
	case 0:				/* append */
sl@0
   935
	    if (objc != 5) {
sl@0
   936
		goto wrongNumArgs;
sl@0
   937
	    }
sl@0
   938
	    if (Tcl_GetIntFromObj(interp, objv[4], &length) != TCL_OK) {
sl@0
   939
		return TCL_ERROR;
sl@0
   940
	    }
sl@0
   941
	    if (varPtr[varIndex] == NULL) {
sl@0
   942
		SetVarToObj(varIndex, Tcl_NewObj());
sl@0
   943
	    }
sl@0
   944
	    
sl@0
   945
	    /*
sl@0
   946
	     * If the object bound to variable "varIndex" is shared, we must
sl@0
   947
	     * "copy on write" and append to a copy of the object. 
sl@0
   948
	     */
sl@0
   949
	    
sl@0
   950
	    if (Tcl_IsShared(varPtr[varIndex])) {
sl@0
   951
		SetVarToObj(varIndex, Tcl_DuplicateObj(varPtr[varIndex]));
sl@0
   952
	    }
sl@0
   953
	    string = Tcl_GetString(objv[3]);
sl@0
   954
	    Tcl_AppendToObj(varPtr[varIndex], string, length);
sl@0
   955
	    Tcl_SetObjResult(interp, varPtr[varIndex]);
sl@0
   956
	    break;
sl@0
   957
	case 1:				/* appendstrings */
sl@0
   958
	    if (objc > (MAX_STRINGS+3)) {
sl@0
   959
		goto wrongNumArgs;
sl@0
   960
	    }
sl@0
   961
	    if (varPtr[varIndex] == NULL) {
sl@0
   962
		SetVarToObj(varIndex, Tcl_NewObj());
sl@0
   963
	    }
sl@0
   964
sl@0
   965
	    /*
sl@0
   966
	     * If the object bound to variable "varIndex" is shared, we must
sl@0
   967
	     * "copy on write" and append to a copy of the object. 
sl@0
   968
	     */
sl@0
   969
sl@0
   970
	    if (Tcl_IsShared(varPtr[varIndex])) {
sl@0
   971
		SetVarToObj(varIndex, Tcl_DuplicateObj(varPtr[varIndex]));
sl@0
   972
	    }
sl@0
   973
	    for (i = 3;  i < objc;  i++) {
sl@0
   974
		strings[i-3] = Tcl_GetString(objv[i]);
sl@0
   975
	    }
sl@0
   976
	    for ( ; i < 12 + 3; i++) {
sl@0
   977
		strings[i - 3] = NULL;
sl@0
   978
	    }
sl@0
   979
	    Tcl_AppendStringsToObj(varPtr[varIndex], strings[0], strings[1],
sl@0
   980
		    strings[2], strings[3], strings[4], strings[5],
sl@0
   981
		    strings[6], strings[7], strings[8], strings[9],
sl@0
   982
		    strings[10], strings[11]);
sl@0
   983
	    Tcl_SetObjResult(interp, varPtr[varIndex]);
sl@0
   984
	    break;
sl@0
   985
	case 2:				/* get */
sl@0
   986
	    if (objc != 3) {
sl@0
   987
		goto wrongNumArgs;
sl@0
   988
	    }
sl@0
   989
	    if (CheckIfVarUnset(interp, varIndex)) {
sl@0
   990
		return TCL_ERROR;
sl@0
   991
	    }
sl@0
   992
	    Tcl_SetObjResult(interp, varPtr[varIndex]);
sl@0
   993
	    break;
sl@0
   994
	case 3:				/* get2 */
sl@0
   995
	    if (objc != 3) {
sl@0
   996
		goto wrongNumArgs;
sl@0
   997
	    }
sl@0
   998
	    if (CheckIfVarUnset(interp, varIndex)) {
sl@0
   999
		return TCL_ERROR;
sl@0
  1000
	    }
sl@0
  1001
	    string = Tcl_GetString(varPtr[varIndex]);
sl@0
  1002
	    Tcl_AppendToObj(Tcl_GetObjResult(interp), string, -1);
sl@0
  1003
	    break;
sl@0
  1004
	case 4:				/* length */
sl@0
  1005
	    if (objc != 3) {
sl@0
  1006
		goto wrongNumArgs;
sl@0
  1007
	    }
sl@0
  1008
	    Tcl_SetIntObj(Tcl_GetObjResult(interp), (varPtr[varIndex] != NULL)
sl@0
  1009
		    ? varPtr[varIndex]->length : -1);
sl@0
  1010
	    break;
sl@0
  1011
	case 5:				/* length2 */
sl@0
  1012
	    if (objc != 3) {
sl@0
  1013
		goto wrongNumArgs;
sl@0
  1014
	    }
sl@0
  1015
	    if (varPtr[varIndex] != NULL) {
sl@0
  1016
		strPtr = (TestString *)
sl@0
  1017
		    (varPtr[varIndex])->internalRep.otherValuePtr;
sl@0
  1018
		length = (int) strPtr->allocated;
sl@0
  1019
	    } else {
sl@0
  1020
		length = -1;
sl@0
  1021
	    }
sl@0
  1022
	    Tcl_SetIntObj(Tcl_GetObjResult(interp), length);
sl@0
  1023
	    break;
sl@0
  1024
	case 6:				/* set */
sl@0
  1025
	    if (objc != 4) {
sl@0
  1026
		goto wrongNumArgs;
sl@0
  1027
	    }
sl@0
  1028
sl@0
  1029
	    /*
sl@0
  1030
	     * If the object currently bound to the variable with index
sl@0
  1031
	     * varIndex has ref count 1 (i.e. the object is unshared) we
sl@0
  1032
	     * can modify that object directly. Otherwise, if RC>1 (i.e.
sl@0
  1033
	     * the object is shared), we must create a new object to
sl@0
  1034
	     * modify/set and decrement the old formerly-shared object's
sl@0
  1035
	     * ref count. This is "copy on write".
sl@0
  1036
	     */
sl@0
  1037
    
sl@0
  1038
	    string = Tcl_GetStringFromObj(objv[3], &length);
sl@0
  1039
	    if ((varPtr[varIndex] != NULL)
sl@0
  1040
		    && !Tcl_IsShared(varPtr[varIndex])) {
sl@0
  1041
		Tcl_SetStringObj(varPtr[varIndex], string, length);
sl@0
  1042
	    } else {
sl@0
  1043
		SetVarToObj(varIndex, Tcl_NewStringObj(string, length));
sl@0
  1044
	    }
sl@0
  1045
	    Tcl_SetObjResult(interp, varPtr[varIndex]);
sl@0
  1046
	    break;
sl@0
  1047
	case 7:				/* set2 */
sl@0
  1048
	    if (objc != 4) {
sl@0
  1049
		goto wrongNumArgs;
sl@0
  1050
	    }
sl@0
  1051
	    SetVarToObj(varIndex, objv[3]);
sl@0
  1052
	    break;
sl@0
  1053
	case 8:				/* setlength */
sl@0
  1054
	    if (objc != 4) {
sl@0
  1055
		goto wrongNumArgs;
sl@0
  1056
	    }
sl@0
  1057
	    if (Tcl_GetIntFromObj(interp, objv[3], &length) != TCL_OK) {
sl@0
  1058
		return TCL_ERROR;
sl@0
  1059
	    }
sl@0
  1060
	    if (varPtr[varIndex] != NULL) {
sl@0
  1061
		Tcl_SetObjLength(varPtr[varIndex], length);
sl@0
  1062
	    }
sl@0
  1063
	    break;
sl@0
  1064
	case 9:				/* ualloc */
sl@0
  1065
	    if (objc != 3) {
sl@0
  1066
		goto wrongNumArgs;
sl@0
  1067
	    }
sl@0
  1068
	    if (varPtr[varIndex] != NULL) {
sl@0
  1069
		strPtr = (TestString *)
sl@0
  1070
		    (varPtr[varIndex])->internalRep.otherValuePtr;
sl@0
  1071
		length = (int) strPtr->uallocated;
sl@0
  1072
	    } else {
sl@0
  1073
		length = -1;
sl@0
  1074
	    }
sl@0
  1075
	    Tcl_SetIntObj(Tcl_GetObjResult(interp), length);
sl@0
  1076
	    break;
sl@0
  1077
	case 10:			/* getunicode */
sl@0
  1078
	    if (objc != 3) {
sl@0
  1079
		goto wrongNumArgs;
sl@0
  1080
	    }
sl@0
  1081
	    Tcl_GetUnicodeFromObj(varPtr[varIndex], NULL);
sl@0
  1082
	    break;
sl@0
  1083
    }
sl@0
  1084
sl@0
  1085
    return TCL_OK;
sl@0
  1086
}
sl@0
  1087

sl@0
  1088
/*
sl@0
  1089
 *----------------------------------------------------------------------
sl@0
  1090
 *
sl@0
  1091
 * SetVarToObj --
sl@0
  1092
 *
sl@0
  1093
 *	Utility routine to assign a Tcl_Obj* to a test variable. The
sl@0
  1094
 *	Tcl_Obj* can be NULL.
sl@0
  1095
 *
sl@0
  1096
 * Results:
sl@0
  1097
 *	None.
sl@0
  1098
 *
sl@0
  1099
 * Side effects:
sl@0
  1100
 *	This routine handles ref counting details for assignment:
sl@0
  1101
 *	i.e. the old value's ref count must be decremented (if not NULL) and
sl@0
  1102
 *	the new one incremented (also if not NULL).
sl@0
  1103
 *
sl@0
  1104
 *----------------------------------------------------------------------
sl@0
  1105
 */
sl@0
  1106
sl@0
  1107
static void
sl@0
  1108
SetVarToObj(varIndex, objPtr)
sl@0
  1109
    int varIndex;		/* Designates the assignment variable. */
sl@0
  1110
    Tcl_Obj *objPtr;		/* Points to object to assign to var. */
sl@0
  1111
{
sl@0
  1112
    if (varPtr[varIndex] != NULL) {
sl@0
  1113
	Tcl_DecrRefCount(varPtr[varIndex]);
sl@0
  1114
    }
sl@0
  1115
    varPtr[varIndex] = objPtr;
sl@0
  1116
    if (objPtr != NULL) {
sl@0
  1117
	Tcl_IncrRefCount(objPtr);
sl@0
  1118
    }
sl@0
  1119
}
sl@0
  1120

sl@0
  1121
/*
sl@0
  1122
 *----------------------------------------------------------------------
sl@0
  1123
 *
sl@0
  1124
 * GetVariableIndex --
sl@0
  1125
 *
sl@0
  1126
 *	Utility routine to get a test variable index from the command line.
sl@0
  1127
 *
sl@0
  1128
 * Results:
sl@0
  1129
 *	A standard Tcl object result.
sl@0
  1130
 *
sl@0
  1131
 * Side effects:
sl@0
  1132
 *	None.
sl@0
  1133
 *
sl@0
  1134
 *----------------------------------------------------------------------
sl@0
  1135
 */
sl@0
  1136
sl@0
  1137
static int
sl@0
  1138
GetVariableIndex(interp, string, indexPtr)
sl@0
  1139
    Tcl_Interp *interp;         /* Interpreter for error reporting. */
sl@0
  1140
    char *string;               /* String containing a variable index
sl@0
  1141
				 * specified as a nonnegative number less
sl@0
  1142
				 * than NUMBER_OF_OBJECT_VARS. */
sl@0
  1143
    int *indexPtr;              /* Place to store converted result. */
sl@0
  1144
{
sl@0
  1145
    int index;
sl@0
  1146
    
sl@0
  1147
    if (Tcl_GetInt(interp, string, &index) != TCL_OK) {
sl@0
  1148
	return TCL_ERROR;
sl@0
  1149
    }
sl@0
  1150
    if (index < 0 || index >= NUMBER_OF_OBJECT_VARS) {
sl@0
  1151
	Tcl_ResetResult(interp);
sl@0
  1152
	Tcl_AppendToObj(Tcl_GetObjResult(interp), "bad variable index", -1);
sl@0
  1153
	return TCL_ERROR;
sl@0
  1154
    }
sl@0
  1155
sl@0
  1156
    *indexPtr = index;
sl@0
  1157
    return TCL_OK;
sl@0
  1158
}
sl@0
  1159

sl@0
  1160
/*
sl@0
  1161
 *----------------------------------------------------------------------
sl@0
  1162
 *
sl@0
  1163
 * CheckIfVarUnset --
sl@0
  1164
 *
sl@0
  1165
 *	Utility procedure that checks whether a test variable is readable:
sl@0
  1166
 *	i.e., that varPtr[varIndex] is non-NULL.
sl@0
  1167
 *
sl@0
  1168
 * Results:
sl@0
  1169
 *	1 if the test variable is unset (NULL); 0 otherwise.
sl@0
  1170
 *
sl@0
  1171
 * Side effects:
sl@0
  1172
 *	Sets the interpreter result to an error message if the variable is
sl@0
  1173
 *	unset (NULL).
sl@0
  1174
 *
sl@0
  1175
 *----------------------------------------------------------------------
sl@0
  1176
 */
sl@0
  1177
sl@0
  1178
static int
sl@0
  1179
CheckIfVarUnset(interp, varIndex)
sl@0
  1180
    Tcl_Interp *interp;		/* Interpreter for error reporting. */
sl@0
  1181
    int varIndex;		/* Index of the test variable to check. */
sl@0
  1182
{
sl@0
  1183
    if (varPtr[varIndex] == NULL) {
sl@0
  1184
	char buf[32 + TCL_INTEGER_SPACE];
sl@0
  1185
	
sl@0
  1186
	sprintf(buf, "variable %d is unset (NULL)", varIndex);
sl@0
  1187
	Tcl_ResetResult(interp);
sl@0
  1188
	Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1);
sl@0
  1189
	return 1;
sl@0
  1190
    }
sl@0
  1191
    return 0;
sl@0
  1192
}