tclTestObj.c

Go to the documentation of this file.
00001 /*
00002  * tclTestObj.c --
00003  *
00004  *      This file contains C command functions for the additional Tcl commands
00005  *      that are used for testing implementations of the Tcl object types.
00006  *      These commands are not normally included in Tcl applications; they're
00007  *      only used for testing.
00008  *
00009  * Copyright (c) 1995-1998 Sun Microsystems, Inc.
00010  * Copyright (c) 1999 by Scriptics Corporation.
00011  * Copyright (c) 2005 by Kevin B. Kenny.  All rights reserved.
00012  *
00013  * See the file "license.terms" for information on usage and redistribution of
00014  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
00015  *
00016  * RCS: @(#) $Id: tclTestObj.c,v 1.21 2007/12/13 15:23:20 dgp Exp $
00017  */
00018 
00019 #include "tclInt.h"
00020 #include "tommath.h"
00021 
00022 /*
00023  * An array of Tcl_Obj pointers used in the commands that operate on or get
00024  * the values of Tcl object-valued variables. varPtr[i] is the i-th variable's
00025  * Tcl_Obj *.
00026  */
00027 
00028 #define NUMBER_OF_OBJECT_VARS 20
00029 static Tcl_Obj *varPtr[NUMBER_OF_OBJECT_VARS];
00030 
00031 /*
00032  * Forward declarations for functions defined later in this file:
00033  */
00034 
00035 static int              CheckIfVarUnset(Tcl_Interp *interp, int varIndex);
00036 static int              GetVariableIndex(Tcl_Interp *interp,
00037                             char *string, int *indexPtr);
00038 static void             SetVarToObj(int varIndex, Tcl_Obj *objPtr);
00039 int                     TclObjTest_Init(Tcl_Interp *interp);
00040 static int              TestbignumobjCmd(ClientData dummy, Tcl_Interp *interp,
00041                             int objc, Tcl_Obj *const objv[]);
00042 static int              TestbooleanobjCmd(ClientData dummy,
00043                             Tcl_Interp *interp, int objc,
00044                             Tcl_Obj *const objv[]);
00045 static int              TestdoubleobjCmd(ClientData dummy, Tcl_Interp *interp,
00046                             int objc, Tcl_Obj *const objv[]);
00047 static int              TestindexobjCmd(ClientData dummy, Tcl_Interp *interp,
00048                             int objc, Tcl_Obj *const objv[]);
00049 static int              TestintobjCmd(ClientData dummy, Tcl_Interp *interp,
00050                             int objc, Tcl_Obj *const objv[]);
00051 static int              TestobjCmd(ClientData dummy, Tcl_Interp *interp,
00052                             int objc, Tcl_Obj *const objv[]);
00053 static int              TeststringobjCmd(ClientData dummy, Tcl_Interp *interp,
00054                             int objc, Tcl_Obj *const objv[]);
00055 
00056 typedef struct TestString {
00057     int numChars;
00058     size_t allocated;
00059     size_t uallocated;
00060     Tcl_UniChar unicode[2];
00061 } TestString;
00062 
00063 /*
00064  *----------------------------------------------------------------------
00065  *
00066  * TclObjTest_Init --
00067  *
00068  *      This function creates additional commands that are used to test the
00069  *      Tcl object support.
00070  *
00071  * Results:
00072  *      Returns a standard Tcl completion code, and leaves an error
00073  *      message in the interp's result if an error occurs.
00074  *
00075  * Side effects:
00076  *      Creates and registers several new testing commands.
00077  *
00078  *----------------------------------------------------------------------
00079  */
00080 
00081 int
00082 TclObjTest_Init(
00083     Tcl_Interp *interp)
00084 {
00085     register int i;
00086 
00087     for (i = 0;  i < NUMBER_OF_OBJECT_VARS;  i++) {
00088         varPtr[i] = NULL;
00089     }
00090 
00091     Tcl_CreateObjCommand(interp, "testbignumobj", TestbignumobjCmd,
00092             (ClientData) 0, NULL);
00093     Tcl_CreateObjCommand(interp, "testbooleanobj", TestbooleanobjCmd,
00094             (ClientData) 0, NULL);
00095     Tcl_CreateObjCommand(interp, "testdoubleobj", TestdoubleobjCmd,
00096             (ClientData) 0, NULL);
00097     Tcl_CreateObjCommand(interp, "testintobj", TestintobjCmd,
00098             (ClientData) 0, NULL);
00099     Tcl_CreateObjCommand(interp, "testindexobj", TestindexobjCmd,
00100             (ClientData) 0, NULL);
00101     Tcl_CreateObjCommand(interp, "testobj", TestobjCmd, (ClientData) 0, NULL);
00102     Tcl_CreateObjCommand(interp, "teststringobj", TeststringobjCmd,
00103             (ClientData) 0, NULL);
00104     return TCL_OK;
00105 }
00106 
00107 /*
00108  *----------------------------------------------------------------------
00109  *
00110  * TestbignumobjCmd --
00111  *
00112  *      This function implmenets the "testbignumobj" command.  It is used
00113  *      to exercise the bignum Tcl object type implementation.
00114  *
00115  * Results:
00116  *      Returns a standard Tcl object result.
00117  *
00118  * Side effects:
00119  *      Creates and frees bignum objects; converts objects to have bignum
00120  *      type.
00121  *
00122  *----------------------------------------------------------------------
00123  */
00124 
00125 static int
00126 TestbignumobjCmd(
00127     ClientData clientData,      /* unused */
00128     Tcl_Interp *interp,         /* Tcl interpreter */
00129     int objc,                   /* Argument count */
00130     Tcl_Obj *const objv[])      /* Argument vector */
00131 {
00132     const char * subcmds[] = {
00133         "set",      "get",      "mult10",      "div10", NULL
00134     };
00135     enum options {
00136         BIGNUM_SET, BIGNUM_GET, BIGNUM_MULT10, BIGNUM_DIV10
00137     };
00138 
00139     int index, varIndex;
00140     char* string;
00141     mp_int bignumValue, newValue;
00142 
00143     if (objc < 3) {
00144         Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?...");
00145         return TCL_ERROR;
00146     }
00147     if (Tcl_GetIndexFromObj(interp, objv[1], subcmds, "option", 0,
00148             &index) != TCL_OK) {
00149         return TCL_ERROR;
00150     }
00151     string = Tcl_GetString(objv[2]);
00152     if (GetVariableIndex(interp, string, &varIndex) != TCL_OK) {
00153         return TCL_ERROR;
00154     }
00155 
00156     switch (index) {
00157     case BIGNUM_SET:
00158         if (objc != 4) {
00159             Tcl_WrongNumArgs(interp, 2, objv, "var value");
00160             return TCL_ERROR;
00161         }
00162         string = Tcl_GetString(objv[3]);
00163         if (mp_init(&bignumValue) != MP_OKAY) {
00164             Tcl_SetObjResult(interp,
00165                     Tcl_NewStringObj("error in mp_init", -1));
00166             return TCL_ERROR;
00167         }
00168         if (mp_read_radix(&bignumValue, string, 10) != MP_OKAY) {
00169             mp_clear(&bignumValue);
00170             Tcl_SetObjResult(interp,
00171                     Tcl_NewStringObj("error in mp_read_radix", -1));
00172             return TCL_ERROR;
00173         }
00174 
00175         /*
00176          * If the object currently bound to the variable with index varIndex
00177          * has ref count 1 (i.e. the object is unshared) we can modify that
00178          * object directly.  Otherwise, if RC>1 (i.e. the object is shared),
00179          * we must create a new object to modify/set and decrement the old
00180          * formerly-shared object's ref count. This is "copy on write".
00181          */
00182 
00183         if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
00184             Tcl_SetBignumObj(varPtr[varIndex], &bignumValue);
00185         } else {
00186             SetVarToObj(varIndex, Tcl_NewBignumObj(&bignumValue));
00187         }
00188         break;
00189 
00190     case BIGNUM_GET:
00191         if (objc != 3) {
00192             Tcl_WrongNumArgs(interp, 2, objv, "varIndex");
00193             return TCL_ERROR;
00194         }
00195         if (CheckIfVarUnset(interp, varIndex)) {
00196             return TCL_ERROR;
00197         }
00198         break;
00199 
00200     case BIGNUM_MULT10:
00201         if (objc != 3) {
00202             Tcl_WrongNumArgs(interp, 2, objv, "varIndex");
00203             return TCL_ERROR;
00204         }
00205         if (CheckIfVarUnset(interp, varIndex)) {
00206             return TCL_ERROR;
00207         }
00208         if (Tcl_GetBignumFromObj(interp, varPtr[varIndex],
00209                 &bignumValue) != TCL_OK) {
00210             return TCL_ERROR;
00211         }
00212         if (mp_init(&newValue) != MP_OKAY
00213                 || (mp_mul_d(&bignumValue, 10, &newValue) != MP_OKAY)) {
00214             mp_clear(&bignumValue);
00215             mp_clear(&newValue);
00216             Tcl_SetObjResult(interp,
00217                     Tcl_NewStringObj("error in mp_mul_d", -1));
00218             return TCL_ERROR;
00219         }
00220         mp_clear(&bignumValue);
00221         if (!Tcl_IsShared(varPtr[varIndex])) {
00222             Tcl_SetBignumObj(varPtr[varIndex], &newValue);
00223         } else {
00224             SetVarToObj(varIndex, Tcl_NewBignumObj(&newValue));
00225         }
00226         break;
00227 
00228     case BIGNUM_DIV10:
00229         if (objc != 3) {
00230             Tcl_WrongNumArgs(interp, 2, objv, "varIndex");
00231             return TCL_ERROR;
00232         }
00233         if (CheckIfVarUnset(interp, varIndex)) {
00234             return TCL_ERROR;
00235         }
00236         if (Tcl_GetBignumFromObj(interp, varPtr[varIndex],
00237                 &bignumValue) != TCL_OK) {
00238             return TCL_ERROR;
00239         }
00240         if (mp_init(&newValue) != MP_OKAY
00241                 || (mp_div_d(&bignumValue, 10, &newValue, NULL) != MP_OKAY)) {
00242             mp_clear(&bignumValue);
00243             mp_clear(&newValue);
00244             Tcl_SetObjResult(interp,
00245                     Tcl_NewStringObj("error in mp_div_d", -1));
00246             return TCL_ERROR;
00247         }
00248         mp_clear(&bignumValue);
00249         if (!Tcl_IsShared(varPtr[varIndex])) {
00250             Tcl_SetBignumObj(varPtr[varIndex], &newValue);
00251         } else {
00252             SetVarToObj(varIndex, Tcl_NewBignumObj(&newValue));
00253         }
00254     }
00255 
00256     Tcl_SetObjResult(interp, varPtr[varIndex]);
00257     return TCL_OK;
00258 }
00259 
00260 /*
00261  *----------------------------------------------------------------------
00262  *
00263  * TestbooleanobjCmd --
00264  *
00265  *      This function implements the "testbooleanobj" command.  It is used to
00266  *      test the boolean Tcl object type implementation.
00267  *
00268  * Results:
00269  *      A standard Tcl object result.
00270  *
00271  * Side effects:
00272  *      Creates and frees boolean objects, and also converts objects to
00273  *      have boolean type.
00274  *
00275  *----------------------------------------------------------------------
00276  */
00277 
00278 static int
00279 TestbooleanobjCmd(
00280     ClientData clientData,      /* Not used. */
00281     Tcl_Interp *interp,         /* Current interpreter. */
00282     int objc,                   /* Number of arguments. */
00283     Tcl_Obj *const objv[])      /* Argument objects. */
00284 {
00285     int varIndex, boolValue;
00286     char *index, *subCmd;
00287 
00288     if (objc < 3) {
00289         wrongNumArgs:
00290         Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
00291         return TCL_ERROR;
00292     }
00293 
00294     index = Tcl_GetString(objv[2]);
00295     if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
00296         return TCL_ERROR;
00297     }
00298 
00299     subCmd = Tcl_GetString(objv[1]);
00300     if (strcmp(subCmd, "set") == 0) {
00301         if (objc != 4) {
00302             goto wrongNumArgs;
00303         }
00304         if (Tcl_GetBooleanFromObj(interp, objv[3], &boolValue) != TCL_OK) {
00305             return TCL_ERROR;
00306         }
00307 
00308         /*
00309          * If the object currently bound to the variable with index varIndex
00310          * has ref count 1 (i.e. the object is unshared) we can modify that
00311          * object directly. Otherwise, if RC>1 (i.e. the object is shared),
00312          * we must create a new object to modify/set and decrement the old
00313          * formerly-shared object's ref count. This is "copy on write".
00314          */
00315 
00316         if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
00317             Tcl_SetBooleanObj(varPtr[varIndex], boolValue);
00318         } else {
00319             SetVarToObj(varIndex, Tcl_NewBooleanObj(boolValue));
00320         }
00321         Tcl_SetObjResult(interp, varPtr[varIndex]);
00322     } else if (strcmp(subCmd, "get") == 0) {
00323         if (objc != 3) {
00324             goto wrongNumArgs;
00325         }
00326         if (CheckIfVarUnset(interp, varIndex)) {
00327             return TCL_ERROR;
00328         }
00329         Tcl_SetObjResult(interp, varPtr[varIndex]);
00330     } else if (strcmp(subCmd, "not") == 0) {
00331         if (objc != 3) {
00332             goto wrongNumArgs;
00333         }
00334         if (CheckIfVarUnset(interp, varIndex)) {
00335             return TCL_ERROR;
00336         }
00337         if (Tcl_GetBooleanFromObj(interp, varPtr[varIndex],
00338                                   &boolValue) != TCL_OK) {
00339             return TCL_ERROR;
00340         }
00341         if (!Tcl_IsShared(varPtr[varIndex])) {
00342             Tcl_SetBooleanObj(varPtr[varIndex], !boolValue);
00343         } else {
00344             SetVarToObj(varIndex, Tcl_NewBooleanObj(!boolValue));
00345         }
00346         Tcl_SetObjResult(interp, varPtr[varIndex]);
00347     } else {
00348         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
00349                 "bad option \"", Tcl_GetString(objv[1]),
00350                 "\": must be set, get, or not", NULL);
00351         return TCL_ERROR;
00352     }
00353     return TCL_OK;
00354 }
00355 
00356 /*
00357  *----------------------------------------------------------------------
00358  *
00359  * TestdoubleobjCmd --
00360  *
00361  *      This function implements the "testdoubleobj" command.  It is used to
00362  *      test the double-precision floating point Tcl object type
00363  *      implementation.
00364  *
00365  * Results:
00366  *      A standard Tcl object result.
00367  *
00368  * Side effects:
00369  *      Creates and frees double objects, and also converts objects to
00370  *      have double type.
00371  *
00372  *----------------------------------------------------------------------
00373  */
00374 
00375 static int
00376 TestdoubleobjCmd(
00377     ClientData clientData,      /* Not used. */
00378     Tcl_Interp *interp,         /* Current interpreter. */
00379     int objc,                   /* Number of arguments. */
00380     Tcl_Obj *const objv[])      /* Argument objects. */
00381 {
00382     int varIndex;
00383     double doubleValue;
00384     char *index, *subCmd, *string;
00385 
00386     if (objc < 3) {
00387         wrongNumArgs:
00388         Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
00389         return TCL_ERROR;
00390     }
00391 
00392     index = Tcl_GetString(objv[2]);
00393     if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
00394         return TCL_ERROR;
00395     }
00396 
00397     subCmd = Tcl_GetString(objv[1]);
00398     if (strcmp(subCmd, "set") == 0) {
00399         if (objc != 4) {
00400             goto wrongNumArgs;
00401         }
00402         string = Tcl_GetString(objv[3]);
00403         if (Tcl_GetDouble(interp, string, &doubleValue) != TCL_OK) {
00404             return TCL_ERROR;
00405         }
00406 
00407         /*
00408          * If the object currently bound to the variable with index varIndex
00409          * has ref count 1 (i.e. the object is unshared) we can modify that
00410          * object directly. Otherwise, if RC>1 (i.e. the object is shared), we
00411          * must create a new object to modify/set and decrement the old
00412          * formerly-shared object's ref count. This is "copy on write".
00413          */
00414 
00415         if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
00416             Tcl_SetDoubleObj(varPtr[varIndex], doubleValue);
00417         } else {
00418             SetVarToObj(varIndex, Tcl_NewDoubleObj(doubleValue));
00419         }
00420         Tcl_SetObjResult(interp, varPtr[varIndex]);
00421     } else if (strcmp(subCmd, "get") == 0) {
00422         if (objc != 3) {
00423             goto wrongNumArgs;
00424         }
00425         if (CheckIfVarUnset(interp, varIndex)) {
00426             return TCL_ERROR;
00427         }
00428         Tcl_SetObjResult(interp, varPtr[varIndex]);
00429     } else if (strcmp(subCmd, "mult10") == 0) {
00430         if (objc != 3) {
00431             goto wrongNumArgs;
00432         }
00433         if (CheckIfVarUnset(interp, varIndex)) {
00434             return TCL_ERROR;
00435         }
00436         if (Tcl_GetDoubleFromObj(interp, varPtr[varIndex],
00437                                  &doubleValue) != TCL_OK) {
00438             return TCL_ERROR;
00439         }
00440         if (!Tcl_IsShared(varPtr[varIndex])) {
00441             Tcl_SetDoubleObj(varPtr[varIndex], (doubleValue * 10.0));
00442         } else {
00443             SetVarToObj(varIndex, Tcl_NewDoubleObj( (doubleValue * 10.0) ));
00444         }
00445         Tcl_SetObjResult(interp, varPtr[varIndex]);
00446     } else if (strcmp(subCmd, "div10") == 0) {
00447         if (objc != 3) {
00448             goto wrongNumArgs;
00449         }
00450         if (CheckIfVarUnset(interp, varIndex)) {
00451             return TCL_ERROR;
00452         }
00453         if (Tcl_GetDoubleFromObj(interp, varPtr[varIndex],
00454                                  &doubleValue) != TCL_OK) {
00455             return TCL_ERROR;
00456         }
00457         if (!Tcl_IsShared(varPtr[varIndex])) {
00458             Tcl_SetDoubleObj(varPtr[varIndex], (doubleValue / 10.0));
00459         } else {
00460             SetVarToObj(varIndex, Tcl_NewDoubleObj( (doubleValue / 10.0) ));
00461         }
00462         Tcl_SetObjResult(interp, varPtr[varIndex]);
00463     } else {
00464         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
00465                 "bad option \"", Tcl_GetString(objv[1]),
00466                 "\": must be set, get, mult10, or div10", NULL);
00467         return TCL_ERROR;
00468     }
00469     return TCL_OK;
00470 }
00471 
00472 /*
00473  *----------------------------------------------------------------------
00474  *
00475  * TestindexobjCmd --
00476  *
00477  *      This function implements the "testindexobj" command. It is used to
00478  *      test the index Tcl object type implementation.
00479  *
00480  * Results:
00481  *      A standard Tcl object result.
00482  *
00483  * Side effects:
00484  *      Creates and frees int objects, and also converts objects to
00485  *      have int type.
00486  *
00487  *----------------------------------------------------------------------
00488  */
00489 
00490 static int
00491 TestindexobjCmd(
00492     ClientData clientData,      /* Not used. */
00493     Tcl_Interp *interp,         /* Current interpreter. */
00494     int objc,                   /* Number of arguments. */
00495     Tcl_Obj *const objv[])      /* Argument objects. */
00496 {
00497     int allowAbbrev, index, index2, setError, i, result;
00498     const char **argv;
00499     static const char *tablePtr[] = {"a", "b", "check", NULL};
00500     /*
00501      * Keep this structure declaration in sync with tclIndexObj.c
00502      */
00503     struct IndexRep {
00504         VOID *tablePtr;                 /* Pointer to the table of strings */
00505         int offset;                     /* Offset between table entries */
00506         int index;                      /* Selected index into table. */
00507     };
00508     struct IndexRep *indexRep;
00509 
00510     if ((objc == 3) && (strcmp(Tcl_GetString(objv[1]),
00511             "check") == 0)) {
00512         /*
00513          * This code checks to be sure that the results of Tcl_GetIndexFromObj
00514          * are properly cached in the object and returned on subsequent
00515          * lookups.
00516          */
00517 
00518         if (Tcl_GetIntFromObj(interp, objv[2], &index2) != TCL_OK) {
00519             return TCL_ERROR;
00520         }
00521 
00522         Tcl_GetIndexFromObj(NULL, objv[1], tablePtr, "token", 0, &index);
00523         indexRep = (struct IndexRep *) objv[1]->internalRep.otherValuePtr;
00524         indexRep->index = index2;
00525         result = Tcl_GetIndexFromObj(NULL, objv[1],
00526                 tablePtr, "token", 0, &index);
00527         if (result == TCL_OK) {
00528             Tcl_SetIntObj(Tcl_GetObjResult(interp), index);
00529         }
00530         return result;
00531     }
00532 
00533     if (objc < 5) {
00534         Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args", -1);
00535         return TCL_ERROR;
00536     }
00537 
00538     if (Tcl_GetBooleanFromObj(interp, objv[1], &setError) != TCL_OK) {
00539         return TCL_ERROR;
00540     }
00541     if (Tcl_GetBooleanFromObj(interp, objv[2], &allowAbbrev) != TCL_OK) {
00542         return TCL_ERROR;
00543     }
00544 
00545     argv = (const char **) ckalloc((unsigned) ((objc-3) * sizeof(char *)));
00546     for (i = 4; i < objc; i++) {
00547         argv[i-4] = Tcl_GetString(objv[i]);
00548     }
00549     argv[objc-4] = NULL;
00550 
00551     /*
00552      * Tcl_GetIndexFromObj assumes that the table is statically-allocated so
00553      * that its address is different for each index object. If we accidently
00554      * allocate a table at the same address as that cached in the index
00555      * object, clear out the object's cached state.
00556      */
00557 
00558     if ( objv[3]->typePtr != NULL
00559          && !strcmp( "index", objv[3]->typePtr->name ) ) {
00560         indexRep = (struct IndexRep *) objv[3]->internalRep.otherValuePtr;
00561         if (indexRep->tablePtr == (VOID *) argv) {
00562             objv[3]->typePtr->freeIntRepProc(objv[3]);
00563             objv[3]->typePtr = NULL;
00564         }
00565     }
00566 
00567     result = Tcl_GetIndexFromObj((setError? interp : NULL), objv[3],
00568             argv, "token", (allowAbbrev? 0 : TCL_EXACT), &index);
00569     ckfree((char *) argv);
00570     if (result == TCL_OK) {
00571         Tcl_SetIntObj(Tcl_GetObjResult(interp), index);
00572     }
00573     return result;
00574 }
00575 
00576 /*
00577  *----------------------------------------------------------------------
00578  *
00579  * TestintobjCmd --
00580  *
00581  *      This function implements the "testintobj" command. It is used to
00582  *      test the int Tcl object type implementation.
00583  *
00584  * Results:
00585  *      A standard Tcl object result.
00586  *
00587  * Side effects:
00588  *      Creates and frees int objects, and also converts objects to
00589  *      have int type.
00590  *
00591  *----------------------------------------------------------------------
00592  */
00593 
00594 static int
00595 TestintobjCmd(
00596     ClientData clientData,      /* Not used. */
00597     Tcl_Interp *interp,         /* Current interpreter. */
00598     int objc,                   /* Number of arguments. */
00599     Tcl_Obj *const objv[])      /* Argument objects. */
00600 {
00601     int intValue, varIndex, i;
00602     long longValue;
00603     char *index, *subCmd, *string;
00604 
00605     if (objc < 3) {
00606         wrongNumArgs:
00607         Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
00608         return TCL_ERROR;
00609     }
00610 
00611     index = Tcl_GetString(objv[2]);
00612     if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
00613         return TCL_ERROR;
00614     }
00615 
00616     subCmd = Tcl_GetString(objv[1]);
00617     if (strcmp(subCmd, "set") == 0) {
00618         if (objc != 4) {
00619             goto wrongNumArgs;
00620         }
00621         string = Tcl_GetString(objv[3]);
00622         if (Tcl_GetInt(interp, string, &i) != TCL_OK) {
00623             return TCL_ERROR;
00624         }
00625         intValue = i;
00626 
00627         /*
00628          * If the object currently bound to the variable with index varIndex
00629          * has ref count 1 (i.e. the object is unshared) we can modify that
00630          * object directly. Otherwise, if RC>1 (i.e. the object is shared), we
00631          * must create a new object to modify/set and decrement the old
00632          * formerly-shared object's ref count. This is "copy on write".
00633          */
00634 
00635         if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
00636             Tcl_SetIntObj(varPtr[varIndex], intValue);
00637         } else {
00638             SetVarToObj(varIndex, Tcl_NewIntObj(intValue));
00639         }
00640         Tcl_SetObjResult(interp, varPtr[varIndex]);
00641     } else if (strcmp(subCmd, "set2") == 0) { /* doesn't set result */
00642         if (objc != 4) {
00643             goto wrongNumArgs;
00644         }
00645         string = Tcl_GetString(objv[3]);
00646         if (Tcl_GetInt(interp, string, &i) != TCL_OK) {
00647             return TCL_ERROR;
00648         }
00649         intValue = i;
00650         if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
00651             Tcl_SetIntObj(varPtr[varIndex], intValue);
00652         } else {
00653             SetVarToObj(varIndex, Tcl_NewIntObj(intValue));
00654         }
00655     } else if (strcmp(subCmd, "setlong") == 0) {
00656         if (objc != 4) {
00657             goto wrongNumArgs;
00658         }
00659         string = Tcl_GetString(objv[3]);
00660         if (Tcl_GetInt(interp, string, &i) != TCL_OK) {
00661             return TCL_ERROR;
00662         }
00663         intValue = i;
00664         if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
00665             Tcl_SetLongObj(varPtr[varIndex], intValue);
00666         } else {
00667             SetVarToObj(varIndex, Tcl_NewLongObj(intValue));
00668         }
00669         Tcl_SetObjResult(interp, varPtr[varIndex]);
00670     } else if (strcmp(subCmd, "setmaxlong") == 0) {
00671         long maxLong = LONG_MAX;
00672         if (objc != 3) {
00673             goto wrongNumArgs;
00674         }
00675         if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
00676             Tcl_SetLongObj(varPtr[varIndex], maxLong);
00677         } else {
00678             SetVarToObj(varIndex, Tcl_NewLongObj(maxLong));
00679         }
00680     } else if (strcmp(subCmd, "ismaxlong") == 0) {
00681         if (objc != 3) {
00682             goto wrongNumArgs;
00683         }
00684         if (CheckIfVarUnset(interp, varIndex)) {
00685             return TCL_ERROR;
00686         }
00687         if (Tcl_GetLongFromObj(interp, varPtr[varIndex], &longValue) != TCL_OK) {
00688             return TCL_ERROR;
00689         }
00690         Tcl_AppendToObj(Tcl_GetObjResult(interp),
00691                 ((longValue == LONG_MAX)? "1" : "0"), -1);
00692     } else if (strcmp(subCmd, "get") == 0) {
00693         if (objc != 3) {
00694             goto wrongNumArgs;
00695         }
00696         if (CheckIfVarUnset(interp, varIndex)) {
00697             return TCL_ERROR;
00698         }
00699         Tcl_SetObjResult(interp, varPtr[varIndex]);
00700     } else if (strcmp(subCmd, "get2") == 0) {
00701         if (objc != 3) {
00702             goto wrongNumArgs;
00703         }
00704         if (CheckIfVarUnset(interp, varIndex)) {
00705             return TCL_ERROR;
00706         }
00707         string = Tcl_GetString(varPtr[varIndex]);
00708         Tcl_AppendToObj(Tcl_GetObjResult(interp), string, -1);
00709     } else if (strcmp(subCmd, "inttoobigtest") == 0) {
00710         /*
00711          * If long ints have more bits than ints on this platform, verify that
00712          * Tcl_GetIntFromObj returns an error if the long int held in an
00713          * integer object's internal representation is too large to fit in an
00714          * int.
00715          */
00716 
00717         if (objc != 3) {
00718             goto wrongNumArgs;
00719         }
00720 #if (INT_MAX == LONG_MAX)   /* int is same size as long int */
00721         Tcl_AppendToObj(Tcl_GetObjResult(interp), "1", -1);
00722 #else
00723         if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
00724             Tcl_SetLongObj(varPtr[varIndex], LONG_MAX);
00725         } else {
00726             SetVarToObj(varIndex, Tcl_NewLongObj(LONG_MAX));
00727         }
00728         if (Tcl_GetIntFromObj(interp, varPtr[varIndex], &i) != TCL_OK) {
00729             Tcl_ResetResult(interp);
00730             Tcl_AppendToObj(Tcl_GetObjResult(interp), "1", -1);
00731             return TCL_OK;
00732         }
00733         Tcl_AppendToObj(Tcl_GetObjResult(interp), "0", -1);
00734 #endif
00735     } else if (strcmp(subCmd, "mult10") == 0) {
00736         if (objc != 3) {
00737             goto wrongNumArgs;
00738         }
00739         if (CheckIfVarUnset(interp, varIndex)) {
00740             return TCL_ERROR;
00741         }
00742         if (Tcl_GetIntFromObj(interp, varPtr[varIndex],
00743                               &intValue) != TCL_OK) {
00744             return TCL_ERROR;
00745         }
00746         if (!Tcl_IsShared(varPtr[varIndex])) {
00747             Tcl_SetIntObj(varPtr[varIndex], (intValue * 10));
00748         } else {
00749             SetVarToObj(varIndex, Tcl_NewIntObj( (intValue * 10) ));
00750         }
00751         Tcl_SetObjResult(interp, varPtr[varIndex]);
00752     } else if (strcmp(subCmd, "div10") == 0) {
00753         if (objc != 3) {
00754             goto wrongNumArgs;
00755         }
00756         if (CheckIfVarUnset(interp, varIndex)) {
00757             return TCL_ERROR;
00758         }
00759         if (Tcl_GetIntFromObj(interp, varPtr[varIndex],
00760                               &intValue) != TCL_OK) {
00761             return TCL_ERROR;
00762         }
00763         if (!Tcl_IsShared(varPtr[varIndex])) {
00764             Tcl_SetIntObj(varPtr[varIndex], (intValue / 10));
00765         } else {
00766             SetVarToObj(varIndex, Tcl_NewIntObj( (intValue / 10) ));
00767         }
00768         Tcl_SetObjResult(interp, varPtr[varIndex]);
00769     } else {
00770         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
00771                 "bad option \"", Tcl_GetString(objv[1]),
00772                 "\": must be set, get, get2, mult10, or div10", NULL);
00773         return TCL_ERROR;
00774     }
00775     return TCL_OK;
00776 }
00777 
00778 /*
00779  *----------------------------------------------------------------------
00780  *
00781  * TestobjCmd --
00782  *
00783  *      This function implements the "testobj" command. It is used to test
00784  *      the type-independent portions of the Tcl object type implementation.
00785  *
00786  * Results:
00787  *      A standard Tcl object result.
00788  *
00789  * Side effects:
00790  *      Creates and frees objects.
00791  *
00792  *----------------------------------------------------------------------
00793  */
00794 
00795 static int
00796 TestobjCmd(
00797     ClientData clientData,      /* Not used. */
00798     Tcl_Interp *interp,         /* Current interpreter. */
00799     int objc,                   /* Number of arguments. */
00800     Tcl_Obj *const objv[])      /* Argument objects. */
00801 {
00802     int varIndex, destIndex, i;
00803     char *index, *subCmd, *string;
00804     Tcl_ObjType *targetType;
00805 
00806     if (objc < 2) {
00807         wrongNumArgs:
00808         Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
00809         return TCL_ERROR;
00810     }
00811 
00812     subCmd = Tcl_GetString(objv[1]);
00813     if (strcmp(subCmd, "assign") == 0) {
00814         if (objc != 4) {
00815             goto wrongNumArgs;
00816         }
00817         index = Tcl_GetString(objv[2]);
00818         if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
00819             return TCL_ERROR;
00820         }
00821         if (CheckIfVarUnset(interp, varIndex)) {
00822             return TCL_ERROR;
00823         }
00824         string = Tcl_GetString(objv[3]);
00825         if (GetVariableIndex(interp, string, &destIndex) != TCL_OK) {
00826             return TCL_ERROR;
00827         }
00828         SetVarToObj(destIndex, varPtr[varIndex]);
00829         Tcl_SetObjResult(interp, varPtr[destIndex]);
00830      } else if (strcmp(subCmd, "convert") == 0) {
00831         char *typeName;
00832         if (objc != 4) {
00833             goto wrongNumArgs;
00834         }
00835         index = Tcl_GetString(objv[2]);
00836         if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
00837             return TCL_ERROR;
00838         }
00839         if (CheckIfVarUnset(interp, varIndex)) {
00840             return TCL_ERROR;
00841         }
00842         typeName = Tcl_GetString(objv[3]);
00843         if ((targetType = Tcl_GetObjType(typeName)) == NULL) {
00844             Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
00845                     "no type ", typeName, " found", NULL);
00846             return TCL_ERROR;
00847         }
00848         if (Tcl_ConvertToType(interp, varPtr[varIndex], targetType)
00849             != TCL_OK) {
00850             return TCL_ERROR;
00851         }
00852         Tcl_SetObjResult(interp, varPtr[varIndex]);
00853     } else if (strcmp(subCmd, "duplicate") == 0) {
00854         if (objc != 4) {
00855             goto wrongNumArgs;
00856         }
00857         index = Tcl_GetString(objv[2]);
00858         if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
00859             return TCL_ERROR;
00860         }
00861         if (CheckIfVarUnset(interp, varIndex)) {
00862             return TCL_ERROR;
00863         }
00864         string = Tcl_GetString(objv[3]);
00865         if (GetVariableIndex(interp, string, &destIndex) != TCL_OK) {
00866             return TCL_ERROR;
00867         }
00868         SetVarToObj(destIndex, Tcl_DuplicateObj(varPtr[varIndex]));
00869         Tcl_SetObjResult(interp, varPtr[destIndex]);
00870     } else if (strcmp(subCmd, "freeallvars") == 0) {
00871         if (objc != 2) {
00872             goto wrongNumArgs;
00873         }
00874         for (i = 0;  i < NUMBER_OF_OBJECT_VARS;  i++) {
00875             if (varPtr[i] != NULL) {
00876                 Tcl_DecrRefCount(varPtr[i]);
00877                 varPtr[i] = NULL;
00878             }
00879         }
00880     } else if ( strcmp ( subCmd, "invalidateStringRep" ) == 0 ) {
00881         if ( objc != 3 ) {
00882             goto wrongNumArgs;
00883         }
00884         index = Tcl_GetString( objv[2] );
00885         if ( GetVariableIndex( interp, index, &varIndex ) != TCL_OK ) {
00886             return TCL_ERROR;
00887         }
00888         if (CheckIfVarUnset(interp, varIndex)) {
00889             return TCL_ERROR;
00890         }
00891         Tcl_InvalidateStringRep( varPtr[varIndex] );
00892         Tcl_SetObjResult( interp, varPtr[varIndex] );
00893     } else if (strcmp(subCmd, "newobj") == 0) {
00894         if (objc != 3) {
00895             goto wrongNumArgs;
00896         }
00897         index = Tcl_GetString(objv[2]);
00898         if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
00899             return TCL_ERROR;
00900         }
00901         SetVarToObj(varIndex, Tcl_NewObj());
00902         Tcl_SetObjResult(interp, varPtr[varIndex]);
00903     } else if (strcmp(subCmd, "objtype") == 0) {
00904         const char *typeName;
00905 
00906         /*
00907          * return an object containing the name of the argument's type
00908          * of internal rep.  If none exists, return "none".
00909          */
00910 
00911         if (objc != 3) {
00912             goto wrongNumArgs;
00913         }
00914         if (objv[2]->typePtr == NULL) {
00915             Tcl_SetObjResult(interp, Tcl_NewStringObj("none", -1));
00916         } else {
00917             typeName = objv[2]->typePtr->name;
00918             Tcl_SetObjResult(interp, Tcl_NewStringObj(typeName, -1));
00919         }
00920     } else if (strcmp(subCmd, "refcount") == 0) {
00921         char buf[TCL_INTEGER_SPACE];
00922 
00923         if (objc != 3) {
00924             goto wrongNumArgs;
00925         }
00926         index = Tcl_GetString(objv[2]);
00927         if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
00928             return TCL_ERROR;
00929         }
00930         if (CheckIfVarUnset(interp, varIndex)) {
00931             return TCL_ERROR;
00932         }
00933         TclFormatInt(buf, varPtr[varIndex]->refCount);
00934         Tcl_SetResult(interp, buf, TCL_VOLATILE);
00935     } else if (strcmp(subCmd, "type") == 0) {
00936         if (objc != 3) {
00937             goto wrongNumArgs;
00938         }
00939         index = Tcl_GetString(objv[2]);
00940         if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
00941             return TCL_ERROR;
00942         }
00943         if (CheckIfVarUnset(interp, varIndex)) {
00944             return TCL_ERROR;
00945         }
00946         if (varPtr[varIndex]->typePtr == NULL) { /* a string! */
00947             Tcl_AppendToObj(Tcl_GetObjResult(interp), "string", -1);
00948         } else {
00949             Tcl_AppendToObj(Tcl_GetObjResult(interp),
00950                     varPtr[varIndex]->typePtr->name, -1);
00951         }
00952     } else if (strcmp(subCmd, "types") == 0) {
00953         if (objc != 2) {
00954             goto wrongNumArgs;
00955         }
00956         if (Tcl_AppendAllObjTypes(interp,
00957                 Tcl_GetObjResult(interp)) != TCL_OK) {
00958             return TCL_ERROR;
00959         }
00960     } else {
00961         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
00962                 "bad option \"", Tcl_GetString(objv[1]),
00963                 "\": must be assign, convert, duplicate, freeallvars, "
00964                 "newobj, objcount, objtype, refcount, type, or types", NULL);
00965         return TCL_ERROR;
00966     }
00967     return TCL_OK;
00968 }
00969 
00970 /*
00971  *----------------------------------------------------------------------
00972  *
00973  * TeststringobjCmd --
00974  *
00975  *      This function implements the "teststringobj" command. It is used to
00976  *      test the string Tcl object type implementation.
00977  *
00978  * Results:
00979  *      A standard Tcl object result.
00980  *
00981  * Side effects:
00982  *      Creates and frees string objects, and also converts objects to
00983  *      have string type.
00984  *
00985  *----------------------------------------------------------------------
00986  */
00987 
00988 static int
00989 TeststringobjCmd(
00990     ClientData clientData,      /* Not used. */
00991     Tcl_Interp *interp,         /* Current interpreter. */
00992     int objc,                   /* Number of arguments. */
00993     Tcl_Obj *const objv[])      /* Argument objects. */
00994 {
00995     int varIndex, option, i, length;
00996 #define MAX_STRINGS 11
00997     char *index, *string, *strings[MAX_STRINGS+1];
00998     TestString *strPtr;
00999     static const char *options[] = {
01000         "append", "appendstrings", "get", "get2", "length", "length2",
01001         "set", "set2", "setlength", "ualloc", "getunicode", NULL
01002     };
01003 
01004     if (objc < 3) {
01005         wrongNumArgs:
01006         Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
01007         return TCL_ERROR;
01008     }
01009 
01010     index = Tcl_GetString(objv[2]);
01011     if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
01012         return TCL_ERROR;
01013     }
01014 
01015     if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, &option)
01016             != TCL_OK) {
01017         return TCL_ERROR;
01018     }
01019     switch (option) {
01020         case 0:                         /* append */
01021             if (objc != 5) {
01022                 goto wrongNumArgs;
01023             }
01024             if (Tcl_GetIntFromObj(interp, objv[4], &length) != TCL_OK) {
01025                 return TCL_ERROR;
01026             }
01027             if (varPtr[varIndex] == NULL) {
01028                 SetVarToObj(varIndex, Tcl_NewObj());
01029             }
01030 
01031             /*
01032              * If the object bound to variable "varIndex" is shared, we must
01033              * "copy on write" and append to a copy of the object.
01034              */
01035 
01036             if (Tcl_IsShared(varPtr[varIndex])) {
01037                 SetVarToObj(varIndex, Tcl_DuplicateObj(varPtr[varIndex]));
01038             }
01039             string = Tcl_GetString(objv[3]);
01040             Tcl_AppendToObj(varPtr[varIndex], string, length);
01041             Tcl_SetObjResult(interp, varPtr[varIndex]);
01042             break;
01043         case 1:                         /* appendstrings */
01044             if (objc > (MAX_STRINGS+3)) {
01045                 goto wrongNumArgs;
01046             }
01047             if (varPtr[varIndex] == NULL) {
01048                 SetVarToObj(varIndex, Tcl_NewObj());
01049             }
01050 
01051             /*
01052              * If the object bound to variable "varIndex" is shared, we must
01053              * "copy on write" and append to a copy of the object.
01054              */
01055 
01056             if (Tcl_IsShared(varPtr[varIndex])) {
01057                 SetVarToObj(varIndex, Tcl_DuplicateObj(varPtr[varIndex]));
01058             }
01059             for (i = 3;  i < objc;  i++) {
01060                 strings[i-3] = Tcl_GetString(objv[i]);
01061             }
01062             for ( ; i < 12 + 3; i++) {
01063                 strings[i - 3] = NULL;
01064             }
01065             Tcl_AppendStringsToObj(varPtr[varIndex], strings[0], strings[1],
01066                     strings[2], strings[3], strings[4], strings[5],
01067                     strings[6], strings[7], strings[8], strings[9],
01068                     strings[10], strings[11]);
01069             Tcl_SetObjResult(interp, varPtr[varIndex]);
01070             break;
01071         case 2:                         /* get */
01072             if (objc != 3) {
01073                 goto wrongNumArgs;
01074             }
01075             if (CheckIfVarUnset(interp, varIndex)) {
01076                 return TCL_ERROR;
01077             }
01078             Tcl_SetObjResult(interp, varPtr[varIndex]);
01079             break;
01080         case 3:                         /* get2 */
01081             if (objc != 3) {
01082                 goto wrongNumArgs;
01083             }
01084             if (CheckIfVarUnset(interp, varIndex)) {
01085                 return TCL_ERROR;
01086             }
01087             string = Tcl_GetString(varPtr[varIndex]);
01088             Tcl_AppendToObj(Tcl_GetObjResult(interp), string, -1);
01089             break;
01090         case 4:                         /* length */
01091             if (objc != 3) {
01092                 goto wrongNumArgs;
01093             }
01094             Tcl_SetIntObj(Tcl_GetObjResult(interp), (varPtr[varIndex] != NULL)
01095                     ? varPtr[varIndex]->length : -1);
01096             break;
01097         case 5:                         /* length2 */
01098             if (objc != 3) {
01099                 goto wrongNumArgs;
01100             }
01101             if (varPtr[varIndex] != NULL) {
01102                 strPtr = (TestString *)
01103                     (varPtr[varIndex])->internalRep.otherValuePtr;
01104                 length = (int) strPtr->allocated;
01105             } else {
01106                 length = -1;
01107             }
01108             Tcl_SetIntObj(Tcl_GetObjResult(interp), length);
01109             break;
01110         case 6:                         /* set */
01111             if (objc != 4) {
01112                 goto wrongNumArgs;
01113             }
01114 
01115             /*
01116              * If the object currently bound to the variable with index
01117              * varIndex has ref count 1 (i.e. the object is unshared) we can
01118              * modify that object directly. Otherwise, if RC>1 (i.e. the
01119              * object is shared), we must create a new object to modify/set
01120              * and decrement the old formerly-shared object's ref count. This
01121              * is "copy on write".
01122              */
01123 
01124             string = Tcl_GetStringFromObj(objv[3], &length);
01125             if ((varPtr[varIndex] != NULL)
01126                     && !Tcl_IsShared(varPtr[varIndex])) {
01127                 Tcl_SetStringObj(varPtr[varIndex], string, length);
01128             } else {
01129                 SetVarToObj(varIndex, Tcl_NewStringObj(string, length));
01130             }
01131             Tcl_SetObjResult(interp, varPtr[varIndex]);
01132             break;
01133         case 7:                         /* set2 */
01134             if (objc != 4) {
01135                 goto wrongNumArgs;
01136             }
01137             SetVarToObj(varIndex, objv[3]);
01138             break;
01139         case 8:                         /* setlength */
01140             if (objc != 4) {
01141                 goto wrongNumArgs;
01142             }
01143             if (Tcl_GetIntFromObj(interp, objv[3], &length) != TCL_OK) {
01144                 return TCL_ERROR;
01145             }
01146             if (varPtr[varIndex] != NULL) {
01147                 Tcl_SetObjLength(varPtr[varIndex], length);
01148             }
01149             break;
01150         case 9:                         /* ualloc */
01151             if (objc != 3) {
01152                 goto wrongNumArgs;
01153             }
01154             if (varPtr[varIndex] != NULL) {
01155                 strPtr = (TestString *)
01156                     (varPtr[varIndex])->internalRep.otherValuePtr;
01157                 length = (int) strPtr->uallocated;
01158             } else {
01159                 length = -1;
01160             }
01161             Tcl_SetIntObj(Tcl_GetObjResult(interp), length);
01162             break;
01163         case 10:                        /* getunicode */
01164             if (objc != 3) {
01165                 goto wrongNumArgs;
01166             }
01167             Tcl_GetUnicodeFromObj(varPtr[varIndex], NULL);
01168             break;
01169     }
01170 
01171     return TCL_OK;
01172 }
01173 
01174 /*
01175  *----------------------------------------------------------------------
01176  *
01177  * SetVarToObj --
01178  *
01179  *      Utility routine to assign a Tcl_Obj* to a test variable. The
01180  *      Tcl_Obj* can be NULL.
01181  *
01182  * Results:
01183  *      None.
01184  *
01185  * Side effects:
01186  *      This routine handles ref counting details for assignment: i.e. the old
01187  *      value's ref count must be decremented (if not NULL) and the new one
01188  *      incremented (also if not NULL).
01189  *
01190  *----------------------------------------------------------------------
01191  */
01192 
01193 static void
01194 SetVarToObj(
01195     int varIndex,               /* Designates the assignment variable. */
01196     Tcl_Obj *objPtr)            /* Points to object to assign to var. */
01197 {
01198     if (varPtr[varIndex] != NULL) {
01199         Tcl_DecrRefCount(varPtr[varIndex]);
01200     }
01201     varPtr[varIndex] = objPtr;
01202     if (objPtr != NULL) {
01203         Tcl_IncrRefCount(objPtr);
01204     }
01205 }
01206 
01207 /*
01208  *----------------------------------------------------------------------
01209  *
01210  * GetVariableIndex --
01211  *
01212  *      Utility routine to get a test variable index from the command line.
01213  *
01214  * Results:
01215  *      A standard Tcl object result.
01216  *
01217  * Side effects:
01218  *      None.
01219  *
01220  *----------------------------------------------------------------------
01221  */
01222 
01223 static int
01224 GetVariableIndex(
01225     Tcl_Interp *interp,         /* Interpreter for error reporting. */
01226     char *string,               /* String containing a variable index
01227                                  * specified as a nonnegative number less than
01228                                  * NUMBER_OF_OBJECT_VARS. */
01229     int *indexPtr)              /* Place to store converted result. */
01230 {
01231     int index;
01232 
01233     if (Tcl_GetInt(interp, string, &index) != TCL_OK) {
01234         return TCL_ERROR;
01235     }
01236     if (index < 0 || index >= NUMBER_OF_OBJECT_VARS) {
01237         Tcl_ResetResult(interp);
01238         Tcl_AppendToObj(Tcl_GetObjResult(interp), "bad variable index", -1);
01239         return TCL_ERROR;
01240     }
01241 
01242     *indexPtr = index;
01243     return TCL_OK;
01244 }
01245 
01246 /*
01247  *----------------------------------------------------------------------
01248  *
01249  * CheckIfVarUnset --
01250  *
01251  *      Utility function that checks whether a test variable is readable:
01252  *      i.e., that varPtr[varIndex] is non-NULL.
01253  *
01254  * Results:
01255  *      1 if the test variable is unset (NULL); 0 otherwise.
01256  *
01257  * Side effects:
01258  *      Sets the interpreter result to an error message if the variable is
01259  *      unset (NULL).
01260  *
01261  *----------------------------------------------------------------------
01262  */
01263 
01264 static int
01265 CheckIfVarUnset(
01266     Tcl_Interp *interp,         /* Interpreter for error reporting. */
01267     int varIndex)               /* Index of the test variable to check. */
01268 {
01269     if (varPtr[varIndex] == NULL) {
01270         char buf[32 + TCL_INTEGER_SPACE];
01271 
01272         sprintf(buf, "variable %d is unset (NULL)", varIndex);
01273         Tcl_ResetResult(interp);
01274         Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1);
01275         return 1;
01276     }
01277     return 0;
01278 }
01279 
01280 /*
01281  * Local Variables:
01282  * mode: c
01283  * c-basic-offset: 4
01284  * fill-column: 78
01285  * End:
01286  */



Generated on Wed Mar 12 12:18:22 2008 by  doxygen 1.5.1