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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [itcl/] [itk/] [generic/] [itk_option.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * ------------------------------------------------------------------------
3
 *      PACKAGE:  [incr Tk]
4
 *  DESCRIPTION:  Building mega-widgets with [incr Tcl]
5
 *
6
 *  [incr Tk] provides a framework for building composite "mega-widgets"
7
 *  using [incr Tcl] classes.  It defines a set of base classes that are
8
 *  specialized to create all other widgets.
9
 *
10
 *  This file defines procedures used to manage mega-widget options
11
 *  specified within class definitions.
12
 *
13
 * ========================================================================
14
 *  AUTHOR:  Michael J. McLennan
15
 *           Bell Labs Innovations for Lucent Technologies
16
 *           mmclennan@lucent.com
17
 *           http://www.tcltk.com/itcl
18
 *
19
 *     RCS:  $Id: itk_option.c,v 1.1.1.1 2002-01-16 10:24:47 markom Exp $
20
 * ========================================================================
21
 *           Copyright (c) 1993-1998  Lucent Technologies, Inc.
22
 * ------------------------------------------------------------------------
23
 * See the file "license.terms" for information on usage and redistribution
24
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
25
 */
26
#include "itk.h"
27
 
28
/*
29
 *  FORWARD DECLARATIONS
30
 */
31
static char* ItkTraceClassDestroy _ANSI_ARGS_((ClientData cdata,
32
    Tcl_Interp *interp, char *name1, char *name2, int flags));
33
static Tcl_HashTable* ItkGetClassesWithOptInfo _ANSI_ARGS_((
34
    Tcl_Interp *interp));
35
static void ItkFreeClassesWithOptInfo _ANSI_ARGS_((ClientData cdata,
36
    Tcl_Interp *interp));
37
 
38
 
39
/*
40
 * ------------------------------------------------------------------------
41
 *  Itk_ClassOptionDefineCmd()
42
 *
43
 *  Invoked when a class definition is being parse to handle an
44
 *  itk_option declaration.  Adds a new option to a mega-widget
45
 *  declaration, with some code that will be executed whenever the
46
 *  option is changed via "configure".  If there is already an existing
47
 *  option by that name, then this new option is folded into the
48
 *  existing option, but the <init> value is ignored.  The X11 resource
49
 *  database names must be consistent with the existing option.
50
 *
51
 *  Handles the following syntax:
52
 *
53
 *      itk_option define <switch> <resName> <resClass> <init> ?<config>?
54
 *
55
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
56
 * ------------------------------------------------------------------------
57
 */
58
/* ARGSUSED */
59
int
60
Itk_ClassOptionDefineCmd(clientData, interp, objc, objv)
61
    ClientData clientData;   /* class parser info */
62
    Tcl_Interp *interp;      /* current interpreter */
63
    int objc;                /* number of arguments */
64
    Tcl_Obj *CONST objv[];   /* argument objects */
65
{
66
    ItclObjectInfo *info = (ItclObjectInfo*)clientData;
67
    ItclClass *cdefn = (ItclClass*)Itcl_PeekStack(&info->cdefnStack);
68
 
69
    int newEntry;
70
    char *switchName, *resName, *resClass, *init, *config;
71
    ItkClassOptTable *optTable;
72
    Tcl_HashEntry *entry;
73
    ItkClassOption *opt;
74
 
75
    /*
76
     *  Make sure that the arguments look right.  The option switch
77
     *  name must start with a '-'.
78
     */
79
    if (objc < 5 || objc > 6) {
80
        Tcl_WrongNumArgs(interp, 1, objv,
81
            "-switch resourceName resourceClass init ?config?");
82
        return TCL_ERROR;
83
    }
84
 
85
    switchName = Tcl_GetStringFromObj(objv[1], (int*)NULL);
86
    if (*switchName != '-') {
87
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
88
            "bad option name \"", switchName, "\": should be -", switchName,
89
            (char*)NULL);
90
        return TCL_ERROR;
91
    }
92
    if (strstr(switchName, ".")) {
93
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
94
            "bad option name \"", switchName, "\": illegal character \".\"",
95
            (char*)NULL);
96
        return TCL_ERROR;
97
    }
98
 
99
    resName = Tcl_GetStringFromObj(objv[2], (int*)NULL);
100
    if (!islower((int)*resName)) {
101
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
102
            "bad resource name \"", resName,
103
            "\": should start with a lower case letter",
104
            (char*)NULL);
105
        return TCL_ERROR;
106
    }
107
 
108
    resClass = Tcl_GetStringFromObj(objv[3], (int*)NULL);
109
    if (!isupper((int)*resClass)) {
110
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
111
            "bad resource class \"", resClass,
112
            "\": should start with an upper case letter",
113
            (char*)NULL);
114
        return TCL_ERROR;
115
    }
116
 
117
    /*
118
     *  Make sure that this option has not already been defined in
119
     *  the context of this class.  Options can be redefined in
120
     *  other classes, but can only be defined once in a given
121
     *  class.  This ensures that there will be no confusion about
122
     *  which option is being referenced if the configuration code
123
     *  is redefined by a subsequent "body" command.
124
     */
125
    optTable = Itk_CreateClassOptTable(interp, cdefn);
126
    entry = Tcl_CreateHashEntry(&optTable->options, switchName, &newEntry);
127
 
128
    if (!newEntry) {
129
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
130
            "option \"", switchName, "\" already defined in class \"",
131
            cdefn->fullname, "\"",
132
            (char*)NULL);
133
        return TCL_ERROR;
134
    }
135
 
136
    /*
137
     *  Create a new option record and add it to the table for this
138
     *  class.
139
     */
140
    init = Tcl_GetStringFromObj(objv[4], (int*)NULL);
141
 
142
    if (objc == 6) {
143
        config = Tcl_GetStringFromObj(objv[5], (int*)NULL);
144
    } else {
145
        config = NULL;
146
    }
147
 
148
    if (Itk_CreateClassOption(interp, cdefn, switchName, resName, resClass,
149
        init, config, &opt) != TCL_OK) {
150
        return TCL_ERROR;
151
    }
152
 
153
    Tcl_SetHashValue(entry, (ClientData)opt);
154
    Itk_OptListAdd(&optTable->order, entry);
155
    return TCL_OK;
156
}
157
 
158
 
159
/*
160
 * ------------------------------------------------------------------------
161
 *  Itk_ClassOptionIllegalCmd()
162
 *
163
 *  Invoked when a class definition is being parse to handle an
164
 *  itk_option declaration.  Handles an "illegal" declaration like
165
 *  "add" or "remove", which can only be used after a widget has
166
 *  been created.  Returns TCL_ERROR along with an error message.
167
 * ------------------------------------------------------------------------
168
 */
169
/* ARGSUSED */
170
int
171
Itk_ClassOptionIllegalCmd(clientData, interp, objc, objv)
172
    ClientData clientData;   /* class parser info */
173
    Tcl_Interp *interp;      /* current interpreter */
174
    int objc;                /* number of arguments */
175
    Tcl_Obj *CONST objv[];   /* argument objects */
176
{
177
    char *op = Tcl_GetStringFromObj(objv[0], (int*)NULL);
178
 
179
    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
180
        "can only ", op, " options for a specific widget\n",
181
        "(move this command into the constructor)",
182
        (char*)NULL);
183
 
184
    return TCL_ERROR;
185
}
186
 
187
 
188
/*
189
 * ------------------------------------------------------------------------
190
 *  Itk_ConfigClassOption()
191
 *
192
 *  Invoked whenever a class-based configuration option has been
193
 *  configured with a new value.  If the option has any extra code
194
 *  associated with it, the code is invoked at this point to bring
195
 *  the widget up-to-date.
196
 *
197
 *  Returns TCL_OK on success, or TCL_ERROR (along with an error
198
 *  message in the interpreter) if anything goes wrong.
199
 * ------------------------------------------------------------------------
200
 */
201
/* ARGSUSED */
202
int
203
Itk_ConfigClassOption(interp, contextObj, cdata, newval)
204
    Tcl_Interp *interp;        /* interpreter managing the class */
205
    ItclObject *contextObj;    /* object being configured */
206
    ClientData cdata;          /* class option */
207
    char *newval;              /* new value for this option */
208
{
209
    ItkClassOption *opt = (ItkClassOption*)cdata;
210
    int result = TCL_OK;
211
    ItclMemberCode *mcode;
212
 
213
    /*
214
     *  If the option has any config code, execute it now.
215
     *  Make sure that the namespace context is set up correctly.
216
     */
217
    mcode = opt->member->code;
218
    if (mcode && mcode->procPtr->bodyPtr) {
219
        result = Itcl_EvalMemberCode(interp, (ItclMemberFunc*)NULL,
220
            opt->member, contextObj, 0, (Tcl_Obj**)NULL);
221
    }
222
    return result;
223
}
224
 
225
 
226
/*
227
 * ------------------------------------------------------------------------
228
 *  Itk_CreateClassOptTable()
229
 *
230
 *  Finds or creates an option table which will contain all of the
231
 *  class-based configuration options for a mega-widget.  These are
232
 *  the options included in the class definition which add new behavior
233
 *  to the mega-widget.
234
 *
235
 *  This table is automatically deleted by ItkTraceClassDestroy
236
 *  whenever the class namespace is destroyed.  The "unset" operation
237
 *  of a private class variable is used to detect the destruction of
238
 *  the namespace.
239
 *
240
 *  Returns a pointer to an option table which will contain pointers to
241
 *  ItkClassOption records.
242
 * ------------------------------------------------------------------------
243
 */
244
ItkClassOptTable*
245
Itk_CreateClassOptTable(interp, cdefn)
246
    Tcl_Interp *interp;        /* interpreter managing the class */
247
    ItclClass *cdefn;          /* class definition */
248
{
249
    int newEntry, result;
250
    Tcl_HashTable *itkClasses;
251
    Tcl_HashEntry *entry;
252
    ItkClassOptTable *optTable;
253
    Tcl_CallFrame frame;
254
 
255
    /*
256
     *  Look for the specified class definition in the table.
257
     *  If it does not yet exist, then create a new slot for it.
258
     *  When a table is created for the first time, add a
259
     *  special sentinel variable "_itk_option_data" to the
260
     *  class namespace, and put a trace on this variable.
261
     *  Whenever it is destroyed, have it delete the option table
262
     *  for this class.
263
     */
264
    itkClasses = ItkGetClassesWithOptInfo(interp);
265
 
266
    entry = Tcl_CreateHashEntry(itkClasses, (char*)cdefn, &newEntry);
267
    if (newEntry) {
268
        optTable = (ItkClassOptTable*)ckalloc(sizeof(ItkClassOptTable));
269
        Tcl_InitHashTable(&optTable->options, TCL_STRING_KEYS);
270
        Itk_OptListInit(&optTable->order, &optTable->options);
271
 
272
        Tcl_SetHashValue(entry, (ClientData)optTable);
273
 
274
        result = Tcl_PushCallFrame(interp, &frame,
275
             cdefn->namesp, /* isProcCallFrame */ 0);
276
 
277
        if (result == TCL_OK) {
278
            Tcl_TraceVar(interp, "_itk_option_data",
279
                (TCL_TRACE_UNSETS | TCL_NAMESPACE_ONLY),
280
                ItkTraceClassDestroy, (ClientData)cdefn);
281
            Tcl_PopCallFrame(interp);
282
        }
283
    }
284
    else {
285
        optTable = (ItkClassOptTable*)Tcl_GetHashValue(entry);
286
    }
287
    return optTable;
288
}
289
 
290
 
291
/*
292
 * ------------------------------------------------------------------------
293
 *  Itk_FindClassOptTable()
294
 *
295
 *  Looks for an option table containing all of the class-based
296
 *  configuration options for a mega-widget.  These are the options
297
 *  included in a class definition which add new behavior to the
298
 *  mega-widget.
299
 *
300
 *  Returns a pointer to an option table which will contain pointers to
301
 *  Itk_ClassOption records.  If a table does not exist for this class,
302
 *  this returns NULL.
303
 * ------------------------------------------------------------------------
304
 */
305
ItkClassOptTable*
306
Itk_FindClassOptTable(cdefn)
307
    ItclClass *cdefn;          /* class definition */
308
{
309
    Tcl_HashTable *itkClasses;
310
    Tcl_HashEntry *entry;
311
 
312
    /*
313
     *  Look for the specified class definition in the table.
314
     */
315
    itkClasses = ItkGetClassesWithOptInfo(cdefn->interp);
316
    entry = Tcl_FindHashEntry(itkClasses, (char*)cdefn);
317
    if (entry) {
318
        return (ItkClassOptTable*)Tcl_GetHashValue(entry);
319
    }
320
    return NULL;
321
}
322
 
323
 
324
/*
325
 * ------------------------------------------------------------------------
326
 *  ItkTraceClassDestroy()
327
 *
328
 *  Invoked automatically whenever the "_itk_option_data" variable
329
 *  is destroyed within a class namespace.  This should be a signal
330
 *  that the namespace is being destroyed.
331
 *
332
 *  Releases any option data that exists for the class.
333
 *
334
 *  Returns NULL on success, or a pointer to a string describing any
335
 *  error that is encountered.
336
 * ------------------------------------------------------------------------
337
 */
338
/* ARGSUSED */
339
static char*
340
ItkTraceClassDestroy(cdata, interp, name1, name2, flags)
341
    ClientData cdata;          /* class definition data */
342
    Tcl_Interp *interp;        /* interpreter managing the class */
343
    char *name1;               /* name of variable involved in trace */
344
    char *name2;               /* name of array element within variable */
345
    int flags;                 /* flags describing trace */
346
{
347
    ItclClass *cdefn = (ItclClass*)cdata;
348
 
349
    Tcl_HashTable *itkClasses;
350
    Tcl_HashEntry *entry;
351
    ItkClassOptTable *optTable;
352
    Tcl_HashSearch place;
353
    ItkClassOption *opt;
354
 
355
    /*
356
     *  Look for the specified class definition in the table.
357
     *  If it is found, delete all the option records and tear
358
     *  down the table.
359
     */
360
    itkClasses = ItkGetClassesWithOptInfo(cdefn->interp);
361
    entry = Tcl_FindHashEntry(itkClasses, (char*)cdefn);
362
    if (entry) {
363
        optTable = (ItkClassOptTable*)Tcl_GetHashValue(entry);
364
        Tcl_DeleteHashEntry(entry);
365
 
366
        entry = Tcl_FirstHashEntry(&optTable->options, &place);
367
        while (entry) {
368
            opt = (ItkClassOption*)Tcl_GetHashValue(entry);
369
            Itk_DelClassOption(opt);
370
            entry = Tcl_NextHashEntry(&place);
371
        }
372
        Tcl_DeleteHashTable(&optTable->options);
373
        Itk_OptListFree(&optTable->order);
374
        ckfree((char*)optTable);
375
    }
376
    return NULL;
377
}
378
 
379
 
380
/*
381
 * ------------------------------------------------------------------------
382
 *  Itk_CreateClassOption()
383
 *
384
 *  Creates the data representing a configuration option for an
385
 *  Archetype mega-widget.  This record represents an option included
386
 *  in the class definition.  It adds new behavior to the mega-widget
387
 *  class.
388
 *
389
 *  If successful, returns TCL_OK along with a pointer to the option
390
 *  record.  Returns TCL_ERROR (along with an error message in the
391
 *  interpreter) if anything goes wrong.
392
 * ------------------------------------------------------------------------
393
 */
394
int
395
Itk_CreateClassOption(interp, cdefn, switchName, resName, resClass,
396
    defVal, config, optPtr)
397
 
398
    Tcl_Interp *interp;            /* interpreter managing the class */
399
    ItclClass *cdefn;              /* class containing this option */
400
    char *switchName;              /* name of command-line switch */
401
    char *resName;                 /* resource name in X11 database */
402
    char *resClass;                /* resource class name in X11 database */
403
    char *defVal;                  /* last-resort default value */
404
    char *config;                  /* configuration code */
405
    ItkClassOption **optPtr;       /* returns: option record */
406
{
407
    ItkClassOption *opt;
408
    ItclMemberCode *mcode;
409
 
410
    /*
411
     *  If this option has any "config" code, then try to create
412
     *  an implementation for it.
413
     */
414
    if (config) {
415
        if (Itcl_CreateMemberCode(interp, cdefn, (char*)NULL, config,
416
            &mcode) != TCL_OK) {
417
 
418
            return TCL_ERROR;
419
        }
420
        Itcl_PreserveData((ClientData)mcode);
421
        Itcl_EventuallyFree((ClientData)mcode, Itcl_DeleteMemberCode);
422
    }
423
    else {
424
        mcode = NULL;
425
    }
426
 
427
    /*
428
     *  Create the record to represent this option.
429
     */
430
    opt = (ItkClassOption*)ckalloc(sizeof(ItkClassOption));
431
    opt->member = Itcl_CreateMember(interp, cdefn, switchName);
432
    opt->member->code = mcode;
433
 
434
    opt->resName = (char*)ckalloc((unsigned)(strlen(resName)+1));
435
    strcpy(opt->resName, resName);
436
 
437
    opt->resClass = (char*)ckalloc((unsigned)(strlen(resClass)+1));
438
    strcpy(opt->resClass, resClass);
439
 
440
    opt->init = (char*)ckalloc((unsigned)(strlen(defVal)+1));
441
    strcpy(opt->init, defVal);
442
 
443
    *optPtr = opt;
444
    return TCL_OK;
445
}
446
 
447
/*
448
 * ------------------------------------------------------------------------
449
 *  Itk_FindClassOption()
450
 *
451
 *  Searches for a class-based configuration option for an Archetype
452
 *  mega-widget.   The specified name is treated as the "switch" name
453
 *  (e.g., "-option"), but this procedure will recognize it even without
454
 *  the leading "-".
455
 *
456
 *  If an option is found that was defined in the specified class,
457
 *  then this procedure returns a pointer to the option definition.
458
 *  Otherwise, it returns NULL.
459
 * ------------------------------------------------------------------------
460
 */
461
ItkClassOption*
462
Itk_FindClassOption(cdefn, switchName)
463
    ItclClass *cdefn;              /* class containing this option */
464
    char *switchName;              /* name of command-line switch */
465
{
466
    ItkClassOption *opt = NULL;
467
 
468
    Tcl_DString buffer;
469
    ItkClassOptTable *optTable;
470
    Tcl_HashEntry *entry;
471
 
472
    /*
473
     *  If the switch does not have a leading "-", add it on.
474
     */
475
    Tcl_DStringInit(&buffer);
476
    if (*switchName != '-') {
477
        Tcl_DStringAppend(&buffer, "-", -1);
478
        Tcl_DStringAppend(&buffer, switchName, -1);
479
        switchName = Tcl_DStringValue(&buffer);
480
    }
481
 
482
    /*
483
     *  Look for the option table for the specified class, and check
484
     *  for the requested switch.
485
     */
486
    optTable = Itk_FindClassOptTable(cdefn);
487
    if (optTable) {
488
        entry = Tcl_FindHashEntry(&optTable->options, switchName);
489
        if (entry) {
490
            opt = (ItkClassOption*)Tcl_GetHashValue(entry);
491
        }
492
    }
493
    Tcl_DStringFree(&buffer);
494
    return opt;
495
}
496
 
497
/*
498
 * ------------------------------------------------------------------------
499
 *  Itk_DelClassOption()
500
 *
501
 *  Destroys a configuration option previously created by
502
 *  Itk_CreateClassOption().
503
 * ------------------------------------------------------------------------
504
 */
505
void
506
Itk_DelClassOption(opt)
507
    ItkClassOption *opt;  /* pointer to option data */
508
{
509
    Itcl_DeleteMember(opt->member);
510
    ckfree(opt->resName);
511
    ckfree(opt->resClass);
512
    ckfree(opt->init);
513
 
514
    ckfree((char*)opt);
515
}
516
 
517
 
518
/*
519
 * ------------------------------------------------------------------------
520
 *  ItkGetClassesWithOptInfo()
521
 *
522
 *  Returns a pointer to a hash table containing the list of registered
523
 *  classes in the specified interpreter.  If the hash table does not
524
 *  already exist, it is created.
525
 * ------------------------------------------------------------------------
526
 */
527
static Tcl_HashTable*
528
ItkGetClassesWithOptInfo(interp)
529
    Tcl_Interp *interp;  /* interpreter handling this registration */
530
{
531
    Tcl_HashTable* classesTable;
532
 
533
    /*
534
     *  If the registration table does not yet exist, then create it.
535
     */
536
    classesTable = (Tcl_HashTable*)Tcl_GetAssocData(interp,
537
        "itk_classesWithOptInfo", (Tcl_InterpDeleteProc**)NULL);
538
 
539
    if (!classesTable) {
540
        classesTable = (Tcl_HashTable*)ckalloc(sizeof(Tcl_HashTable));
541
        Tcl_InitHashTable(classesTable, TCL_ONE_WORD_KEYS);
542
        Tcl_SetAssocData(interp, "itk_classesWithOptInfo",
543
            ItkFreeClassesWithOptInfo, (ClientData)classesTable);
544
    }
545
    return classesTable;
546
}
547
 
548
/*
549
 * ------------------------------------------------------------------------
550
 *  ItkFreeClassesWithOptInfo()
551
 *
552
 *  When an interpreter is deleted, this procedure is called to
553
 *  free up the associated data created by ItkGetClassesWithOptInfo.
554
 * ------------------------------------------------------------------------
555
 */
556
static void
557
ItkFreeClassesWithOptInfo(clientData, interp)
558
    ClientData clientData;       /* associated data */
559
    Tcl_Interp *interp;          /* interpreter being freed */
560
{
561
    Tcl_HashTable *tablePtr = (Tcl_HashTable*)clientData;
562
    Tcl_HashSearch place, place2;
563
    Tcl_HashEntry *entry, *entry2;
564
    ItkClassOptTable *optTable;
565
    ItkClassOption *opt;
566
 
567
    entry = Tcl_FirstHashEntry(tablePtr, &place);
568
    while (entry) {
569
        optTable = (ItkClassOptTable*)Tcl_GetHashValue(entry);
570
 
571
        entry2 = Tcl_FirstHashEntry(&optTable->options, &place2);
572
        while (entry2) {
573
            opt = (ItkClassOption*)Tcl_GetHashValue(entry2);
574
            Itk_DelClassOption(opt);
575
            entry2 = Tcl_NextHashEntry(&place2);
576
        }
577
        Tcl_DeleteHashTable(&optTable->options);
578
        Itk_OptListFree(&optTable->order);
579
        ckfree((char*)optTable);
580
 
581
        entry = Tcl_NextHashEntry(&place);
582
    }
583
 
584
    Tcl_DeleteHashTable(tablePtr);
585
    ckfree((char*)tablePtr);
586
}

powered by: WebSVN 2.1.0

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