tclTestObj.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:34k
源码类别:

通讯编程

开发平台:

Visual C++

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