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

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

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


Revision 1.2 - (hide annotations) (download) (as text)
Thu Jun 24 15:34:13 1999 UTC (20 years, 3 months ago) by segfault
Branch: MAIN
Changes since 1.1: +3 -0 lines
File MIME type: text/x-chdr
This patch fixes the problem of users with +f still being ignored in the
case of a telnet flood.  Patch sent by dw, manually applied by SegFault.

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23