source: trunk/kitgen/8.x/blt/generic/bltSwitch.c@ 176

Last change on this file since 176 was 175, checked in by demin, 12 years ago

initial commit

File size: 14.7 KB
Line 
1/*
2 * bltSwitch.c --
3 *
4 * This module implements command/argument switch parsing
5 * procedures for the BLT toolkit.
6 *
7 * Copyright 1991-1998 Lucent Technologies, Inc.
8 *
9 * Permission to use, copy, modify, and distribute this software and
10 * its documentation for any purpose and without fee is hereby
11 * granted, provided that the above copyright notice appear in all
12 * copies and that both that the copyright notice and warranty
13 * disclaimer appear in supporting documentation, and that the names
14 * of Lucent Technologies any of their entities not be used in
15 * advertising or publicity pertaining to distribution of the software
16 * without specific, written prior permission.
17 *
18 * Lucent Technologies disclaims all warranties with regard to this
19 * software, including all implied warranties of merchantability and
20 * fitness. In no event shall Lucent Technologies be liable for any
21 * special, indirect or consequential damages or any damages
22 * whatsoever resulting from loss of use, data or profits, whether in
23 * an action of contract, negligence or other tortuous action, arising
24 * out of or in connection with the use or performance of this
25 * software.
26 */
27
28#include "bltInt.h"
29#if defined(__STDC__)
30#include <stdarg.h>
31#else
32#include <varargs.h>
33#endif
34
35#include "bltSwitch.h"
36
37/*
38 *--------------------------------------------------------------
39 *
40 * FindSwitchSpec --
41 *
42 * Search through a table of configuration specs, looking for
43 * one that matches a given argvName.
44 *
45 * Results:
46 * The return value is a pointer to the matching entry, or NULL
47 * if nothing matched. In that case an error message is left
48 * in the interp's result.
49 *
50 * Side effects:
51 * None.
52 *
53 *--------------------------------------------------------------
54 */
55static Blt_SwitchSpec *
56FindSwitchSpec(interp, specs, name, needFlags, hateFlags)
57 Tcl_Interp *interp; /* Used for reporting errors. */
58 Blt_SwitchSpec *specs; /* Pointer to table of configuration
59 * specifications for a widget. */
60 char *name; /* Name (suitable for use in a "switch"
61 * command) identifying particular option. */
62 int needFlags; /* Flags that must be present in matching
63 * entry. */
64 int hateFlags; /* Flags that must NOT be present in
65 * matching entry. */
66{
67 register Blt_SwitchSpec *specPtr;
68 register char c; /* First character of current argument. */
69 Blt_SwitchSpec *matchPtr; /* Matching spec, or NULL. */
70 size_t length;
71
72 c = name[1];
73 length = strlen(name);
74 matchPtr = NULL;
75
76 for (specPtr = specs; specPtr->type != BLT_SWITCH_END; specPtr++) {
77 if (specPtr->switchName == NULL) {
78 continue;
79 }
80 if ((specPtr->switchName[1] != c)
81 || (strncmp(specPtr->switchName, name, length) != 0)) {
82 continue;
83 }
84 if (((specPtr->flags & needFlags) != needFlags)
85 || (specPtr->flags & hateFlags)) {
86 continue;
87 }
88 if (specPtr->switchName[length] == 0) {
89 return specPtr; /* Stop on a perfect match. */
90 }
91 if (matchPtr != NULL) {
92 Tcl_AppendResult(interp, "ambiguous option \"", name, "\"",
93 (char *) NULL);
94 return (Blt_SwitchSpec *) NULL;
95 }
96 matchPtr = specPtr;
97 }
98
99 if (matchPtr == NULL) {
100 Tcl_AppendResult(interp, "unknown option \"", name, "\"", (char *)NULL);
101 return (Blt_SwitchSpec *) NULL;
102 }
103 return matchPtr;
104}
105
106/*
107 *--------------------------------------------------------------
108 *
109 * DoSwitch --
110 *
111 * This procedure applies a single configuration option
112 * to a widget record.
113 *
114 * Results:
115 * A standard Tcl return value.
116 *
117 * Side effects:
118 * WidgRec is modified as indicated by specPtr and value.
119 * The old value is recycled, if that is appropriate for
120 * the value type.
121 *
122 *--------------------------------------------------------------
123 */
124static int
125DoSwitch(interp, specPtr, string, record)
126 Tcl_Interp *interp; /* Interpreter for error reporting. */
127 Blt_SwitchSpec *specPtr; /* Specifier to apply. */
128 char *string; /* Value to use to fill in widgRec. */
129 ClientData record; /* Record whose fields are to be
130 * modified. Values must be properly
131 * initialized. */
132{
133 char *ptr;
134 int isNull;
135 int count;
136
137 isNull = ((*string == '\0') && (specPtr->flags & BLT_SWITCH_NULL_OK));
138 do {
139 ptr = (char *)record + specPtr->offset;
140 switch (specPtr->type) {
141 case BLT_SWITCH_BOOLEAN:
142 if (Tcl_GetBoolean(interp, string, (int *)ptr) != TCL_OK) {
143 return TCL_ERROR;
144 }
145 break;
146
147 case BLT_SWITCH_INT:
148 if (Tcl_GetInt(interp, string, (int *)ptr) != TCL_OK) {
149 return TCL_ERROR;
150 }
151 break;
152
153 case BLT_SWITCH_INT_NONNEGATIVE:
154 if (Tcl_GetInt(interp, string, &count) != TCL_OK) {
155 return TCL_ERROR;
156 }
157 if (count < 0) {
158 Tcl_AppendResult(interp, "bad value \"", string, "\": ",
159 "can't be negative", (char *)NULL);
160 return TCL_ERROR;
161 }
162 *((int *)ptr) = count;
163 break;
164
165 case BLT_SWITCH_INT_POSITIVE:
166 if (Tcl_GetInt(interp, string, &count) != TCL_OK) {
167 return TCL_ERROR;
168 }
169 if (count <= 0) {
170 Tcl_AppendResult(interp, "bad value \"", string, "\": ",
171 "must be positive", (char *)NULL);
172 return TCL_ERROR;
173 }
174 *((int *)ptr) = count;
175 break;
176
177 case BLT_SWITCH_DOUBLE:
178 if (Tcl_GetDouble(interp, string, (double *)ptr) != TCL_OK) {
179 return TCL_ERROR;
180 }
181 break;
182
183 case BLT_SWITCH_STRING:
184 {
185 char *old, *new, **strPtr;
186
187 strPtr = (char **)ptr;
188 if (isNull) {
189 new = NULL;
190 } else {
191 new = Blt_Strdup(string);
192 }
193 old = *strPtr;
194 if (old != NULL) {
195 Blt_Free(old);
196 }
197 *strPtr = new;
198 }
199 break;
200
201 case BLT_SWITCH_LIST:
202 if (Tcl_SplitList(interp, string, &count, (char ***)ptr)
203 != TCL_OK) {
204 return TCL_ERROR;
205 }
206 break;
207
208 case BLT_SWITCH_CUSTOM:
209 if ((*specPtr->customPtr->parseProc) \
210 (specPtr->customPtr->clientData, interp, specPtr->switchName,
211 string, record, specPtr->offset) != TCL_OK) {
212 return TCL_ERROR;
213 }
214 break;
215
216 default:
217 Tcl_AppendResult(interp, "bad switch table: unknown type \"",
218 Blt_Itoa(specPtr->type), "\"", (char *)NULL);
219 return TCL_ERROR;
220 }
221 specPtr++;
222 } while ((specPtr->switchName == NULL) &&
223 (specPtr->type != BLT_SWITCH_END));
224 return TCL_OK;
225}
226
227/*
228 *--------------------------------------------------------------
229 *
230 * Blt_ProcessSwitches --
231 *
232 * Process command-line options and database options to
233 * fill in fields of a widget record with resources and
234 * other parameters.
235 *
236 * Results:
237 * Returns the number of arguments comsumed by parsing the
238 * command line. If an error occurred, -1 will be returned
239 * and an error messages can be found as the interpreter
240 * result.
241 *
242 * Side effects:
243 * The fields of widgRec get filled in with information
244 * from argc/argv and the option database. Old information
245 * in widgRec's fields gets recycled.
246 *
247 *--------------------------------------------------------------
248 */
249int
250Blt_ProcessSwitches(interp, specs, argc, argv, record, flags)
251 Tcl_Interp *interp; /* Interpreter for error reporting. */
252 Blt_SwitchSpec *specs; /* Describes legal options. */
253 int argc; /* Number of elements in argv. */
254 char **argv; /* Command-line options. */
255 char *record; /* Record whose fields are to be
256 * modified. Values must be properly
257 * initialized. */
258 int flags; /* Used to specify additional flags
259 * that must be present in switch specs
260 * for them to be considered. Also,
261 * may have BLT_SWITCH_ARGV_ONLY set. */
262{
263 register int count;
264 char *arg;
265 register Blt_SwitchSpec *specPtr;
266 int needFlags; /* Specs must contain this set of flags
267 * or else they are not considered. */
268 int hateFlags; /* If a spec contains any bits here, it's
269 * not considered. */
270
271 needFlags = flags & ~(BLT_SWITCH_USER_BIT - 1);
272 hateFlags = 0;
273
274 /*
275 * Pass 1: Clear the change flags on all the specs so that we
276 * can check it later.
277 */
278 for (specPtr = specs; specPtr->type != BLT_SWITCH_END; specPtr++) {
279 specPtr->flags &= ~BLT_SWITCH_SPECIFIED;
280 }
281 /*
282 * Pass 2: Process the arguments that match entries in the specs.
283 * It's an error if the argument doesn't match anything.
284 */
285 for (count = 0; count < argc; count++) {
286 arg = argv[count];
287 if (flags & BLT_SWITCH_OBJV_PARTIAL) {
288 if ((arg[0] != '-') || ((arg[1] == '-') && (argv[2] == '\0'))) {
289 /*
290 * If the argument doesn't start with a '-' (not a switch)
291 * or is '--', stop processing and return the number of
292 * arguments comsumed.
293 */
294 return count;
295 }
296 }
297 specPtr = FindSwitchSpec(interp, specs, arg, needFlags, hateFlags);
298 if (specPtr == NULL) {
299 return -1;
300 }
301 if (specPtr->type == BLT_SWITCH_FLAG) {
302 char *ptr;
303
304 ptr = record + specPtr->offset;
305 *((int *)ptr) |= specPtr->value;
306 } else if (specPtr->type == BLT_SWITCH_VALUE) {
307 char *ptr;
308
309 ptr = record + specPtr->offset;
310 *((int *)ptr) = specPtr->value;
311 } else {
312 if ((count + 1) == argc) {
313 Tcl_AppendResult(interp, "value for \"", arg, "\" missing",
314 (char *) NULL);
315 return -1;
316 }
317 count++;
318 if (DoSwitch(interp, specPtr, argv[count], record) != TCL_OK) {
319 char msg[100];
320
321 sprintf(msg, "\n (processing \"%.40s\" option)",
322 specPtr->switchName);
323 Tcl_AddErrorInfo(interp, msg);
324 return -1;
325 }
326 }
327 specPtr->flags |= BLT_SWITCH_SPECIFIED;
328 }
329 return count;
330}
331
332#if (TCL_VERSION_NUMBER >= _VERSION(8,0,0))
333
334/*
335 *--------------------------------------------------------------
336 *
337 * Blt_ProcessObjSwitches --
338 *
339 * Process command-line options and database options to
340 * fill in fields of a widget record with resources and
341 * other parameters.
342 *
343 * Results:
344 * Returns the number of arguments comsumed by parsing the
345 * command line. If an error occurred, -1 will be returned
346 * and an error messages can be found as the interpreter
347 * result.
348 *
349 * Side effects:
350 * The fields of widgRec get filled in with information
351 * from argc/argv and the option database. Old information
352 * in widgRec's fields gets recycled.
353 *
354 *--------------------------------------------------------------
355 */
356int
357Blt_ProcessObjSwitches(interp, specs, objc, objv, record, flags)
358 Tcl_Interp *interp; /* Interpreter for error reporting. */
359 Blt_SwitchSpec *specs; /* Describes legal options. */
360 int objc; /* Number of elements in argv. */
361 Tcl_Obj *CONST *objv; /* Command-line options. */
362 char *record; /* Record whose fields are to be
363 * modified. Values must be properly
364 * initialized. */
365 int flags; /* Used to specify additional flags
366 * that must be present in switch specs
367 * for them to be considered. Also,
368 * may have BLT_SWITCH_ARGV_ONLY set. */
369{
370 register Blt_SwitchSpec *specPtr;
371 register int count;
372 int needFlags; /* Specs must contain this set of flags
373 * or else they are not considered. */
374 int hateFlags; /* If a spec contains any bits here, it's
375 * not considered. */
376
377 needFlags = flags & ~(BLT_SWITCH_USER_BIT - 1);
378 hateFlags = 0;
379
380 /*
381 * Pass 1: Clear the change flags on all the specs so that we
382 * can check it later.
383 */
384 for (specPtr = specs; specPtr->type != BLT_SWITCH_END; specPtr++) {
385 specPtr->flags &= ~BLT_SWITCH_SPECIFIED;
386 }
387 /*
388 * Pass 2: Process the arguments that match entries in the specs.
389 * It's an error if the argument doesn't match anything.
390 */
391 for (count = 0; count < objc; count++) {
392 char *arg;
393
394 arg = Tcl_GetString(objv[count]);
395 if (flags & BLT_SWITCH_OBJV_PARTIAL) {
396 if ((arg[0] != '-') || ((arg[1] == '-') && (arg[2] == '\0'))) {
397 /*
398 * If the argument doesn't start with a '-' (not a switch)
399 * or is '--', stop processing and return the number of
400 * arguments comsumed.
401 */
402 return count;
403 }
404 }
405 specPtr = FindSwitchSpec(interp, specs, arg, needFlags, hateFlags);
406 if (specPtr == NULL) {
407 return -1;
408 }
409 if (specPtr->type == BLT_SWITCH_FLAG) {
410 char *ptr;
411
412 ptr = record + specPtr->offset;
413 *((int *)ptr) |= specPtr->value;
414 } else if (specPtr->type == BLT_SWITCH_VALUE) {
415 char *ptr;
416
417 ptr = record + specPtr->offset;
418 *((int *)ptr) = specPtr->value;
419 } else {
420 count++;
421 if (count == objc) {
422 Tcl_AppendResult(interp, "value for \"", arg, "\" missing",
423 (char *) NULL);
424 return -1;
425 }
426 arg = Tcl_GetString(objv[count]);
427 if (DoSwitch(interp, specPtr, arg, record) != TCL_OK) {
428 char msg[100];
429
430 sprintf(msg, "\n (processing \"%.40s\" option)",
431 specPtr->switchName);
432 Tcl_AddErrorInfo(interp, msg);
433 return -1;
434 }
435 }
436 specPtr->flags |= BLT_SWITCH_SPECIFIED;
437 }
438 return count;
439}
440#endif
441
442/*
443 *----------------------------------------------------------------------
444 *
445 * Blt_FreeSwitches --
446 *
447 * Free up all resources associated with switch options.
448 *
449 * Results:
450 * None.
451 *
452 *----------------------------------------------------------------------
453 */
454
455/* ARGSUSED */
456void
457Blt_FreeSwitches(specs, record, needFlags)
458 Blt_SwitchSpec *specs; /* Describes legal options. */
459 char *record; /* Record whose fields contain current
460 * values for options. */
461 int needFlags; /* Used to specify additional flags
462 * that must be present in config specs
463 * for them to be considered. */
464{
465 register Blt_SwitchSpec *specPtr;
466
467 for (specPtr = specs; specPtr->type != BLT_SWITCH_END; specPtr++) {
468 if ((specPtr->flags & needFlags) == needFlags) {
469 char *ptr;
470
471 ptr = record + specPtr->offset;
472 switch (specPtr->type) {
473 case BLT_SWITCH_STRING:
474 case BLT_SWITCH_LIST:
475 if (*((char **) ptr) != NULL) {
476 Blt_Free(*((char **) ptr));
477 *((char **) ptr) = NULL;
478 }
479 break;
480
481 case BLT_SWITCH_CUSTOM:
482 if ((*(char **)ptr != NULL) &&
483 (specPtr->customPtr->freeProc != NULL)) {
484 (*specPtr->customPtr->freeProc)(*(char **)ptr);
485 *((char **) ptr) = NULL;
486 }
487 break;
488
489 default:
490 break;
491 }
492 }
493 }
494}
495
496
497/*
498 *----------------------------------------------------------------------
499 *
500 * Blt_SwitchModified --
501 *
502 * Given the configuration specifications and one or more option
503 * patterns (terminated by a NULL), indicate if any of the matching
504 * configuration options has been reset.
505 *
506 * Results:
507 * Returns 1 if one of the options has changed, 0 otherwise.
508 *
509 *----------------------------------------------------------------------
510 */
511int Blt_SwitchChanged
512TCL_VARARGS_DEF(Blt_SwitchSpec *, arg1)
513{
514 va_list argList;
515 Blt_SwitchSpec *specs;
516 register Blt_SwitchSpec *specPtr;
517 register char *switchName;
518
519 specs = TCL_VARARGS_START(Blt_SwitchSpec *, arg1, argList);
520 while ((switchName = va_arg(argList, char *)) != NULL) {
521 for (specPtr = specs; specPtr->type != BLT_SWITCH_END; specPtr++) {
522 if ((Tcl_StringMatch(specPtr->switchName, switchName)) &&
523 (specPtr->flags & BLT_SWITCH_SPECIFIED)) {
524 va_end(argList);
525 return 1;
526 }
527 }
528 }
529 va_end(argList);
530 return 0;
531}
Note: See TracBrowser for help on using the repository browser.