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

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tix/] [generic/] [tixMethod.c] - Blame information for rev 578

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

Line No. Rev Author Line
1 578 markom
/*
2
 * tixMethod.c --
3
 *
4
 *      Handle the calling of class methods.
5
 *
6
 *      Implements the basic OOP class mechanism for the Tix Intrinsics.
7
 *
8
 * Copyright (c) 1996, Expert Interface Technologies
9
 *
10
 * See the file "license.terms" for information on usage and redistribution
11
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12
 *
13
 */
14
 
15
 
16
/* ToDo:
17
 *
18
 * 1) Tix_CallMethod() needs to be re-written
19
 *
20
 */
21
#include <tclInt.h>
22
#include <tk.h>
23
#include <tixPort.h>
24
#include <tixInt.h>
25
#include <tixItcl.h>
26
 
27
#define GetMethodTable(interp) (_TixGetHashTable(interp, "tixMethodTab", MethodTableDeleteProc))
28
 
29
static int              Tix_CallMethodByContext _ANSI_ARGS_((
30
                            Tcl_Interp * interp, char * context,
31
                            char * widRec, char * method, int argc,
32
                            char ** argv));
33
static void             Tix_RestoreContext _ANSI_ARGS_((
34
                            Tcl_Interp * interp, char * widRec,
35
                            char * oldContext));
36
static void             Tix_SetContext _ANSI_ARGS_((
37
                            Tcl_Interp * interp, char * widRec,
38
                            char * newContext));
39
static char *           Tix_SaveContext _ANSI_ARGS_((Tcl_Interp * interp,
40
                            char * widRec));
41
static void             MethodTableDeleteProc _ANSI_ARGS_((
42
                            ClientData clientData, Tcl_Interp *interp));
43
 
44
/*
45
 *
46
 * argv[1] = widget record
47
 * argv[2] = method
48
 * argv[3+] = args
49
 *
50
 */
51
TIX_DEFINE_CMD(Tix_CallMethodCmd)
52
{
53
    char * context;
54
    char * newContext;
55
    char * widRec = argv[1];
56
    char * method = argv[2];
57
    int    result;
58
 
59
    if (argc<3) {
60
        return Tix_ArgcError(interp, argc, argv, 1, "w method ...");
61
    }
62
 
63
    if ((context = GET_RECORD(interp, widRec, "className")) == NULL) {
64
        Tcl_ResetResult(interp);
65
        Tcl_AppendResult(interp, "invalid object reference \"", widRec,
66
            "\"", (char*)NULL);
67
        return TCL_ERROR;
68
    }
69
 
70
    newContext = Tix_FindMethod(interp, context, method);
71
 
72
    if (newContext) {
73
        result = Tix_CallMethodByContext(interp, newContext, widRec, method,
74
            argc-3, argv+3);
75
    } else {
76
        Tcl_ResetResult(interp);
77
        Tcl_AppendResult(interp, "cannot call method \"", method,
78
            "\" for context \"", context, "\".", (char*)NULL);
79
        Tcl_SetVar(interp, "errorInfo", interp->result, TCL_GLOBAL_ONLY);
80
        result = TCL_ERROR;
81
    }
82
 
83
    return result;
84
}
85
 
86
/*
87
 *
88
 * argv[1] = widget record
89
 * argv[2] = method
90
 * argv[3+] = args
91
 *
92
 */
93
TIX_DEFINE_CMD(Tix_ChainMethodCmd)
94
{
95
    char * context;
96
    char * superClassContext;
97
    char * newContext;
98
    char * widRec = argv[1];
99
    char * method = argv[2];
100
    int    result;
101
 
102
    if (argc<3) {
103
        return Tix_ArgcError(interp, argc, argv, 1, "w method ...");
104
    }
105
 
106
    if ((context = Tix_GetContext(interp, widRec)) == NULL) {
107
        return TCL_ERROR;
108
    }
109
 
110
    if (Tix_SuperClass(interp, context, &superClassContext) != TCL_OK) {
111
        return TCL_ERROR;
112
    }
113
 
114
    if (superClassContext == NULL) {
115
        Tcl_ResetResult(interp);
116
        Tcl_AppendResult(interp, "no superclass exists for context \"",
117
            context, "\".", (char*)NULL);
118
        result = TCL_ERROR;
119
        goto done;
120
    }
121
 
122
    newContext = Tix_FindMethod(interp, superClassContext, method);
123
 
124
    if (newContext) {
125
        result = Tix_CallMethodByContext(interp, newContext, widRec,
126
            method, argc-3, argv+3);
127
    } else {
128
        Tcl_ResetResult(interp);
129
        Tcl_AppendResult(interp, "cannot chain method \"", method,
130
            "\" for context \"", context, "\".", (char*)NULL);
131
        Tcl_SetVar(interp, "errorInfo", interp->result, TCL_GLOBAL_ONLY);
132
        result = TCL_ERROR;
133
        goto done;
134
    }
135
 
136
  done:
137
    return result;
138
}
139
 
140
/*
141
 *
142
 * argv[1] = widget record
143
 * argv[2] = class (context)
144
 * argv[3] = method
145
 *
146
 */
147
TIX_DEFINE_CMD(Tix_GetMethodCmd)
148
{
149
    char * newContext;
150
    char * context= argv[2];
151
    char * method = argv[3];
152
    char * cmdName;
153
 
154
    if (argc!=4) {
155
        return Tix_ArgcError(interp, argc, argv, 1, "w class method");
156
    }
157
 
158
    newContext = Tix_FindMethod(interp, context, method);
159
 
160
    if (newContext) {
161
        cmdName = Tix_GetMethodFullName(newContext, method);
162
        Tcl_ResetResult(interp);
163
        Tcl_AppendResult(interp, cmdName, NULL);
164
        ckfree(cmdName);
165
    } else {
166
        Tcl_SetResult(interp, "", TCL_STATIC);
167
    }
168
 
169
    return TCL_OK;
170
}
171
 
172
/*----------------------------------------------------------------------
173
 * Tix_FindMethod
174
 *
175
 *      Starting with class "context", find the first class that defines
176
 * the method. This class must be the same as the class "context" or
177
 * a superclass of the class "context".
178
 */
179
char *
180
Tix_FindMethod(interp, context, method)
181
    Tcl_Interp * interp;
182
    char * context;
183
    char * method;
184
{
185
    char      * theContext;
186
    int         isNew;
187
    char      * key;
188
    Tcl_HashEntry *hashPtr;
189
 
190
    key = Tix_GetMethodFullName(context, method);
191
    hashPtr = Tcl_CreateHashEntry(GetMethodTable(interp), key, &isNew);
192
    ckfree(key);
193
 
194
    if (!isNew) {
195
        theContext = (char *) Tcl_GetHashValue(hashPtr);
196
    } else {
197
        for (theContext = context; theContext;) {
198
            if (Tix_ExistMethod(interp, theContext, method)) {
199
                break;
200
            }
201
            /* Go to its superclass and see if it has the method */
202
            if (Tix_SuperClass(interp, theContext, &theContext) != TCL_OK) {
203
                return NULL;
204
            }
205
            if (theContext == NULL) {
206
                return NULL;
207
            }
208
        }
209
 
210
        if (theContext != NULL) {
211
            /*
212
             * theContext may point to the stack. We have to put it
213
             * in some more permanent place.
214
             */
215
            theContext = (char*)tixStrDup(theContext);
216
        }
217
        Tcl_SetHashValue(hashPtr, (char*)theContext);
218
    }
219
 
220
    return theContext;
221
}
222
 
223
/*----------------------------------------------------------------------
224
 * Tix_CallMethod
225
 *
226
 *      Starting with class "context", find the first class that defines
227
 * the method. Call this method.
228
 */
229
int Tix_CallMethod(interp, context, widRec, method, argc, argv)
230
    Tcl_Interp * interp;
231
    char * context;
232
    char * widRec;
233
    char * method;
234
    int argc;
235
    char ** argv;
236
{
237
    char * targetContext;
238
 
239
    targetContext = Tix_FindMethod(interp, context, method);
240
    if (targetContext != NULL) {
241
        return Tix_CallMethodByContext(interp, targetContext, widRec, method,
242
            argc, argv);
243
    }
244
    else {
245
        Tcl_ResetResult(interp);
246
        Tcl_AppendResult(interp, "cannot call method \"", method,
247
            "\" for context \"", context, "\".", (char*)NULL);
248
        Tcl_SetVar(interp, "errorInfo", interp->result, TCL_GLOBAL_ONLY);
249
        return TCL_ERROR;
250
    }
251
}
252
 
253
/*----------------------------------------------------------------------
254
 * Tix_FindConfigSpec
255
 *
256
 *      Starting with class "classRec", find the first class that defines
257
 * the option flag. This class must be the same as the class "classRec" or
258
 * a superclass of the class "classRec".
259
 */
260
 
261
/* save the old context: calling a method of a superclass will
262
 * change the context of a widget.
263
 */
264
static char * Tix_SaveContext(interp, widRec)
265
    Tcl_Interp * interp;
266
    char * widRec;
267
{
268
    char * context;
269
 
270
    if ((context = GET_RECORD(interp, widRec, "context")) == NULL) {
271
        Tcl_ResetResult(interp);
272
        Tcl_AppendResult(interp, "invalid object reference \"", widRec,
273
            "\"", (char*)NULL);
274
        return NULL;
275
    }
276
    else {
277
        return (char*)tixStrDup(context);
278
    }
279
}
280
 
281
static void Tix_RestoreContext(interp, widRec, oldContext)
282
    Tcl_Interp * interp;
283
    char * widRec;
284
    char * oldContext;
285
{
286
    SET_RECORD(interp, widRec, "context", oldContext);
287
    ckfree(oldContext);
288
}
289
 
290
static void Tix_SetContext(interp, widRec, newContext)
291
    Tcl_Interp * interp;
292
    char * widRec;
293
    char * newContext;
294
{
295
    SET_RECORD(interp, widRec, "context", newContext);
296
}
297
 
298
 
299
char * Tix_GetContext(interp, widRec)
300
    Tcl_Interp * interp;
301
    char * widRec;
302
{
303
    char * context;
304
 
305
    if ((context = GET_RECORD(interp, widRec, "context")) == NULL) {
306
        Tcl_ResetResult(interp);
307
        Tcl_AppendResult(interp, "invalid object reference \"", widRec,
308
            "\"", (char*)NULL);
309
        return NULL;
310
    } else {
311
        return context;
312
    }
313
}
314
 
315
int Tix_SuperClass(interp, class, superClass_ret)
316
    Tcl_Interp * interp;
317
    char * class;
318
    char ** superClass_ret;
319
{
320
    char * superclass;
321
 
322
    if ((superclass = GET_RECORD(interp, class, "superClass")) == NULL) {
323
        Tcl_ResetResult(interp);
324
        Tcl_AppendResult(interp, "invalid class \"", class,
325
            "\"; ", (char*)NULL);
326
        return TCL_ERROR;
327
    }
328
 
329
    if (strlen(superclass) == 0) {
330
        *superClass_ret = (char*) NULL;
331
    } else {
332
        *superClass_ret =  superclass;
333
    }
334
 
335
    return TCL_OK;
336
}
337
 
338
char * Tix_GetMethodFullName(context, method)
339
    char * context;
340
    char * method;
341
{
342
    char * buff;
343
    int    max;
344
    int    conLen;
345
 
346
    conLen = strlen(context);
347
    max = conLen + strlen(method) + 3;
348
    buff = (char*)ckalloc(max * sizeof(char));
349
 
350
    strcpy(buff, context);
351
    strcpy(buff+conLen, ":");
352
    strcpy(buff+conLen+1, method);
353
 
354
    return buff;
355
}
356
 
357
#undef ITCL_2
358
 
359
#if !defined(ITCL_2) && !defined(TK_8_0_OR_LATER)
360
 
361
#define Tix_GetCommandInfo Tcl_GetCommandInfo
362
 
363
#else
364
/*
365
 *----------------------------------------------------------------------
366
 *
367
 * Tix_GetCommandInfo --
368
 *
369
 *      Returns various information about a Tcl command. Modified from
370
 *      Tcl_GetCommandInfo to work with ITcl 2.0. Always work in the global
371
 *      name space.
372
 *
373
 * Results:
374
 *      If cmdName exists in interp, then *infoPtr is modified to
375
 *      hold information about cmdName and 1 is returned.  If the
376
 *      command doesn't exist then 0 is returned and *infoPtr isn't
377
 *      modified.
378
 *
379
 * Side effects:
380
 *      None.
381
 *
382
 *----------------------------------------------------------------------
383
 */
384
int Tix_GetCommandInfo(interp, cmdName, infoPtr)
385
    Tcl_Interp *interp;
386
    char *cmdName;
387
    Tcl_CmdInfo *infoPtr;
388
{
389
    register Interp *iPtr = (Interp *) interp;
390
    int result;
391
    DECLARE_ITCL_NAMESP(nameSp, interp);
392
 
393
    result = TixItclSetGlobalNameSp(&nameSp, interp);
394
 
395
    if (result != 0) {
396
        result = Tcl_GetCommandInfo(interp, cmdName, infoPtr);
397
    }
398
 
399
    TixItclRestoreGlobalNameSp(&nameSp, interp);
400
    return result;
401
}
402
#endif
403
 
404
int Tix_ExistMethod(interp, context, method)
405
    Tcl_Interp * interp;
406
    char * context;
407
    char * method;
408
{
409
    char * cmdName;
410
    Tcl_CmdInfo dummy;
411
    int exist;
412
 
413
    cmdName = Tix_GetMethodFullName(context, method);
414
    exist = Tix_GetCommandInfo(interp, cmdName, &dummy);
415
 
416
    if (!exist) {
417
        if (Tix_GlobalVarEval(interp, "auto_load ", cmdName,
418
                (char*)NULL)!= TCL_OK) {
419
            goto done;
420
        }
421
        if (strcmp(interp->result, "1") == 0) {
422
            exist = 1;
423
        }
424
    }
425
 
426
  done:
427
    ckfree(cmdName);
428
    Tcl_SetResult(interp, NULL, TCL_STATIC);
429
    return exist;
430
}
431
 
432
/* %% There is a dirty version that uses the old argv, without having to
433
 * malloc a new argv.
434
 */
435
static int Tix_CallMethodByContext(interp, context, widRec, method, argc, argv)
436
    Tcl_Interp * interp;
437
    char * context;
438
    char * widRec;
439
    char * method;
440
    int    argc;
441
    char ** argv;
442
{
443
    char  * cmdName;
444
    int     i, result;
445
    char  * oldContext;
446
    char ** newArgv;
447
 
448
    if ((oldContext = Tix_SaveContext(interp, widRec)) == NULL) {
449
        return TCL_ERROR;
450
    }
451
    Tix_SetContext(interp, widRec, context);
452
 
453
    cmdName = Tix_GetMethodFullName(context, method);
454
 
455
    /* Create a new argv list */
456
    newArgv = (char**)ckalloc((argc+2)*sizeof(char*));
457
    newArgv[0] = cmdName;
458
    newArgv[1] = widRec;
459
    for (i=0; i< argc; i++) {
460
        newArgv[i+2] = argv[i];
461
    }
462
    result = Tix_EvalArgv(interp, argc+2, newArgv);
463
 
464
    Tix_RestoreContext(interp, widRec, oldContext);
465
    ckfree((char*)newArgv);
466
    ckfree(cmdName);
467
 
468
    return result;
469
}
470
 
471
#ifndef ITCL_2
472
 
473
#define Tix_GlobalEvalArgv(interp, cmdInfoPtr, argc, argv) \
474
    (*(cmdInfoPtr)->proc)((cmdInfoPtr)->clientData, interp, argc, argv)
475
 
476
#else
477
 
478
EXTERN int              Tix_GlobalEvalArgv _ANSI_ARGS_((Tcl_Interp * interp,
479
                            Tcl_CmdInfo * cmdInfoPtr, int argc));
480
 
481
int
482
Tix_GlobalEvalArgv(interp, cmdInfoPtr, argc, argv)
483
    Tcl_Interp * interp;
484
    Tcl_CmdInfo * cmdInfoPtr;
485
    int argc;
486
    char ** argv;
487
{
488
    register Interp *iPtr = (Interp *) interp;
489
    int result;
490
    CallFrame *savedVarFramePtr;
491
    Itcl_ActiveNamespace nsToken;
492
 
493
    savedVarFramePtr = iPtr->varFramePtr;
494
    iPtr->varFramePtr = NULL;
495
 
496
    nsToken = Itcl_ActivateNamesp(interp, (Itcl_Namespace)iPtr->globalNs);
497
    if (nsToken == NULL) {
498
        result = TCL_ERROR;
499
    }
500
    else {
501
        result = (*cmdInfoPtr->proc)(cmdInfoPtr->clientData,interp,argc,argv);
502
        Itcl_DeactivateNamesp(interp, nsToken);
503
    }
504
 
505
    iPtr->varFramePtr = savedVarFramePtr;
506
    return result;
507
}
508
#endif /* ITCL_2 */
509
 
510
int Tix_EvalArgv(interp, argc, argv)
511
    Tcl_Interp * interp;
512
    int argc;
513
    char ** argv;
514
{
515
    Tcl_CmdInfo cmdInfo;
516
 
517
    if (!Tix_GetCommandInfo(interp, argv[0], &cmdInfo)) {
518
        char * cmdArgv[2];
519
 
520
        /*
521
         * This comand is not defined yet -- looks like we have to auto-load it
522
         */
523
        if (!Tix_GetCommandInfo(interp, "auto_load", &cmdInfo)) {
524
            Tcl_ResetResult(interp);
525
            Tcl_AppendResult(interp, "cannot execute command \"auto_load\"",
526
                NULL);
527
            return TCL_ERROR;
528
        }
529
 
530
        cmdArgv[0] = "auto_load";
531
        cmdArgv[1] = argv[0];
532
 
533
        if ((*cmdInfo.proc)(cmdInfo.clientData, interp, 2, cmdArgv)!= TCL_OK){
534
            return TCL_ERROR;
535
        }
536
 
537
        if (!Tix_GetCommandInfo(interp, argv[0], &cmdInfo)) {
538
            Tcl_ResetResult(interp);
539
            Tcl_AppendResult(interp, "cannot autoload command \"",
540
                argv[0], "\"",NULL);
541
            return TCL_ERROR;
542
        }
543
    }
544
 
545
    return Tix_GlobalEvalArgv(interp, &cmdInfo, argc, argv);
546
}
547
 
548
char *
549
Tix_FindPublicMethod(interp, cPtr, method)
550
    Tcl_Interp * interp;
551
    TixClassRecord * cPtr;
552
    char * method;
553
{
554
    int i;
555
    int len = strlen(method);
556
 
557
    for (i=0; i<cPtr->nMethods; i++) {
558
        if (cPtr->methods[i][0] == method[0] &&
559
            strncmp(cPtr->methods[i], method, len)==0) {
560
            return cPtr->methods[i];
561
        }
562
    }
563
    return 0;
564
}
565
 
566
/*
567
 *----------------------------------------------------------------------
568
 * MethodTableDeleteProc --
569
 *
570
 *      This procedure is called when the interp is about to
571
 *      be deleted. It cleans up the hash entries and destroys the hash
572
 *      table.
573
 *
574
 * Results:
575
 *      None.
576
 *
577
 * Side effects:
578
 *      All class method contexts are deleted for this interpreter.
579
 *----------------------------------------------------------------------
580
 */
581
 
582
static void
583
MethodTableDeleteProc(clientData, interp)
584
    ClientData clientData;
585
    Tcl_Interp *interp;
586
{
587
    Tcl_HashTable * methodTablePtr = (Tcl_HashTable*)clientData;
588
    Tcl_HashSearch hashSearch;
589
    Tcl_HashEntry *hashPtr;
590
    char * context;
591
 
592
    for (hashPtr = Tcl_FirstHashEntry(methodTablePtr, &hashSearch);
593
         hashPtr;
594
         hashPtr = Tcl_NextHashEntry(&hashSearch)) {
595
 
596
        context = (char*)Tcl_GetHashValue(hashPtr);
597
        if (context) {
598
            ckfree(context);
599
        }
600
        Tcl_DeleteHashEntry(hashPtr);
601
    }
602
    Tcl_DeleteHashTable(methodTablePtr);
603
    ckfree((char*)methodTablePtr);
604
}

powered by: WebSVN 2.1.0

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