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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [itcl/] [itcl/] [generic/] [itcl_class.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 class definitions.  Classes are composed of
16
 *  data members (public/protected/common) and the member functions
17
 *  (methods/procs) that operate on them.  Each class has its own
18
 *  namespace which manages the class scope.
19
 *
20
 * ========================================================================
21
 *  AUTHOR:  Michael J. McLennan
22
 *           Bell Labs Innovations for Lucent Technologies
23
 *           mmclennan@lucent.com
24
 *           http://www.tcltk.com/itcl
25
 *
26
 *     RCS:  $Id: itcl_class.c,v 1.1.1.1 2002-01-16 10:24:46 markom Exp $
27
 * ========================================================================
28
 *           Copyright (c) 1993-1998  Lucent Technologies, Inc.
29
 * ------------------------------------------------------------------------
30
 * See the file "license.terms" for information on usage and redistribution
31
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
32
 */
33
#include "itclInt.h"
34
 
35
/*
36
 * This structure is a subclass of Tcl_ResolvedVarInfo that contains the
37
 * ItclVarLookup info needed at runtime.
38
 */
39
typedef struct ItclResolvedVarInfo {
40
    Tcl_ResolvedVarInfo vinfo;        /* This must be the first element. */
41
    ItclVarLookup *vlookup;           /* Pointer to lookup info. */
42
} ItclResolvedVarInfo;
43
 
44
/*
45
 *  FORWARD DECLARATIONS
46
 */
47
static void ItclDestroyClass _ANSI_ARGS_((ClientData cdata));
48
static void ItclDestroyClassNamesp _ANSI_ARGS_((ClientData cdata));
49
static void ItclFreeClass _ANSI_ARGS_((char* cdata));
50
 
51
static Tcl_Var ItclClassRuntimeVarResolver _ANSI_ARGS_((
52
    Tcl_Interp *interp, Tcl_ResolvedVarInfo *vinfoPtr));
53
 
54
 
55
/*
56
 * ------------------------------------------------------------------------
57
 *  Itcl_CreateClass()
58
 *
59
 *  Creates a namespace and its associated class definition data.
60
 *  If a namespace already exists with that name, then this routine
61
 *  returns TCL_ERROR, along with an error message in the interp.
62
 *  If successful, it returns TCL_OK and a pointer to the new class
63
 *  definition.
64
 * ------------------------------------------------------------------------
65
 */
66
int
67
Itcl_CreateClass(interp, path, info, rPtr)
68
    Tcl_Interp* interp;      /* interpreter that will contain new class */
69
    char* path;              /* name of new class */
70
    ItclObjectInfo *info;    /* info for all known objects */
71
    ItclClass **rPtr;        /* returns: pointer to class definition */
72
{
73
    char *head, *tail;
74
    Tcl_DString buffer;
75
    Tcl_Command cmd;
76
    Tcl_Namespace *classNs;
77
    ItclClass *cdPtr;
78
    ItclVarDefn *vdefn;
79
    Tcl_HashEntry *entry;
80
    int newEntry;
81
 
82
    /*
83
     *  Make sure that a class with the given name does not
84
     *  already exist in the current namespace context.  If a
85
     *  namespace exists, that's okay.  It may have been created
86
     *  to contain stubs during a "namespace import" operation.
87
     *  We'll just replace the namespace data below with the
88
     *  proper class data.
89
     */
90
    classNs = Tcl_FindNamespace(interp, path, (Tcl_Namespace*)NULL,
91
        /* flags */ 0);
92
 
93
    if (classNs != NULL && Itcl_IsClassNamespace(classNs)) {
94
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
95
            "class \"", path, "\" already exists",
96
            (char*)NULL);
97
        return TCL_ERROR;
98
    }
99
 
100
    /*
101
     *  Make sure that a command with the given class name does not
102
     *  already exist in the current namespace.  This prevents the
103
     *  usual Tcl commands from being clobbered when a programmer
104
     *  makes a bogus call like "class info".
105
     */
106
    cmd = Tcl_FindCommand(interp, path, (Tcl_Namespace*)NULL,
107
        /* flags */ TCL_NAMESPACE_ONLY);
108
 
109
    if (cmd != NULL && !Itcl_IsStub(cmd)) {
110
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
111
            "command \"", path, "\" already exists",
112
            (char*)NULL);
113
 
114
        if (strstr(path,"::") == NULL) {
115
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
116
                " in namespace \"",
117
                Tcl_GetCurrentNamespace(interp)->fullName, "\"",
118
                (char*)NULL);
119
        }
120
        return TCL_ERROR;
121
    }
122
 
123
    /*
124
     *  Make sure that the class name does not have any goofy
125
     *  characters:
126
     *
127
     *    .  =>  reserved for member access like:  class.publicVar
128
     */
129
    Itcl_ParseNamespPath(path, &buffer, &head, &tail);
130
 
131
    if (strstr(tail,".")) {
132
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
133
            "bad class name \"", tail, "\"",
134
            (char*)NULL);
135
        Tcl_DStringFree(&buffer);
136
        return TCL_ERROR;
137
    }
138
    Tcl_DStringFree(&buffer);
139
 
140
    /*
141
     *  Allocate class definition data.
142
     */
143
    cdPtr = (ItclClass*)ckalloc(sizeof(ItclClass));
144
    cdPtr->name = NULL;
145
    cdPtr->fullname = NULL;
146
    cdPtr->interp = interp;
147
    cdPtr->info = info;  Itcl_PreserveData((ClientData)info);
148
    cdPtr->namesp = NULL;
149
    cdPtr->accessCmd = NULL;
150
 
151
    Tcl_InitHashTable(&cdPtr->variables, TCL_STRING_KEYS);
152
    Tcl_InitHashTable(&cdPtr->functions, TCL_STRING_KEYS);
153
 
154
    cdPtr->numInstanceVars = 0;
155
    Tcl_InitHashTable(&cdPtr->resolveVars, TCL_STRING_KEYS);
156
    Tcl_InitHashTable(&cdPtr->resolveCmds, TCL_STRING_KEYS);
157
 
158
    Itcl_InitList(&cdPtr->bases);
159
    Itcl_InitList(&cdPtr->derived);
160
 
161
    cdPtr->initCode = NULL;
162
    cdPtr->unique   = 0;
163
    cdPtr->flags    = 0;
164
 
165
    /*
166
     *  Initialize the heritage info--each class starts with its
167
     *  own class definition in the heritage.  Base classes are
168
     *  added to the heritage from the "inherit" statement.
169
     */
170
    Tcl_InitHashTable(&cdPtr->heritage, TCL_ONE_WORD_KEYS);
171
    (void) Tcl_CreateHashEntry(&cdPtr->heritage, (char*)cdPtr, &newEntry);
172
 
173
    /*
174
     *  Create a namespace to represent the class.  Add the class
175
     *  definition info as client data for the namespace.  If the
176
     *  namespace already exists, then replace any existing client
177
     *  data with the class data.
178
     */
179
    Itcl_PreserveData((ClientData)cdPtr);
180
 
181
    if (classNs == NULL) {
182
        classNs = Tcl_CreateNamespace(interp, path,
183
            (ClientData)cdPtr, ItclDestroyClassNamesp);
184
    }
185
    else {
186
        if (classNs->clientData && classNs->deleteProc) {
187
            (*classNs->deleteProc)(classNs->clientData);
188
        }
189
        classNs->clientData = (ClientData)cdPtr;
190
        classNs->deleteProc = ItclDestroyClassNamesp;
191
    }
192
 
193
    Itcl_EventuallyFree((ClientData)cdPtr, ItclFreeClass);
194
 
195
    if (classNs == NULL) {
196
        Itcl_ReleaseData((ClientData)cdPtr);
197
        return TCL_ERROR;
198
    }
199
 
200
    cdPtr->namesp = classNs;
201
 
202
    cdPtr->name = (char*)ckalloc((unsigned)(strlen(classNs->name)+1));
203
    strcpy(cdPtr->name, classNs->name);
204
 
205
    cdPtr->fullname = (char*)ckalloc((unsigned)(strlen(classNs->fullName)+1));
206
    strcpy(cdPtr->fullname, classNs->fullName);
207
 
208
    /*
209
     *  Add special name resolution procedures to the class namespace
210
     *  so that members are accessed according to the rules for
211
     *  [incr Tcl].
212
     */
213
    Tcl_SetNamespaceResolvers(classNs, Itcl_ClassCmdResolver,
214
        Itcl_ClassVarResolver, Itcl_ClassCompiledVarResolver);
215
 
216
    /*
217
     *  Add the built-in "this" variable to the list of data members.
218
     */
219
    (void) Itcl_CreateVarDefn(interp, cdPtr, "this",
220
        (char*)NULL, (char*)NULL, &vdefn);
221
 
222
    vdefn->member->protection = ITCL_PROTECTED;  /* always "protected" */
223
    vdefn->member->flags |= ITCL_THIS_VAR;       /* mark as "this" variable */
224
 
225
    entry = Tcl_CreateHashEntry(&cdPtr->variables, "this", &newEntry);
226
    Tcl_SetHashValue(entry, (ClientData)vdefn);
227
 
228
    /*
229
     *  Create a command in the current namespace to manage the class:
230
     *    <className>
231
     *    <className> <objName> ?<constructor-args>?
232
     */
233
    Itcl_PreserveData((ClientData)cdPtr);
234
 
235
    cdPtr->accessCmd = Tcl_CreateObjCommand(interp,
236
        cdPtr->fullname, Itcl_HandleClass,
237
        (ClientData)cdPtr, ItclDestroyClass);
238
 
239
    *rPtr = cdPtr;
240
    return TCL_OK;
241
}
242
 
243
 
244
/*
245
 * ------------------------------------------------------------------------
246
 *  Itcl_DeleteClass()
247
 *
248
 *  Deletes a class by deleting all derived classes and all objects in
249
 *  that class, and finally, by destroying the class namespace.  This
250
 *  procedure provides a friendly way of doing this.  If any errors
251
 *  are detected along the way, the process is aborted.
252
 *
253
 *  Returns TCL_OK if successful, or TCL_ERROR (along with an error
254
 *  message in the interpreter) if anything goes wrong.
255
 * ------------------------------------------------------------------------
256
 */
257
int
258
Itcl_DeleteClass(interp, cdefnPtr)
259
    Tcl_Interp *interp;     /* interpreter managing this class */
260
    ItclClass *cdefnPtr;    /* class namespace */
261
{
262
    ItclClass *cdPtr = NULL;
263
 
264
    Itcl_ListElem *elem;
265
    ItclObject *contextObj;
266
    Tcl_HashEntry *entry;
267
    Tcl_HashSearch place;
268
    Tcl_DString buffer;
269
 
270
    /*
271
     *  Destroy all derived classes, since these lose their meaning
272
     *  when the base class goes away.  If anything goes wrong,
273
     *  abort with an error.
274
     *
275
     *  TRICKY NOTE:  When a derived class is destroyed, it
276
     *    automatically deletes itself from the "derived" list.
277
     */
278
    elem = Itcl_FirstListElem(&cdefnPtr->derived);
279
    while (elem) {
280
        cdPtr = (ItclClass*)Itcl_GetListValue(elem);
281
        elem = Itcl_NextListElem(elem);  /* advance here--elem will go away */
282
 
283
        if (Itcl_DeleteClass(interp, cdPtr) != TCL_OK) {
284
            goto deleteClassFail;
285
        }
286
    }
287
 
288
    /*
289
     *  Scan through and find all objects that belong to this class.
290
     *  Note that more specialized objects have already been
291
     *  destroyed above, when derived classes were destroyed.
292
     *  Destroy objects and report any errors.
293
     */
294
    entry = Tcl_FirstHashEntry(&cdefnPtr->info->objects, &place);
295
    while (entry) {
296
        contextObj = (ItclObject*)Tcl_GetHashValue(entry);
297
        if (contextObj->classDefn == cdefnPtr) {
298
            if (Itcl_DeleteObject(interp, contextObj) != TCL_OK) {
299
                cdPtr = cdefnPtr;
300
                goto deleteClassFail;
301
            }
302
        }
303
        entry = Tcl_NextHashEntry(&place);
304
    }
305
 
306
    /*
307
     *  Destroy the namespace associated with this class.
308
     *
309
     *  TRICKY NOTE:
310
     *    The cleanup procedure associated with the namespace is
311
     *    invoked automatically.  It does all of the same things
312
     *    above, but it also disconnects this class from its
313
     *    base-class lists, and removes the class access command.
314
     */
315
    Tcl_DeleteNamespace(cdefnPtr->namesp);
316
    return TCL_OK;
317
 
318
deleteClassFail:
319
    Tcl_DStringInit(&buffer);
320
    Tcl_DStringAppend(&buffer, "\n    (while deleting class \"", -1);
321
    Tcl_DStringAppend(&buffer, cdPtr->namesp->fullName, -1);
322
    Tcl_DStringAppend(&buffer, "\")", -1);
323
    Tcl_AddErrorInfo(interp, Tcl_DStringValue(&buffer));
324
    Tcl_DStringFree(&buffer);
325
    return TCL_ERROR;
326
}
327
 
328
 
329
/*
330
 * ------------------------------------------------------------------------
331
 *  ItclDestroyClass()
332
 *
333
 *  Invoked whenever the access command for a class is destroyed.
334
 *  Destroys the namespace associated with the class, which also
335
 *  destroys all objects in the class and all derived classes.
336
 *  Disconnects this class from the "derived" class lists of its
337
 *  base classes, and releases any claim to the class definition
338
 *  data.  If this is the last use of that data, the class will
339
 *  completely vanish at this point.
340
 * ------------------------------------------------------------------------
341
 */
342
static void
343
ItclDestroyClass(cdata)
344
    ClientData cdata;  /* class definition to be destroyed */
345
{
346
    ItclClass *cdefnPtr = (ItclClass*)cdata;
347
    cdefnPtr->accessCmd = NULL;
348
 
349
    Tcl_DeleteNamespace(cdefnPtr->namesp);
350
    Itcl_ReleaseData((ClientData)cdefnPtr);
351
}
352
 
353
 
354
/*
355
 * ------------------------------------------------------------------------
356
 *  ItclDestroyClassNamesp()
357
 *
358
 *  Invoked whenever the namespace associated with a class is destroyed.
359
 *  Destroys all objects associated with this class and all derived
360
 *  classes.  Disconnects this class from the "derived" class lists
361
 *  of its base classes, and removes the class access command.  Releases
362
 *  any claim to the class definition data.  If this is the last use
363
 *  of that data, the class will completely vanish at this point.
364
 * ------------------------------------------------------------------------
365
 */
366
static void
367
ItclDestroyClassNamesp(cdata)
368
    ClientData cdata;  /* class definition to be destroyed */
369
{
370
    ItclClass *cdefnPtr = (ItclClass*)cdata;
371
    ItclObject *contextObj;
372
    Itcl_ListElem *elem, *belem;
373
    ItclClass *cdPtr, *basePtr, *derivedPtr;
374
    Tcl_HashEntry *entry;
375
    Tcl_HashSearch place;
376
 
377
    /*
378
     *  Destroy all derived classes, since these lose their meaning
379
     *  when the base class goes away.
380
     *
381
     *  TRICKY NOTE:  When a derived class is destroyed, it
382
     *    automatically deletes itself from the "derived" list.
383
     */
384
    elem = Itcl_FirstListElem(&cdefnPtr->derived);
385
    while (elem) {
386
        cdPtr = (ItclClass*)Itcl_GetListValue(elem);
387
        elem = Itcl_NextListElem(elem);  /* advance here--elem will go away */
388
 
389
        Tcl_DeleteNamespace(cdPtr->namesp);
390
    }
391
 
392
    /*
393
     *  Scan through and find all objects that belong to this class.
394
     *  Destroy them quietly by deleting their access command.
395
     */
396
    entry = Tcl_FirstHashEntry(&cdefnPtr->info->objects, &place);
397
    while (entry) {
398
        contextObj = (ItclObject*)Tcl_GetHashValue(entry);
399
        if (contextObj->classDefn == cdefnPtr) {
400
            Tcl_DeleteCommandFromToken(cdefnPtr->interp, contextObj->accessCmd);
401
        }
402
        entry = Tcl_NextHashEntry(&place);
403
    }
404
 
405
    /*
406
     *  Next, remove this class from the "derived" list in
407
     *  all base classes.
408
     */
409
    belem = Itcl_FirstListElem(&cdefnPtr->bases);
410
    while (belem) {
411
        basePtr = (ItclClass*)Itcl_GetListValue(belem);
412
 
413
        elem = Itcl_FirstListElem(&basePtr->derived);
414
        while (elem) {
415
            derivedPtr = (ItclClass*)Itcl_GetListValue(elem);
416
            if (derivedPtr == cdefnPtr) {
417
                Itcl_ReleaseData( Itcl_GetListValue(elem) );
418
                elem = Itcl_DeleteListElem(elem);
419
            } else {
420
                elem = Itcl_NextListElem(elem);
421
            }
422
        }
423
        belem = Itcl_NextListElem(belem);
424
    }
425
 
426
    /*
427
     *  Next, destroy the access command associated with the class.
428
     */
429
    if (cdefnPtr->accessCmd) {
430
        Command *cmdPtr = (Command*)cdefnPtr->accessCmd;
431
 
432
        cmdPtr->deleteProc = Itcl_ReleaseData;
433
        Tcl_DeleteCommandFromToken(cdefnPtr->interp, cdefnPtr->accessCmd);
434
    }
435
 
436
    /*
437
     *  Release the namespace's claim on the class definition.
438
     */
439
    Itcl_ReleaseData((ClientData)cdefnPtr);
440
}
441
 
442
 
443
/*
444
 * ------------------------------------------------------------------------
445
 *  ItclFreeClass()
446
 *
447
 *  Frees all memory associated with a class definition.  This is
448
 *  usually invoked automatically by Itcl_ReleaseData(), when class
449
 *  data is no longer being used.
450
 * ------------------------------------------------------------------------
451
 */
452
static void
453
ItclFreeClass(cdata)
454
    char *cdata;  /* class definition to be destroyed */
455
{
456
    ItclClass *cdefnPtr = (ItclClass*)cdata;
457
 
458
    int newEntry;
459
    Itcl_ListElem *elem;
460
    Tcl_HashSearch place;
461
    Tcl_HashEntry *entry, *hPtr;
462
    ItclVarDefn *vdefn;
463
    ItclVarLookup *vlookup;
464
    Var *varPtr;
465
    Tcl_HashTable varTable;
466
 
467
    /*
468
     *  Tear down the list of derived classes.  This list should
469
     *  really be empty if everything is working properly, but
470
     *  release it here just in case.
471
     */
472
    elem = Itcl_FirstListElem(&cdefnPtr->derived);
473
    while (elem) {
474
        Itcl_ReleaseData( Itcl_GetListValue(elem) );
475
        elem = Itcl_NextListElem(elem);
476
    }
477
    Itcl_DeleteList(&cdefnPtr->derived);
478
 
479
    /*
480
     *  Tear down the variable resolution table.  Some records
481
     *  appear multiple times in the table (for x, foo::x, etc.)
482
     *  so each one has a reference count.
483
     */
484
    Tcl_InitHashTable(&varTable, TCL_STRING_KEYS);
485
 
486
    entry = Tcl_FirstHashEntry(&cdefnPtr->resolveVars, &place);
487
    while (entry) {
488
        vlookup = (ItclVarLookup*)Tcl_GetHashValue(entry);
489
        if (--vlookup->usage == 0) {
490
            /*
491
             *  If this is a common variable owned by this class,
492
             *  then release the class's hold on it.  If it's no
493
             *  longer being used, move it into a variable table
494
             *  for destruction.
495
             */
496
            if ( (vlookup->vdefn->member->flags & ITCL_COMMON) != 0 &&
497
                 vlookup->vdefn->member->classDefn == cdefnPtr ) {
498
                varPtr = (Var*)vlookup->var.common;
499
                if (--varPtr->refCount == 0) {
500
                    hPtr = Tcl_CreateHashEntry(&varTable,
501
                        vlookup->vdefn->member->fullname, &newEntry);
502
                    Tcl_SetHashValue(hPtr, (ClientData) varPtr);
503
                }
504
            }
505
            ckfree((char*)vlookup);
506
        }
507
        entry = Tcl_NextHashEntry(&place);
508
    }
509
 
510
    TclDeleteVars((Interp*)cdefnPtr->interp, &varTable);
511
    Tcl_DeleteHashTable(&cdefnPtr->resolveVars);
512
 
513
    /*
514
     *  Tear down the virtual method table...
515
     */
516
    Tcl_DeleteHashTable(&cdefnPtr->resolveCmds);
517
 
518
    /*
519
     *  Delete all variable definitions.
520
     */
521
    entry = Tcl_FirstHashEntry(&cdefnPtr->variables, &place);
522
    while (entry) {
523
        vdefn = (ItclVarDefn*)Tcl_GetHashValue(entry);
524
        Itcl_DeleteVarDefn(vdefn);
525
        entry = Tcl_NextHashEntry(&place);
526
    }
527
    Tcl_DeleteHashTable(&cdefnPtr->variables);
528
 
529
    /*
530
     *  Delete all function definitions.
531
     */
532
    entry = Tcl_FirstHashEntry(&cdefnPtr->functions, &place);
533
    while (entry) {
534
        Itcl_ReleaseData( Tcl_GetHashValue(entry) );
535
        entry = Tcl_NextHashEntry(&place);
536
    }
537
    Tcl_DeleteHashTable(&cdefnPtr->functions);
538
 
539
    /*
540
     *  Release the claim on all base classes.
541
     */
542
    elem = Itcl_FirstListElem(&cdefnPtr->bases);
543
    while (elem) {
544
        Itcl_ReleaseData( Itcl_GetListValue(elem) );
545
        elem = Itcl_NextListElem(elem);
546
    }
547
    Itcl_DeleteList(&cdefnPtr->bases);
548
    Tcl_DeleteHashTable(&cdefnPtr->heritage);
549
 
550
    /*
551
     *  Free up the object initialization code.
552
     */
553
    if (cdefnPtr->initCode) {
554
        Tcl_DecrRefCount(cdefnPtr->initCode);
555
    }
556
 
557
    Itcl_ReleaseData((ClientData)cdefnPtr->info);
558
 
559
    ckfree(cdefnPtr->name);
560
    ckfree(cdefnPtr->fullname);
561
 
562
    ckfree((char*)cdefnPtr);
563
}
564
 
565
 
566
/*
567
 * ------------------------------------------------------------------------
568
 *  Itcl_IsClassNamespace()
569
 *
570
 *  Checks to see whether or not the given namespace represents an
571
 *  [incr Tcl] class.  Returns non-zero if so, and zero otherwise.
572
 * ------------------------------------------------------------------------
573
 */
574
int
575
Itcl_IsClassNamespace(namesp)
576
    Tcl_Namespace *namesp;  /* namespace being tested */
577
{
578
    Namespace *nsPtr = (Namespace*)namesp;
579
 
580
    if (nsPtr != NULL) {
581
        return (nsPtr->deleteProc == ItclDestroyClassNamesp);
582
    }
583
    return 0;
584
}
585
 
586
 
587
/*
588
 * ------------------------------------------------------------------------
589
 *  Itcl_IsClass()
590
 *
591
 *  Checks the given Tcl command to see if it represents an itcl class.
592
 *  Returns non-zero if the command is associated with a class.
593
 * ------------------------------------------------------------------------
594
 */
595
int
596
Itcl_IsClass(cmd)
597
    Tcl_Command cmd;         /* command being tested */
598
{
599
    Command *cmdPtr = (Command*)cmd;
600
 
601
    if (cmdPtr->deleteProc == ItclDestroyClass) {
602
        return 1;
603
    }
604
 
605
    /*
606
     *  This may be an imported command.  Try to get the real
607
     *  command and see if it represents a class.
608
     */
609
    cmdPtr = (Command*)TclGetOriginalCommand(cmd);
610
    if (cmdPtr && cmdPtr->deleteProc == ItclDestroyClass) {
611
        return 1;
612
    }
613
    return 0;
614
}
615
 
616
 
617
/*
618
 * ------------------------------------------------------------------------
619
 *  Itcl_FindClass()
620
 *
621
 *  Searches for the specified class in the active namespace.  If the
622
 *  class is found, this procedure returns a pointer to the class
623
 *  definition.  Otherwise, if the autoload flag is non-zero, an
624
 *  attempt will be made to autoload the class definition.  If it
625
 *  still can't be found, this procedure returns NULL, along with an
626
 *  error message in the interpreter.
627
 * ------------------------------------------------------------------------
628
 */
629
ItclClass*
630
Itcl_FindClass(interp, path, autoload)
631
    Tcl_Interp* interp;      /* interpreter containing class */
632
    char* path;              /* path name for class */
633
{
634
    Tcl_Namespace* classNs;
635
 
636
    /*
637
     *  Search for a namespace with the specified name, and if
638
     *  one is found, see if it is a class namespace.
639
     */
640
    classNs = Itcl_FindClassNamespace(interp, path);
641
 
642
    if (classNs && Itcl_IsClassNamespace(classNs)) {
643
        return (ItclClass*)classNs->clientData;
644
    }
645
 
646
    /*
647
     *  If the autoload flag is set, try to autoload the class
648
     *  definition.
649
     */
650
    if (autoload) {
651
        if (Tcl_VarEval(interp, "::auto_load ", path, (char*)NULL) != TCL_OK) {
652
            char msg[256];
653
            sprintf(msg, "\n    (while attempting to autoload class \"%.200s\")", path);
654
            Tcl_AddErrorInfo(interp, msg);
655
            return NULL;
656
        }
657
        Tcl_ResetResult(interp);
658
 
659
        classNs = Itcl_FindClassNamespace(interp, path);
660
        if (classNs && Itcl_IsClassNamespace(classNs)) {
661
            return (ItclClass*)classNs->clientData;
662
        }
663
    }
664
 
665
    Tcl_AppendResult(interp, "class \"", path, "\" not found in context \"",
666
        Tcl_GetCurrentNamespace(interp)->fullName, "\"",
667
        (char*)NULL);
668
 
669
    return NULL;
670
}
671
 
672
/*
673
 * ------------------------------------------------------------------------
674
 *  Itcl_FindClassNamespace()
675
 *
676
 *  Searches for the specified class namespace.  The normal Tcl procedure
677
 *  Tcl_FindNamespace also searches for namespaces, but only in the
678
 *  current namespace context.  This makes it hard to find one class
679
 *  from within another.  For example, suppose. you have two namespaces
680
 *  Foo and Bar.  If you're in the context of Foo and you look for
681
 *  Bar, you won't find it with Tcl_FindNamespace.  This behavior is
682
 *  okay for namespaces, but wrong for classes.
683
 *
684
 *  This procedure search for a class namespace.  If the name is
685
 *  absolute (i.e., starts with "::"), then that one name is checked,
686
 *  and the class is either found or not.  But if the name is relative,
687
 *  it is sought in the current namespace context and in the global
688
 *  context, just like the normal command lookup.
689
 *
690
 *  This procedure returns a pointer to the desired namespace, or
691
 *  NULL if the namespace was not found.
692
 * ------------------------------------------------------------------------
693
 */
694
Tcl_Namespace*
695
Itcl_FindClassNamespace(interp, path)
696
    Tcl_Interp* interp;        /* interpreter containing class */
697
    char* path;                /* path name for class */
698
{
699
    Tcl_Namespace* contextNs = Tcl_GetCurrentNamespace(interp);
700
    Tcl_Namespace* classNs;
701
    Tcl_DString buffer;
702
 
703
    /*
704
     *  Look up the namespace.  If the name is not absolute, then
705
     *  see if it's the current namespace, and try the global
706
     *  namespace as well.
707
     */
708
    classNs = Tcl_FindNamespace(interp, path, (Tcl_Namespace*)NULL,
709
        /* flags */ 0);
710
 
711
    if ( !classNs && contextNs->parentPtr != NULL &&
712
         (*path != ':' || *(path+1) != ':') ) {
713
 
714
        if (strcmp(contextNs->name, path) == 0) {
715
            classNs = contextNs;
716
        }
717
        else {
718
            Tcl_DStringInit(&buffer);
719
            Tcl_DStringAppend(&buffer, "::", -1);
720
            Tcl_DStringAppend(&buffer, path, -1);
721
 
722
            classNs = Tcl_FindNamespace(interp, Tcl_DStringValue(&buffer),
723
                (Tcl_Namespace*)NULL, /* flags */ 0);
724
 
725
            Tcl_DStringFree(&buffer);
726
        }
727
    }
728
    return classNs;
729
}
730
 
731
 
732
/*
733
 * ------------------------------------------------------------------------
734
 *  Itcl_HandleClass()
735
 *
736
 *  Invoked by Tcl whenever the user issues the command associated with
737
 *  a class name.  Handles the following syntax:
738
 *
739
 *    <className>
740
 *    <className> <objName> ?<args>...?
741
 *
742
 *  Without any arguments, the command does nothing.  In the olden days,
743
 *  this allowed the class name to be invoked by itself to prompt the
744
 *  autoloader to load the class definition.  Today, this behavior is
745
 *  retained for backward compatibility with old releases.
746
 *
747
 *  If arguments are specified, then this procedure creates a new
748
 *  object named <objName> in the appropriate class.  Note that if
749
 *  <objName> contains "#auto", that part is automatically replaced
750
 *  by a unique string built from the class name.
751
 * ------------------------------------------------------------------------
752
 */
753
int
754
Itcl_HandleClass(clientData, interp, objc, objv)
755
    ClientData clientData;   /* class definition */
756
    Tcl_Interp *interp;      /* current interpreter */
757
    int objc;                /* number of arguments */
758
    Tcl_Obj *CONST objv[];   /* argument objects */
759
{
760
    ItclClass *cdefnPtr = (ItclClass*)clientData;
761
    int result = TCL_OK;
762
 
763
    char unique[256];    /* buffer used for unique part of object names */
764
    Tcl_DString buffer;  /* buffer used to build object names */
765
    char *token, *objName, tmp, *start, *pos, *match;
766
 
767
    ItclObject *newObj;
768
    Tcl_CallFrame frame;
769
 
770
    /*
771
     *  If the command is invoked without an object name, then do nothing.
772
     *  This used to support autoloading--that the class name could be
773
     *  invoked as a command by itself, prompting the autoloader to
774
     *  load the class definition.  We retain the behavior here for
775
     *  backward-compatibility with earlier releases.
776
     */
777
    if (objc == 1) {
778
        return TCL_OK;
779
    }
780
 
781
    /*
782
     *  If the object name is "::", and if this is an old-style class
783
     *  definition, then treat the remaining arguments as a command
784
     *  in the class namespace.  This used to be the way of invoking
785
     *  a class proc, but the new syntax is "class::proc" (without
786
     *  spaces).
787
     */
788
    token = Tcl_GetStringFromObj(objv[1], (int*)NULL);
789
    if ((*token == ':') && (strcmp(token,"::") == 0) && (objc > 2)) {
790
        if ((cdefnPtr->flags & ITCL_OLD_STYLE) != 0) {
791
 
792
            result = Tcl_PushCallFrame(interp, &frame,
793
                 cdefnPtr->namesp, /* isProcCallFrame */ 0);
794
 
795
            if (result != TCL_OK) {
796
                return result;
797
            }
798
            result = Itcl_EvalArgs(interp, objc-2, objv+2);
799
 
800
            Tcl_PopCallFrame(interp);
801
            return result;
802
        }
803
 
804
        /*
805
         *  If this is not an old-style class, then return an error
806
         *  describing the syntax change.
807
         */
808
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
809
            "syntax \"class :: proc\" is an anachronism\n",
810
            "[incr Tcl] no longer supports this syntax.\n",
811
            "Instead, remove the spaces from your procedure invocations:\n",
812
            "  ",
813
            Tcl_GetStringFromObj(objv[0], (int*)NULL), "::",
814
            Tcl_GetStringFromObj(objv[2], (int*)NULL), " ?args?",
815
            (char*)NULL);
816
        return TCL_ERROR;
817
    }
818
 
819
    /*
820
     *  Otherwise, we have a proper object name.  Create a new instance
821
     *  with that name.  If the name contains "#auto", replace this with
822
     *  a uniquely generated string based on the class name.
823
     */
824
    Tcl_DStringInit(&buffer);
825
    objName = NULL;
826
 
827
    match = "#auto";
828
    start = token;
829
    for (pos=start; *pos != '\0'; pos++) {
830
        if (*pos == *match) {
831
            if (*(++match) == '\0') {
832
                tmp = *start;
833
                *start = '\0';  /* null-terminate first part */
834
 
835
                /*
836
                 *  Substitute a unique part in for "#auto", and keep
837
                 *  incrementing a counter until a valid name is found.
838
                 */
839
                do {
840
                    sprintf(unique,"%.200s%d", cdefnPtr->name,
841
                        cdefnPtr->unique++);
842
                    unique[0] = tolower(unique[0]);
843
 
844
                    Tcl_DStringTrunc(&buffer, 0);
845
                    Tcl_DStringAppend(&buffer, token, -1);
846
                    Tcl_DStringAppend(&buffer, unique, -1);
847
                    Tcl_DStringAppend(&buffer, start+5, -1);
848
 
849
                    objName = Tcl_DStringValue(&buffer);
850
                    if (Itcl_FindObject(interp, objName, &newObj) != TCL_OK) {
851
                        break;  /* if an error is found, bail out! */
852
                    }
853
                } while (newObj != NULL);
854
 
855
                *start = tmp;       /* undo null-termination */
856
                objName = Tcl_DStringValue(&buffer);
857
                break;              /* object name is ready to go! */
858
            }
859
        }
860
        else {
861
            match = "#auto";
862
            pos = start++;
863
        }
864
    }
865
 
866
    /*
867
     *  If "#auto" was not found, then just use object name as-is.
868
     */
869
    if (objName == NULL) {
870
        objName = token;
871
    }
872
 
873
    /*
874
     *  Try to create a new object.  If successful, return the
875
     *  object name as the result of this command.
876
     */
877
    result = Itcl_CreateObject(interp, objName, cdefnPtr,
878
        objc-2, objv+2, &newObj);
879
 
880
    if (result == TCL_OK) {
881
        Tcl_SetResult(interp, objName, TCL_VOLATILE);
882
    }
883
 
884
    Tcl_DStringFree(&buffer);
885
    return result;
886
}
887
 
888
 
889
/*
890
 * ------------------------------------------------------------------------
891
 *  Itcl_ClassCmdResolver()
892
 *
893
 *  Used by the class namespaces to handle name resolution for all
894
 *  commands.  This procedure looks for references to class methods
895
 *  and procs, and returns TCL_OK along with the appropriate Tcl
896
 *  command in the rPtr argument.  If a particular command is private,
897
 *  this procedure returns TCL_ERROR and access to the command is
898
 *  denied.  If a command is not recognized, this procedure returns
899
 *  TCL_CONTINUE, and lookup continues via the normal Tcl name
900
 *  resolution rules.
901
 * ------------------------------------------------------------------------
902
 */
903
int
904
Itcl_ClassCmdResolver(interp, name, context, flags, rPtr)
905
    Tcl_Interp *interp;       /* current interpreter */
906
    char* name;               /* name of the command being accessed */
907
    Tcl_Namespace *context;   /* namespace performing the resolution */
908
    int flags;                /* TCL_LEAVE_ERR_MSG => leave error messages
909
                               *   in interp if anything goes wrong */
910
    Tcl_Command *rPtr;        /* returns: resolved command */
911
{
912
    ItclClass *cdefn = (ItclClass*)context->clientData;
913
 
914
    Tcl_HashEntry *entry;
915
    ItclMemberFunc *mfunc;
916
    Command *cmdPtr;
917
 
918
    /*
919
     *  If the command is a member function, and if it is
920
     *  accessible, return its Tcl command handle.
921
     */
922
    entry = Tcl_FindHashEntry(&cdefn->resolveCmds, name);
923
    if (!entry) {
924
        return TCL_CONTINUE;
925
    }
926
 
927
    mfunc = (ItclMemberFunc*)Tcl_GetHashValue(entry);
928
 
929
 
930
    /*
931
     *  For protected/private functions, figure out whether or
932
     *  not the function is accessible from the current context.
933
     *
934
     *  TRICKY NOTE:  Use Itcl_GetTrueNamespace to determine
935
     *    the current context.  If the current call frame is
936
     *    "transparent", this handles it properly.
937
     */
938
    if (mfunc->member->protection != ITCL_PUBLIC) {
939
        context = Itcl_GetTrueNamespace(interp, cdefn->info);
940
 
941
        if (!Itcl_CanAccessFunc(mfunc, context)) {
942
 
943
            if ((flags & TCL_LEAVE_ERR_MSG) != 0) {
944
                Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
945
                    "can't access \"", name, "\": ",
946
                    Itcl_ProtectionStr(mfunc->member->protection),
947
                    " variable",
948
                    (char*)NULL);
949
            }
950
            return TCL_ERROR;
951
        }
952
    }
953
 
954
    /*
955
     *  Looks like we found an accessible member function.
956
     *
957
     *  TRICKY NOTE:  Check to make sure that the command handle
958
     *    is still valid.  If someone has deleted or renamed the
959
     *    command, it may not be.  This is just the time to catch
960
     *    it--as it is being resolved again by the compiler.
961
     */
962
    cmdPtr = (Command*)mfunc->accessCmd;
963
    if (!cmdPtr || cmdPtr->deleted) {
964
        mfunc->accessCmd = NULL;
965
 
966
        if ((flags & TCL_LEAVE_ERR_MSG) != 0) {
967
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
968
                "can't access \"", name, "\": deleted or redefined\n",
969
                "(use the \"body\" command to redefine methods/procs)",
970
                (char*)NULL);
971
        }
972
        return TCL_ERROR;   /* disallow access! */
973
    }
974
 
975
    *rPtr = mfunc->accessCmd;
976
    return TCL_OK;
977
}
978
 
979
 
980
/*
981
 * ------------------------------------------------------------------------
982
 *  Itcl_ClassVarResolver()
983
 *
984
 *  Used by the class namespaces to handle name resolution for runtime
985
 *  variable accesses.  This procedure looks for references to both
986
 *  common variables and instance variables at runtime.  It is used as
987
 *  a second line of defense, to handle references that could not be
988
 *  resolved as compiled locals.
989
 *
990
 *  If a variable is found, this procedure returns TCL_OK along with
991
 *  the appropriate Tcl variable in the rPtr argument.  If a particular
992
 *  variable is private, this procedure returns TCL_ERROR and access
993
 *  to the variable is denied.  If a variable is not recognized, this
994
 *  procedure returns TCL_CONTINUE, and lookup continues via the normal
995
 *  Tcl name resolution rules.
996
 * ------------------------------------------------------------------------
997
 */
998
int
999
Itcl_ClassVarResolver(interp, name, context, flags, rPtr)
1000
    Tcl_Interp *interp;       /* current interpreter */
1001
    char* name;               /* name of the variable being accessed */
1002
    Tcl_Namespace *context;   /* namespace performing the resolution */
1003
    int flags;                /* TCL_LEAVE_ERR_MSG => leave error messages
1004
                               *   in interp if anything goes wrong */
1005
    Tcl_Var *rPtr;            /* returns: resolved variable */
1006
{
1007
    ItclClass *cdefn = (ItclClass*)context->clientData;
1008
    ItclObject *contextObj;
1009
    Tcl_CallFrame *framePtr;
1010
    Tcl_HashEntry *entry;
1011
    ItclVarLookup *vlookup;
1012
 
1013
    assert(Itcl_IsClassNamespace(context));
1014
 
1015
    /*
1016
     *  If this is a global variable, handle it in the usual
1017
     *  Tcl manner.
1018
     */
1019
    if (flags & TCL_GLOBAL_ONLY) {
1020
        return TCL_CONTINUE;
1021
    }
1022
 
1023
    /*
1024
     *  See if the variable is a known data member and accessible.
1025
     */
1026
    entry = Tcl_FindHashEntry(&cdefn->resolveVars, name);
1027
    if (entry == NULL) {
1028
        return TCL_CONTINUE;
1029
    }
1030
 
1031
    vlookup = (ItclVarLookup*)Tcl_GetHashValue(entry);
1032
    if (!vlookup->accessible) {
1033
        return TCL_CONTINUE;
1034
    }
1035
 
1036
    /*
1037
     * If this is a common data member, then its variable
1038
     * is easy to find.  Return it directly.
1039
     */
1040
    if ((vlookup->vdefn->member->flags & ITCL_COMMON) != 0) {
1041
        *rPtr = vlookup->var.common;
1042
        return TCL_OK;
1043
    }
1044
 
1045
    /*
1046
     *  If this is an instance variable, then we have to
1047
     *  find the object context, then index into its data
1048
     *  array to get the actual variable.
1049
     */
1050
    framePtr = _Tcl_GetCallFrame(interp, 0);
1051
 
1052
    entry = Tcl_FindHashEntry(&cdefn->info->contextFrames, (char*)framePtr);
1053
    if (entry == NULL) {
1054
        return TCL_CONTINUE;
1055
    }
1056
    contextObj = (ItclObject*)Tcl_GetHashValue(entry);
1057
 
1058
    /*
1059
     *  TRICKY NOTE:  We've resolved the variable in the current
1060
     *    class context, but we must also be careful to get its
1061
     *    index from the most-specific class context.  Variables
1062
     *    are arranged differently depending on which class
1063
     *    constructed the object.
1064
     */
1065
    if (contextObj->classDefn != vlookup->vdefn->member->classDefn) {
1066
        entry = Tcl_FindHashEntry(&contextObj->classDefn->resolveVars,
1067
            vlookup->vdefn->member->fullname);
1068
 
1069
        if (entry) {
1070
            vlookup = (ItclVarLookup*)Tcl_GetHashValue(entry);
1071
        }
1072
    }
1073
    *rPtr = (Tcl_Var)contextObj->data[vlookup->var.index];
1074
    return TCL_OK;
1075
}
1076
 
1077
 
1078
/*
1079
 * ------------------------------------------------------------------------
1080
 *  Itcl_ClassCompiledVarResolver()
1081
 *
1082
 *  Used by the class namespaces to handle name resolution for compile
1083
 *  time variable accesses.  This procedure looks for references to
1084
 *  both common variables and instance variables at compile time.  If
1085
 *  the variables are found, they are characterized in a generic way
1086
 *  by their ItclVarLookup record.  At runtime, Tcl constructs the
1087
 *  compiled local variables by calling ItclClassRuntimeVarResolver.
1088
 *
1089
 *  If a variable is found, this procedure returns TCL_OK along with
1090
 *  information about the variable in the rPtr argument.  If a particular
1091
 *  variable is private, this procedure returns TCL_ERROR and access
1092
 *  to the variable is denied.  If a variable is not recognized, this
1093
 *  procedure returns TCL_CONTINUE, and lookup continues via the normal
1094
 *  Tcl name resolution rules.
1095
 * ------------------------------------------------------------------------
1096
 */
1097
int
1098
Itcl_ClassCompiledVarResolver(interp, name, length, context, rPtr)
1099
    Tcl_Interp *interp;         /* current interpreter */
1100
    char* name;                 /* name of the variable being accessed */
1101
    int length;                 /* number of characters in name */
1102
    Tcl_Namespace *context;     /* namespace performing the resolution */
1103
    Tcl_ResolvedVarInfo **rPtr; /* returns: info that makes it possible to
1104
                                 *   resolve the variable at runtime */
1105
{
1106
    ItclClass *cdefn = (ItclClass*)context->clientData;
1107
    Tcl_HashEntry *entry;
1108
    ItclVarLookup *vlookup;
1109
    char *buffer, storage[64];
1110
 
1111
    assert(Itcl_IsClassNamespace(context));
1112
 
1113
    /*
1114
     *  Copy the name to local storage so we can NULL terminate it.
1115
     *  If the name is long, allocate extra space for it.
1116
     */
1117
    if (length < sizeof(storage)) {
1118
        buffer = storage;
1119
    } else {
1120
        buffer = (char*)ckalloc((unsigned)(length+1));
1121
    }
1122
    memcpy((void*)buffer, (void*)name, (size_t)length);
1123
    buffer[length] = '\0';
1124
 
1125
    entry = Tcl_FindHashEntry(&cdefn->resolveVars, buffer);
1126
 
1127
    if (buffer != storage) {
1128
        ckfree(buffer);
1129
    }
1130
 
1131
    /*
1132
     *  If the name is not found, or if it is inaccessible,
1133
     *  continue on with the normal Tcl name resolution rules.
1134
     */
1135
    if (entry == NULL) {
1136
        return TCL_CONTINUE;
1137
    }
1138
 
1139
    vlookup = (ItclVarLookup*)Tcl_GetHashValue(entry);
1140
    if (!vlookup->accessible) {
1141
        return TCL_CONTINUE;
1142
    }
1143
 
1144
    /*
1145
     *  Return the ItclVarLookup record.  At runtime, Tcl will
1146
     *  call ItclClassRuntimeVarResolver with this record, to
1147
     *  plug in the appropriate variable for the current object
1148
     *  context.
1149
     */
1150
    (*rPtr) = (Tcl_ResolvedVarInfo *) ckalloc(sizeof(ItclResolvedVarInfo));
1151
    (*rPtr)->fetchProc = ItclClassRuntimeVarResolver;
1152
    (*rPtr)->deleteProc = NULL;
1153
    ((ItclResolvedVarInfo*)(*rPtr))->vlookup = vlookup;
1154
 
1155
    return TCL_OK;
1156
}
1157
 
1158
 
1159
/*
1160
 * ------------------------------------------------------------------------
1161
 *  ItclClassRuntimeVarResolver()
1162
 *
1163
 *  Invoked when Tcl sets up the call frame for an [incr Tcl] method/proc
1164
 *  at runtime.  Resolves data members identified earlier by
1165
 *  Itcl_ClassCompiledVarResolver.  Returns the Tcl_Var representation
1166
 *  for the data member.
1167
 * ------------------------------------------------------------------------
1168
 */
1169
static Tcl_Var
1170
ItclClassRuntimeVarResolver(interp, resVarInfo)
1171
    Tcl_Interp *interp;               /* current interpreter */
1172
    Tcl_ResolvedVarInfo *resVarInfo;  /* contains ItclVarLookup rep
1173
                                       * for variable */
1174
{
1175
    ItclVarLookup *vlookup = ((ItclResolvedVarInfo*)resVarInfo)->vlookup;
1176
 
1177
    Tcl_CallFrame *framePtr;
1178
    ItclClass *cdefn;
1179
    ItclObject *contextObj;
1180
    Tcl_HashEntry *entry;
1181
 
1182
    /*
1183
     *  If this is a common data member, then the associated
1184
     *  variable is known directly.
1185
     */
1186
    if ((vlookup->vdefn->member->flags & ITCL_COMMON) != 0) {
1187
        return vlookup->var.common;
1188
    }
1189
    cdefn = vlookup->vdefn->member->classDefn;
1190
 
1191
    /*
1192
     *  Otherwise, get the current object context and find the
1193
     *  variable in its data table.
1194
     *
1195
     *  TRICKY NOTE:  Get the index for this variable using the
1196
     *    virtual table for the MOST-SPECIFIC class.
1197
     */
1198
    framePtr = _Tcl_GetCallFrame(interp, 0);
1199
 
1200
    entry = Tcl_FindHashEntry(&cdefn->info->contextFrames, (char*)framePtr);
1201
    if (entry) {
1202
        contextObj = (ItclObject*)Tcl_GetHashValue(entry);
1203
 
1204
        if (contextObj != NULL) {
1205
            if (contextObj->classDefn != vlookup->vdefn->member->classDefn) {
1206
                entry = Tcl_FindHashEntry(&contextObj->classDefn->resolveVars,
1207
                    vlookup->vdefn->member->fullname);
1208
 
1209
                if (entry) {
1210
                    vlookup = (ItclVarLookup*)Tcl_GetHashValue(entry);
1211
                }
1212
            }
1213
            return (Tcl_Var)contextObj->data[vlookup->var.index];
1214
        }
1215
    }
1216
    return NULL;
1217
}
1218
 
1219
 
1220
/*
1221
 * ------------------------------------------------------------------------
1222
 *  Itcl_BuildVirtualTables()
1223
 *
1224
 *  Invoked whenever the class heritage changes or members are added or
1225
 *  removed from a class definition to rebuild the member lookup
1226
 *  tables.  There are two tables:
1227
 *
1228
 *  METHODS:  resolveCmds
1229
 *    Used primarily in Itcl_ClassCmdResolver() to resolve all
1230
 *    command references in a namespace.
1231
 *
1232
 *  DATA MEMBERS:  resolveVars
1233
 *    Used primarily in Itcl_ClassVarResolver() to quickly resolve
1234
 *    variable references in each class scope.
1235
 *
1236
 *  These tables store every possible name for each command/variable
1237
 *  (member, class::member, namesp::class::member, etc.).  Members
1238
 *  in a derived class may shadow members with the same name in a
1239
 *  base class.  In that case, the simple name in the resolution
1240
 *  table will point to the most-specific member.
1241
 * ------------------------------------------------------------------------
1242
 */
1243
void
1244
Itcl_BuildVirtualTables(cdefnPtr)
1245
    ItclClass* cdefnPtr;       /* class definition being updated */
1246
{
1247
    Tcl_HashEntry *entry, *hPtr;
1248
    Tcl_HashSearch place;
1249
    ItclVarLookup *vlookup;
1250
    ItclVarDefn *vdefn;
1251
    ItclMemberFunc *mfunc;
1252
    ItclHierIter hier;
1253
    ItclClass *cdPtr;
1254
    Namespace* nsPtr;
1255
    Tcl_DString buffer, buffer2;
1256
    int newEntry;
1257
 
1258
    Tcl_DStringInit(&buffer);
1259
    Tcl_DStringInit(&buffer2);
1260
 
1261
    /*
1262
     *  Clear the variable resolution table.
1263
     */
1264
    entry = Tcl_FirstHashEntry(&cdefnPtr->resolveVars, &place);
1265
    while (entry) {
1266
        vlookup = (ItclVarLookup*)Tcl_GetHashValue(entry);
1267
        if (--vlookup->usage == 0) {
1268
            ckfree((char*)vlookup);
1269
        }
1270
        entry = Tcl_NextHashEntry(&place);
1271
    }
1272
    Tcl_DeleteHashTable(&cdefnPtr->resolveVars);
1273
    Tcl_InitHashTable(&cdefnPtr->resolveVars, TCL_STRING_KEYS);
1274
    cdefnPtr->numInstanceVars = 0;
1275
 
1276
    /*
1277
     *  Set aside the first object-specific slot for the built-in
1278
     *  "this" variable.  Only allocate one of these, even though
1279
     *  there is a definition for "this" in each class scope.
1280
     */
1281
    cdefnPtr->numInstanceVars++;
1282
 
1283
    /*
1284
     *  Scan through all classes in the hierarchy, from most to
1285
     *  least specific.  Add a lookup entry for each variable
1286
     *  into the table.
1287
     */
1288
    Itcl_InitHierIter(&hier, cdefnPtr);
1289
    cdPtr = Itcl_AdvanceHierIter(&hier);
1290
    while (cdPtr != NULL) {
1291
        entry = Tcl_FirstHashEntry(&cdPtr->variables, &place);
1292
        while (entry) {
1293
            vdefn = (ItclVarDefn*)Tcl_GetHashValue(entry);
1294
 
1295
            vlookup = (ItclVarLookup*)ckalloc(sizeof(ItclVarLookup));
1296
            vlookup->vdefn = vdefn;
1297
            vlookup->usage = 0;
1298
            vlookup->leastQualName = NULL;
1299
 
1300
            /*
1301
             *  If this variable is PRIVATE to another class scope,
1302
             *  then mark it as "inaccessible".
1303
             */
1304
            vlookup->accessible =
1305
                ( vdefn->member->protection != ITCL_PRIVATE ||
1306
                  vdefn->member->classDefn == cdefnPtr );
1307
 
1308
            /*
1309
             *  If this is a common variable, then keep a reference to
1310
             *  the variable directly.  Otherwise, keep an index into
1311
             *  the object's variable table.
1312
             */
1313
            if ((vdefn->member->flags & ITCL_COMMON) != 0) {
1314
                nsPtr = (Namespace*)cdPtr->namesp;
1315
                hPtr = Tcl_FindHashEntry(&nsPtr->varTable, vdefn->member->name);
1316
                assert(hPtr != NULL);
1317
 
1318
                vlookup->var.common = (Tcl_Var)Tcl_GetHashValue(hPtr);
1319
            }
1320
            else {
1321
                /*
1322
                 *  If this is a reference to the built-in "this"
1323
                 *  variable, then its index is "0".  Otherwise,
1324
                 *  add another slot to the end of the table.
1325
                 */
1326
                if ((vdefn->member->flags & ITCL_THIS_VAR) != 0) {
1327
                    vlookup->var.index = 0;
1328
                }
1329
                else {
1330
                    vlookup->var.index = cdefnPtr->numInstanceVars++;
1331
                }
1332
            }
1333
 
1334
            /*
1335
             *  Create all possible names for this variable and enter
1336
             *  them into the variable resolution table:
1337
             *     var
1338
             *     class::var
1339
             *     namesp1::class::var
1340
             *     namesp2::namesp1::class::var
1341
             *     ...
1342
             */
1343
            Tcl_DStringSetLength(&buffer, 0);
1344
            Tcl_DStringAppend(&buffer, vdefn->member->name, -1);
1345
            nsPtr = (Namespace*)cdPtr->namesp;
1346
 
1347
            while (1) {
1348
                entry = Tcl_CreateHashEntry(&cdefnPtr->resolveVars,
1349
                    Tcl_DStringValue(&buffer), &newEntry);
1350
 
1351
                if (newEntry) {
1352
                    Tcl_SetHashValue(entry, (ClientData)vlookup);
1353
                    vlookup->usage++;
1354
 
1355
                    if (!vlookup->leastQualName) {
1356
                        vlookup->leastQualName =
1357
                            Tcl_GetHashKey(&cdefnPtr->resolveVars, entry);
1358
                    }
1359
                }
1360
 
1361
                if (nsPtr == NULL) {
1362
                    break;
1363
                }
1364
                Tcl_DStringSetLength(&buffer2, 0);
1365
                Tcl_DStringAppend(&buffer2, Tcl_DStringValue(&buffer), -1);
1366
                Tcl_DStringSetLength(&buffer, 0);
1367
                Tcl_DStringAppend(&buffer, nsPtr->name, -1);
1368
                Tcl_DStringAppend(&buffer, "::", -1);
1369
                Tcl_DStringAppend(&buffer, Tcl_DStringValue(&buffer2), -1);
1370
 
1371
                nsPtr = nsPtr->parentPtr;
1372
            }
1373
 
1374
            /*
1375
             *  If this record is not needed, free it now.
1376
             */
1377
            if (vlookup->usage == 0) {
1378
                ckfree((char*)vlookup);
1379
            }
1380
            entry = Tcl_NextHashEntry(&place);
1381
        }
1382
        cdPtr = Itcl_AdvanceHierIter(&hier);
1383
    }
1384
    Itcl_DeleteHierIter(&hier);
1385
 
1386
    /*
1387
     *  Clear the command resolution table.
1388
     */
1389
    Tcl_DeleteHashTable(&cdefnPtr->resolveCmds);
1390
    Tcl_InitHashTable(&cdefnPtr->resolveCmds, TCL_STRING_KEYS);
1391
 
1392
    /*
1393
     *  Scan through all classes in the hierarchy, from most to
1394
     *  least specific.  Look for the first (most-specific) definition
1395
     *  of each member function, and enter it into the table.
1396
     */
1397
    Itcl_InitHierIter(&hier, cdefnPtr);
1398
    cdPtr = Itcl_AdvanceHierIter(&hier);
1399
    while (cdPtr != NULL) {
1400
        entry = Tcl_FirstHashEntry(&cdPtr->functions, &place);
1401
        while (entry) {
1402
            mfunc = (ItclMemberFunc*)Tcl_GetHashValue(entry);
1403
 
1404
            /*
1405
             *  Create all possible names for this function and enter
1406
             *  them into the command resolution table:
1407
             *     func
1408
             *     class::func
1409
             *     namesp1::class::func
1410
             *     namesp2::namesp1::class::func
1411
             *     ...
1412
             */
1413
            Tcl_DStringSetLength(&buffer, 0);
1414
            Tcl_DStringAppend(&buffer, mfunc->member->name, -1);
1415
            nsPtr = (Namespace*)cdPtr->namesp;
1416
 
1417
            while (1) {
1418
                entry = Tcl_CreateHashEntry(&cdefnPtr->resolveCmds,
1419
                    Tcl_DStringValue(&buffer), &newEntry);
1420
 
1421
                if (newEntry) {
1422
                    Tcl_SetHashValue(entry, (ClientData)mfunc);
1423
                }
1424
 
1425
                if (nsPtr == NULL) {
1426
                    break;
1427
                }
1428
                Tcl_DStringSetLength(&buffer2, 0);
1429
                Tcl_DStringAppend(&buffer2, Tcl_DStringValue(&buffer), -1);
1430
                Tcl_DStringSetLength(&buffer, 0);
1431
                Tcl_DStringAppend(&buffer, nsPtr->name, -1);
1432
                Tcl_DStringAppend(&buffer, "::", -1);
1433
                Tcl_DStringAppend(&buffer, Tcl_DStringValue(&buffer2), -1);
1434
 
1435
                nsPtr = nsPtr->parentPtr;
1436
            }
1437
            entry = Tcl_NextHashEntry(&place);
1438
        }
1439
        cdPtr = Itcl_AdvanceHierIter(&hier);
1440
    }
1441
    Itcl_DeleteHierIter(&hier);
1442
 
1443
    Tcl_DStringFree(&buffer);
1444
    Tcl_DStringFree(&buffer2);
1445
}
1446
 
1447
 
1448
/*
1449
 * ------------------------------------------------------------------------
1450
 *  Itcl_CreateVarDefn()
1451
 *
1452
 *  Creates a new class variable definition.  If this is a public
1453
 *  variable, it may have a bit of "config" code that is used to
1454
 *  update the object whenever the variable is modified via the
1455
 *  built-in "configure" method.
1456
 *
1457
 *  Returns TCL_ERROR along with an error message in the specified
1458
 *  interpreter if anything goes wrong.  Otherwise, this returns
1459
 *  TCL_OK and a pointer to the new variable definition in "vdefnPtr".
1460
 * ------------------------------------------------------------------------
1461
 */
1462
int
1463
Itcl_CreateVarDefn(interp, cdefn, name, init, config, vdefnPtr)
1464
    Tcl_Interp *interp;       /* interpreter managing this transaction */
1465
    ItclClass* cdefn;         /* class containing this variable */
1466
    char* name;               /* variable name */
1467
    char* init;               /* initial value */
1468
    char* config;             /* code invoked when variable is configured */
1469
    ItclVarDefn** vdefnPtr;   /* returns: new variable definition */
1470
{
1471
    int newEntry;
1472
    ItclVarDefn *vdefn;
1473
    ItclMemberCode *mcode;
1474
    Tcl_HashEntry *entry;
1475
 
1476
    /*
1477
     *  Add this variable to the variable table for the class.
1478
     *  Make sure that the variable name does not already exist.
1479
     */
1480
    entry = Tcl_CreateHashEntry(&cdefn->variables, name, &newEntry);
1481
    if (!newEntry) {
1482
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1483
            "variable name \"", name, "\" already defined in class \"",
1484
            cdefn->fullname, "\"",
1485
            (char*)NULL);
1486
        return TCL_ERROR;
1487
    }
1488
 
1489
    /*
1490
     *  If this variable has some "config" code, try to capture
1491
     *  its implementation.
1492
     */
1493
    if (config) {
1494
        if (Itcl_CreateMemberCode(interp, cdefn, (char*)NULL, config,
1495
            &mcode) != TCL_OK) {
1496
 
1497
            Tcl_DeleteHashEntry(entry);
1498
            return TCL_ERROR;
1499
        }
1500
        Itcl_PreserveData((ClientData)mcode);
1501
        Itcl_EventuallyFree((ClientData)mcode, Itcl_DeleteMemberCode);
1502
    }
1503
    else {
1504
        mcode = NULL;
1505
    }
1506
 
1507
 
1508
    /*
1509
     *  If everything looks good, create the variable definition.
1510
     */
1511
    vdefn = (ItclVarDefn*)ckalloc(sizeof(ItclVarDefn));
1512
    vdefn->member = Itcl_CreateMember(interp, cdefn, name);
1513
    vdefn->member->code = mcode;
1514
 
1515
    if (vdefn->member->protection == ITCL_DEFAULT_PROTECT) {
1516
        vdefn->member->protection = ITCL_PROTECTED;
1517
    }
1518
 
1519
    if (init) {
1520
        vdefn->init = (char*)ckalloc((unsigned)(strlen(init)+1));
1521
        strcpy(vdefn->init, init);
1522
    }
1523
    else {
1524
        vdefn->init = NULL;
1525
    }
1526
 
1527
    Tcl_SetHashValue(entry, (ClientData)vdefn);
1528
 
1529
    *vdefnPtr = vdefn;
1530
    return TCL_OK;
1531
}
1532
 
1533
/*
1534
 * ------------------------------------------------------------------------
1535
 *  Itcl_DeleteVarDefn()
1536
 *
1537
 *  Destroys a variable definition created by Itcl_CreateVarDefn(),
1538
 *  freeing all resources associated with it.
1539
 * ------------------------------------------------------------------------
1540
 */
1541
void
1542
Itcl_DeleteVarDefn(vdefn)
1543
    ItclVarDefn *vdefn;   /* variable definition to be destroyed */
1544
{
1545
    Itcl_DeleteMember(vdefn->member);
1546
 
1547
    if (vdefn->init) {
1548
        ckfree(vdefn->init);
1549
    }
1550
    ckfree((char*)vdefn);
1551
}
1552
 
1553
 
1554
/*
1555
 * ------------------------------------------------------------------------
1556
 *  Itcl_GetCommonVar()
1557
 *
1558
 *  Returns the current value for a common class variable.  The member
1559
 *  name is interpreted with respect to the given class scope.  That
1560
 *  scope is installed as the current context before querying the
1561
 *  variable.  This by-passes the protection level in case the variable
1562
 *  is "private".
1563
 *
1564
 *  If successful, this procedure returns a pointer to a string value
1565
 *  which remains alive until the variable changes it value.  If
1566
 *  anything goes wrong, this returns NULL.
1567
 * ------------------------------------------------------------------------
1568
 */
1569
char*
1570
Itcl_GetCommonVar(interp, name, contextClass)
1571
    Tcl_Interp *interp;        /* current interpreter */
1572
    char *name;                /* name of desired instance variable */
1573
    ItclClass *contextClass;   /* name is interpreted in this scope */
1574
{
1575
    char *val = NULL;
1576
    int result;
1577
    Tcl_CallFrame frame;
1578
 
1579
    /*
1580
     *  Activate the namespace for the given class.  That installs
1581
     *  the appropriate name resolution rules and by-passes any
1582
     *  security restrictions.
1583
     */
1584
    result = Tcl_PushCallFrame(interp, &frame,
1585
                 contextClass->namesp, /*isProcCallFrame*/ 0);
1586
 
1587
    if (result == TCL_OK) {
1588
        val = Tcl_GetVar2(interp, name, (char*)NULL, 0);
1589
        Tcl_PopCallFrame(interp);
1590
    }
1591
    return val;
1592
}
1593
 
1594
 
1595
/*
1596
 * ------------------------------------------------------------------------
1597
 *  Itcl_CreateMember()
1598
 *
1599
 *  Creates the data record representing a class member.  This is the
1600
 *  generic representation for a data member or member function.
1601
 *  Returns a pointer to the new representation.
1602
 * ------------------------------------------------------------------------
1603
 */
1604
ItclMember*
1605
Itcl_CreateMember(interp, cdefn, name)
1606
    Tcl_Interp* interp;            /* interpreter managing this action */
1607
    ItclClass *cdefn;              /* class definition */
1608
    char* name;                    /* name of new member */
1609
{
1610
    ItclMember *memPtr;
1611
    int fullsize;
1612
 
1613
    /*
1614
     *  Allocate the memory for a class member and fill in values.
1615
     */
1616
    memPtr = (ItclMember*)ckalloc(sizeof(ItclMember));
1617
    memPtr->interp       = interp;
1618
    memPtr->classDefn    = cdefn;
1619
    memPtr->flags        = 0;
1620
    memPtr->protection   = Itcl_Protection(interp, 0);
1621
    memPtr->code         = NULL;
1622
 
1623
    fullsize = strlen(cdefn->fullname) + strlen(name) + 2;
1624
    memPtr->fullname = (char*)ckalloc((unsigned)(fullsize+1));
1625
    strcpy(memPtr->fullname, cdefn->fullname);
1626
    strcat(memPtr->fullname, "::");
1627
    strcat(memPtr->fullname, name);
1628
 
1629
    memPtr->name = (char*)ckalloc((unsigned)(strlen(name)+1));
1630
    strcpy(memPtr->name, name);
1631
 
1632
    return memPtr;
1633
}
1634
 
1635
 
1636
/*
1637
 * ------------------------------------------------------------------------
1638
 *  Itcl_DeleteMember()
1639
 *
1640
 *  Destroys all data associated with the given member function definition.
1641
 *  Usually invoked by the interpreter when a member function is deleted.
1642
 * ------------------------------------------------------------------------
1643
 */
1644
void
1645
Itcl_DeleteMember(memPtr)
1646
    ItclMember *memPtr;  /* pointer to member function definition */
1647
{
1648
    if (memPtr) {
1649
        ckfree(memPtr->name);
1650
        ckfree(memPtr->fullname);
1651
 
1652
        if (memPtr->code) {
1653
            Itcl_ReleaseData((ClientData)memPtr->code);
1654
        }
1655
        memPtr->code = NULL;
1656
 
1657
        ckfree((char*)memPtr);
1658
    }
1659
}
1660
 
1661
 
1662
/*
1663
 * ------------------------------------------------------------------------
1664
 *  Itcl_InitHierIter()
1665
 *
1666
 *  Initializes an iterator for traversing the hierarchy of the given
1667
 *  class.  Subsequent calls to Itcl_AdvanceHierIter() will return
1668
 *  the base classes in order from most-to-least specific.
1669
 * ------------------------------------------------------------------------
1670
 */
1671
void
1672
Itcl_InitHierIter(iter,cdefn)
1673
    ItclHierIter *iter;   /* iterator used for traversal */
1674
    ItclClass *cdefn;     /* class definition for start of traversal */
1675
{
1676
    Itcl_InitStack(&iter->stack);
1677
    Itcl_PushStack((ClientData)cdefn, &iter->stack);
1678
    iter->current = cdefn;
1679
}
1680
 
1681
/*
1682
 * ------------------------------------------------------------------------
1683
 *  Itcl_DeleteHierIter()
1684
 *
1685
 *  Destroys an iterator for traversing class hierarchies, freeing
1686
 *  all memory associated with it.
1687
 * ------------------------------------------------------------------------
1688
 */
1689
void
1690
Itcl_DeleteHierIter(iter)
1691
    ItclHierIter *iter;  /* iterator used for traversal */
1692
{
1693
    Itcl_DeleteStack(&iter->stack);
1694
    iter->current = NULL;
1695
}
1696
 
1697
/*
1698
 * ------------------------------------------------------------------------
1699
 *  Itcl_AdvanceHierIter()
1700
 *
1701
 *  Moves a class hierarchy iterator forward to the next base class.
1702
 *  Returns a pointer to the current class definition, or NULL when
1703
 *  the end of the hierarchy has been reached.
1704
 * ------------------------------------------------------------------------
1705
 */
1706
ItclClass*
1707
Itcl_AdvanceHierIter(iter)
1708
    ItclHierIter *iter;  /* iterator used for traversal */
1709
{
1710
    register Itcl_ListElem *elem;
1711
    ItclClass *cdPtr;
1712
 
1713
    iter->current = (ItclClass*)Itcl_PopStack(&iter->stack);
1714
 
1715
    /*
1716
     *  Push classes onto the stack in reverse order, so that
1717
     *  they will be popped off in the proper order.
1718
     */
1719
    if (iter->current) {
1720
        cdPtr = (ItclClass*)iter->current;
1721
        elem = Itcl_LastListElem(&cdPtr->bases);
1722
        while (elem) {
1723
            Itcl_PushStack(Itcl_GetListValue(elem), &iter->stack);
1724
            elem = Itcl_PrevListElem(elem);
1725
        }
1726
    }
1727
    return iter->current;
1728
}

powered by: WebSVN 2.1.0

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