OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [itcl/] [itcl/] [generic/] [itcl_cmds.c] - Blame information for rev 1773

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * ------------------------------------------------------------------------
3
 *      PACKAGE:  [incr Tcl]
4
 *  DESCRIPTION:  Object-Oriented Extensions to Tcl
5
 *
6
 *  [incr Tcl] provides object-oriented extensions to Tcl, much as
7
 *  C++ provides object-oriented extensions to C.  It provides a means
8
 *  of encapsulating related procedures together with their shared data
9
 *  in a local namespace that is hidden from the outside world.  It
10
 *  promotes code re-use through inheritance.  More than anything else,
11
 *  it encourages better organization of Tcl applications through the
12
 *  object-oriented paradigm, leading to code that is easier to
13
 *  understand and maintain.
14
 *
15
 *  This file defines information that tracks classes and objects
16
 *  at a global level for a given interpreter.
17
 *
18
 * ========================================================================
19
 *  AUTHOR:  Michael J. McLennan
20
 *           Bell Labs Innovations for Lucent Technologies
21
 *           mmclennan@lucent.com
22
 *           http://www.tcltk.com/itcl
23
 *
24
 *     RCS:  $Id: itcl_cmds.c,v 1.1.1.1 2002-01-16 10:24:46 markom Exp $
25
 * ========================================================================
26
 *           Copyright (c) 1993-1998  Lucent Technologies, Inc.
27
 * ------------------------------------------------------------------------
28
 * See the file "license.terms" for information on usage and redistribution
29
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
30
 */
31
#include "itclInt.h"
32
 
33
/*
34
 *  FORWARD DECLARATIONS
35
 */
36
static void ItclDelObjectInfo _ANSI_ARGS_((char* cdata));
37
static int Initialize _ANSI_ARGS_((Tcl_Interp *interp));
38
static int ItclHandleStubCmd _ANSI_ARGS_((ClientData clientData,
39
    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
40
static void ItclDeleteStub _ANSI_ARGS_((ClientData cdata));
41
 
42
/*
43
 * The following string is the startup script executed in new
44
 * interpreters.  It locates the Tcl code in the [incr Tcl] library
45
 * directory and loads it in.
46
 */
47
 
48
static char initScript[] = "\n\
49
namespace eval ::itcl {\n\
50
    proc _find_init {} {\n\
51
        global env tcl_library\n\
52
        variable library\n\
53
        variable version\n\
54
        rename _find_init {}\n\
55
        if {[catch {uplevel #0 source -rsrc itcl}] == 0} {\n\
56
            return\n\
57
        }\n\
58
        tcl_findLibrary itcl 3.0 {} itcl.tcl ITCL_LIBRARY ::itcl::library {} {} itcl\n\
59
   }\n\
60
    _find_init\n\
61
}";
62
 
63
/*
64
 * The following script is used to initialize Itcl in a safe interpreter.
65
 */
66
 
67
static char safeInitScript[] =
68
"proc ::itcl::local {class name args} {\n\
69
    set ptr [uplevel eval [list $class $name] $args]\n\
70
    uplevel [list set itcl-local-$ptr $ptr]\n\
71
    set cmd [uplevel namespace which -command $ptr]\n\
72
    uplevel [list trace variable itcl-local-$ptr u \"::itcl::delete object $cmd; list\"]\n\
73
    return $ptr\n\
74
}";
75
 
76
 
77
/*
78
 * ------------------------------------------------------------------------
79
 *  Initialize()
80
 *
81
 *  Invoked whenever a new interpeter is created to install the
82
 *  [incr Tcl] package.  Usually invoked within Tcl_AppInit() at
83
 *  the start of execution.
84
 *
85
 *  Creates the "::itcl" namespace and installs access commands for
86
 *  creating classes and querying info.
87
 *
88
 *  Returns TCL_OK on success, or TCL_ERROR (along with an error
89
 *  message in the interpreter) if anything goes wrong.
90
 * ------------------------------------------------------------------------
91
 */
92
static int
93
Initialize(interp)
94
    Tcl_Interp *interp;  /* interpreter to be updated */
95
{
96
    Tcl_CmdInfo cmdInfo;
97
    Tcl_Namespace *itclNs;
98
    ItclObjectInfo *info;
99
 
100
    if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 1) == NULL) {
101
        return TCL_ERROR;
102
    }
103
 
104
    /*
105
     *  See if [incr Tcl] is already installed.
106
     */
107
    if (Tcl_GetCommandInfo(interp, "::itcl::class", &cmdInfo)) {
108
        Tcl_SetResult(interp, "already installed: [incr Tcl]", TCL_STATIC);
109
        return TCL_ERROR;
110
    }
111
 
112
    /*
113
     *  Initialize the ensemble package first, since we need this
114
     *  for other parts of [incr Tcl].
115
     */
116
    if (Itcl_EnsembleInit(interp) != TCL_OK) {
117
        return TCL_ERROR;
118
    }
119
 
120
    /*
121
     *  Create the top-level data structure for tracking objects.
122
     *  Store this as "associated data" for easy access, but link
123
     *  it to the itcl namespace for ownership.
124
     */
125
    info = (ItclObjectInfo*)ckalloc(sizeof(ItclObjectInfo));
126
    info->interp = interp;
127
    Tcl_InitHashTable(&info->objects, TCL_ONE_WORD_KEYS);
128
    Itcl_InitStack(&info->transparentFrames);
129
    Tcl_InitHashTable(&info->contextFrames, TCL_ONE_WORD_KEYS);
130
    info->protection = ITCL_DEFAULT_PROTECT;
131
    Itcl_InitStack(&info->cdefnStack);
132
 
133
    Tcl_SetAssocData(interp, ITCL_INTERP_DATA,
134
        (Tcl_InterpDeleteProc*)NULL, (ClientData)info);
135
 
136
    /*
137
     *  Install commands into the "::itcl" namespace.
138
     */
139
    Tcl_CreateObjCommand(interp, "::itcl::class", Itcl_ClassCmd,
140
        (ClientData)info, Itcl_ReleaseData);
141
    Itcl_PreserveData((ClientData)info);
142
 
143
    Tcl_CreateObjCommand(interp, "::itcl::body", Itcl_BodyCmd,
144
        (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
145
 
146
    Tcl_CreateObjCommand(interp, "::itcl::configbody", Itcl_ConfigBodyCmd,
147
        (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
148
 
149
    Itcl_EventuallyFree((ClientData)info, ItclDelObjectInfo);
150
 
151
    /*
152
     *  Create the "itcl::find" command for high-level queries.
153
     */
154
    if (Itcl_CreateEnsemble(interp, "::itcl::find") != TCL_OK) {
155
        return TCL_ERROR;
156
    }
157
    if (Itcl_AddEnsemblePart(interp, "::itcl::find",
158
            "classes", "?pattern?",
159
            Itcl_FindClassesCmd,
160
            (ClientData)info, Itcl_ReleaseData) != TCL_OK) {
161
        return TCL_ERROR;
162
    }
163
    Itcl_PreserveData((ClientData)info);
164
 
165
    if (Itcl_AddEnsemblePart(interp, "::itcl::find",
166
            "objects", "?-class className? ?-isa className? ?pattern?",
167
            Itcl_FindObjectsCmd,
168
            (ClientData)info, Itcl_ReleaseData) != TCL_OK) {
169
        return TCL_ERROR;
170
    }
171
    Itcl_PreserveData((ClientData)info);
172
 
173
 
174
    /*
175
     *  Create the "itcl::delete" command to delete objects
176
     *  and classes.
177
     */
178
    if (Itcl_CreateEnsemble(interp, "::itcl::delete") != TCL_OK) {
179
        return TCL_ERROR;
180
    }
181
    if (Itcl_AddEnsemblePart(interp, "::itcl::delete",
182
            "class", "name ?name...?",
183
            Itcl_DelClassCmd,
184
            (ClientData)info, Itcl_ReleaseData) != TCL_OK) {
185
        return TCL_ERROR;
186
    }
187
    Itcl_PreserveData((ClientData)info);
188
 
189
    if (Itcl_AddEnsemblePart(interp, "::itcl::delete",
190
            "object", "name ?name...?",
191
            Itcl_DelObjectCmd,
192
            (ClientData)info, Itcl_ReleaseData) != TCL_OK) {
193
        return TCL_ERROR;
194
    }
195
    Itcl_PreserveData((ClientData)info);
196
 
197
    /*
198
     *  Add "code" and "scope" commands for handling scoped values.
199
     */
200
    Tcl_CreateObjCommand(interp, "::itcl::code", Itcl_CodeCmd,
201
        (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
202
 
203
    Tcl_CreateObjCommand(interp, "::itcl::scope", Itcl_ScopeCmd,
204
        (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
205
 
206
    /*
207
     *  Add commands for handling import stubs at the Tcl level.
208
     */
209
    if (Itcl_CreateEnsemble(interp, "::itcl::import::stub") != TCL_OK) {
210
        return TCL_ERROR;
211
    }
212
    if (Itcl_AddEnsemblePart(interp, "::itcl::import::stub",
213
            "create", "name", Itcl_StubCreateCmd,
214
            (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL) != TCL_OK) {
215
        return TCL_ERROR;
216
    }
217
    if (Itcl_AddEnsemblePart(interp, "::itcl::import::stub",
218
            "exists", "name", Itcl_StubExistsCmd,
219
            (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL) != TCL_OK) {
220
        return TCL_ERROR;
221
    }
222
 
223
    /*
224
     *  Install a variable resolution procedure to handle scoped
225
     *  values everywhere within the interpreter.
226
     */
227
    Tcl_AddInterpResolvers(interp, "itcl", (Tcl_ResolveCmdProc*)NULL,
228
        Itcl_ScopedVarResolver, (Tcl_ResolveCompiledVarProc*)NULL);
229
 
230
    /*
231
     *  Install the "itcl::parser" namespace used to parse the
232
     *  class definitions.
233
     */
234
    if (Itcl_ParseInit(interp, info) != TCL_OK) {
235
        return TCL_ERROR;
236
    }
237
 
238
    /*
239
     *  Create "itcl::builtin" namespace for commands that
240
     *  are automatically built into class definitions.
241
     */
242
    if (Itcl_BiInit(interp) != TCL_OK) {
243
        return TCL_ERROR;
244
    }
245
 
246
    /*
247
     *  Install stuff needed for backward compatibility with previous
248
     *  version of [incr Tcl].
249
     */
250
    if (Itcl_OldInit(interp, info) != TCL_OK) {
251
        return TCL_ERROR;
252
    }
253
 
254
    /*
255
     *  Export all commands in the "itcl" namespace so that they
256
     *  can be imported with something like "namespace import itcl::*"
257
     */
258
    itclNs = Tcl_FindNamespace(interp, "::itcl", (Tcl_Namespace*)NULL,
259
        TCL_LEAVE_ERR_MSG);
260
 
261
    if (!itclNs ||
262
        Tcl_Export(interp, itclNs, "*", /* resetListFirst */ 1) != TCL_OK) {
263
        return TCL_ERROR;
264
    }
265
 
266
    /*
267
     *  Set up the variables containing version info.
268
     */
269
 
270
    Tcl_SetVar(interp, "::itcl::patchLevel", ITCL_PATCH_LEVEL,
271
        TCL_NAMESPACE_ONLY);
272
 
273
    Tcl_SetVar(interp, "::itcl::version", ITCL_VERSION,
274
        TCL_NAMESPACE_ONLY);
275
 
276
    /*
277
     *  Package is now loaded.
278
     */
279
    if (Tcl_PkgProvide(interp, "Itcl", ITCL_VERSION) != TCL_OK) {
280
        return TCL_ERROR;
281
    }
282
    return TCL_OK;
283
}
284
 
285
 
286
/*
287
 * ------------------------------------------------------------------------
288
 *  Itcl_Init()
289
 *
290
 *  Invoked whenever a new INTERPRETER is created to install the
291
 *  [incr Tcl] package.  Usually invoked within Tcl_AppInit() at
292
 *  the start of execution.
293
 *
294
 *  Creates the "::itcl" namespace and installs access commands for
295
 *  creating classes and querying info.
296
 *
297
 *  Returns TCL_OK on success, or TCL_ERROR (along with an error
298
 *  message in the interpreter) if anything goes wrong.
299
 * ------------------------------------------------------------------------
300
 */
301
int
302
Itcl_Init(interp)
303
    Tcl_Interp *interp;  /* interpreter to be updated */
304
{
305
    if (Initialize(interp) != TCL_OK) {
306
        return TCL_ERROR;
307
    }
308
    return Tcl_Eval(interp, initScript);
309
}
310
 
311
 
312
/*
313
 * ------------------------------------------------------------------------
314
 *  Itcl_SafeInit()
315
 *
316
 *  Invoked whenever a new SAFE INTERPRETER is created to install
317
 *  the [incr Tcl] package.
318
 *
319
 *  Creates the "::itcl" namespace and installs access commands for
320
 *  creating classes and querying info.
321
 *
322
 *  Returns TCL_OK on success, or TCL_ERROR (along with an error
323
 *  message in the interpreter) if anything goes wrong.
324
 * ------------------------------------------------------------------------
325
 */
326
int
327
Itcl_SafeInit(interp)
328
    Tcl_Interp *interp;  /* interpreter to be updated */
329
{
330
    if (Initialize(interp) != TCL_OK) {
331
        return TCL_ERROR;
332
    }
333
    return Tcl_Eval(interp, safeInitScript);
334
}
335
 
336
 
337
/*
338
 * ------------------------------------------------------------------------
339
 *  ItclDelObjectInfo()
340
 *
341
 *  Invoked when the management info for [incr Tcl] is no longer being
342
 *  used in an interpreter.  This will only occur when all class
343
 *  manipulation commands are removed from the interpreter.
344
 * ------------------------------------------------------------------------
345
 */
346
static void
347
ItclDelObjectInfo(cdata)
348
    char* cdata;    /* client data for class command */
349
{
350
    ItclObjectInfo *info = (ItclObjectInfo*)cdata;
351
 
352
    ItclObject *contextObj;
353
    Tcl_HashSearch place;
354
    Tcl_HashEntry *entry;
355
 
356
    /*
357
     *  Destroy all known objects by deleting their access
358
     *  commands.
359
     */
360
    entry = Tcl_FirstHashEntry(&info->objects, &place);
361
    while (entry) {
362
        contextObj = (ItclObject*)Tcl_GetHashValue(entry);
363
        Tcl_DeleteCommandFromToken(info->interp, contextObj->accessCmd);
364
        entry = Tcl_NextHashEntry(&place);
365
    }
366
    Tcl_DeleteHashTable(&info->objects);
367
 
368
    /*
369
     *  Discard all known object contexts.
370
     */
371
    entry = Tcl_FirstHashEntry(&info->contextFrames, &place);
372
    while (entry) {
373
        Itcl_ReleaseData( Tcl_GetHashValue(entry) );
374
        entry = Tcl_NextHashEntry(&place);
375
    }
376
    Tcl_DeleteHashTable(&info->contextFrames);
377
 
378
    Itcl_DeleteStack(&info->transparentFrames);
379
    Itcl_DeleteStack(&info->cdefnStack);
380
    ckfree((char*)info);
381
}
382
 
383
 
384
/*
385
 * ------------------------------------------------------------------------
386
 *  Itcl_FindClassesCmd()
387
 *
388
 *  Part of the "::info" ensemble.  Invoked by Tcl whenever the user
389
 *  issues an "info classes" command to query the list of classes
390
 *  in the current namespace.  Handles the following syntax:
391
 *
392
 *    info classes ?<pattern>?
393
 *
394
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
395
 * ------------------------------------------------------------------------
396
 */
397
/* ARGSUSED */
398
int
399
Itcl_FindClassesCmd(clientData, interp, objc, objv)
400
    ClientData clientData;   /* class/object info */
401
    Tcl_Interp *interp;      /* current interpreter */
402
    int objc;                /* number of arguments */
403
    Tcl_Obj *CONST objv[];   /* argument objects */
404
{
405
    Tcl_Namespace *activeNs = Tcl_GetCurrentNamespace(interp);
406
    Tcl_Namespace *globalNs = Tcl_GetGlobalNamespace(interp);
407
    int forceFullNames = 0;
408
 
409
    char *pattern;
410
    char *name;
411
    int i, nsearch, newEntry;
412
    Tcl_HashTable unique;
413
    Tcl_HashEntry *entry;
414
    Tcl_HashSearch place;
415
    Tcl_Namespace *search[2];
416
    Tcl_Command cmd, originalCmd;
417
    Namespace *nsPtr;
418
    Tcl_Obj *listPtr, *objPtr;
419
 
420
    if (objc > 2) {
421
        Tcl_WrongNumArgs(interp, 1, objv, "?pattern?");
422
        return TCL_ERROR;
423
    }
424
 
425
    if (objc == 2) {
426
        pattern = Tcl_GetStringFromObj(objv[1], (int*)NULL);
427
        forceFullNames = (strstr(pattern, "::") != NULL);
428
    } else {
429
        pattern = NULL;
430
    }
431
 
432
    /*
433
     *  Search through all commands in the current namespace and
434
     *  in the global namespace.  If we find any commands that
435
     *  represent classes, report them.
436
     */
437
    listPtr = Tcl_NewListObj(0, (Tcl_Obj* CONST*)NULL);
438
 
439
    nsearch = 0;
440
    search[nsearch++] = activeNs;
441
    if (activeNs != globalNs) {
442
        search[nsearch++] = globalNs;
443
    }
444
 
445
    Tcl_InitHashTable(&unique, TCL_ONE_WORD_KEYS);
446
 
447
    for (i=0; i < nsearch; i++) {
448
        nsPtr = (Namespace*)search[i];
449
 
450
        entry = Tcl_FirstHashEntry(&nsPtr->cmdTable, &place);
451
        while (entry) {
452
            cmd = (Tcl_Command)Tcl_GetHashValue(entry);
453
            if (Itcl_IsClass(cmd)) {
454
                originalCmd = TclGetOriginalCommand(cmd);
455
 
456
                /*
457
                 *  Report full names if:
458
                 *  - the pattern has namespace qualifiers
459
                 *  - the class namespace is not in the current namespace
460
                 *  - the class's object creation command is imported from
461
                 *      another namespace.
462
                 *
463
                 *  Otherwise, report short names.
464
                 */
465
                if (forceFullNames || nsPtr != (Namespace*)activeNs ||
466
                    originalCmd != NULL) {
467
 
468
                    objPtr = Tcl_NewStringObj((char*)NULL, 0);
469
                    Tcl_GetCommandFullName(interp, cmd, objPtr);
470
                    name = Tcl_GetStringFromObj(objPtr, (int*)NULL);
471
                } else {
472
                    name = Tcl_GetCommandName(interp, cmd);
473
                    objPtr = Tcl_NewStringObj(name, -1);
474
                }
475
 
476
                if (originalCmd) {
477
                    cmd = originalCmd;
478
                }
479
                Tcl_CreateHashEntry(&unique, (char*)cmd, &newEntry);
480
 
481
                if (newEntry && (!pattern || Tcl_StringMatch(name, pattern))) {
482
                    Tcl_ListObjAppendElement((Tcl_Interp*)NULL,
483
                        listPtr, objPtr);
484
                }
485
            }
486
            entry = Tcl_NextHashEntry(&place);
487
        }
488
    }
489
    Tcl_DeleteHashTable(&unique);
490
 
491
    Tcl_SetObjResult(interp, listPtr);
492
    return TCL_OK;
493
}
494
 
495
 
496
/*
497
 * ------------------------------------------------------------------------
498
 *  Itcl_FindObjectsCmd()
499
 *
500
 *  Part of the "::info" ensemble.  Invoked by Tcl whenever the user
501
 *  issues an "info objects" command to query the list of known objects.
502
 *  Handles the following syntax:
503
 *
504
 *    info objects ?-class <className>? ?-isa <className>? ?<pattern>?
505
 *
506
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
507
 * ------------------------------------------------------------------------
508
 */
509
int
510
Itcl_FindObjectsCmd(clientData, interp, objc, objv)
511
    ClientData clientData;   /* class/object info */
512
    Tcl_Interp *interp;      /* current interpreter */
513
    int objc;                /* number of arguments */
514
    Tcl_Obj *CONST objv[];   /* argument objects */
515
{
516
    Tcl_Namespace *activeNs = Tcl_GetCurrentNamespace(interp);
517
    Tcl_Namespace *globalNs = Tcl_GetGlobalNamespace(interp);
518
    int forceFullNames = 0;
519
 
520
    char *pattern = NULL;
521
    ItclClass *classDefn = NULL;
522
    ItclClass *isaDefn = NULL;
523
 
524
    char *name, *token;
525
    int i, pos, nsearch, newEntry, match;
526
    ItclObject *contextObj;
527
    Tcl_HashTable unique;
528
    Tcl_HashEntry *entry;
529
    Tcl_HashSearch place;
530
    Tcl_Namespace *search[2];
531
    Tcl_Command cmd, originalCmd;
532
    Namespace *nsPtr;
533
    Command *cmdPtr;
534
    Tcl_Obj *listPtr, *objPtr;
535
 
536
    /*
537
     *  Parse arguments:
538
     *  objects ?-class <className>? ?-isa <className>? ?<pattern>?
539
     */
540
    pos = 0;
541
    while (++pos < objc) {
542
        token = Tcl_GetStringFromObj(objv[pos], (int*)NULL);
543
        if (*token != '-') {
544
            if (!pattern) {
545
                pattern = token;
546
                forceFullNames = (strstr(pattern, "::") != NULL);
547
            } else {
548
                break;
549
            }
550
        }
551
        else if ((pos+1 < objc) && (strcmp(token,"-class") == 0)) {
552
            name = Tcl_GetStringFromObj(objv[pos+1], (int*)NULL);
553
            classDefn = Itcl_FindClass(interp, name, /* autoload */ 1);
554
            if (classDefn == NULL) {
555
                return TCL_ERROR;
556
            }
557
            pos++;
558
        }
559
        else if ((pos+1 < objc) && (strcmp(token,"-isa") == 0)) {
560
            name = Tcl_GetStringFromObj(objv[pos+1], (int*)NULL);
561
            isaDefn = Itcl_FindClass(interp, name, /* autoload */ 1);
562
            if (isaDefn == NULL) {
563
                return TCL_ERROR;
564
            }
565
            pos++;
566
        }
567
        else {
568
            break;
569
        }
570
    }
571
 
572
    if (pos < objc) {
573
        Tcl_WrongNumArgs(interp, 1, objv,
574
            "?-class className? ?-isa className? ?pattern?");
575
        return TCL_ERROR;
576
    }
577
 
578
    /*
579
     *  Search through all commands in the current namespace and
580
     *  in the global namespace.  If we find any commands that
581
     *  represent objects, report them.
582
     */
583
    listPtr = Tcl_NewListObj(0, (Tcl_Obj* CONST*)NULL);
584
 
585
    nsearch = 0;
586
    search[nsearch++] = activeNs;
587
    if (activeNs != globalNs) {
588
        search[nsearch++] = globalNs;
589
    }
590
 
591
    Tcl_InitHashTable(&unique, TCL_ONE_WORD_KEYS);
592
 
593
    for (i=0; i < nsearch; i++) {
594
        nsPtr = (Namespace*)search[i];
595
 
596
        entry = Tcl_FirstHashEntry(&nsPtr->cmdTable, &place);
597
        while (entry) {
598
            cmd = (Tcl_Command)Tcl_GetHashValue(entry);
599
            if (Itcl_IsObject(cmd)) {
600
                originalCmd = TclGetOriginalCommand(cmd);
601
                if (originalCmd) {
602
                    cmd = originalCmd;
603
                }
604
                cmdPtr = (Command*)cmd;
605
                contextObj = (ItclObject*)cmdPtr->objClientData;
606
 
607
                /*
608
                 *  Report full names if:
609
                 *  - the pattern has namespace qualifiers
610
                 *  - the class namespace is not in the current namespace
611
                 *  - the class's object creation command is imported from
612
                 *      another namespace.
613
                 *
614
                 *  Otherwise, report short names.
615
                 */
616
                if (forceFullNames || nsPtr != (Namespace*)activeNs ||
617
                    originalCmd != NULL) {
618
 
619
                    objPtr = Tcl_NewStringObj((char*)NULL, 0);
620
                    Tcl_GetCommandFullName(interp, cmd, objPtr);
621
                    name = Tcl_GetStringFromObj(objPtr, (int*)NULL);
622
                } else {
623
                    name = Tcl_GetCommandName(interp, cmd);
624
                    objPtr = Tcl_NewStringObj(name, -1);
625
                }
626
 
627
                Tcl_CreateHashEntry(&unique, (char*)cmd, &newEntry);
628
 
629
                match = 0;
630
                if (newEntry && (!pattern || Tcl_StringMatch(name, pattern))) {
631
                    if (!classDefn || (contextObj->classDefn == classDefn)) {
632
                        if (!isaDefn) {
633
                            match = 1;
634
                        } else {
635
                            entry = Tcl_FindHashEntry(
636
                                &contextObj->classDefn->heritage,
637
                                (char*)isaDefn);
638
 
639
                            if (entry) {
640
                                match = 1;
641
                            }
642
                        }
643
                    }
644
                }
645
 
646
                if (match) {
647
                    Tcl_ListObjAppendElement((Tcl_Interp*)NULL,
648
                        listPtr, objPtr);
649
                } else {
650
                    Tcl_IncrRefCount(objPtr);  /* throw away the name */
651
                    Tcl_DecrRefCount(objPtr);
652
                }
653
            }
654
            entry = Tcl_NextHashEntry(&place);
655
        }
656
    }
657
    Tcl_DeleteHashTable(&unique);
658
 
659
    Tcl_SetObjResult(interp, listPtr);
660
    return TCL_OK;
661
}
662
 
663
 
664
/*
665
 * ------------------------------------------------------------------------
666
 *  Itcl_ProtectionCmd()
667
 *
668
 *  Invoked by Tcl whenever the user issues a protection setting
669
 *  command like "public" or "private".  Creates commands and
670
 *  variables, and assigns a protection level to them.  Protection
671
 *  levels are defined as follows:
672
 *
673
 *    public    => accessible from any namespace
674
 *    protected => accessible from selected namespaces
675
 *    private   => accessible only in the namespace where it was defined
676
 *
677
 *  Handles the following syntax:
678
 *
679
 *    public <command> ?<arg> <arg>...?
680
 *
681
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
682
 * ------------------------------------------------------------------------
683
 */
684
int
685
Itcl_ProtectionCmd(clientData, interp, objc, objv)
686
    ClientData clientData;   /* protection level (public/protected/private) */
687
    Tcl_Interp *interp;      /* current interpreter */
688
    int objc;                /* number of arguments */
689
    Tcl_Obj *CONST objv[];   /* argument objects */
690
{
691
    int pLevel = (int)clientData;
692
 
693
    int result;
694
    int oldLevel;
695
 
696
    if (objc < 2) {
697
        Tcl_WrongNumArgs(interp, 1, objv, "command ?arg arg...?");
698
        return TCL_ERROR;
699
    }
700
 
701
    oldLevel = Itcl_Protection(interp, pLevel);
702
 
703
    if (objc == 2) {
704
      /* CYGNUS LOCAL - Fix for 8.1 */
705
#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0
706
        result = Tcl_EvalObj(interp, objv[1]);
707
#else
708
        result = Tcl_EvalObj(interp, objv[1], 0);
709
#endif
710
        /* END CYGNUS LOCAL */
711
    } else {
712
        result = Itcl_EvalArgs(interp, objc-1, objv+1);
713
    }
714
 
715
    if (result == TCL_BREAK) {
716
        Tcl_SetResult(interp, "invoked \"break\" outside of a loop",
717
            TCL_STATIC);
718
        result = TCL_ERROR;
719
    }
720
    else if (result == TCL_CONTINUE) {
721
        Tcl_SetResult(interp, "invoked \"continue\" outside of a loop",
722
            TCL_STATIC);
723
        result = TCL_ERROR;
724
    }
725
    else if (result != TCL_OK) {
726
        char mesg[256], *name;
727
        name = Tcl_GetStringFromObj(objv[0], (int*)NULL);
728
        sprintf(mesg, "\n    (%.100s body line %d)",
729
            name, interp->errorLine);
730
        Tcl_AddErrorInfo(interp, mesg);
731
    }
732
 
733
    Itcl_Protection(interp, oldLevel);
734
    return result;
735
}
736
 
737
 
738
/*
739
 * ------------------------------------------------------------------------
740
 *  Itcl_DelClassCmd()
741
 *
742
 *  Part of the "delete" ensemble.  Invoked by Tcl whenever the
743
 *  user issues a "delete class" command to delete classes.
744
 *  Handles the following syntax:
745
 *
746
 *    delete class <name> ?<name>...?
747
 *
748
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
749
 * ------------------------------------------------------------------------
750
 */
751
/* ARGSUSED */
752
int
753
Itcl_DelClassCmd(clientData, interp, objc, objv)
754
    ClientData clientData;   /* unused */
755
    Tcl_Interp *interp;      /* current interpreter */
756
    int objc;                /* number of arguments */
757
    Tcl_Obj *CONST objv[];   /* argument objects */
758
{
759
    int i;
760
    char *name;
761
    ItclClass *cdefn;
762
 
763
    /*
764
     *  Since destroying a base class will destroy all derived
765
     *  classes, calls like "destroy class Base Derived" could
766
     *  fail.  Break this into two passes:  first check to make
767
     *  sure that all classes on the command line are valid,
768
     *  then delete them.
769
     */
770
    for (i=1; i < objc; i++) {
771
        name = Tcl_GetStringFromObj(objv[i], (int*)NULL);
772
        cdefn = Itcl_FindClass(interp, name, /* autoload */ 1);
773
        if (cdefn == NULL) {
774
            return TCL_ERROR;
775
        }
776
    }
777
 
778
    for (i=1; i < objc; i++) {
779
        name = Tcl_GetStringFromObj(objv[i], (int*)NULL);
780
        cdefn = Itcl_FindClass(interp, name, /* autoload */ 0);
781
 
782
        if (cdefn) {
783
            Tcl_ResetResult(interp);
784
            if (Itcl_DeleteClass(interp, cdefn) != TCL_OK) {
785
                return TCL_ERROR;
786
            }
787
        }
788
    }
789
    Tcl_ResetResult(interp);
790
    return TCL_OK;
791
}
792
 
793
 
794
/*
795
 * ------------------------------------------------------------------------
796
 *  Itcl_DelObjectCmd()
797
 *
798
 *  Part of the "delete" ensemble.  Invoked by Tcl whenever the user
799
 *  issues a "delete object" command to delete [incr Tcl] objects.
800
 *  Handles the following syntax:
801
 *
802
 *    delete object <name> ?<name>...?
803
 *
804
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
805
 * ------------------------------------------------------------------------
806
 */
807
int
808
Itcl_DelObjectCmd(clientData, interp, objc, objv)
809
    ClientData clientData;   /* object management info */
810
    Tcl_Interp *interp;      /* current interpreter */
811
    int objc;                /* number of arguments */
812
    Tcl_Obj *CONST objv[];   /* argument objects */
813
{
814
    int i;
815
    char *name;
816
    ItclObject *contextObj;
817
 
818
    /*
819
     *  Scan through the list of objects and attempt to delete them.
820
     *  If anything goes wrong (i.e., destructors fail), then
821
     *  abort with an error.
822
     */
823
    for (i=1; i < objc; i++) {
824
        name = Tcl_GetStringFromObj(objv[i], (int*)NULL);
825
        if (Itcl_FindObject(interp, name, &contextObj) != TCL_OK) {
826
            return TCL_ERROR;
827
        }
828
 
829
        if (contextObj == NULL) {
830
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
831
                "object \"", name, "\" not found",
832
                (char*)NULL);
833
            return TCL_ERROR;
834
        }
835
 
836
        if (Itcl_DeleteObject(interp, contextObj) != TCL_OK) {
837
            return TCL_ERROR;
838
        }
839
    }
840
    return TCL_OK;
841
}
842
 
843
 
844
/*
845
 * ------------------------------------------------------------------------
846
 *  Itcl_ScopeCmd()
847
 *
848
 *  Invoked by Tcl whenever the user issues a "scope" command to
849
 *  create a fully qualified variable name.  Handles the following
850
 *  syntax:
851
 *
852
 *    scope <variable>
853
 *
854
 *  If the input string is already fully qualified (starts with "::"),
855
 *  then this procedure does nothing.  Otherwise, it looks for a
856
 *  data member called <variable> and returns its fully qualified
857
 *  name.  If the <variable> is a common data member, this procedure
858
 *  returns a name of the form:
859
 *
860
 *    ::namesp::namesp::class::variable
861
 *
862
 *  If the <variable> is an instance variable, this procedure returns
863
 *  a name of the form:
864
 *
865
 *    @itcl ::namesp::namesp::object variable
866
 *
867
 *  This kind of scoped value is recognized by the Itcl_ScopedVarResolver
868
 *  proc, which handles variable resolution for the entire interpreter.
869
 *
870
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
871
 * ------------------------------------------------------------------------
872
 */
873
/* ARGSUSED */
874
int
875
Itcl_ScopeCmd(dummy, interp, objc, objv)
876
    ClientData dummy;        /* unused */
877
    Tcl_Interp *interp;      /* current interpreter */
878
    int objc;                /* number of arguments */
879
    Tcl_Obj *CONST objv[];   /* argument objects */
880
{
881
    int result = TCL_OK;
882
    Tcl_Namespace *contextNs = Tcl_GetCurrentNamespace(interp);
883
    char *openParen = NULL;
884
 
885
    register char *p;
886
    char *token;
887
    ItclClass *contextClass;
888
    ItclObject *contextObj;
889
    ItclObjectInfo *info;
890
    Tcl_CallFrame *framePtr;
891
    Tcl_HashEntry *entry;
892
    ItclVarLookup *vlookup;
893
    Tcl_Obj *objPtr;
894
    Tcl_Var var;
895
 
896
    if (objc != 2) {
897
        Tcl_WrongNumArgs(interp, 1, objv, "varname");
898
        return TCL_ERROR;
899
    }
900
 
901
    /*
902
     *  If this looks like a fully qualified name already,
903
     *  then return it as is.
904
     */
905
    token = Tcl_GetStringFromObj(objv[1], (int*)NULL);
906
    if (*token == ':' && *(token+1) == ':') {
907
        Tcl_SetObjResult(interp, objv[1]);
908
        return TCL_OK;
909
    }
910
 
911
    /*
912
     *  If the variable name is an array reference, pick out
913
     *  the array name and use that for the lookup operations
914
     *  below.
915
     */
916
    for (p=token; *p != '\0'; p++) {
917
        if (*p == '(') {
918
            openParen = p;
919
        }
920
        else if (*p == ')' && openParen) {
921
            *openParen = '\0';
922
            break;
923
        }
924
    }
925
 
926
    /*
927
     *  Figure out what context we're in.  If this is a class,
928
     *  then look up the variable in the class definition.
929
     *  If this is a namespace, then look up the variable in its
930
     *  varTable.  Note that the normal Itcl_GetContext function
931
     *  returns an error if we're not in a class context, so we
932
     *  perform a similar function here, the hard way.
933
     *
934
     *  TRICKY NOTE:  If this is an array reference, we'll get
935
     *    the array variable as the variable name.  We must be
936
     *    careful to add the index (everything from openParen
937
     *    onward) as well.
938
     */
939
    if (Itcl_IsClassNamespace(contextNs)) {
940
        contextClass = (ItclClass*)contextNs->clientData;
941
 
942
        entry = Tcl_FindHashEntry(&contextClass->resolveVars, token);
943
        if (!entry) {
944
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
945
                "variable \"", token, "\" not found in class \"",
946
                contextClass->fullname, "\"",
947
                (char*)NULL);
948
            result = TCL_ERROR;
949
            goto scopeCmdDone;
950
        }
951
        vlookup = (ItclVarLookup*)Tcl_GetHashValue(entry);
952
 
953
        if (vlookup->vdefn->member->flags & ITCL_COMMON) {
954
            Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
955
            Tcl_AppendToObj(resultPtr, vlookup->vdefn->member->fullname, -1);
956
            if (openParen) {
957
                *openParen = '(';
958
                Tcl_AppendToObj(resultPtr, openParen, -1);
959
                openParen = NULL;
960
            }
961
            result = TCL_OK;
962
            goto scopeCmdDone;
963
        }
964
 
965
        /*
966
         *  If this is not a common variable, then we better have
967
         *  an object context.  Return the name "@itcl object variable".
968
         */
969
        framePtr = _Tcl_GetCallFrame(interp, 0);
970
        info = contextClass->info;
971
 
972
        entry = Tcl_FindHashEntry(&info->contextFrames, (char*)framePtr);
973
        if (!entry) {
974
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
975
                "can't scope variable \"", token,
976
                "\": missing object context\"",
977
                (char*)NULL);
978
            result = TCL_ERROR;
979
            goto scopeCmdDone;
980
        }
981
        contextObj = (ItclObject*)Tcl_GetHashValue(entry);
982
 
983
        Tcl_AppendElement(interp, "@itcl");
984
 
985
        objPtr = Tcl_NewStringObj((char*)NULL, 0);
986
        Tcl_IncrRefCount(objPtr);
987
        Tcl_GetCommandFullName(interp, contextObj->accessCmd, objPtr);
988
        Tcl_AppendElement(interp, Tcl_GetStringFromObj(objPtr, (int*)NULL));
989
        Tcl_DecrRefCount(objPtr);
990
 
991
        objPtr = Tcl_NewStringObj((char*)NULL, 0);
992
        Tcl_IncrRefCount(objPtr);
993
        Tcl_AppendToObj(objPtr, vlookup->vdefn->member->fullname, -1);
994
 
995
        if (openParen) {
996
            *openParen = '(';
997
            Tcl_AppendToObj(objPtr, openParen, -1);
998
            openParen = NULL;
999
        }
1000
        Tcl_AppendElement(interp, Tcl_GetStringFromObj(objPtr, (int*)NULL));
1001
        Tcl_DecrRefCount(objPtr);
1002
    }
1003
 
1004
    /*
1005
     *  We must be in an ordinary namespace context.  Resolve
1006
     *  the variable using Tcl_FindNamespaceVar.
1007
     *
1008
     *  TRICKY NOTE:  If this is an array reference, we'll get
1009
     *    the array variable as the variable name.  We must be
1010
     *    careful to add the index (everything from openParen
1011
     *    onward) as well.
1012
     */
1013
    else {
1014
        Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
1015
 
1016
        var = Tcl_FindNamespaceVar(interp, token, contextNs,
1017
            TCL_NAMESPACE_ONLY);
1018
 
1019
        if (!var) {
1020
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1021
                "variable \"", token, "\" not found in namespace \"",
1022
                contextNs->fullName, "\"",
1023
                (char*)NULL);
1024
            result = TCL_ERROR;
1025
            goto scopeCmdDone;
1026
        }
1027
 
1028
        Tcl_GetVariableFullName(interp, var, resultPtr);
1029
        if (openParen) {
1030
            *openParen = '(';
1031
            Tcl_AppendToObj(resultPtr, openParen, -1);
1032
            openParen = NULL;
1033
        }
1034
    }
1035
 
1036
scopeCmdDone:
1037
    if (openParen) {
1038
        *openParen = '(';
1039
    }
1040
    return result;
1041
}
1042
 
1043
 
1044
/*
1045
 * ------------------------------------------------------------------------
1046
 *  Itcl_CodeCmd()
1047
 *
1048
 *  Invoked by Tcl whenever the user issues a "code" command to
1049
 *  create a scoped command string.  Handles the following syntax:
1050
 *
1051
 *    code ?-namespace foo? arg ?arg arg ...?
1052
 *
1053
 *  Unlike the scope command, the code command DOES NOT look for
1054
 *  scoping information at the beginning of the command.  So scopes
1055
 *  will nest in the code command.
1056
 *
1057
 *  The code command is similar to the "namespace code" command in
1058
 *  Tcl, but it preserves the list structure of the input arguments,
1059
 *  so it is a lot more useful.
1060
 *
1061
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
1062
 * ------------------------------------------------------------------------
1063
 */
1064
/* ARGSUSED */
1065
int
1066
Itcl_CodeCmd(dummy, interp, objc, objv)
1067
    ClientData dummy;        /* unused */
1068
    Tcl_Interp *interp;      /* current interpreter */
1069
    int objc;                /* number of arguments */
1070
    Tcl_Obj *CONST objv[];   /* argument objects */
1071
{
1072
    Tcl_Namespace *contextNs = Tcl_GetCurrentNamespace(interp);
1073
 
1074
    int pos;
1075
    char *token;
1076
    Tcl_Obj *listPtr, *objPtr;
1077
 
1078
    /*
1079
     *  Handle flags like "-namespace"...
1080
     */
1081
    for (pos=1; pos < objc; pos++) {
1082
        token = Tcl_GetStringFromObj(objv[pos], (int*)NULL);
1083
        if (*token != '-') {
1084
            break;
1085
        }
1086
 
1087
        if (strcmp(token, "-namespace") == 0) {
1088
            if (objc == 2) {
1089
                Tcl_WrongNumArgs(interp, 1, objv,
1090
                    "?-namespace name? command ?arg arg...?");
1091
                return TCL_ERROR;
1092
            } else {
1093
                token = Tcl_GetStringFromObj(objv[pos+1], (int*)NULL);
1094
                contextNs = Tcl_FindNamespace(interp, token,
1095
                    (Tcl_Namespace*)NULL, TCL_LEAVE_ERR_MSG);
1096
 
1097
                if (!contextNs) {
1098
                    return TCL_ERROR;
1099
                }
1100
                pos++;
1101
            }
1102
        }
1103
        else if (strcmp(token, "--") == 0) {
1104
            pos++;
1105
            break;
1106
        }
1107
        else {
1108
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1109
                "bad option \"", token, "\": should be -namespace or --",
1110
                (char*)NULL);
1111
            return TCL_ERROR;
1112
        }
1113
    }
1114
 
1115
    if (objc < 2) {
1116
        Tcl_WrongNumArgs(interp, 1, objv,
1117
            "?-namespace name? command ?arg arg...?");
1118
        return TCL_ERROR;
1119
    }
1120
 
1121
    /*
1122
     *  Now construct a scoped command by integrating the
1123
     *  current namespace context, and appending the remaining
1124
     *  arguments AS A LIST...
1125
     */
1126
    listPtr = Tcl_NewListObj(0, (Tcl_Obj**)NULL);
1127
 
1128
    Tcl_ListObjAppendElement(interp, listPtr,
1129
        Tcl_NewStringObj("namespace", -1));
1130
    Tcl_ListObjAppendElement(interp, listPtr,
1131
        Tcl_NewStringObj("inscope", -1));
1132
 
1133
    if (contextNs == Tcl_GetGlobalNamespace(interp)) {
1134
        objPtr = Tcl_NewStringObj("::", -1);
1135
    } else {
1136
        objPtr = Tcl_NewStringObj(contextNs->fullName, -1);
1137
    }
1138
    Tcl_ListObjAppendElement(interp, listPtr, objPtr);
1139
 
1140
    if (objc-pos == 1) {
1141
        objPtr = objv[pos];
1142
    } else {
1143
        objPtr = Tcl_NewListObj(objc-pos, &objv[pos]);
1144
    }
1145
    Tcl_ListObjAppendElement(interp, listPtr, objPtr);
1146
 
1147
    Tcl_SetObjResult(interp, listPtr);
1148
    return TCL_OK;
1149
}
1150
 
1151
 
1152
/*
1153
 * ------------------------------------------------------------------------
1154
 *  Itcl_StubCreateCmd()
1155
 *
1156
 *  Invoked by Tcl whenever the user issues a "stub create" command to
1157
 *  create an autoloading stub for imported commands.  Handles the
1158
 *  following syntax:
1159
 *
1160
 *    stub create <name>
1161
 *
1162
 *  Creates a command called <name>.  Executing this command will cause
1163
 *  the real command <name> to be autoloaded.
1164
 * ------------------------------------------------------------------------
1165
 */
1166
int
1167
Itcl_StubCreateCmd(clientData, interp, objc, objv)
1168
    ClientData clientData;   /* not used */
1169
    Tcl_Interp *interp;      /* current interpreter */
1170
    int objc;                /* number of arguments */
1171
    Tcl_Obj *CONST objv[];   /* argument objects */
1172
{
1173
    char *cmdName;
1174
    Command *cmdPtr;
1175
 
1176
    if (objc != 2) {
1177
        Tcl_WrongNumArgs(interp, 1, objv, "name");
1178
        return TCL_ERROR;
1179
    }
1180
    cmdName = Tcl_GetStringFromObj(objv[1], (int*)NULL);
1181
 
1182
    /*
1183
     *  Create a stub command with the characteristic ItclDeleteStub
1184
     *  procedure.  That way, we can recognize this command later
1185
     *  on as a stub.  Save the cmd token as client data, so we can
1186
     *  get the full name of this command later on.
1187
     */
1188
    cmdPtr = (Command *) Tcl_CreateObjCommand(interp, cmdName,
1189
        ItclHandleStubCmd, (ClientData)NULL,
1190
        (Tcl_CmdDeleteProc*)ItclDeleteStub);
1191
 
1192
    cmdPtr->objClientData = (ClientData) cmdPtr;
1193
 
1194
    return TCL_OK;
1195
}
1196
 
1197
 
1198
/*
1199
 * ------------------------------------------------------------------------
1200
 *  Itcl_StubExistsCmd()
1201
 *
1202
 *  Invoked by Tcl whenever the user issues a "stub exists" command to
1203
 *  see if an existing command is an autoloading stub.  Handles the
1204
 *  following syntax:
1205
 *
1206
 *    stub exists <name>
1207
 *
1208
 *  Looks for a command called <name> and checks to see if it is an
1209
 *  autoloading stub.  Returns a boolean result.
1210
 * ------------------------------------------------------------------------
1211
 */
1212
int
1213
Itcl_StubExistsCmd(clientData, interp, objc, objv)
1214
    ClientData clientData;   /* not used */
1215
    Tcl_Interp *interp;      /* current interpreter */
1216
    int objc;                /* number of arguments */
1217
    Tcl_Obj *CONST objv[];   /* argument objects */
1218
{
1219
    char *cmdName;
1220
    Tcl_Command cmd;
1221
 
1222
    if (objc != 2) {
1223
        Tcl_WrongNumArgs(interp, 1, objv, "name");
1224
        return TCL_ERROR;
1225
    }
1226
    cmdName = Tcl_GetStringFromObj(objv[1], (int*)NULL);
1227
 
1228
    cmd = Tcl_FindCommand(interp, cmdName, (Tcl_Namespace*)NULL, 0);
1229
 
1230
    if (cmd != NULL && Itcl_IsStub(cmd)) {
1231
        Tcl_SetIntObj(Tcl_GetObjResult(interp), 1);
1232
    } else {
1233
        Tcl_SetIntObj(Tcl_GetObjResult(interp), 0);
1234
    }
1235
    return TCL_OK;
1236
}
1237
 
1238
 
1239
/*
1240
 * ------------------------------------------------------------------------
1241
 *  Itcl_IsStub()
1242
 *
1243
 *  Checks the given Tcl command to see if it represents an autoloading
1244
 *  stub created by the "stub create" command.  Returns non-zero if
1245
 *  the command is indeed a stub.
1246
 * ------------------------------------------------------------------------
1247
 */
1248
int
1249
Itcl_IsStub(cmd)
1250
    Tcl_Command cmd;         /* command being tested */
1251
{
1252
    Command *cmdPtr = (Command*)cmd;
1253
 
1254
    /*
1255
     *  This may be an imported command, but don't try to get the
1256
     *  original.  Just check to see if this particular command
1257
     *  is a stub.  If we really want the original command, we'll
1258
     *  find it at a higher level.
1259
     */
1260
    if (cmdPtr->deleteProc == ItclDeleteStub) {
1261
        return 1;
1262
    }
1263
    return 0;
1264
}
1265
 
1266
 
1267
/*
1268
 * ------------------------------------------------------------------------
1269
 *  ItclHandleStubCmd()
1270
 *
1271
 *  Invoked by Tcl to handle commands created by "stub create".
1272
 *  Calls "auto_load" with the full name of the current command to
1273
 *  trigger autoloading of the real implementation.  Then, calls the
1274
 *  command to handle its function.  If successful, this command
1275
 *  returns TCL_OK along with the result from the real implementation
1276
 *  of this command.  Otherwise, it returns TCL_ERROR, along with an
1277
 *  error message in the interpreter.
1278
 * ------------------------------------------------------------------------
1279
 */
1280
static int
1281
ItclHandleStubCmd(clientData, interp, objc, objv)
1282
    ClientData clientData;   /* command token for this stub */
1283
    Tcl_Interp *interp;      /* current interpreter */
1284
    int objc;                /* number of arguments */
1285
    Tcl_Obj *CONST objv[];   /* argument objects */
1286
{
1287
    Tcl_Command cmd = (Tcl_Command) clientData;
1288
 
1289
    int result, loaded;
1290
    char *cmdName;
1291
    int cmdlinec;
1292
    Tcl_Obj **cmdlinev;
1293
    Tcl_Obj *objAutoLoad[2], *objPtr, *cmdNamePtr, *cmdlinePtr;
1294
 
1295
    cmdNamePtr = Tcl_NewStringObj((char*)NULL, 0);
1296
    Tcl_GetCommandFullName(interp, cmd, cmdNamePtr);
1297
    Tcl_IncrRefCount(cmdNamePtr);
1298
    cmdName = Tcl_GetStringFromObj(cmdNamePtr, (int*)NULL);
1299
 
1300
    /*
1301
     *  Try to autoload the real command for this stub.
1302
     */
1303
    objAutoLoad[0] = Tcl_NewStringObj("::auto_load", -1);
1304
    Tcl_IncrRefCount(objAutoLoad[0]);
1305
    objAutoLoad[1] = cmdNamePtr;
1306
    Tcl_IncrRefCount(objAutoLoad[1]);
1307
 
1308
    result = Itcl_EvalArgs(interp, 2, objAutoLoad);
1309
 
1310
    Tcl_DecrRefCount(objAutoLoad[0]);
1311
    Tcl_DecrRefCount(objAutoLoad[1]);
1312
 
1313
    if (result != TCL_OK) {
1314
        Tcl_DecrRefCount(cmdNamePtr);
1315
        return TCL_ERROR;
1316
    }
1317
 
1318
    objPtr = Tcl_GetObjResult(interp);
1319
    result = Tcl_GetIntFromObj(interp, objPtr, &loaded);
1320
    if (result != TCL_OK || !loaded) {
1321
        Tcl_ResetResult(interp);
1322
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1323
            "can't autoload \"", cmdName, "\"", (char*)NULL);
1324
        Tcl_DecrRefCount(cmdNamePtr);
1325
        return TCL_ERROR;
1326
    }
1327
 
1328
    /*
1329
     *  At this point, the real implementation has been loaded.
1330
     *  Invoke the command again with the arguments passed in.
1331
     */
1332
    cmdlinePtr = Itcl_CreateArgs(interp, cmdName, objc-1, objv+1);
1333
 
1334
    (void) Tcl_ListObjGetElements((Tcl_Interp*)NULL, cmdlinePtr,
1335
        &cmdlinec, &cmdlinev);
1336
 
1337
    Tcl_ResetResult(interp);
1338
    result = Itcl_EvalArgs(interp, cmdlinec, cmdlinev);
1339
    Tcl_DecrRefCount(cmdlinePtr);
1340
 
1341
    return result;
1342
}
1343
 
1344
 
1345
/*
1346
 * ------------------------------------------------------------------------
1347
 *  ItclDeleteStub()
1348
 *
1349
 *  Invoked by Tcl whenever a stub command is deleted.  This procedure
1350
 *  does nothing, but its presence identifies a command as a stub.
1351
 * ------------------------------------------------------------------------
1352
 */
1353
/* ARGSUSED */
1354
static void
1355
ItclDeleteStub(cdata)
1356
    ClientData cdata;      /* not used */
1357
{
1358
    /* do nothing */
1359
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.