os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclTestObj.c
First public contribution.
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.
9 * Copyright (c) 1995-1998 Sun Microsystems, Inc.
10 * Copyright (c) 1999 by Scriptics Corporation.
12 * See the file "license.terms" for information on usage and redistribution
13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15 * RCS: @(#) $Id: tclTestObj.c,v 1.12 2002/12/04 13:09:24 vincentdarley Exp $
21 * An array of Tcl_Obj pointers used in the commands that operate on or get
22 * the values of Tcl object-valued variables. varPtr[i] is the i-th
23 * variable's Tcl_Obj *.
26 #define NUMBER_OF_OBJECT_VARS 20
27 static Tcl_Obj *varPtr[NUMBER_OF_OBJECT_VARS];
30 * Forward declarations for procedures defined later in this file:
33 static int CheckIfVarUnset _ANSI_ARGS_((Tcl_Interp *interp,
35 static int GetVariableIndex _ANSI_ARGS_((Tcl_Interp *interp,
36 char *string, int *indexPtr));
37 static void SetVarToObj _ANSI_ARGS_((int varIndex,
39 int TclObjTest_Init _ANSI_ARGS_((Tcl_Interp *interp));
40 static int TestbooleanobjCmd _ANSI_ARGS_((ClientData dummy,
41 Tcl_Interp *interp, int objc,
42 Tcl_Obj *CONST objv[]));
43 static int TestconvertobjCmd _ANSI_ARGS_((ClientData dummy,
44 Tcl_Interp *interp, int objc,
45 Tcl_Obj *CONST objv[]));
46 static int TestdoubleobjCmd _ANSI_ARGS_((ClientData dummy,
47 Tcl_Interp *interp, int objc,
48 Tcl_Obj *CONST objv[]));
49 static int TestindexobjCmd _ANSI_ARGS_((ClientData dummy,
50 Tcl_Interp *interp, int objc,
51 Tcl_Obj *CONST objv[]));
52 static int TestintobjCmd _ANSI_ARGS_((ClientData dummy,
53 Tcl_Interp *interp, int objc,
54 Tcl_Obj *CONST objv[]));
55 static int TestobjCmd _ANSI_ARGS_((ClientData dummy,
56 Tcl_Interp *interp, int objc,
57 Tcl_Obj *CONST objv[]));
58 static int TeststringobjCmd _ANSI_ARGS_((ClientData dummy,
59 Tcl_Interp *interp, int objc,
60 Tcl_Obj *CONST objv[]));
62 typedef struct TestString {
66 Tcl_UniChar unicode[2];
71 *----------------------------------------------------------------------
75 * This procedure creates additional commands that are used to test the
79 * Returns a standard Tcl completion code, and leaves an error
80 * message in the interp's result if an error occurs.
83 * Creates and registers several new testing commands.
85 *----------------------------------------------------------------------
89 TclObjTest_Init(interp)
94 for (i = 0; i < NUMBER_OF_OBJECT_VARS; i++) {
98 Tcl_CreateObjCommand(interp, "testbooleanobj", TestbooleanobjCmd,
99 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
100 Tcl_CreateObjCommand(interp, "testconvertobj", TestconvertobjCmd,
101 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
102 Tcl_CreateObjCommand(interp, "testdoubleobj", TestdoubleobjCmd,
103 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
104 Tcl_CreateObjCommand(interp, "testintobj", TestintobjCmd,
105 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
106 Tcl_CreateObjCommand(interp, "testindexobj", TestindexobjCmd,
107 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
108 Tcl_CreateObjCommand(interp, "testobj", TestobjCmd,
109 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
110 Tcl_CreateObjCommand(interp, "teststringobj", TeststringobjCmd,
111 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
116 *----------------------------------------------------------------------
118 * TestbooleanobjCmd --
120 * This procedure implements the "testbooleanobj" command. It is used
121 * to test the boolean Tcl object type implementation.
124 * A standard Tcl object result.
127 * Creates and frees boolean objects, and also converts objects to
130 *----------------------------------------------------------------------
134 TestbooleanobjCmd(clientData, interp, objc, objv)
135 ClientData clientData; /* Not used. */
136 Tcl_Interp *interp; /* Current interpreter. */
137 int objc; /* Number of arguments. */
138 Tcl_Obj *CONST objv[]; /* Argument objects. */
140 int varIndex, boolValue;
141 char *index, *subCmd;
145 Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
149 index = Tcl_GetString(objv[2]);
150 if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
154 subCmd = Tcl_GetString(objv[1]);
155 if (strcmp(subCmd, "set") == 0) {
159 if (Tcl_GetBooleanFromObj(interp, objv[3], &boolValue) != TCL_OK) {
164 * If the object currently bound to the variable with index varIndex
165 * has ref count 1 (i.e. the object is unshared) we can modify that
166 * object directly. Otherwise, if RC>1 (i.e. the object is shared),
167 * we must create a new object to modify/set and decrement the old
168 * formerly-shared object's ref count. This is "copy on write".
171 if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
172 Tcl_SetBooleanObj(varPtr[varIndex], boolValue);
174 SetVarToObj(varIndex, Tcl_NewBooleanObj(boolValue));
176 Tcl_SetObjResult(interp, varPtr[varIndex]);
177 } else if (strcmp(subCmd, "get") == 0) {
181 if (CheckIfVarUnset(interp, varIndex)) {
184 Tcl_SetObjResult(interp, varPtr[varIndex]);
185 } else if (strcmp(subCmd, "not") == 0) {
189 if (CheckIfVarUnset(interp, varIndex)) {
192 if (Tcl_GetBooleanFromObj(interp, varPtr[varIndex],
193 &boolValue) != TCL_OK) {
196 if (!Tcl_IsShared(varPtr[varIndex])) {
197 Tcl_SetBooleanObj(varPtr[varIndex], !boolValue);
199 SetVarToObj(varIndex, Tcl_NewBooleanObj(!boolValue));
201 Tcl_SetObjResult(interp, varPtr[varIndex]);
203 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
204 "bad option \"", Tcl_GetString(objv[1]),
205 "\": must be set, get, or not", (char *) NULL);
212 *----------------------------------------------------------------------
214 * TestconvertobjCmd --
216 * This procedure implements the "testconvertobj" command. It is used
217 * to test converting objects to new types.
220 * A standard Tcl object result.
223 * Converts objects to new types.
225 *----------------------------------------------------------------------
229 TestconvertobjCmd(clientData, interp, objc, objv)
230 ClientData clientData; /* Not used. */
231 Tcl_Interp *interp; /* Current interpreter. */
232 int objc; /* Number of arguments. */
233 Tcl_Obj *CONST objv[]; /* Argument objects. */
240 Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
244 subCmd = Tcl_GetString(objv[1]);
245 if (strcmp(subCmd, "double") == 0) {
251 if (Tcl_GetDoubleFromObj(interp, objv[2], &d) != TCL_OK) {
254 sprintf(buf, "%f", d);
255 Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1);
257 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
258 "bad option \"", Tcl_GetString(objv[1]),
259 "\": must be double", (char *) NULL);
266 *----------------------------------------------------------------------
268 * TestdoubleobjCmd --
270 * This procedure implements the "testdoubleobj" command. It is used
271 * to test the double-precision floating point Tcl object type
275 * A standard Tcl object result.
278 * Creates and frees double objects, and also converts objects to
281 *----------------------------------------------------------------------
285 TestdoubleobjCmd(clientData, interp, objc, objv)
286 ClientData clientData; /* Not used. */
287 Tcl_Interp *interp; /* Current interpreter. */
288 int objc; /* Number of arguments. */
289 Tcl_Obj *CONST objv[]; /* Argument objects. */
293 char *index, *subCmd, *string;
297 Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
301 index = Tcl_GetString(objv[2]);
302 if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
306 subCmd = Tcl_GetString(objv[1]);
307 if (strcmp(subCmd, "set") == 0) {
311 string = Tcl_GetString(objv[3]);
312 if (Tcl_GetDouble(interp, string, &doubleValue) != TCL_OK) {
317 * If the object currently bound to the variable with index varIndex
318 * has ref count 1 (i.e. the object is unshared) we can modify that
319 * object directly. Otherwise, if RC>1 (i.e. the object is shared),
320 * we must create a new object to modify/set and decrement the old
321 * formerly-shared object's ref count. This is "copy on write".
324 if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
325 Tcl_SetDoubleObj(varPtr[varIndex], doubleValue);
327 SetVarToObj(varIndex, Tcl_NewDoubleObj(doubleValue));
329 Tcl_SetObjResult(interp, varPtr[varIndex]);
330 } else if (strcmp(subCmd, "get") == 0) {
334 if (CheckIfVarUnset(interp, varIndex)) {
337 Tcl_SetObjResult(interp, varPtr[varIndex]);
338 } else if (strcmp(subCmd, "mult10") == 0) {
342 if (CheckIfVarUnset(interp, varIndex)) {
345 if (Tcl_GetDoubleFromObj(interp, varPtr[varIndex],
346 &doubleValue) != TCL_OK) {
349 if (!Tcl_IsShared(varPtr[varIndex])) {
350 Tcl_SetDoubleObj(varPtr[varIndex], (doubleValue * 10.0));
352 SetVarToObj(varIndex, Tcl_NewDoubleObj( (doubleValue * 10.0) ));
354 Tcl_SetObjResult(interp, varPtr[varIndex]);
355 } else if (strcmp(subCmd, "div10") == 0) {
359 if (CheckIfVarUnset(interp, varIndex)) {
362 if (Tcl_GetDoubleFromObj(interp, varPtr[varIndex],
363 &doubleValue) != TCL_OK) {
366 if (!Tcl_IsShared(varPtr[varIndex])) {
367 Tcl_SetDoubleObj(varPtr[varIndex], (doubleValue / 10.0));
369 SetVarToObj(varIndex, Tcl_NewDoubleObj( (doubleValue / 10.0) ));
371 Tcl_SetObjResult(interp, varPtr[varIndex]);
373 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
374 "bad option \"", Tcl_GetString(objv[1]),
375 "\": must be set, get, mult10, or div10", (char *) NULL);
382 *----------------------------------------------------------------------
386 * This procedure implements the "testindexobj" command. It is used to
387 * test the index Tcl object type implementation.
390 * A standard Tcl object result.
393 * Creates and frees int objects, and also converts objects to
396 *----------------------------------------------------------------------
400 TestindexobjCmd(clientData, interp, objc, objv)
401 ClientData clientData; /* Not used. */
402 Tcl_Interp *interp; /* Current interpreter. */
403 int objc; /* Number of arguments. */
404 Tcl_Obj *CONST objv[]; /* Argument objects. */
406 int allowAbbrev, index, index2, setError, i, result;
408 static CONST char *tablePtr[] = {"a", "b", "check", (char *) NULL};
410 * Keep this structure declaration in sync with tclIndexObj.c
413 VOID *tablePtr; /* Pointer to the table of strings */
414 int offset; /* Offset between table entries */
415 int index; /* Selected index into table. */
417 struct IndexRep *indexRep;
419 if ((objc == 3) && (strcmp(Tcl_GetString(objv[1]),
422 * This code checks to be sure that the results of
423 * Tcl_GetIndexFromObj are properly cached in the object and
424 * returned on subsequent lookups.
427 if (Tcl_GetIntFromObj(interp, objv[2], &index2) != TCL_OK) {
431 Tcl_GetIndexFromObj((Tcl_Interp *) NULL, objv[1], tablePtr,
433 indexRep = (struct IndexRep *) objv[1]->internalRep.otherValuePtr;
434 indexRep->index = index2;
435 result = Tcl_GetIndexFromObj((Tcl_Interp *) NULL, objv[1],
436 tablePtr, "token", 0, &index);
437 if (result == TCL_OK) {
438 Tcl_SetIntObj(Tcl_GetObjResult(interp), index);
444 Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args", -1);
448 if (Tcl_GetBooleanFromObj(interp, objv[1], &setError) != TCL_OK) {
451 if (Tcl_GetBooleanFromObj(interp, objv[2], &allowAbbrev) != TCL_OK) {
455 argv = (CONST char **) ckalloc((unsigned) ((objc-3) * sizeof(char *)));
456 for (i = 4; i < objc; i++) {
457 argv[i-4] = Tcl_GetString(objv[i]);
462 * Tcl_GetIndexFromObj assumes that the table is statically-allocated
463 * so that its address is different for each index object. If we
464 * accidently allocate a table at the same address as that cached in
465 * the index object, clear out the object's cached state.
468 if ( objv[3]->typePtr != NULL
469 && !strcmp( "index", objv[3]->typePtr->name ) ) {
470 indexRep = (struct IndexRep *) objv[3]->internalRep.otherValuePtr;
471 if (indexRep->tablePtr == (VOID *) argv) {
472 objv[3]->typePtr->freeIntRepProc(objv[3]);
473 objv[3]->typePtr = NULL;
477 result = Tcl_GetIndexFromObj((setError? interp : NULL), objv[3],
478 argv, "token", (allowAbbrev? 0 : TCL_EXACT), &index);
479 ckfree((char *) argv);
480 if (result == TCL_OK) {
481 Tcl_SetIntObj(Tcl_GetObjResult(interp), index);
487 *----------------------------------------------------------------------
491 * This procedure implements the "testintobj" command. It is used to
492 * test the int Tcl object type implementation.
495 * A standard Tcl object result.
498 * Creates and frees int objects, and also converts objects to
501 *----------------------------------------------------------------------
505 TestintobjCmd(clientData, interp, objc, objv)
506 ClientData clientData; /* Not used. */
507 Tcl_Interp *interp; /* Current interpreter. */
508 int objc; /* Number of arguments. */
509 Tcl_Obj *CONST objv[]; /* Argument objects. */
511 int intValue, varIndex, i;
513 char *index, *subCmd, *string;
517 Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
521 index = Tcl_GetString(objv[2]);
522 if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
526 subCmd = Tcl_GetString(objv[1]);
527 if (strcmp(subCmd, "set") == 0) {
531 string = Tcl_GetString(objv[3]);
532 if (Tcl_GetInt(interp, string, &i) != TCL_OK) {
538 * If the object currently bound to the variable with index varIndex
539 * has ref count 1 (i.e. the object is unshared) we can modify that
540 * object directly. Otherwise, if RC>1 (i.e. the object is shared),
541 * we must create a new object to modify/set and decrement the old
542 * formerly-shared object's ref count. This is "copy on write".
545 if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
546 Tcl_SetIntObj(varPtr[varIndex], intValue);
548 SetVarToObj(varIndex, Tcl_NewIntObj(intValue));
550 Tcl_SetObjResult(interp, varPtr[varIndex]);
551 } else if (strcmp(subCmd, "set2") == 0) { /* doesn't set result */
555 string = Tcl_GetString(objv[3]);
556 if (Tcl_GetInt(interp, string, &i) != TCL_OK) {
560 if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
561 Tcl_SetIntObj(varPtr[varIndex], intValue);
563 SetVarToObj(varIndex, Tcl_NewIntObj(intValue));
565 } else if (strcmp(subCmd, "setlong") == 0) {
569 string = Tcl_GetString(objv[3]);
570 if (Tcl_GetInt(interp, string, &i) != TCL_OK) {
574 if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
575 Tcl_SetLongObj(varPtr[varIndex], intValue);
577 SetVarToObj(varIndex, Tcl_NewLongObj(intValue));
579 Tcl_SetObjResult(interp, varPtr[varIndex]);
580 } else if (strcmp(subCmd, "setmaxlong") == 0) {
581 long maxLong = LONG_MAX;
585 if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
586 Tcl_SetLongObj(varPtr[varIndex], maxLong);
588 SetVarToObj(varIndex, Tcl_NewLongObj(maxLong));
590 } else if (strcmp(subCmd, "ismaxlong") == 0) {
594 if (CheckIfVarUnset(interp, varIndex)) {
597 if (Tcl_GetLongFromObj(interp, varPtr[varIndex], &longValue) != TCL_OK) {
600 Tcl_AppendToObj(Tcl_GetObjResult(interp),
601 ((longValue == LONG_MAX)? "1" : "0"), -1);
602 } else if (strcmp(subCmd, "get") == 0) {
606 if (CheckIfVarUnset(interp, varIndex)) {
609 Tcl_SetObjResult(interp, varPtr[varIndex]);
610 } else if (strcmp(subCmd, "get2") == 0) {
614 if (CheckIfVarUnset(interp, varIndex)) {
617 string = Tcl_GetString(varPtr[varIndex]);
618 Tcl_AppendToObj(Tcl_GetObjResult(interp), string, -1);
619 } else if (strcmp(subCmd, "inttoobigtest") == 0) {
621 * If long ints have more bits than ints on this platform, verify
622 * that Tcl_GetIntFromObj returns an error if the long int held
623 * in an integer object's internal representation is too large
630 #if (INT_MAX == LONG_MAX) /* int is same size as long int */
631 Tcl_AppendToObj(Tcl_GetObjResult(interp), "1", -1);
633 if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
634 Tcl_SetLongObj(varPtr[varIndex], LONG_MAX);
636 SetVarToObj(varIndex, Tcl_NewLongObj(LONG_MAX));
638 if (Tcl_GetIntFromObj(interp, varPtr[varIndex], &i) != TCL_OK) {
639 Tcl_ResetResult(interp);
640 Tcl_AppendToObj(Tcl_GetObjResult(interp), "1", -1);
643 Tcl_AppendToObj(Tcl_GetObjResult(interp), "0", -1);
645 } else if (strcmp(subCmd, "mult10") == 0) {
649 if (CheckIfVarUnset(interp, varIndex)) {
652 if (Tcl_GetIntFromObj(interp, varPtr[varIndex],
653 &intValue) != TCL_OK) {
656 if (!Tcl_IsShared(varPtr[varIndex])) {
657 Tcl_SetIntObj(varPtr[varIndex], (intValue * 10));
659 SetVarToObj(varIndex, Tcl_NewIntObj( (intValue * 10) ));
661 Tcl_SetObjResult(interp, varPtr[varIndex]);
662 } else if (strcmp(subCmd, "div10") == 0) {
666 if (CheckIfVarUnset(interp, varIndex)) {
669 if (Tcl_GetIntFromObj(interp, varPtr[varIndex],
670 &intValue) != TCL_OK) {
673 if (!Tcl_IsShared(varPtr[varIndex])) {
674 Tcl_SetIntObj(varPtr[varIndex], (intValue / 10));
676 SetVarToObj(varIndex, Tcl_NewIntObj( (intValue / 10) ));
678 Tcl_SetObjResult(interp, varPtr[varIndex]);
680 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
681 "bad option \"", Tcl_GetString(objv[1]),
682 "\": must be set, get, get2, mult10, or div10",
690 *----------------------------------------------------------------------
694 * This procedure implements the "testobj" command. It is used to test
695 * the type-independent portions of the Tcl object type implementation.
698 * A standard Tcl object result.
701 * Creates and frees objects.
703 *----------------------------------------------------------------------
707 TestobjCmd(clientData, interp, objc, objv)
708 ClientData clientData; /* Not used. */
709 Tcl_Interp *interp; /* Current interpreter. */
710 int objc; /* Number of arguments. */
711 Tcl_Obj *CONST objv[]; /* Argument objects. */
713 int varIndex, destIndex, i;
714 char *index, *subCmd, *string;
715 Tcl_ObjType *targetType;
719 Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
723 subCmd = Tcl_GetString(objv[1]);
724 if (strcmp(subCmd, "assign") == 0) {
728 index = Tcl_GetString(objv[2]);
729 if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
732 if (CheckIfVarUnset(interp, varIndex)) {
735 string = Tcl_GetString(objv[3]);
736 if (GetVariableIndex(interp, string, &destIndex) != TCL_OK) {
739 SetVarToObj(destIndex, varPtr[varIndex]);
740 Tcl_SetObjResult(interp, varPtr[destIndex]);
741 } else if (strcmp(subCmd, "convert") == 0) {
746 index = Tcl_GetString(objv[2]);
747 if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
750 if (CheckIfVarUnset(interp, varIndex)) {
753 typeName = Tcl_GetString(objv[3]);
754 if ((targetType = Tcl_GetObjType(typeName)) == NULL) {
755 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
756 "no type ", typeName, " found", (char *) NULL);
759 if (Tcl_ConvertToType(interp, varPtr[varIndex], targetType)
763 Tcl_SetObjResult(interp, varPtr[varIndex]);
764 } else if (strcmp(subCmd, "duplicate") == 0) {
768 index = Tcl_GetString(objv[2]);
769 if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
772 if (CheckIfVarUnset(interp, varIndex)) {
775 string = Tcl_GetString(objv[3]);
776 if (GetVariableIndex(interp, string, &destIndex) != TCL_OK) {
779 SetVarToObj(destIndex, Tcl_DuplicateObj(varPtr[varIndex]));
780 Tcl_SetObjResult(interp, varPtr[destIndex]);
781 } else if (strcmp(subCmd, "freeallvars") == 0) {
785 for (i = 0; i < NUMBER_OF_OBJECT_VARS; i++) {
786 if (varPtr[i] != NULL) {
787 Tcl_DecrRefCount(varPtr[i]);
791 } else if ( strcmp ( subCmd, "invalidateStringRep" ) == 0 ) {
795 index = Tcl_GetString( objv[2] );
796 if ( GetVariableIndex( interp, index, &varIndex ) != TCL_OK ) {
799 if (CheckIfVarUnset(interp, varIndex)) {
802 Tcl_InvalidateStringRep( varPtr[varIndex] );
803 Tcl_SetObjResult( interp, varPtr[varIndex] );
804 } else if (strcmp(subCmd, "newobj") == 0) {
808 index = Tcl_GetString(objv[2]);
809 if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
812 SetVarToObj(varIndex, Tcl_NewObj());
813 Tcl_SetObjResult(interp, varPtr[varIndex]);
814 } else if (strcmp(subCmd, "objtype") == 0) {
818 * return an object containing the name of the argument's type
819 * of internal rep. If none exists, return "none".
825 if (objv[2]->typePtr == NULL) {
826 Tcl_SetObjResult(interp, Tcl_NewStringObj("none", -1));
828 typeName = objv[2]->typePtr->name;
829 Tcl_SetObjResult(interp, Tcl_NewStringObj(typeName, -1));
831 } else if (strcmp(subCmd, "refcount") == 0) {
832 char buf[TCL_INTEGER_SPACE];
837 index = Tcl_GetString(objv[2]);
838 if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
841 if (CheckIfVarUnset(interp, varIndex)) {
844 TclFormatInt(buf, varPtr[varIndex]->refCount);
845 Tcl_SetResult(interp, buf, TCL_VOLATILE);
846 } else if (strcmp(subCmd, "type") == 0) {
850 index = Tcl_GetString(objv[2]);
851 if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
854 if (CheckIfVarUnset(interp, varIndex)) {
857 if (varPtr[varIndex]->typePtr == NULL) { /* a string! */
858 Tcl_AppendToObj(Tcl_GetObjResult(interp), "string", -1);
860 Tcl_AppendToObj(Tcl_GetObjResult(interp),
861 varPtr[varIndex]->typePtr->name, -1);
863 } else if (strcmp(subCmd, "types") == 0) {
867 if (Tcl_AppendAllObjTypes(interp,
868 Tcl_GetObjResult(interp)) != TCL_OK) {
872 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
874 Tcl_GetString(objv[1]),
875 "\": must be assign, convert, duplicate, freeallvars, ",
876 "newobj, objcount, objtype, refcount, type, or types",
884 *----------------------------------------------------------------------
886 * TeststringobjCmd --
888 * This procedure implements the "teststringobj" command. It is used to
889 * test the string Tcl object type implementation.
892 * A standard Tcl object result.
895 * Creates and frees string objects, and also converts objects to
898 *----------------------------------------------------------------------
902 TeststringobjCmd(clientData, interp, objc, objv)
903 ClientData clientData; /* Not used. */
904 Tcl_Interp *interp; /* Current interpreter. */
905 int objc; /* Number of arguments. */
906 Tcl_Obj *CONST objv[]; /* Argument objects. */
908 int varIndex, option, i, length;
909 #define MAX_STRINGS 11
910 char *index, *string, *strings[MAX_STRINGS+1];
912 static CONST char *options[] = {
913 "append", "appendstrings", "get", "get2", "length", "length2",
914 "set", "set2", "setlength", "ualloc", "getunicode",
920 Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
924 index = Tcl_GetString(objv[2]);
925 if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
929 if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, &option)
938 if (Tcl_GetIntFromObj(interp, objv[4], &length) != TCL_OK) {
941 if (varPtr[varIndex] == NULL) {
942 SetVarToObj(varIndex, Tcl_NewObj());
946 * If the object bound to variable "varIndex" is shared, we must
947 * "copy on write" and append to a copy of the object.
950 if (Tcl_IsShared(varPtr[varIndex])) {
951 SetVarToObj(varIndex, Tcl_DuplicateObj(varPtr[varIndex]));
953 string = Tcl_GetString(objv[3]);
954 Tcl_AppendToObj(varPtr[varIndex], string, length);
955 Tcl_SetObjResult(interp, varPtr[varIndex]);
957 case 1: /* appendstrings */
958 if (objc > (MAX_STRINGS+3)) {
961 if (varPtr[varIndex] == NULL) {
962 SetVarToObj(varIndex, Tcl_NewObj());
966 * If the object bound to variable "varIndex" is shared, we must
967 * "copy on write" and append to a copy of the object.
970 if (Tcl_IsShared(varPtr[varIndex])) {
971 SetVarToObj(varIndex, Tcl_DuplicateObj(varPtr[varIndex]));
973 for (i = 3; i < objc; i++) {
974 strings[i-3] = Tcl_GetString(objv[i]);
976 for ( ; i < 12 + 3; i++) {
977 strings[i - 3] = NULL;
979 Tcl_AppendStringsToObj(varPtr[varIndex], strings[0], strings[1],
980 strings[2], strings[3], strings[4], strings[5],
981 strings[6], strings[7], strings[8], strings[9],
982 strings[10], strings[11]);
983 Tcl_SetObjResult(interp, varPtr[varIndex]);
989 if (CheckIfVarUnset(interp, varIndex)) {
992 Tcl_SetObjResult(interp, varPtr[varIndex]);
998 if (CheckIfVarUnset(interp, varIndex)) {
1001 string = Tcl_GetString(varPtr[varIndex]);
1002 Tcl_AppendToObj(Tcl_GetObjResult(interp), string, -1);
1004 case 4: /* length */
1008 Tcl_SetIntObj(Tcl_GetObjResult(interp), (varPtr[varIndex] != NULL)
1009 ? varPtr[varIndex]->length : -1);
1011 case 5: /* length2 */
1015 if (varPtr[varIndex] != NULL) {
1016 strPtr = (TestString *)
1017 (varPtr[varIndex])->internalRep.otherValuePtr;
1018 length = (int) strPtr->allocated;
1022 Tcl_SetIntObj(Tcl_GetObjResult(interp), length);
1030 * If the object currently bound to the variable with index
1031 * varIndex has ref count 1 (i.e. the object is unshared) we
1032 * can modify that object directly. Otherwise, if RC>1 (i.e.
1033 * the object is shared), we must create a new object to
1034 * modify/set and decrement the old formerly-shared object's
1035 * ref count. This is "copy on write".
1038 string = Tcl_GetStringFromObj(objv[3], &length);
1039 if ((varPtr[varIndex] != NULL)
1040 && !Tcl_IsShared(varPtr[varIndex])) {
1041 Tcl_SetStringObj(varPtr[varIndex], string, length);
1043 SetVarToObj(varIndex, Tcl_NewStringObj(string, length));
1045 Tcl_SetObjResult(interp, varPtr[varIndex]);
1051 SetVarToObj(varIndex, objv[3]);
1053 case 8: /* setlength */
1057 if (Tcl_GetIntFromObj(interp, objv[3], &length) != TCL_OK) {
1060 if (varPtr[varIndex] != NULL) {
1061 Tcl_SetObjLength(varPtr[varIndex], length);
1064 case 9: /* ualloc */
1068 if (varPtr[varIndex] != NULL) {
1069 strPtr = (TestString *)
1070 (varPtr[varIndex])->internalRep.otherValuePtr;
1071 length = (int) strPtr->uallocated;
1075 Tcl_SetIntObj(Tcl_GetObjResult(interp), length);
1077 case 10: /* getunicode */
1081 Tcl_GetUnicodeFromObj(varPtr[varIndex], NULL);
1089 *----------------------------------------------------------------------
1093 * Utility routine to assign a Tcl_Obj* to a test variable. The
1094 * Tcl_Obj* can be NULL.
1100 * This routine handles ref counting details for assignment:
1101 * i.e. the old value's ref count must be decremented (if not NULL) and
1102 * the new one incremented (also if not NULL).
1104 *----------------------------------------------------------------------
1108 SetVarToObj(varIndex, objPtr)
1109 int varIndex; /* Designates the assignment variable. */
1110 Tcl_Obj *objPtr; /* Points to object to assign to var. */
1112 if (varPtr[varIndex] != NULL) {
1113 Tcl_DecrRefCount(varPtr[varIndex]);
1115 varPtr[varIndex] = objPtr;
1116 if (objPtr != NULL) {
1117 Tcl_IncrRefCount(objPtr);
1122 *----------------------------------------------------------------------
1124 * GetVariableIndex --
1126 * Utility routine to get a test variable index from the command line.
1129 * A standard Tcl object result.
1134 *----------------------------------------------------------------------
1138 GetVariableIndex(interp, string, indexPtr)
1139 Tcl_Interp *interp; /* Interpreter for error reporting. */
1140 char *string; /* String containing a variable index
1141 * specified as a nonnegative number less
1142 * than NUMBER_OF_OBJECT_VARS. */
1143 int *indexPtr; /* Place to store converted result. */
1147 if (Tcl_GetInt(interp, string, &index) != TCL_OK) {
1150 if (index < 0 || index >= NUMBER_OF_OBJECT_VARS) {
1151 Tcl_ResetResult(interp);
1152 Tcl_AppendToObj(Tcl_GetObjResult(interp), "bad variable index", -1);
1161 *----------------------------------------------------------------------
1163 * CheckIfVarUnset --
1165 * Utility procedure that checks whether a test variable is readable:
1166 * i.e., that varPtr[varIndex] is non-NULL.
1169 * 1 if the test variable is unset (NULL); 0 otherwise.
1172 * Sets the interpreter result to an error message if the variable is
1175 *----------------------------------------------------------------------
1179 CheckIfVarUnset(interp, varIndex)
1180 Tcl_Interp *interp; /* Interpreter for error reporting. */
1181 int varIndex; /* Index of the test variable to check. */
1183 if (varPtr[varIndex] == NULL) {
1184 char buf[32 + TCL_INTEGER_SPACE];
1186 sprintf(buf, "variable %d is unset (NULL)", varIndex);
1187 Tcl_ResetResult(interp);
1188 Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1);