Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/tcl8.5.2/generic/tclTestObj.c @ 25

Last change on this file since 25 was 25, checked in by landauf, 16 years ago

added tcl to libs

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