/[cvs]/eggdrop1.4/src/tcl.c
ViewVC logotype

Contents of /eggdrop1.4/src/tcl.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.7 - (show annotations) (download) (as text)
Sun Jul 25 18:57:41 1999 UTC (20 years, 4 months ago) by guppy
Branch: MAIN
Changes since 1.6: +2 -0 lines
File MIME type: text/x-chdr
hi

1 /*
2 * tcl.c -- handles:
3 * the code for every command eggdrop adds to Tcl
4 * Tcl initialization
5 * getting and setting Tcl/eggdrop variables
6 *
7 * dprintf'ized, 4feb1996
8 */
9 /*
10 * This file is part of the eggdrop source code
11 * copyright (c) 1997 Robey Pointer
12 * and is distributed according to the GNU general public license.
13 * For full details, read the top of 'main.c' or the file called
14 * COPYING that was distributed with this code.
15 */
16
17 #include "main.h"
18
19 /* used for read/write to internal strings */
20 typedef struct {
21 char *str; /* pointer to actual string in eggdrop */
22 int max; /* max length (negative: read-only var when protect is on) */
23 /* (0: read-only ALWAYS) */
24 int flags; /* 1 = directory */
25 } strinfo;
26
27 typedef struct {
28 int *var;
29 int ro;
30 } intinfo;
31
32 int protect_readonly = 0; /* turn on/off readonly protection */
33 char whois_fields[121] = ""; /* fields to display in a .whois */
34 Tcl_Interp *interp; /* eggdrop always uses the same interpreter */
35
36 extern int backgrd, flood_telnet_thr, flood_telnet_time;
37 extern int shtime, share_greet, require_p, keep_all_logs;
38 extern int use_stderr, allow_new_telnets, stealth_telnets;
39 extern int default_flags, conmask, switch_logfiles_at, connect_timeout;
40 extern int firewallport, reserved_port, notify_users_at;
41 extern int flood_thr, ignore_time;
42 extern char origbotname[], botuser[], motdfile[], admin[], userfile[],
43 firewall[], helpdir[], notify_new[], hostname[], myip[], moddir[],
44 tempdir[], owner[], network[], botnetnick[], bannerfile[];
45 extern int die_on_sighup, die_on_sigterm, max_logs, max_logsize, enable_simul;
46 extern int dcc_total, debug_output, identtimeout, protect_telnet;
47 extern int egg_numver, share_unlinks, dcc_sanitycheck, sort_users;
48 extern struct dcc_t *dcc;
49 extern char egg_version[];
50 extern tcl_timer_t *timer, *utimer;
51 extern time_t online_since;
52 extern log_t *logs;
53 extern int tands;
54 extern int resolve_timeout;
55 extern char natip[];
56 extern int default_uflags; /* drummer */
57
58 /* confvar patch by aaronwl */
59 extern char configfile[];
60 int dcc_flood_thr = 3;
61 int debug_tcl = 0;
62 int use_silence = 0;
63 int use_invites = 0; /* Jason/drummer */
64 int use_exempts = 0; /* Jason/drummer */
65 int force_expire = 0; /* Rufus */
66 int remote_boots = 2;
67 int allow_dk_cmds = 1;
68 int must_be_owner = 1;
69 int max_dcc = 20; /* needs at least 4 or 5 just to get started
70 * 20 should be enough */
71 int min_dcc_port = 1024; /* dcc-portrange, min port - dw/guppy */
72 int max_dcc_port = 65535; /* dcc-portrange, max port - dw/guppy */
73 int quick_logs = 0; /* quick write logs?
74 * flush em every min instead of every 5 */
75 int par_telnet_flood = 1; /* trigger telnet flood for +f ppl? - dw */
76
77 /* prototypes for tcl */
78 Tcl_Interp *Tcl_CreateInterp();
79 int strtot = 0;
80
81 int expmem_tcl()
82 {
83 int i, tot = 0;
84
85 context;
86 for (i = 0; i < max_logs; i++)
87 if (logs[i].filename != NULL) {
88 tot += strlen(logs[i].filename) + 1;
89 tot += strlen(logs[i].chname) + 1;
90 }
91 return tot + strtot;
92 }
93
94 /***********************************************************************/
95
96 /* logfile [<modes> <channel> <filename>] */
97 static int tcl_logfile STDVAR
98 {
99 int i;
100 char s[151];
101
102 BADARGS(1, 4, " ?logModes channel logFile?");
103 if (argc == 1) {
104 /* they just want a list of the logfiles and modes */
105 for (i = 0; i < max_logs; i++)
106 if (logs[i].filename != NULL) {
107 strcpy(s, masktype(logs[i].mask));
108 strcat(s, " ");
109 strcat(s, logs[i].chname);
110 strcat(s, " ");
111 strcat(s, logs[i].filename);
112 Tcl_AppendElement(interp, s);
113 }
114 return TCL_OK;
115 }
116 BADARGS(4, 4, " ?logModes channel logFile?");
117 for (i = 0; i < max_logs; i++)
118 if ((logs[i].filename != NULL) && (!strcmp(logs[i].filename, argv[3]))) {
119 logs[i].mask = logmodes(argv[1]);
120 nfree(logs[i].chname);
121 logs[i].chname = NULL;
122 if (!logs[i].mask) {
123 /* ending logfile */
124 nfree(logs[i].filename);
125 logs[i].filename = NULL;
126 if (logs[i].f != NULL) {
127 fclose(logs[i].f);
128 logs[i].f = NULL;
129 }
130 } else {
131 logs[i].chname = (char *) nmalloc(strlen(argv[2]) + 1);
132 strcpy(logs[i].chname, argv[2]);
133 }
134 Tcl_AppendResult(interp, argv[3], NULL);
135 return TCL_OK;
136 }
137 for (i = 0; i < max_logs; i++)
138 if (logs[i].filename == NULL) {
139 logs[i].mask = logmodes(argv[1]);
140 logs[i].filename = (char *) nmalloc(strlen(argv[3]) + 1);
141 strcpy(logs[i].filename, argv[3]);
142 logs[i].chname = (char *) nmalloc(strlen(argv[2]) + 1);
143 strcpy(logs[i].chname, argv[2]);
144 Tcl_AppendResult(interp, argv[3], NULL);
145 return TCL_OK;
146 }
147 Tcl_AppendResult(interp, "reached max # of logfiles", NULL);
148 return TCL_ERROR;
149 }
150
151 int findidx(int z)
152 {
153 int j;
154
155 for (j = 0; j < dcc_total; j++)
156 if ((dcc[j].sock == z) && (dcc[j].type->flags & DCT_VALIDIDX))
157 return j;
158 return -1;
159 }
160
161 static void botnet_change(char *new)
162 {
163 if (strcasecmp(botnetnick, new) != 0) {
164 /* trying to change bot's nickname */
165 if (tands > 0) {
166 putlog(LOG_MISC, "*", "* Tried to change my botnet nick, but I'm still linked to a botnet.");
167 putlog(LOG_MISC, "*", "* (Unlink and try again.)");
168 return;
169 } else {
170 if (botnetnick[0])
171 putlog(LOG_MISC, "*", "* IDENTITY CHANGE: %s -> %s", botnetnick, new);
172 strcpy(botnetnick, new);
173 }
174 }
175 }
176
177 /**********************************************************************/
178
179 int init_dcc_max(), init_misc();
180
181 /* used for read/write to integer couplets */
182 typedef struct {
183 int *left; /* left side of couplet */
184 int *right; /* right side */
185 } coupletinfo;
186
187 /* read/write integer couplets (int1:int2) */
188 static char *tcl_eggcouplet(ClientData cdata, Tcl_Interp * irp, char *name1,
189 char *name2, int flags)
190 {
191 char *s, s1[41];
192 coupletinfo *cp = (coupletinfo *) cdata;
193
194 if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) {
195 sprintf(s1, "%d:%d", *(cp->left), *(cp->right));
196 Tcl_SetVar2(interp, name1, name2, s1, TCL_GLOBAL_ONLY);
197 } else { /* writes */
198 s = Tcl_GetVar2(interp, name1, name2, TCL_GLOBAL_ONLY);
199 if (s != NULL) {
200 int nr1, nr2;
201
202 if (strlen(s) > 40)
203 s[40] = 0;
204 sscanf(s, "%d%*c%d", &nr1, &nr2);
205 *(cp->left) = nr1;
206 *(cp->right) = nr2;
207 }
208 }
209 return NULL;
210 }
211
212 /* read/write normal integer */
213 static char *tcl_eggint(ClientData cdata, Tcl_Interp * irp, char *name1,
214 char *name2, int flags)
215 {
216 char *s, s1[40];
217 long l;
218 intinfo *ii = (intinfo *) cdata;
219
220 if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) {
221 /* special cases */
222 if ((int *) ii->var == &conmask)
223 strcpy(s1, masktype(conmask));
224 else if ((int *) ii->var == &default_flags) {
225 struct flag_record fr =
226 {FR_GLOBAL, 0, 0, 0, 0, 0};
227 fr.global = default_flags;
228 fr.udef_global = default_uflags;
229 build_flags(s1, &fr, 0);
230 } else
231 sprintf(s1, "%d", *(int *) ii->var);
232 Tcl_SetVar2(interp, name1, name2, s1, TCL_GLOBAL_ONLY);
233 return NULL;
234 } else { /* writes */
235 s = Tcl_GetVar2(interp, name1, name2, TCL_GLOBAL_ONLY);
236 if (s != NULL) {
237 if ((int *) ii->var == &conmask) {
238 if (s[0])
239 conmask = logmodes(s);
240 else
241 conmask = LOG_MODES | LOG_MISC | LOG_CMDS;
242 } else if ((int *) ii->var == &default_flags) {
243 struct flag_record fr =
244 {FR_GLOBAL, 0, 0, 0, 0, 0};
245
246 break_down_flags(s, &fr, 0);
247 default_flags = sanity_check(fr.global); /* drummer */
248 default_uflags = fr.udef_global;
249 } else if ((ii->ro == 2) || ((ii->ro == 1) && protect_readonly)) {
250 return "read-only variable";
251 } else {
252 if (Tcl_ExprLong(interp, s, &l) == TCL_ERROR)
253 return interp->result;
254 if ((int *) ii->var == &max_dcc) {
255 if (l < max_dcc)
256 return "you can't DECREASE max-dcc";
257 max_dcc = l;
258 init_dcc_max();
259 } else if ((int *) ii->var == &max_logs) {
260 if (l < max_logs)
261 return "you can't DECREASE max-logs";
262 max_logs = l;
263 init_misc();
264 } else
265 *(ii->var) = (int) l;
266 }
267 }
268 return NULL;
269 }
270 }
271
272 /* read/write normal string variable */
273 static char *tcl_eggstr(ClientData cdata, Tcl_Interp * irp, char *name1,
274 char *name2, int flags)
275 {
276 char *s;
277 strinfo *st = (strinfo *) cdata;
278
279 if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) {
280 if ((st->str == firewall) && (firewall[0])) {
281 char s1[161];
282
283 sprintf(s1, "%s:%d", firewall, firewallport);
284 Tcl_SetVar2(interp, name1, name2, s1, TCL_GLOBAL_ONLY);
285 } else
286 Tcl_SetVar2(interp, name1, name2, st->str, TCL_GLOBAL_ONLY);
287 if (st->max <= 0) {
288 if ((flags & TCL_TRACE_UNSETS) && (protect_readonly || (st->max == 0))) {
289 /* no matter what we do, it won't return the error */
290 Tcl_SetVar2(interp, name1, name2, st->str, TCL_GLOBAL_ONLY);
291 Tcl_TraceVar(interp, name1, TCL_TRACE_READS | TCL_TRACE_WRITES |
292 TCL_TRACE_UNSETS, tcl_eggstr, (ClientData) st);
293 return "read-only variable";
294 }
295 }
296 return NULL;
297 } else { /* writes */
298 if ((st->max <= 0) && (protect_readonly || (st->max == 0))) {
299 Tcl_SetVar2(interp, name1, name2, st->str, TCL_GLOBAL_ONLY);
300 return "read-only variable";
301 }
302 s = Tcl_GetVar2(interp, name1, name2, TCL_GLOBAL_ONLY);
303 if (s != NULL) {
304 if (strlen(s) > abs(st->max))
305 s[abs(st->max)] = 0;
306 if (st->str == botnetnick)
307 botnet_change(s);
308 else if (st->str == firewall) {
309 splitc(firewall, s, ':');
310 if (!firewall[0])
311 strcpy(firewall, s);
312 else
313 firewallport = atoi(s);
314 } else
315 strcpy(st->str, s);
316 if ((st->flags) && (s[0])) {
317 if (st->str[strlen(st->str) - 1] != '/')
318 strcat(st->str, "/");
319 }
320 }
321 return NULL;
322 }
323 }
324
325 /* add/remove tcl commands */
326 void add_tcl_commands(tcl_cmds * tab)
327 {
328 int i;
329
330 for (i = 0; tab[i].name; i++)
331 Tcl_CreateCommand(interp, tab[i].name, tab[i].func, NULL, NULL);
332 }
333
334 void rem_tcl_commands(tcl_cmds * tab)
335 {
336 int i;
337
338 for (i = 0; tab[i].name; i++)
339 Tcl_DeleteCommand(interp, tab[i].name);
340 }
341
342 static tcl_strings def_tcl_strings[] =
343 {
344 {"botnet-nick", botnetnick, HANDLEN, 0},
345 {"userfile", userfile, 120, STR_PROTECT},
346 {"motd", motdfile, 120, STR_PROTECT},
347 {"admin", admin, 120, 0},
348 {"help-path", helpdir, 120, STR_DIR | STR_PROTECT},
349 {"temp-path", tempdir, 120, STR_DIR | STR_PROTECT},
350 #ifndef STATIC
351 {"mod-path", moddir, 120, STR_DIR | STR_PROTECT},
352 #endif
353 {"notify-newusers", notify_new, 120, 0},
354 {"owner", owner, 120, STR_PROTECT},
355 {"my-hostname", hostname, 120, 0},
356 {"my-ip", myip, 120, 0},
357 {"network", network, 40, 0},
358 {"whois-fields", whois_fields, 120, 0},
359 {"nat-ip", natip, 120, 0},
360 {"username", botuser, 10, 0},
361 {"version", egg_version, 0, 0},
362 {"firewall", firewall, 120, 0},
363 /* confvar patch by aaronwl */
364 {"config", configfile, 0, 0},
365 {"telnet-banner", bannerfile, 120, STR_PROTECT},
366 {0, 0, 0, 0}
367 };
368
369 /* ints */
370
371 static tcl_ints def_tcl_ints[] =
372 {
373 {"ignore-time", &ignore_time, 0},
374 {"dcc-flood-thr", &dcc_flood_thr, 0},
375 {"hourly-updates", &notify_users_at, 0},
376 {"switch-logfiles-at", &switch_logfiles_at, 0},
377 {"connect-timeout", &connect_timeout, 0},
378 {"reserved-port", &reserved_port, 0},
379 /* booleans (really just ints) */
380 {"require-p", &require_p, 0},
381 {"keep-all-logs", &keep_all_logs, 0},
382 {"open-telnets", &allow_new_telnets, 0},
383 {"stealth-telnets", &stealth_telnets, 0},
384 {"uptime", (int *) &online_since, 2},
385 {"console", &conmask, 0},
386 {"default-flags", &default_flags, 0},
387 /* moved from eggdrop.h */
388 {"numversion", &egg_numver, 2},
389 {"debug-tcl", &debug_tcl, 1},
390 {"die-on-sighup", &die_on_sighup, 1},
391 {"die-on-sigterm", &die_on_sigterm, 1},
392 {"remote-boots", &remote_boots, 1},
393 {"max-dcc", &max_dcc, 0},
394 {"max-logs", &max_logs, 0},
395 {"max-logsize", &max_logsize, 0},
396 {"quick-logs", &quick_logs, 0},
397 {"enable-simul", &enable_simul, 1},
398 {"debug-output", &debug_output, 1},
399 {"protect-telnet", &protect_telnet, 0},
400 {"dcc-sanitycheck", &dcc_sanitycheck, 0},
401 {"sort-users", &sort_users, 0},
402 {"ident-timeout", &identtimeout, 0},
403 {"share-unlinks", &share_unlinks, 0},
404 {"log-time", &shtime, 0},
405 {"allow-dk-cmds", &allow_dk_cmds, 0},
406 {"resolve-timeout", &resolve_timeout, 0},
407 {"must-be-owner", &must_be_owner, 1},
408 {"use-silence", &use_silence, 0}, /* arthur2 */
409 {"paranoid-telnet-flood", &par_telnet_flood, 0},
410 {"use-exempts", &use_exempts, 0}, /* Jason/drummer */
411 {"use-invites", &use_invites, 0}, /* Jason/drummer */
412 {"force-expire", &force_expire, 0}, /* Rufus */
413 {0, 0, 0} /* arthur2 */
414 };
415
416 static tcl_coups def_tcl_coups[] =
417 {
418 {"telnet-flood", &flood_telnet_thr, &flood_telnet_time},
419 {"dcc-portrange", &min_dcc_port, &max_dcc_port}, /* dw */
420 {0, 0, 0}
421 };
422
423 /* set up Tcl variables that will hook into eggdrop internal vars via */
424 /* trace callbacks */
425 static void init_traces()
426 {
427 add_tcl_coups(def_tcl_coups);
428 add_tcl_strings(def_tcl_strings);
429 add_tcl_ints(def_tcl_ints);
430 }
431
432 void kill_tcl()
433 {
434 rem_tcl_coups(def_tcl_coups);
435 rem_tcl_strings(def_tcl_strings);
436 rem_tcl_ints(def_tcl_ints);
437 kill_bind();
438 Tcl_DeleteInterp(interp);
439 }
440
441 extern tcl_cmds tcluser_cmds[], tcldcc_cmds[], tclmisc_cmds[];
442
443 /* not going through Tcl's crazy main() system (what on earth was he
444 * smoking?!) so we gotta initialize the Tcl interpreter */
445 void init_tcl()
446 {
447 char pver[25];
448
449 /* initialize the interpreter */
450 context;
451 interp = Tcl_CreateInterp();
452 Tcl_Init(interp);
453 init_bind();
454 init_traces();
455 /* add new commands */
456 /* isnt this much neater :) */
457 add_tcl_commands(tcluser_cmds);
458 add_tcl_commands(tcldcc_cmds);
459 add_tcl_commands(tclmisc_cmds);
460
461 #define Q(A,B) Tcl_CreateCommand(interp,A,B,NULL,NULL)
462 Q("logfile", tcl_logfile);
463 sscanf(egg_version, "%s", pver);
464 Tcl_PkgProvide(interp, "eggdrop", pver);
465 }
466
467 /**********************************************************************/
468
469 void do_tcl(char *whatzit, char *script)
470 {
471 int code;
472 FILE *f = 0;
473
474 if (debug_tcl) {
475 f = fopen("DEBUG.TCL", "a");
476 if (f != NULL)
477 fprintf(f, "eval: %s\n", script);
478 }
479 set_tcl_vars();
480 context;
481 code = Tcl_Eval(interp, script);
482 if (debug_tcl && (f != NULL)) {
483 fprintf(f, "done eval, result=%d\n", code);
484 fclose(f);
485 }
486 if (code != TCL_OK) {
487 putlog(LOG_MISC, "*", "Tcl error in script for '%s':", whatzit);
488 putlog(LOG_MISC, "*", "%s", interp->result);
489 }
490 }
491
492 /* read and interpret the configfile given */
493 /* return 1 if everything was okay */
494 int readtclprog(char *fname)
495 {
496 int code;
497 FILE *f;
498
499 set_tcl_vars();
500 f = fopen(fname, "r");
501 if (f == NULL)
502 return 0;
503 fclose(f);
504 if (debug_tcl) {
505 f = fopen("DEBUG.TCL", "a");
506 if (f != NULL) {
507 fprintf(f, "Sourcing file %s ...\n", fname);
508 fclose(f);
509 }
510 }
511 code = Tcl_EvalFile(interp, fname);
512 if (code != TCL_OK) {
513 if (use_stderr) {
514 dprintf(DP_STDERR, "Tcl error in file '%s':\n", fname);
515 dprintf(DP_STDERR, "%s\n",
516 Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY));
517 } else {
518 putlog(LOG_MISC, "*", "Tcl error in file '%s':", fname);
519 putlog(LOG_MISC, "*", "%s\n",
520 Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY));
521 }
522 /* try to go on anyway (shrug) */
523 /* no dont it's to risky now */
524 return 0;
525 }
526 /* refresh internal variables */
527 return 1;
528 }
529
530 void add_tcl_strings(tcl_strings * list)
531 {
532 int i;
533 strinfo *st;
534
535 for (i = 0; list[i].name; i++) {
536 if (list[i].length > 0) {
537 char *p = Tcl_GetVar(interp, list[i].name, TCL_GLOBAL_ONLY);
538
539 if (p != NULL) {
540 strncpy(list[i].buf, p, list[i].length);
541 list[i].buf[list[i].length] = 0;
542 if (list[i].flags & STR_DIR) {
543 int x = strlen(list[i].buf);
544
545 if ((x > 0) && (x < (list[i].length - 1)) &&
546 (list[i].buf[x - 1] != '/')) {
547 list[i].buf[x++] = '/';
548 list[i].buf[x] = 0;
549 }
550 }
551 }
552 }
553 st = (strinfo *) nmalloc(sizeof(strinfo));
554 strtot += sizeof(strinfo);
555 st->max = list[i].length - (list[i].flags & STR_DIR);
556 if (list[i].flags & STR_PROTECT)
557 st->max = -st->max;
558 st->str = list[i].buf;
559 st->flags = (list[i].flags & STR_DIR);
560 Tcl_TraceVar(interp, list[i].name, TCL_TRACE_READS | TCL_TRACE_WRITES |
561 TCL_TRACE_UNSETS, tcl_eggstr, (ClientData) st);
562 }
563 }
564
565 void rem_tcl_strings(tcl_strings * list)
566 {
567 int i;
568 strinfo *st;
569
570 for (i = 0; list[i].name; i++) {
571 st = (strinfo *) Tcl_VarTraceInfo(interp, list[i].name,
572 TCL_TRACE_READS |
573 TCL_TRACE_WRITES |
574 TCL_TRACE_UNSETS,
575 tcl_eggstr, NULL);
576 Tcl_UntraceVar(interp, list[i].name,
577 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
578 tcl_eggstr, st);
579 if (st != NULL) {
580 strtot -= sizeof(strinfo);
581 nfree(st);
582 }
583 }
584 }
585
586 void add_tcl_ints(tcl_ints * list)
587 {
588 int i;
589 intinfo *ii;
590
591 for (i = 0; list[i].name; i++) {
592 char *p = Tcl_GetVar(interp, list[i].name, TCL_GLOBAL_ONLY);
593
594 if (p != NULL)
595 *(list[i].val) = atoi(p);
596 ii = nmalloc(sizeof(intinfo));
597 strtot += sizeof(intinfo);
598 ii->var = list[i].val;
599 ii->ro = list[i].readonly;
600 Tcl_TraceVar(interp, list[i].name,
601 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
602 tcl_eggint, (ClientData) ii);
603 }
604
605 }
606
607 void rem_tcl_ints(tcl_ints * list)
608 {
609 int i;
610 intinfo *ii;
611
612 for (i = 0; list[i].name; i++) {
613 ii = (intinfo *) Tcl_VarTraceInfo(interp, list[i].name,
614 TCL_TRACE_READS |
615 TCL_TRACE_WRITES |
616 TCL_TRACE_UNSETS,
617 tcl_eggint, NULL);
618 Tcl_UntraceVar(interp, list[i].name,
619 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
620 tcl_eggint, (ClientData) ii);
621 if (ii) {
622 strtot -= sizeof(intinfo);
623 nfree(ii);
624 }
625 }
626 }
627
628 /* allocate couplet space for tracing couplets */
629 void add_tcl_coups(tcl_coups * list)
630 {
631 coupletinfo *cp;
632 int i;
633
634 for (i = 0; list[i].name; i++) {
635 cp = (coupletinfo *) nmalloc(sizeof(coupletinfo));
636 strtot += sizeof(coupletinfo);
637 cp->left = list[i].lptr;
638 cp->right = list[i].rptr;
639 Tcl_TraceVar(interp, list[i].name,
640 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
641 tcl_eggcouplet, (ClientData) cp);
642 }
643 }
644
645 void rem_tcl_coups(tcl_coups * list)
646 {
647 coupletinfo *cp;
648 int i;
649
650 for (i = 0; list[i].name; i++) {
651 cp = (coupletinfo *) Tcl_VarTraceInfo(interp, list[i].name,
652 TCL_TRACE_READS |
653 TCL_TRACE_WRITES |
654 TCL_TRACE_UNSETS,
655 tcl_eggcouplet, NULL);
656 strtot -= sizeof(coupletinfo);
657 Tcl_UntraceVar(interp, list[i].name,
658 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
659 tcl_eggcouplet, (ClientData) cp);
660 nfree(cp);
661 }
662 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23