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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [itcl/] [itcl/] [generic/] [itcl_bicmds.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
 *  These procedures handle built-in class methods, including the
16
 *  "isa" method (to query hierarchy info) and the "info" method
17
 *  (to query class/object data).
18
 *
19
 * ========================================================================
20
 *  AUTHOR:  Michael J. McLennan
21
 *           Bell Labs Innovations for Lucent Technologies
22
 *           mmclennan@lucent.com
23
 *           http://www.tcltk.com/itcl
24
 *
25
 *     RCS:  $Id: itcl_bicmds.c,v 1.1.1.1 2002-01-16 10:24:46 markom Exp $
26
 * ========================================================================
27
 *           Copyright (c) 1993-1998  Lucent Technologies, Inc.
28
 * ------------------------------------------------------------------------
29
 * See the file "license.terms" for information on usage and redistribution
30
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
31
 */
32
#include "itclInt.h"
33
 
34
/*
35
 *  Standard list of built-in methods for all objects.
36
 */
37
typedef struct BiMethod {
38
    char* name;              /* method name */
39
    char* usage;             /* string describing usage */
40
    char* registration;      /* registration name for C proc */
41
    Tcl_ObjCmdProc *proc;    /* implementation C proc */
42
} BiMethod;
43
 
44
static BiMethod BiMethodList[] = {
45
    { "cget",      "-option",
46
                   "@itcl-builtin-cget",  Itcl_BiCgetCmd },
47
    { "configure", "?-option? ?value -option value...?",
48
                   "@itcl-builtin-configure",  Itcl_BiConfigureCmd },
49
    { "isa",       "className",
50
                   "@itcl-builtin-isa",  Itcl_BiIsaCmd },
51
};
52
static int BiMethodListLen = sizeof(BiMethodList)/sizeof(BiMethod);
53
 
54
 
55
/*
56
 *  FORWARD DECLARATIONS
57
 */
58
static Tcl_Obj* ItclReportPublicOpt _ANSI_ARGS_((Tcl_Interp *interp,
59
    ItclVarDefn *vdefn, ItclObject *contextObj));
60
 
61
 
62
/*
63
 * ------------------------------------------------------------------------
64
 *  Itcl_BiInit()
65
 *
66
 *  Creates a namespace full of built-in methods/procs for [incr Tcl]
67
 *  classes.  This includes things like the "isa" method and "info"
68
 *  for querying class info.  Usually invoked by Itcl_Init() when
69
 *  [incr Tcl] is first installed into an interpreter.
70
 *
71
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
72
 * ------------------------------------------------------------------------
73
 */
74
int
75
Itcl_BiInit(interp)
76
    Tcl_Interp *interp;      /* current interpreter */
77
{
78
    int i;
79
    Tcl_Namespace *itclBiNs;
80
 
81
    /*
82
     *  Declare all of the built-in methods as C procedures.
83
     */
84
    for (i=0; i < BiMethodListLen; i++) {
85
        if (Itcl_RegisterObjC(interp,
86
                BiMethodList[i].registration+1, BiMethodList[i].proc,
87
                (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL) != TCL_OK) {
88
 
89
            return TCL_ERROR;
90
        }
91
    }
92
 
93
    /*
94
     *  Create the "::itcl::builtin" namespace for built-in class
95
     *  commands.  These commands are imported into each class
96
     *  just before the class definition is parsed.
97
     */
98
    Tcl_CreateObjCommand(interp, "::itcl::builtin::chain", Itcl_BiChainCmd,
99
        (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
100
 
101
    if (Itcl_CreateEnsemble(interp, "::itcl::builtin::info") != TCL_OK) {
102
        return TCL_ERROR;
103
    }
104
 
105
    if (Itcl_AddEnsemblePart(interp, "::itcl::builtin::info",
106
            "class", "",
107
            Itcl_BiInfoClassCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL)
108
            != TCL_OK ||
109
        Itcl_AddEnsemblePart(interp, "::itcl::builtin::info",
110
            "inherit", "",
111
            Itcl_BiInfoInheritCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL)
112
            != TCL_OK ||
113
        Itcl_AddEnsemblePart(interp, "::itcl::builtin::info",
114
            "heritage", "",
115
            Itcl_BiInfoHeritageCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL)
116
            != TCL_OK ||
117
        Itcl_AddEnsemblePart(interp, "::itcl::builtin::info",
118
            "function", "?name? ?-protection? ?-type? ?-name? ?-args? ?-body?",
119
            Itcl_BiInfoFunctionCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL)
120
            != TCL_OK ||
121
        Itcl_AddEnsemblePart(interp, "::itcl::builtin::info",
122
            "variable", "?name? ?-protection? ?-type? ?-name? ?-init? ?-value? ?-config?",
123
            Itcl_BiInfoVariableCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL)
124
            != TCL_OK ||
125
        Itcl_AddEnsemblePart(interp, "::itcl::builtin::info",
126
            "args", "procname",
127
            Itcl_BiInfoArgsCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL)
128
            != TCL_OK ||
129
        Itcl_AddEnsemblePart(interp, "::itcl::builtin::info",
130
            "body", "procname",
131
            Itcl_BiInfoBodyCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL)
132
            != TCL_OK
133
    ) {
134
        return TCL_ERROR;
135
    }
136
 
137
    /*
138
     *  Add an error handler to support all of the usual inquiries
139
     *  for the "info" command in the global namespace.
140
     */
141
    if (Itcl_AddEnsemblePart(interp, "::itcl::builtin::info",
142
            "@error", "",
143
            Itcl_DefaultInfoCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL)
144
            != TCL_OK
145
    ) {
146
        return TCL_ERROR;
147
    }
148
 
149
    /*
150
     *  Export all commands in the built-in namespace so we can
151
     *  import them later on.
152
     */
153
    itclBiNs = Tcl_FindNamespace(interp, "::itcl::builtin",
154
        (Tcl_Namespace*)NULL, TCL_LEAVE_ERR_MSG);
155
 
156
    if (!itclBiNs ||
157
        Tcl_Export(interp, itclBiNs, "*", /* resetListFirst */ 1) != TCL_OK) {
158
        return TCL_ERROR;
159
    }
160
 
161
    return TCL_OK;
162
}
163
 
164
 
165
/*
166
 * ------------------------------------------------------------------------
167
 *  Itcl_InstallBiMethods()
168
 *
169
 *  Invoked when a class is first created, just after the class
170
 *  definition has been parsed, to add definitions for built-in
171
 *  methods to the class.  If a method already exists in the class
172
 *  with the same name as the built-in, then the built-in is skipped.
173
 *  Otherwise, a method definition for the built-in method is added.
174
 *
175
 *  Returns TCL_OK if successful, or TCL_ERROR (along with an error
176
 *  message in the interpreter) if anything goes wrong.
177
 * ------------------------------------------------------------------------
178
 */
179
int
180
Itcl_InstallBiMethods(interp, cdefn)
181
    Tcl_Interp *interp;      /* current interpreter */
182
    ItclClass *cdefn;        /* class definition to be updated */
183
{
184
    int result = TCL_OK;
185
    Tcl_HashEntry *entry = NULL;
186
 
187
    int i;
188
    ItclHierIter hier;
189
    ItclClass *cdPtr;
190
 
191
    /*
192
     *  Scan through all of the built-in methods and see if
193
     *  that method already exists in the class.  If not, add
194
     *  it in.
195
     *
196
     *  TRICKY NOTE:  The virtual tables haven't been built yet,
197
     *    so look for existing methods the hard way--by scanning
198
     *    through all classes.
199
     */
200
    for (i=0; i < BiMethodListLen; i++) {
201
        Itcl_InitHierIter(&hier, cdefn);
202
        cdPtr = Itcl_AdvanceHierIter(&hier);
203
        while (cdPtr) {
204
            entry = Tcl_FindHashEntry(&cdPtr->functions, BiMethodList[i].name);
205
            if (entry) {
206
                break;
207
            }
208
            cdPtr = Itcl_AdvanceHierIter(&hier);
209
        }
210
        Itcl_DeleteHierIter(&hier);
211
 
212
        if (!entry) {
213
            result = Itcl_CreateMethod(interp, cdefn, BiMethodList[i].name,
214
                BiMethodList[i].usage, BiMethodList[i].registration);
215
 
216
            if (result != TCL_OK) {
217
                break;
218
            }
219
        }
220
    }
221
    return result;
222
}
223
 
224
 
225
/*
226
 * ------------------------------------------------------------------------
227
 *  Itcl_BiIsaCmd()
228
 *
229
 *  Invoked whenever the user issues the "isa" method for an object.
230
 *  Handles the following syntax:
231
 *
232
 *    <objName> isa <className>
233
 *
234
 *  Checks to see if the object has the given <className> anywhere
235
 *  in its heritage.  Returns 1 if so, and 0 otherwise.
236
 * ------------------------------------------------------------------------
237
 */
238
/* ARGSUSED */
239
int
240
Itcl_BiIsaCmd(clientData, interp, objc, objv)
241
    ClientData clientData;   /* class definition */
242
    Tcl_Interp *interp;      /* current interpreter */
243
    int objc;                /* number of arguments */
244
    Tcl_Obj *CONST objv[];   /* argument objects */
245
{
246
    ItclClass *contextClass, *cdefn;
247
    ItclObject *contextObj;
248
    char *token;
249
 
250
    /*
251
     *  Make sure that this command is being invoked in the proper
252
     *  context.
253
     */
254
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK) {
255
        return TCL_ERROR;
256
    }
257
 
258
    if (!contextObj) {
259
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
260
            "improper usage: should be \"object isa className\"",
261
            (char*)NULL);
262
        return TCL_ERROR;
263
    }
264
    if (objc != 2) {
265
        token = Tcl_GetStringFromObj(objv[0], (int*)NULL);
266
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
267
            "wrong # args: should be \"object ", token, " className\"",
268
            (char*)NULL);
269
        return TCL_ERROR;
270
    }
271
 
272
    /*
273
     *  Look for the requested class.  If it is not found, then
274
     *  try to autoload it.  If it absolutely cannot be found,
275
     *  signal an error.
276
     */
277
    token = Tcl_GetStringFromObj(objv[1], (int*)NULL);
278
    cdefn = Itcl_FindClass(interp, token, /* autoload */ 1);
279
    if (cdefn == NULL) {
280
        return TCL_ERROR;
281
    }
282
 
283
    if (Itcl_ObjectIsa(contextObj, cdefn)) {
284
        Tcl_SetIntObj(Tcl_GetObjResult(interp), 1);
285
    } else {
286
        Tcl_SetIntObj(Tcl_GetObjResult(interp), 0);
287
    }
288
    return TCL_OK;
289
}
290
 
291
 
292
/*
293
 * ------------------------------------------------------------------------
294
 *  Itcl_BiConfigureCmd()
295
 *
296
 *  Invoked whenever the user issues the "configure" method for an object.
297
 *  Handles the following syntax:
298
 *
299
 *    <objName> configure ?-<option>? ?<value> -<option> <value>...?
300
 *
301
 *  Allows access to public variables as if they were configuration
302
 *  options.  With no arguments, this command returns the current
303
 *  list of public variable options.  If -<option> is specified,
304
 *  this returns the information for just one option:
305
 *
306
 *    -<optionName> <initVal> <currentVal>
307
 *
308
 *  Otherwise, the list of arguments is parsed, and values are
309
 *  assigned to the various public variable options.  When each
310
 *  option changes, a big of "config" code associated with the option
311
 *  is executed, to bring the object up to date.
312
 * ------------------------------------------------------------------------
313
 */
314
/* ARGSUSED */
315
int
316
Itcl_BiConfigureCmd(clientData, interp, objc, objv)
317
    ClientData clientData;   /* class definition */
318
    Tcl_Interp *interp;      /* current interpreter */
319
    int objc;                /* number of arguments */
320
    Tcl_Obj *CONST objv[];   /* argument objects */
321
{
322
    ItclClass *contextClass;
323
    ItclObject *contextObj;
324
 
325
    int i, result;
326
    char *token, *lastval;
327
    ItclClass *cdPtr;
328
    Tcl_HashSearch place;
329
    Tcl_HashEntry *entry;
330
    ItclVarDefn *vdefn;
331
    ItclVarLookup *vlookup;
332
    ItclMember *member;
333
    ItclMemberCode *mcode;
334
    ItclHierIter hier;
335
    Tcl_Obj *resultPtr, *objPtr;
336
    Tcl_DString buffer;
337
    ItclContext context;
338
    Tcl_CallFrame *oldFramePtr, *uplevelFramePtr;
339
 
340
    /*
341
     *  Make sure that this command is being invoked in the proper
342
     *  context.
343
     */
344
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK) {
345
        return TCL_ERROR;
346
    }
347
 
348
    if (!contextObj) {
349
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
350
            "improper usage: should be ",
351
            "\"object configure ?-option? ?value -option value...?\"",
352
            (char*)NULL);
353
        return TCL_ERROR;
354
    }
355
 
356
    /*
357
     *  BE CAREFUL:  work in the virtual scope!
358
     */
359
    contextClass = contextObj->classDefn;
360
 
361
    /*
362
     *  HANDLE:  configure
363
     */
364
    if (objc == 1) {
365
        resultPtr = Tcl_NewListObj(0, (Tcl_Obj**)NULL);
366
 
367
        Itcl_InitHierIter(&hier, contextClass);
368
        while ((cdPtr=Itcl_AdvanceHierIter(&hier)) != NULL) {
369
            entry = Tcl_FirstHashEntry(&cdPtr->variables, &place);
370
            while (entry) {
371
                vdefn = (ItclVarDefn*)Tcl_GetHashValue(entry);
372
                if (vdefn->member->protection == ITCL_PUBLIC) {
373
                    objPtr = ItclReportPublicOpt(interp, vdefn, contextObj);
374
 
375
                    Tcl_ListObjAppendElement((Tcl_Interp*)NULL, resultPtr,
376
                        objPtr);
377
                }
378
                entry = Tcl_NextHashEntry(&place);
379
            }
380
        }
381
        Itcl_DeleteHierIter(&hier);
382
 
383
        Tcl_SetObjResult(interp, resultPtr);
384
        return TCL_OK;
385
    }
386
 
387
    /*
388
     *  HANDLE:  configure -option
389
     */
390
    else if (objc == 2) {
391
        token = Tcl_GetStringFromObj(objv[1], (int*)NULL);
392
        if (*token != '-') {
393
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
394
                "improper usage: should be ",
395
                "\"object configure ?-option? ?value -option value...?\"",
396
                (char*)NULL);
397
            return TCL_ERROR;
398
        }
399
 
400
        vlookup = NULL;
401
        entry = Tcl_FindHashEntry(&contextClass->resolveVars, token+1);
402
        if (entry) {
403
            vlookup = (ItclVarLookup*)Tcl_GetHashValue(entry);
404
 
405
            if (vlookup->vdefn->member->protection != ITCL_PUBLIC) {
406
                vlookup = NULL;
407
            }
408
        }
409
 
410
        if (!vlookup) {
411
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
412
                "unknown option \"", token, "\"",
413
                (char*)NULL);
414
            return TCL_ERROR;
415
        }
416
 
417
        resultPtr = ItclReportPublicOpt(interp, vlookup->vdefn, contextObj);
418
        Tcl_SetObjResult(interp, resultPtr);
419
        return TCL_OK;
420
    }
421
 
422
    /*
423
     *  HANDLE:  configure -option value -option value...
424
     *
425
     *  Be careful to work in the virtual scope.  If this "configure"
426
     *  method was defined in a base class, the current namespace
427
     *  (from Itcl_ExecMethod()) will be that base class.  Activate
428
     *  the derived class namespace here, so that instance variables
429
     *  are accessed properly.
430
     */
431
    result = TCL_OK;
432
 
433
    if (Itcl_PushContext(interp, (ItclMember*)NULL, contextObj->classDefn,
434
        contextObj, &context) != TCL_OK) {
435
        return TCL_ERROR;
436
    }
437
    Tcl_DStringInit(&buffer);
438
 
439
    for (i=1; i < objc; i+=2) {
440
        vlookup = NULL;
441
        token = Tcl_GetStringFromObj(objv[i], (int*)NULL);
442
        if (*token == '-') {
443
            entry = Tcl_FindHashEntry(&contextClass->resolveVars, token+1);
444
            if (entry) {
445
                vlookup = (ItclVarLookup*)Tcl_GetHashValue(entry);
446
            }
447
        }
448
 
449
        if (!vlookup || vlookup->vdefn->member->protection != ITCL_PUBLIC) {
450
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
451
                "unknown option \"", token, "\"",
452
                (char*)NULL);
453
            result = TCL_ERROR;
454
            goto configureDone;
455
        }
456
        if (i == objc-1) {
457
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
458
                "value for \"", token, "\" missing",
459
                (char*)NULL);
460
            result = TCL_ERROR;
461
            goto configureDone;
462
        }
463
 
464
        member = vlookup->vdefn->member;
465
        lastval = Tcl_GetVar2(interp, member->fullname, (char*)NULL, 0);
466
        Tcl_DStringSetLength(&buffer, 0);
467
        Tcl_DStringAppend(&buffer, (lastval) ? lastval : "", -1);
468
 
469
        token = Tcl_GetStringFromObj(objv[i+1], (int*)NULL);
470
 
471
        if (Tcl_SetVar2(interp, member->fullname, (char*)NULL, token,
472
            TCL_LEAVE_ERR_MSG) == NULL) {
473
 
474
            char msg[256];
475
            sprintf(msg, "\n    (error in configuration of public variable \"%.100s\")", member->fullname);
476
            Tcl_AddErrorInfo(interp, msg);
477
            result = TCL_ERROR;
478
            goto configureDone;
479
        }
480
 
481
        /*
482
         *  If this variable has some "config" code, invoke it now.
483
         *
484
         *  TRICKY NOTE:  Be careful to evaluate the code one level
485
         *    up in the call stack, so that it's executed in the
486
         *    calling context, and not in the context that we've
487
         *    set up for public variable access.
488
         */
489
        mcode = member->code;
490
        if (mcode && mcode->procPtr->bodyPtr) {
491
 
492
            uplevelFramePtr = _Tcl_GetCallFrame(interp, 1);
493
            oldFramePtr = _Tcl_ActivateCallFrame(interp, uplevelFramePtr);
494
 
495
            result = Itcl_EvalMemberCode(interp, (ItclMemberFunc*)NULL,
496
                member, contextObj, 0, (Tcl_Obj**)NULL);
497
 
498
            (void) _Tcl_ActivateCallFrame(interp, oldFramePtr);
499
 
500
            if (result == TCL_OK) {
501
                Tcl_ResetResult(interp);
502
            } else {
503
                char msg[256];
504
                sprintf(msg, "\n    (error in configuration of public variable \"%.100s\")", member->fullname);
505
                Tcl_AddErrorInfo(interp, msg);
506
 
507
                Tcl_SetVar2(interp, member->fullname,(char*)NULL,
508
                    Tcl_DStringValue(&buffer), 0);
509
 
510
                goto configureDone;
511
            }
512
        }
513
    }
514
 
515
configureDone:
516
    Itcl_PopContext(interp, &context);
517
    Tcl_DStringFree(&buffer);
518
 
519
    return result;
520
}
521
 
522
 
523
/*
524
 * ------------------------------------------------------------------------
525
 *  Itcl_BiCgetCmd()
526
 *
527
 *  Invoked whenever the user issues the "cget" method for an object.
528
 *  Handles the following syntax:
529
 *
530
 *    <objName> cget -<option>
531
 *
532
 *  Allows access to public variables as if they were configuration
533
 *  options.  Mimics the behavior of the usual "cget" method for
534
 *  Tk widgets.  Returns the current value of the public variable
535
 *  with name <option>.
536
 * ------------------------------------------------------------------------
537
 */
538
/* ARGSUSED */
539
int
540
Itcl_BiCgetCmd(clientData, interp, objc, objv)
541
    ClientData clientData;   /* class definition */
542
    Tcl_Interp *interp;      /* current interpreter */
543
    int objc;                /* number of arguments */
544
    Tcl_Obj *CONST objv[];   /* argument objects */
545
{
546
    ItclClass *contextClass;
547
    ItclObject *contextObj;
548
 
549
    char *name, *val;
550
    ItclVarLookup *vlookup;
551
    Tcl_HashEntry *entry;
552
 
553
    /*
554
     *  Make sure that this command is being invoked in the proper
555
     *  context.
556
     */
557
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK) {
558
        return TCL_ERROR;
559
    }
560
    if (!contextObj || objc != 2) {
561
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
562
            "improper usage: should be \"object cget -option\"",
563
            (char*)NULL);
564
        return TCL_ERROR;
565
    }
566
 
567
    /*
568
     *  BE CAREFUL:  work in the virtual scope!
569
     */
570
    contextClass = contextObj->classDefn;
571
 
572
    name = Tcl_GetStringFromObj(objv[1], (int*)NULL);
573
 
574
    vlookup = NULL;
575
    entry = Tcl_FindHashEntry(&contextClass->resolveVars, name+1);
576
    if (entry) {
577
        vlookup = (ItclVarLookup*)Tcl_GetHashValue(entry);
578
    }
579
 
580
    if (!vlookup || vlookup->vdefn->member->protection != ITCL_PUBLIC) {
581
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
582
            "unknown option \"", name, "\"",
583
            (char*)NULL);
584
        return TCL_ERROR;
585
    }
586
 
587
    val = Itcl_GetInstanceVar(interp, vlookup->vdefn->member->fullname,
588
        contextObj, contextObj->classDefn);
589
 
590
    if (val) {
591
        Tcl_SetResult(interp, val, TCL_VOLATILE);
592
    } else {
593
        Tcl_SetResult(interp, "<undefined>", TCL_STATIC);
594
    }
595
    return TCL_OK;
596
}
597
 
598
 
599
/*
600
 * ------------------------------------------------------------------------
601
 *  ItclReportPublicOpt()
602
 *
603
 *  Returns information about a public variable formatted as a
604
 *  configuration option:
605
 *
606
 *    -<varName> <initVal> <currentVal>
607
 *
608
 *  Used by Itcl_BiConfigureCmd() to report configuration options.
609
 *  Returns a Tcl_Obj containing the information.
610
 * ------------------------------------------------------------------------
611
 */
612
static Tcl_Obj*
613
ItclReportPublicOpt(interp, vdefn, contextObj)
614
    Tcl_Interp *interp;      /* interpreter containing the object */
615
    ItclVarDefn *vdefn;      /* public variable to be reported */
616
    ItclObject *contextObj;  /* object containing this variable */
617
{
618
    char *val;
619
    ItclClass *cdefnPtr;
620
    Tcl_HashEntry *entry;
621
    ItclVarLookup *vlookup;
622
    Tcl_DString optName;
623
    Tcl_Obj *listPtr, *objPtr;
624
 
625
    listPtr = Tcl_NewListObj(0, (Tcl_Obj**)NULL);
626
 
627
    /*
628
     *  Determine how the option name should be reported.
629
     *  If the simple name can be used to find it in the virtual
630
     *  data table, then use the simple name.  Otherwise, this
631
     *  is a shadowed variable; use the full name.
632
     */
633
    Tcl_DStringInit(&optName);
634
    Tcl_DStringAppend(&optName, "-", -1);
635
 
636
    cdefnPtr = (ItclClass*)contextObj->classDefn;
637
    entry = Tcl_FindHashEntry(&cdefnPtr->resolveVars, vdefn->member->fullname);
638
    assert(entry != NULL);
639
    vlookup = (ItclVarLookup*)Tcl_GetHashValue(entry);
640
    Tcl_DStringAppend(&optName, vlookup->leastQualName, -1);
641
 
642
    objPtr = Tcl_NewStringObj(Tcl_DStringValue(&optName), -1);
643
    Tcl_ListObjAppendElement((Tcl_Interp*)NULL, listPtr, objPtr);
644
    Tcl_DStringFree(&optName);
645
 
646
 
647
    if (vdefn->init) {
648
        objPtr = Tcl_NewStringObj(vdefn->init, -1);
649
    } else {
650
        objPtr = Tcl_NewStringObj("<undefined>", -1);
651
    }
652
    Tcl_ListObjAppendElement((Tcl_Interp*)NULL, listPtr, objPtr);
653
 
654
    val = Itcl_GetInstanceVar(interp, vdefn->member->fullname, contextObj,
655
        contextObj->classDefn);
656
 
657
    if (val) {
658
        objPtr = Tcl_NewStringObj(val, -1);
659
    } else {
660
        objPtr = Tcl_NewStringObj("<undefined>", -1);
661
    }
662
    Tcl_ListObjAppendElement((Tcl_Interp*)NULL, listPtr, objPtr);
663
 
664
    return listPtr;
665
}
666
 
667
 
668
/*
669
 * ------------------------------------------------------------------------
670
 *  Itcl_BiChainCmd()
671
 *
672
 *  Invoked to handle the "chain" command, to access the version of
673
 *  a method or proc that exists in a base class.  Handles the
674
 *  following syntax:
675
 *
676
 *    chain ?<arg> <arg>...?
677
 *
678
 *  Looks up the inheritance hierarchy for another implementation
679
 *  of the method/proc that is currently executing.  If another
680
 *  implementation is found, it is invoked with the specified
681
 *  <arg> arguments.  If it is not found, this command does nothing.
682
 *  This allows a base class method to be called out in a generic way,
683
 *  so the code will not have to change if the base class changes.
684
 * ------------------------------------------------------------------------
685
 */
686
/* ARGSUSED */
687
int
688
Itcl_BiChainCmd(dummy, interp, objc, objv)
689
    ClientData dummy;        /* not used */
690
    Tcl_Interp *interp;      /* current interpreter */
691
    int objc;                /* number of arguments */
692
    Tcl_Obj *CONST objv[];   /* argument objects */
693
{
694
    int result = TCL_OK;
695
 
696
    ItclClass *contextClass;
697
    ItclObject *contextObj;
698
 
699
    char *cmd, *head;
700
    ItclClass *cdefn;
701
    ItclHierIter hier;
702
    Tcl_HashEntry *entry;
703
    ItclMemberFunc *mfunc;
704
    Tcl_DString buffer;
705
    CallFrame *framePtr;
706
    Tcl_Obj *cmdlinePtr, **newobjv;
707
 
708
    /*
709
     *  If this command is not invoked within a class namespace,
710
     *  signal an error.
711
     */
712
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK) {
713
        Tcl_ResetResult(interp);
714
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
715
            "cannot chain functions outside of a class context",
716
            (char*)NULL);
717
        return TCL_ERROR;
718
    }
719
 
720
    /*
721
     *  Try to get the command name from the current call frame.
722
     *  If it cannot be determined, do nothing.  Otherwise, trim
723
     *  off any leading path names.
724
     */
725
    framePtr = (CallFrame*) _Tcl_GetCallFrame(interp, 0);
726
    if (!framePtr || !framePtr->objv) {
727
        return TCL_OK;
728
    }
729
    cmd = Tcl_GetStringFromObj(framePtr->objv[0], (int*)NULL);
730
    Itcl_ParseNamespPath(cmd, &buffer, &head, &cmd);
731
 
732
    /*
733
     *  Look for the specified command in one of the base classes.
734
     *  If we have an object context, then start from the most-specific
735
     *  class and walk up the hierarchy to the current context.  If
736
     *  there is multiple inheritance, having the entire inheritance
737
     *  hierarchy will allow us to jump over to another branch of
738
     *  the inheritance tree.
739
     *
740
     *  If there is no object context, just start with the current
741
     *  class context.
742
     */
743
    if (contextObj) {
744
        Itcl_InitHierIter(&hier, contextObj->classDefn);
745
        while ((cdefn=Itcl_AdvanceHierIter(&hier)) != NULL) {
746
            if (cdefn == contextClass) {
747
                break;
748
            }
749
        }
750
    }
751
    else {
752
        Itcl_InitHierIter(&hier, contextClass);
753
        Itcl_AdvanceHierIter(&hier);    /* skip the current class */
754
    }
755
 
756
    /*
757
     *  Now search up the class hierarchy for the next implementation.
758
     *  If found, execute it.  Otherwise, do nothing.
759
     */
760
    while ((cdefn=Itcl_AdvanceHierIter(&hier)) != NULL) {
761
        entry = Tcl_FindHashEntry(&cdefn->functions, cmd);
762
        if (entry) {
763
            mfunc = (ItclMemberFunc*)Tcl_GetHashValue(entry);
764
 
765
            /*
766
             *  NOTE:  Avoid the usual "virtual" behavior of
767
             *         methods by passing the full name as
768
             *         the command argument.
769
             */
770
            cmdlinePtr = Itcl_CreateArgs(interp, mfunc->member->fullname,
771
                objc-1, objv+1);
772
 
773
            (void) Tcl_ListObjGetElements((Tcl_Interp*)NULL, cmdlinePtr,
774
                &objc, &newobjv);
775
 
776
            result = Itcl_EvalArgs(interp, objc, newobjv);
777
 
778
            Tcl_DecrRefCount(cmdlinePtr);
779
            break;
780
        }
781
    }
782
 
783
    Tcl_DStringFree(&buffer);
784
    Itcl_DeleteHierIter(&hier);
785
    return result;
786
}
787
 
788
 
789
/*
790
 * ------------------------------------------------------------------------
791
 *  Itcl_BiInfoClassCmd()
792
 *
793
 *  Returns information regarding the class for an object.  This command
794
 *  can be invoked with or without an object context:
795
 *
796
 *    <objName> info class   <= returns most-specific class name
797
 *    info class             <= returns active namespace name
798
 *
799
 *  Returns a status TCL_OK/TCL_ERROR to indicate success/failure.
800
 * ------------------------------------------------------------------------
801
 */
802
/* ARGSUSED */
803
int
804
Itcl_BiInfoClassCmd(dummy, interp, objc, objv)
805
    ClientData dummy;     /* not used */
806
    Tcl_Interp *interp;   /* current interpreter */
807
    int objc;                /* number of arguments */
808
    Tcl_Obj *CONST objv[];   /* argument objects */
809
{
810
    Tcl_Namespace *activeNs = Tcl_GetCurrentNamespace(interp);
811
    Tcl_Namespace *contextNs = NULL;
812
 
813
    ItclClass *contextClass;
814
    ItclObject *contextObj;
815
 
816
    char *name;
817
 
818
    if (objc != 1) {
819
        Tcl_WrongNumArgs(interp, 1, objv, NULL);
820
        return TCL_ERROR;
821
    }
822
 
823
    /*
824
     *  If this command is not invoked within a class namespace,
825
     *  signal an error.
826
     */
827
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK) {
828
        name = Tcl_GetStringFromObj(objv[0], (int*)NULL);
829
        Tcl_ResetResult(interp);
830
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
831
            "\nget info like this instead: ",
832
            "\n  namespace eval className { info ", name, "... }",
833
            (char*)NULL);
834
        return TCL_ERROR;
835
    }
836
 
837
    /*
838
     *  If there is an object context, then return the most-specific
839
     *  class for the object.  Otherwise, return the class namespace
840
     *  name.  Use normal class names when possible.
841
     */
842
    if (contextObj) {
843
        contextNs = contextObj->classDefn->namesp;
844
    }
845
 
846
    if (contextNs->parentPtr == activeNs) {
847
        name = contextNs->name;
848
    } else {
849
        name = contextNs->fullName;
850
    }
851
 
852
    Tcl_SetResult(interp, name, TCL_VOLATILE);
853
    return TCL_OK;
854
}
855
 
856
 
857
/*
858
 * ------------------------------------------------------------------------
859
 *  Itcl_BiInfoInheritCmd()
860
 *
861
 *  Returns the list of base classes for the current class context.
862
 *  Returns a status TCL_OK/TCL_ERROR to indicate success/failure.
863
 * ------------------------------------------------------------------------
864
 */
865
/* ARGSUSED */
866
int
867
Itcl_BiInfoInheritCmd(dummy, interp, objc, objv)
868
    ClientData dummy;     /* not used */
869
    Tcl_Interp *interp;   /* current interpreter */
870
    int objc;                /* number of arguments */
871
    Tcl_Obj *CONST objv[];   /* argument objects */
872
{
873
    Tcl_Namespace *activeNs = Tcl_GetCurrentNamespace(interp);
874
 
875
    ItclClass *contextClass;
876
    ItclObject *contextObj;
877
 
878
    ItclClass *cdefn;
879
    Itcl_ListElem *elem;
880
    Tcl_Obj *listPtr, *objPtr;
881
 
882
    if (objc != 1) {
883
        Tcl_WrongNumArgs(interp, 1, objv, NULL);
884
        return TCL_ERROR;
885
    }
886
 
887
    /*
888
     *  If this command is not invoked within a class namespace,
889
     *  signal an error.
890
     */
891
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK) {
892
        char *name = Tcl_GetStringFromObj(objv[0], (int*)NULL);
893
        Tcl_ResetResult(interp);
894
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
895
            "\nget info like this instead: ",
896
            "\n  namespace eval className { info ", name, "... }",
897
            (char*)NULL);
898
        return TCL_ERROR;
899
    }
900
 
901
    /*
902
     *  Return the list of base classes.
903
     */
904
    listPtr = Tcl_NewListObj(0, (Tcl_Obj**)NULL);
905
 
906
    elem = Itcl_FirstListElem(&contextClass->bases);
907
    while (elem) {
908
        cdefn = (ItclClass*)Itcl_GetListValue(elem);
909
        if (cdefn->namesp->parentPtr == activeNs) {
910
            objPtr = Tcl_NewStringObj(cdefn->namesp->name, -1);
911
        } else {
912
            objPtr = Tcl_NewStringObj(cdefn->namesp->fullName, -1);
913
        }
914
        Tcl_ListObjAppendElement((Tcl_Interp*)NULL, listPtr, objPtr);
915
        elem = Itcl_NextListElem(elem);
916
    }
917
 
918
    Tcl_SetObjResult(interp, listPtr);
919
    return TCL_OK;
920
}
921
 
922
/*
923
 * ------------------------------------------------------------------------
924
 *  Itcl_BiInfoHeritageCmd()
925
 *
926
 *  Returns the entire derivation hierarchy for this class, presented
927
 *  in the order that classes are traversed for finding data members
928
 *  and member functions.
929
 *
930
 *  Returns a status TCL_OK/TCL_ERROR to indicate success/failure.
931
 * ------------------------------------------------------------------------
932
 */
933
/* ARGSUSED */
934
int
935
Itcl_BiInfoHeritageCmd(dummy, interp, objc, objv)
936
    ClientData dummy;     /* not used */
937
    Tcl_Interp *interp;   /* current interpreter */
938
    int objc;                /* number of arguments */
939
    Tcl_Obj *CONST objv[];   /* argument objects */
940
{
941
    Tcl_Namespace *activeNs = Tcl_GetCurrentNamespace(interp);
942
 
943
    ItclClass *contextClass;
944
    ItclObject *contextObj;
945
 
946
    char *name;
947
    ItclHierIter hier;
948
    Tcl_Obj *listPtr, *objPtr;
949
    ItclClass *cdefn;
950
 
951
    if (objc != 1) {
952
        Tcl_WrongNumArgs(interp, 1, objv, NULL);
953
        return TCL_ERROR;
954
    }
955
 
956
    /*
957
     *  If this command is not invoked within a class namespace,
958
     *  signal an error.
959
     */
960
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK) {
961
        name = Tcl_GetStringFromObj(objv[0], (int*)NULL);
962
        Tcl_ResetResult(interp);
963
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
964
            "\nget info like this instead: ",
965
            "\n  namespace eval className { info ", name, "... }",
966
            (char*)NULL);
967
        return TCL_ERROR;
968
    }
969
 
970
    /*
971
     *  Traverse through the derivation hierarchy and return
972
     *  base class names.
973
     */
974
    listPtr = Tcl_NewListObj(0, (Tcl_Obj**)NULL);
975
 
976
    Itcl_InitHierIter(&hier, contextClass);
977
    while ((cdefn=Itcl_AdvanceHierIter(&hier)) != NULL) {
978
        if (cdefn->namesp->parentPtr == activeNs) {
979
            objPtr = Tcl_NewStringObj(cdefn->namesp->name, -1);
980
        } else {
981
            objPtr = Tcl_NewStringObj(cdefn->namesp->fullName, -1);
982
        }
983
        Tcl_ListObjAppendElement((Tcl_Interp*)NULL, listPtr, objPtr);
984
    }
985
    Itcl_DeleteHierIter(&hier);
986
 
987
    Tcl_SetObjResult(interp, listPtr);
988
    return TCL_OK;
989
}
990
 
991
 
992
/*
993
 * ------------------------------------------------------------------------
994
 *  Itcl_BiInfoFunctionCmd()
995
 *
996
 *  Returns information regarding class member functions (methods/procs).
997
 *  Handles the following syntax:
998
 *
999
 *    info function ?cmdName? ?-protection? ?-type? ?-name? ?-args? ?-body?
1000
 *
1001
 *  If the ?cmdName? is not specified, then a list of all known
1002
 *  command members is returned.  Otherwise, the information for
1003
 *  a specific command is returned.  Returns a status TCL_OK/TCL_ERROR
1004
 *  to indicate success/failure.
1005
 * ------------------------------------------------------------------------
1006
 */
1007
/* ARGSUSED */
1008
int
1009
Itcl_BiInfoFunctionCmd(dummy, interp, objc, objv)
1010
    ClientData dummy;     /* not used */
1011
    Tcl_Interp *interp;   /* current interpreter */
1012
    int objc;                /* number of arguments */
1013
    Tcl_Obj *CONST objv[];   /* argument objects */
1014
{
1015
    char *cmdName = NULL;
1016
    Tcl_Obj *resultPtr = NULL;
1017
    Tcl_Obj *objPtr = NULL;
1018
 
1019
    static char *options[] = {
1020
        "-args", "-body", "-name", "-protection", "-type",
1021
        (char*)NULL
1022
    };
1023
    enum BIfIdx {
1024
        BIfArgsIdx, BIfBodyIdx, BIfNameIdx, BIfProtectIdx, BIfTypeIdx
1025
    } *iflist, iflistStorage[5];
1026
 
1027
    static enum BIfIdx DefInfoFunction[5] = {
1028
        BIfProtectIdx,
1029
        BIfTypeIdx,
1030
        BIfNameIdx,
1031
        BIfArgsIdx,
1032
        BIfBodyIdx
1033
    };
1034
 
1035
    ItclClass *contextClass, *cdefn;
1036
    ItclObject *contextObj;
1037
 
1038
    int i, result;
1039
    char *name, *val;
1040
    Tcl_HashSearch place;
1041
    Tcl_HashEntry *entry;
1042
    ItclMemberFunc *mfunc;
1043
    ItclMemberCode *mcode;
1044
    ItclHierIter hier;
1045
 
1046
    /*
1047
     *  If this command is not invoked within a class namespace,
1048
     *  signal an error.
1049
     */
1050
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK) {
1051
        name = Tcl_GetStringFromObj(objv[0], (int*)NULL);
1052
        Tcl_ResetResult(interp);
1053
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1054
            "\nget info like this instead: ",
1055
            "\n  namespace eval className { info ", name, "... }",
1056
            (char*)NULL);
1057
        return TCL_ERROR;
1058
    }
1059
 
1060
    /*
1061
     *  Process args:
1062
     *  ?cmdName? ?-protection? ?-type? ?-name? ?-args? ?-body?
1063
     */
1064
    objv++;  /* skip over command name */
1065
    objc--;
1066
 
1067
    if (objc > 0) {
1068
        cmdName = Tcl_GetStringFromObj(*objv, (int*)NULL);
1069
        objc--; objv++;
1070
    }
1071
 
1072
    /*
1073
     *  Return info for a specific command.
1074
     */
1075
    if (cmdName) {
1076
        entry = Tcl_FindHashEntry(&contextClass->resolveCmds, cmdName);
1077
        if (entry == NULL) {
1078
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1079
                "\"", cmdName, "\" isn't a member function in class \"",
1080
                contextClass->namesp->fullName, "\"",
1081
                (char*)NULL);
1082
            return TCL_ERROR;
1083
        }
1084
 
1085
        mfunc = (ItclMemberFunc*)Tcl_GetHashValue(entry);
1086
        mcode = mfunc->member->code;
1087
 
1088
        /*
1089
         *  By default, return everything.
1090
         */
1091
        if (objc == 0) {
1092
            objc = 5;
1093
            iflist = DefInfoFunction;
1094
        }
1095
 
1096
        /*
1097
         *  Otherwise, scan through all remaining flags and
1098
         *  figure out what to return.
1099
         */
1100
        else {
1101
            iflist = &iflistStorage[0];
1102
            for (i=0 ; i < objc; i++) {
1103
                result = Tcl_GetIndexFromObj(interp, objv[i],
1104
                    options, "option", 0, (int*)(&iflist[i]));
1105
                if (result != TCL_OK) {
1106
                    return TCL_ERROR;
1107
                }
1108
            }
1109
        }
1110
 
1111
        if (objc > 1) {
1112
            resultPtr = Tcl_NewListObj(0, (Tcl_Obj**)NULL);
1113
        }
1114
 
1115
        for (i=0 ; i < objc; i++) {
1116
            switch (iflist[i]) {
1117
                case BIfArgsIdx:
1118
                    if (mcode && mcode->arglist) {
1119
                        objPtr = Itcl_ArgList(mcode->argcount, mcode->arglist);
1120
                    }
1121
                    else if ((mfunc->member->flags & ITCL_ARG_SPEC) != 0) {
1122
                        objPtr = Itcl_ArgList(mfunc->argcount, mfunc->arglist);
1123
                    }
1124
                    else {
1125
                        objPtr = Tcl_NewStringObj("<undefined>", -1);
1126
                    }
1127
                    break;
1128
 
1129
                case BIfBodyIdx:
1130
                    if (mcode && mcode->procPtr->bodyPtr) {
1131
                        objPtr = mcode->procPtr->bodyPtr;
1132
                    } else {
1133
                        objPtr = Tcl_NewStringObj("<undefined>", -1);
1134
                    }
1135
                    break;
1136
 
1137
                case BIfNameIdx:
1138
                    objPtr = Tcl_NewStringObj(mfunc->member->fullname, -1);
1139
                    break;
1140
 
1141
                case BIfProtectIdx:
1142
                    val = Itcl_ProtectionStr(mfunc->member->protection);
1143
                    objPtr = Tcl_NewStringObj(val, -1);
1144
                    break;
1145
 
1146
                case BIfTypeIdx:
1147
                    val = ((mfunc->member->flags & ITCL_COMMON) != 0)
1148
                        ? "proc" : "method";
1149
                    objPtr = Tcl_NewStringObj(val, -1);
1150
                    break;
1151
            }
1152
 
1153
            if (objc == 1) {
1154
                resultPtr = objPtr;
1155
            } else {
1156
                Tcl_ListObjAppendElement((Tcl_Interp*)NULL, resultPtr, objPtr);
1157
            }
1158
        }
1159
        Tcl_SetObjResult(interp, resultPtr);
1160
    }
1161
 
1162
    /*
1163
     *  Return the list of available commands.
1164
     */
1165
    else {
1166
        resultPtr = Tcl_NewListObj(0, (Tcl_Obj**)NULL);
1167
 
1168
        Itcl_InitHierIter(&hier, contextClass);
1169
        while ((cdefn=Itcl_AdvanceHierIter(&hier)) != NULL) {
1170
            entry = Tcl_FirstHashEntry(&cdefn->functions, &place);
1171
            while (entry) {
1172
                mfunc = (ItclMemberFunc*)Tcl_GetHashValue(entry);
1173
                objPtr = Tcl_NewStringObj(mfunc->member->fullname, -1);
1174
                Tcl_ListObjAppendElement((Tcl_Interp*)NULL, resultPtr, objPtr);
1175
 
1176
                entry = Tcl_NextHashEntry(&place);
1177
            }
1178
        }
1179
        Itcl_DeleteHierIter(&hier);
1180
 
1181
        Tcl_SetObjResult(interp, resultPtr);
1182
    }
1183
    return TCL_OK;
1184
}
1185
 
1186
/*
1187
 * ------------------------------------------------------------------------
1188
 *  Itcl_BiInfoVariableCmd()
1189
 *
1190
 *  Returns information regarding class data members (variables and
1191
 *  commons).  Handles the following syntax:
1192
 *
1193
 *    info variable ?varName? ?-protection? ?-type? ?-name?
1194
 *        ?-init? ?-config? ?-value?
1195
 *
1196
 *  If the ?varName? is not specified, then a list of all known
1197
 *  data members is returned.  Otherwise, the information for a
1198
 *  specific member is returned.  Returns a status TCL_OK/TCL_ERROR
1199
 *  to indicate success/failure.
1200
 * ------------------------------------------------------------------------
1201
 */
1202
/* ARGSUSED */
1203
int
1204
Itcl_BiInfoVariableCmd(dummy, interp, objc, objv)
1205
    ClientData dummy;        /* not used */
1206
    Tcl_Interp *interp;      /* current interpreter */
1207
    int objc;                /* number of arguments */
1208
    Tcl_Obj *CONST objv[];   /* argument objects */
1209
{
1210
    char *varName = NULL;
1211
    Tcl_Obj *resultPtr = NULL;
1212
    Tcl_Obj *objPtr = NULL;
1213
 
1214
    static char *options[] = {
1215
        "-config", "-init", "-name", "-protection", "-type",
1216
        "-value", (char*)NULL
1217
    };
1218
    enum BIvIdx {
1219
        BIvConfigIdx, BIvInitIdx, BIvNameIdx, BIvProtectIdx,
1220
        BIvTypeIdx, BIvValueIdx
1221
    } *ivlist, ivlistStorage[6];
1222
 
1223
    static enum BIvIdx DefInfoVariable[5] = {
1224
        BIvProtectIdx,
1225
        BIvTypeIdx,
1226
        BIvNameIdx,
1227
        BIvInitIdx,
1228
        BIvValueIdx
1229
    };
1230
 
1231
    static enum BIvIdx DefInfoPubVariable[6] = {
1232
        BIvProtectIdx,
1233
        BIvTypeIdx,
1234
        BIvNameIdx,
1235
        BIvInitIdx,
1236
        BIvConfigIdx,
1237
        BIvValueIdx
1238
    };
1239
 
1240
    ItclClass *contextClass;
1241
    ItclObject *contextObj;
1242
 
1243
    int i, result;
1244
    char *val, *name;
1245
    ItclClass *cdefn;
1246
    Tcl_HashSearch place;
1247
    Tcl_HashEntry *entry;
1248
    ItclVarDefn *vdefn;
1249
    ItclVarLookup *vlookup;
1250
    ItclMember *member;
1251
    ItclHierIter hier;
1252
 
1253
    /*
1254
     *  If this command is not invoked within a class namespace,
1255
     *  signal an error.
1256
     */
1257
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK) {
1258
        name = Tcl_GetStringFromObj(objv[0], (int*)NULL);
1259
        Tcl_ResetResult(interp);
1260
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1261
            "\nget info like this instead: ",
1262
            "\n  namespace eval className { info ", name, "... }",
1263
            (char*)NULL);
1264
        return TCL_ERROR;
1265
    }
1266
 
1267
    /*
1268
     *  Process args:
1269
     *  ?varName? ?-protection? ?-type? ?-name? ?-init? ?-config? ?-value?
1270
     */
1271
    objv++;  /* skip over command name */
1272
    objc--;
1273
 
1274
    if (objc > 0) {
1275
        varName = Tcl_GetStringFromObj(*objv, (int*)NULL);
1276
        objc--; objv++;
1277
    }
1278
 
1279
    /*
1280
     *  Return info for a specific variable.
1281
     */
1282
    if (varName) {
1283
        entry = Tcl_FindHashEntry(&contextClass->resolveVars, varName);
1284
        if (entry == NULL) {
1285
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1286
                "\"", varName, "\" isn't a variable in class \"",
1287
                contextClass->namesp->fullName, "\"",
1288
                (char*)NULL);
1289
            return TCL_ERROR;
1290
        }
1291
 
1292
        vlookup = (ItclVarLookup*)Tcl_GetHashValue(entry);
1293
        member = vlookup->vdefn->member;
1294
 
1295
        /*
1296
         *  By default, return everything.
1297
         */
1298
        if (objc == 0) {
1299
            if (member->protection == ITCL_PUBLIC &&
1300
                ((member->flags & ITCL_COMMON) == 0)) {
1301
                ivlist = DefInfoPubVariable;
1302
                objc = 6;
1303
            } else {
1304
                ivlist = DefInfoVariable;
1305
                objc = 5;
1306
            }
1307
        }
1308
 
1309
        /*
1310
         *  Otherwise, scan through all remaining flags and
1311
         *  figure out what to return.
1312
         */
1313
        else {
1314
            ivlist = &ivlistStorage[0];
1315
            for (i=0 ; i < objc; i++) {
1316
                result = Tcl_GetIndexFromObj(interp, objv[i],
1317
                    options, "option", 0, (int*)(&ivlist[i]));
1318
                if (result != TCL_OK) {
1319
                    return TCL_ERROR;
1320
                }
1321
            }
1322
        }
1323
 
1324
        if (objc > 1) {
1325
            resultPtr = Tcl_NewListObj(0, (Tcl_Obj**)NULL);
1326
        }
1327
 
1328
        for (i=0 ; i < objc; i++) {
1329
            switch (ivlist[i]) {
1330
                case BIvConfigIdx:
1331
                    if (member->code && member->code->procPtr->bodyPtr) {
1332
                        objPtr = member->code->procPtr->bodyPtr;
1333
                    } else {
1334
                        objPtr = Tcl_NewStringObj("", -1);
1335
                    }
1336
                    break;
1337
 
1338
                case BIvInitIdx:
1339
                    /*
1340
                     *  If this is the built-in "this" variable, then
1341
                     *  report the object name as its initialization string.
1342
                     */
1343
                    if ((member->flags & ITCL_THIS_VAR) != 0) {
1344
                        if (contextObj && contextObj->accessCmd) {
1345
                            objPtr = Tcl_NewStringObj((char*)NULL, 0);
1346
                            Tcl_GetCommandFullName(
1347
                                contextObj->classDefn->interp,
1348
                                contextObj->accessCmd, objPtr);
1349
                        } else {
1350
                            objPtr = Tcl_NewStringObj("<objectName>", -1);
1351
                        }
1352
                    }
1353
                    else if (vlookup->vdefn->init) {
1354
                        objPtr = Tcl_NewStringObj(vlookup->vdefn->init, -1);
1355
                    }
1356
                    else {
1357
                        objPtr = Tcl_NewStringObj("<undefined>", -1);
1358
                    }
1359
                    break;
1360
 
1361
                case BIvNameIdx:
1362
                    objPtr = Tcl_NewStringObj(member->fullname, -1);
1363
                    break;
1364
 
1365
                case BIvProtectIdx:
1366
                    val = Itcl_ProtectionStr(member->protection);
1367
                    objPtr = Tcl_NewStringObj(val, -1);
1368
                    break;
1369
 
1370
                case BIvTypeIdx:
1371
                    val = ((member->flags & ITCL_COMMON) != 0)
1372
                        ? "common" : "variable";
1373
                    objPtr = Tcl_NewStringObj(val, -1);
1374
                    break;
1375
 
1376
                case BIvValueIdx:
1377
                    if ((member->flags & ITCL_COMMON) != 0) {
1378
                        val = Itcl_GetCommonVar(interp, member->fullname,
1379
                            member->classDefn);
1380
                    }
1381
                    else if (contextObj == NULL) {
1382
                        Tcl_ResetResult(interp);
1383
                        Tcl_AppendResult(interp,
1384
                            "cannot access object-specific info ",
1385
                            "without an object context",
1386
                            (char*)NULL);
1387
                        return TCL_ERROR;
1388
                    }
1389
                    else {
1390
                        val = Itcl_GetInstanceVar(interp, member->fullname,
1391
                            contextObj, member->classDefn);
1392
                    }
1393
 
1394
                    if (val == NULL) {
1395
                        val = "<undefined>";
1396
                    }
1397
                    objPtr = Tcl_NewStringObj(val, -1);
1398
                    break;
1399
            }
1400
 
1401
            if (objc == 1) {
1402
                resultPtr = objPtr;
1403
            } else {
1404
                Tcl_ListObjAppendElement((Tcl_Interp*)NULL, resultPtr,
1405
                    objPtr);
1406
            }
1407
        }
1408
        Tcl_SetObjResult(interp, resultPtr);
1409
    }
1410
 
1411
    /*
1412
     *  Return the list of available variables.  Report the built-in
1413
     *  "this" variable only once, for the most-specific class.
1414
     */
1415
    else {
1416
        resultPtr = Tcl_NewListObj(0, (Tcl_Obj**)NULL);
1417
 
1418
        Itcl_InitHierIter(&hier, contextClass);
1419
        while ((cdefn=Itcl_AdvanceHierIter(&hier)) != NULL) {
1420
            entry = Tcl_FirstHashEntry(&cdefn->variables, &place);
1421
            while (entry) {
1422
                vdefn = (ItclVarDefn*)Tcl_GetHashValue(entry);
1423
                if ((vdefn->member->flags & ITCL_THIS_VAR) != 0) {
1424
                    if (cdefn == contextClass) {
1425
                        objPtr = Tcl_NewStringObj(vdefn->member->fullname, -1);
1426
                        Tcl_ListObjAppendElement((Tcl_Interp*)NULL,
1427
                            resultPtr, objPtr);
1428
                    }
1429
                }
1430
                else {
1431
                    objPtr = Tcl_NewStringObj(vdefn->member->fullname, -1);
1432
                    Tcl_ListObjAppendElement((Tcl_Interp*)NULL,
1433
                        resultPtr, objPtr);
1434
                }
1435
                entry = Tcl_NextHashEntry(&place);
1436
            }
1437
        }
1438
        Itcl_DeleteHierIter(&hier);
1439
 
1440
        Tcl_SetObjResult(interp, resultPtr);
1441
    }
1442
    return TCL_OK;
1443
}
1444
 
1445
 
1446
/*
1447
 * ------------------------------------------------------------------------
1448
 *  Itcl_BiInfoBodyCmd()
1449
 *
1450
 *  Handles the usual "info body" request, returning the body for a
1451
 *  specific proc.  Included here for backward compatibility, since
1452
 *  otherwise Tcl would complain that class procs are not real "procs".
1453
 *  Returns a status TCL_OK/TCL_ERROR to indicate success/failure.
1454
 * ------------------------------------------------------------------------
1455
 */
1456
/* ARGSUSED */
1457
int
1458
Itcl_BiInfoBodyCmd(dummy, interp, objc, objv)
1459
    ClientData dummy;     /* not used */
1460
    Tcl_Interp *interp;   /* current interpreter */
1461
    int objc;                /* number of arguments */
1462
    Tcl_Obj *CONST objv[];   /* argument objects */
1463
{
1464
    char *name;
1465
    ItclClass *contextClass;
1466
    ItclObject *contextObj;
1467
    ItclMemberFunc *mfunc;
1468
    ItclMemberCode *mcode;
1469
    Tcl_HashEntry *entry;
1470
    Tcl_Obj *objPtr;
1471
 
1472
    if (objc != 2) {
1473
        Tcl_WrongNumArgs(interp, 1, objv, "function");
1474
        return TCL_ERROR;
1475
    }
1476
 
1477
    /*
1478
     *  If this command is not invoked within a class namespace,
1479
     *  then treat the procedure name as a normal Tcl procedure.
1480
     */
1481
    if (!Itcl_IsClassNamespace(Tcl_GetCurrentNamespace(interp))) {
1482
        Proc *procPtr;
1483
 
1484
        name = Tcl_GetStringFromObj(objv[1], (int*)NULL);
1485
        procPtr = TclFindProc((Interp*)interp, name);
1486
        if (procPtr == NULL) {
1487
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1488
                "\"", name, "\" isn't a procedure",
1489
                (char*)NULL);
1490
            return TCL_ERROR;
1491
        }
1492
        Tcl_SetObjResult(interp, procPtr->bodyPtr);
1493
    }
1494
 
1495
    /*
1496
     *  Otherwise, treat the name as a class method/proc.
1497
     */
1498
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK) {
1499
        name = Tcl_GetStringFromObj(objv[0], (int*)NULL);
1500
        Tcl_ResetResult(interp);
1501
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1502
            "\nget info like this instead: ",
1503
            "\n  namespace eval className { info ", name, "... }",
1504
            (char*)NULL);
1505
        return TCL_ERROR;
1506
    }
1507
 
1508
    name = Tcl_GetStringFromObj(objv[1], (int*)NULL);
1509
    entry = Tcl_FindHashEntry(&contextClass->resolveCmds, name);
1510
    if (entry == NULL) {
1511
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1512
            "\"", name, "\" isn't a procedure",
1513
            (char*)NULL);
1514
        return TCL_ERROR;
1515
    }
1516
 
1517
    mfunc = (ItclMemberFunc*)Tcl_GetHashValue(entry);
1518
    mcode = mfunc->member->code;
1519
 
1520
    /*
1521
     *  Return a string describing the implementation.
1522
     */
1523
    if (mcode && mcode->procPtr->bodyPtr) {
1524
        objPtr = mcode->procPtr->bodyPtr;
1525
    } else {
1526
        objPtr = Tcl_NewStringObj("<undefined>", -1);
1527
    }
1528
    Tcl_SetObjResult(interp, objPtr);
1529
    return TCL_OK;
1530
}
1531
 
1532
 
1533
/*
1534
 * ------------------------------------------------------------------------
1535
 *  Itcl_BiInfoArgsCmd()
1536
 *
1537
 *  Handles the usual "info args" request, returning the argument list
1538
 *  for a specific proc.  Included here for backward compatibility, since
1539
 *  otherwise Tcl would complain that class procs are not real "procs".
1540
 *  Returns a status TCL_OK/TCL_ERROR to indicate success/failure.
1541
 * ------------------------------------------------------------------------
1542
 */
1543
/* ARGSUSED */
1544
int
1545
Itcl_BiInfoArgsCmd(dummy, interp, objc, objv)
1546
    ClientData dummy;     /* not used */
1547
    Tcl_Interp *interp;   /* current interpreter */
1548
    int objc;                /* number of arguments */
1549
    Tcl_Obj *CONST objv[];   /* argument objects */
1550
{
1551
    char *name;
1552
    ItclClass *contextClass;
1553
    ItclObject *contextObj;
1554
    ItclMemberFunc *mfunc;
1555
    ItclMemberCode *mcode;
1556
    Tcl_HashEntry *entry;
1557
    Tcl_Obj *objPtr;
1558
 
1559
    if (objc != 2) {
1560
        Tcl_WrongNumArgs(interp, 1, objv, "function");
1561
        return TCL_ERROR;
1562
    }
1563
 
1564
    name = Tcl_GetStringFromObj(objv[1], (int*)NULL);
1565
 
1566
    /*
1567
     *  If this command is not invoked within a class namespace,
1568
     *  then treat the procedure name as a normal Tcl procedure.
1569
     */
1570
    if (!Itcl_IsClassNamespace(Tcl_GetCurrentNamespace(interp))) {
1571
        Proc *procPtr;
1572
        CompiledLocal *localPtr;
1573
 
1574
        procPtr = TclFindProc((Interp*)interp, name);
1575
        if (procPtr == NULL) {
1576
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1577
                "\"", name, "\" isn't a procedure",
1578
                (char*)NULL);
1579
            return TCL_ERROR;
1580
        }
1581
 
1582
        objPtr = Tcl_NewListObj(0, (Tcl_Obj**)NULL);
1583
        for (localPtr = procPtr->firstLocalPtr;
1584
             localPtr != NULL;
1585
             localPtr = localPtr->nextPtr) {
1586
            if (TclIsVarArgument(localPtr)) {
1587
                Tcl_ListObjAppendElement(interp, objPtr,
1588
                    Tcl_NewStringObj(localPtr->name, -1));
1589
            }
1590
        }
1591
 
1592
        Tcl_SetObjResult(interp, objPtr);
1593
    }
1594
 
1595
    /*
1596
     *  Otherwise, treat the name as a class method/proc.
1597
     */
1598
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK) {
1599
        name = Tcl_GetStringFromObj(objv[0], (int*)NULL);
1600
        Tcl_ResetResult(interp);
1601
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1602
            "\nget info like this instead: ",
1603
            "\n  namespace eval className { info ", name, "... }",
1604
            (char*)NULL);
1605
        return TCL_ERROR;
1606
    }
1607
 
1608
    entry = Tcl_FindHashEntry(&contextClass->resolveCmds, name);
1609
    if (entry == NULL) {
1610
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1611
            "\"", name, "\" isn't a procedure",
1612
            (char*)NULL);
1613
        return TCL_ERROR;
1614
    }
1615
 
1616
    mfunc = (ItclMemberFunc*)Tcl_GetHashValue(entry);
1617
    mcode = mfunc->member->code;
1618
 
1619
    /*
1620
     *  Return a string describing the argument list.
1621
     */
1622
    if (mcode && mcode->arglist != NULL) {
1623
        objPtr = Itcl_ArgList(mcode->argcount, mcode->arglist);
1624
    }
1625
    else if ((mfunc->member->flags & ITCL_ARG_SPEC) != 0) {
1626
        objPtr = Itcl_ArgList(mfunc->argcount, mfunc->arglist);
1627
    }
1628
    else {
1629
        objPtr = Tcl_NewStringObj("<undefined>", -1);
1630
    }
1631
    Tcl_SetObjResult(interp, objPtr);
1632
    return TCL_OK;
1633
}
1634
 
1635
 
1636
/*
1637
 * ------------------------------------------------------------------------
1638
 *  Itcl_DefaultInfoCmd()
1639
 *
1640
 *  Handles any unknown options for the "itcl::builtin::info" command
1641
 *  by passing requests on to the usual "::info" command.  If the
1642
 *  option is recognized, then it is handled.  Otherwise, if it is
1643
 *  still unknown, then an error message is returned with the list
1644
 *  of possible options.
1645
 *
1646
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
1647
 * ------------------------------------------------------------------------
1648
 */
1649
/* ARGSUSED */
1650
int
1651
Itcl_DefaultInfoCmd(dummy, interp, objc, objv)
1652
    ClientData dummy;     /* not used */
1653
    Tcl_Interp *interp;   /* current interpreter */
1654
    int objc;                /* number of arguments */
1655
    Tcl_Obj *CONST objv[];   /* argument objects */
1656
{
1657
    int result;
1658
    char *name;
1659
    Tcl_Command cmd;
1660
    Command *cmdPtr;
1661
    Tcl_Obj *resultPtr;
1662
 
1663
    /*
1664
     *  Look for the usual "::info" command, and use it to
1665
     *  evaluate the unknown option.
1666
     */
1667
    cmd = Tcl_FindCommand(interp, "::info", (Tcl_Namespace*)NULL, 0);
1668
    if (cmd == NULL) {
1669
        name = Tcl_GetStringFromObj(objv[0], (int*)NULL);
1670
        Tcl_ResetResult(interp);
1671
 
1672
        resultPtr = Tcl_GetObjResult(interp);
1673
        Tcl_AppendStringsToObj(resultPtr,
1674
            "bad option \"", name, "\" should be one of...\n",
1675
            (char*)NULL);
1676
        Itcl_GetEnsembleUsageForObj(interp, objv[0], resultPtr);
1677
 
1678
        return TCL_ERROR;
1679
    }
1680
 
1681
    cmdPtr = (Command*)cmd;
1682
    result = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, objc, objv);
1683
 
1684
    /*
1685
     *  If the option was not recognized by the usual "info" command,
1686
     *  then we got a "bad option" error message.  Add the options
1687
     *  for the current ensemble to the error message.
1688
     */
1689
    if (result != TCL_OK && strncmp(interp->result,"bad option",10) == 0) {
1690
        resultPtr = Tcl_GetObjResult(interp);
1691
        Tcl_AppendToObj(resultPtr, "\nor", -1);
1692
        Itcl_GetEnsembleUsageForObj(interp, objv[0], resultPtr);
1693
    }
1694
    return result;
1695
}

powered by: WebSVN 2.1.0

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