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 |
|
|
}
|