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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [tcl/] [generic/] [tclEvent.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tclEvent.c --
3
 *
4
 *      This file implements some general event related interfaces including
5
 *      background errors, exit handlers, and the "vwait" and "update"
6
 *      command procedures.
7
 *
8
 * Copyright (c) 1990-1994 The Regents of the University of California.
9
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
10
 *
11
 * See the file "license.terms" for information on usage and redistribution
12
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13
 *
14
 * RCS: @(#) $Id: tclEvent.c,v 1.1.1.1 2002-01-16 10:25:26 markom Exp $
15
 */
16
 
17
#include "tclInt.h"
18
#include "tclPort.h"
19
 
20
/*
21
 * The data structure below is used to report background errors.  One
22
 * such structure is allocated for each error;  it holds information
23
 * about the interpreter and the error until bgerror can be invoked
24
 * later as an idle handler.
25
 */
26
 
27
typedef struct BgError {
28
    Tcl_Interp *interp;         /* Interpreter in which error occurred.  NULL
29
                                 * means this error report has been cancelled
30
                                 * (a previous report generated a break). */
31
    char *errorMsg;             /* The error message (interp->result when
32
                                 * the error occurred).  Malloc-ed. */
33
    char *errorInfo;            /* Value of the errorInfo variable
34
                                 * (malloc-ed). */
35
    char *errorCode;            /* Value of the errorCode variable
36
                                 * (malloc-ed). */
37
    struct BgError *nextPtr;    /* Next in list of all pending error
38
                                 * reports for this interpreter, or NULL
39
                                 * for end of list. */
40
} BgError;
41
 
42
/*
43
 * One of the structures below is associated with the "tclBgError"
44
 * assoc data for each interpreter.  It keeps track of the head and
45
 * tail of the list of pending background errors for the interpreter.
46
 */
47
 
48
typedef struct ErrAssocData {
49
    BgError *firstBgPtr;        /* First in list of all background errors
50
                                 * waiting to be processed for this
51
                                 * interpreter (NULL if none). */
52
    BgError *lastBgPtr;         /* Last in list of all background errors
53
                                 * waiting to be processed for this
54
                                 * interpreter (NULL if none). */
55
} ErrAssocData;
56
 
57
/*
58
 * For each exit handler created with a call to Tcl_CreateExitHandler
59
 * there is a structure of the following type:
60
 */
61
 
62
typedef struct ExitHandler {
63
    Tcl_ExitProc *proc;         /* Procedure to call when process exits. */
64
    ClientData clientData;      /* One word of information to pass to proc. */
65
    struct ExitHandler *nextPtr;/* Next in list of all exit handlers for
66
                                 * this application, or NULL for end of list. */
67
} ExitHandler;
68
 
69
static ExitHandler *firstExitPtr = NULL;
70
                                /* First in list of all exit handlers for
71
                                 * application. */
72
 
73
/*
74
 * The following variable is a "secret" indication to Tcl_Exit that
75
 * it should dump out the state of memory before exiting.  If the
76
 * value is non-NULL, it gives the name of the file in which to
77
 * dump memory usage information.
78
 */
79
 
80
char *tclMemDumpFileName = NULL;
81
 
82
/*
83
 * This variable is set to 1 when Tcl_Exit is called, and at the end of
84
 * its work, it is reset to 0. The variable is checked by TclInExit() to
85
 * allow different behavior for exit-time processing, e.g. in closing of
86
 * files and pipes.
87
 */
88
 
89
static int tclInExit = 0;
90
 
91
/*
92
 * Prototypes for procedures referenced only in this file:
93
 */
94
 
95
static void             BgErrorDeleteProc _ANSI_ARGS_((ClientData clientData,
96
                            Tcl_Interp *interp));
97
static void             HandleBgErrors _ANSI_ARGS_((ClientData clientData));
98
static char *           VwaitVarProc _ANSI_ARGS_((ClientData clientData,
99
                            Tcl_Interp *interp, char *name1, char *name2,
100
                            int flags));
101
 
102
/*
103
 *----------------------------------------------------------------------
104
 *
105
 * Tcl_BackgroundError --
106
 *
107
 *      This procedure is invoked to handle errors that occur in Tcl
108
 *      commands that are invoked in "background" (e.g. from event or
109
 *      timer bindings).
110
 *
111
 * Results:
112
 *      None.
113
 *
114
 * Side effects:
115
 *      The command "bgerror" is invoked later as an idle handler to
116
 *      process the error, passing it the error message.  If that fails,
117
 *      then an error message is output on stderr.
118
 *
119
 *----------------------------------------------------------------------
120
 */
121
 
122
void
123
Tcl_BackgroundError(interp)
124
    Tcl_Interp *interp;         /* Interpreter in which an error has
125
                                 * occurred. */
126
{
127
    BgError *errPtr;
128
    char *errResult, *varValue;
129
    ErrAssocData *assocPtr;
130
 
131
    /*
132
     * The Tcl_AddErrorInfo call below (with an empty string) ensures that
133
     * errorInfo gets properly set.  It's needed in cases where the error
134
     * came from a utility procedure like Tcl_GetVar instead of Tcl_Eval;
135
     * in these cases errorInfo still won't have been set when this
136
     * procedure is called.
137
     */
138
 
139
    Tcl_AddErrorInfo(interp, "");
140
 
141
    errResult = TclGetStringFromObj(Tcl_GetObjResult(interp), (int *) NULL);
142
 
143
    errPtr = (BgError *) ckalloc(sizeof(BgError));
144
    errPtr->interp = interp;
145
    errPtr->errorMsg = (char *) ckalloc((unsigned) (strlen(errResult) + 1));
146
    strcpy(errPtr->errorMsg, errResult);
147
    varValue = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
148
    if (varValue == NULL) {
149
        varValue = errPtr->errorMsg;
150
    }
151
    errPtr->errorInfo = (char *) ckalloc((unsigned) (strlen(varValue) + 1));
152
    strcpy(errPtr->errorInfo, varValue);
153
    varValue = Tcl_GetVar(interp, "errorCode", TCL_GLOBAL_ONLY);
154
    if (varValue == NULL) {
155
        varValue = "";
156
    }
157
    errPtr->errorCode = (char *) ckalloc((unsigned) (strlen(varValue) + 1));
158
    strcpy(errPtr->errorCode, varValue);
159
    errPtr->nextPtr = NULL;
160
 
161
    assocPtr = (ErrAssocData *) Tcl_GetAssocData(interp, "tclBgError",
162
            (Tcl_InterpDeleteProc **) NULL);
163
    if (assocPtr == NULL) {
164
 
165
        /*
166
         * This is the first time a background error has occurred in
167
         * this interpreter.  Create associated data to keep track of
168
         * pending error reports.
169
         */
170
 
171
        assocPtr = (ErrAssocData *) ckalloc(sizeof(ErrAssocData));
172
        assocPtr->firstBgPtr = NULL;
173
        assocPtr->lastBgPtr = NULL;
174
        Tcl_SetAssocData(interp, "tclBgError", BgErrorDeleteProc,
175
                (ClientData) assocPtr);
176
    }
177
    if (assocPtr->firstBgPtr == NULL) {
178
        assocPtr->firstBgPtr = errPtr;
179
        Tcl_DoWhenIdle(HandleBgErrors, (ClientData) assocPtr);
180
    } else {
181
        assocPtr->lastBgPtr->nextPtr = errPtr;
182
    }
183
    assocPtr->lastBgPtr = errPtr;
184
    Tcl_ResetResult(interp);
185
}
186
 
187
/*
188
 *----------------------------------------------------------------------
189
 *
190
 * HandleBgErrors --
191
 *
192
 *      This procedure is invoked as an idle handler to process all of
193
 *      the accumulated background errors.
194
 *
195
 * Results:
196
 *      None.
197
 *
198
 * Side effects:
199
 *      Depends on what actions "bgerror" takes for the errors.
200
 *
201
 *----------------------------------------------------------------------
202
 */
203
 
204
static void
205
HandleBgErrors(clientData)
206
    ClientData clientData;      /* Pointer to ErrAssocData structure. */
207
{
208
    Tcl_Interp *interp;
209
    char *command;
210
    char *argv[2];
211
    int code;
212
    BgError *errPtr;
213
    ErrAssocData *assocPtr = (ErrAssocData *) clientData;
214
    Tcl_Channel errChannel;
215
 
216
    Tcl_Preserve((ClientData) assocPtr);
217
 
218
    while (assocPtr->firstBgPtr != NULL) {
219
        interp = assocPtr->firstBgPtr->interp;
220
        if (interp == NULL) {
221
            goto doneWithInterp;
222
        }
223
 
224
        /*
225
         * Restore important state variables to what they were at
226
         * the time the error occurred.
227
         */
228
 
229
        Tcl_SetVar(interp, "errorInfo", assocPtr->firstBgPtr->errorInfo,
230
                TCL_GLOBAL_ONLY);
231
        Tcl_SetVar(interp, "errorCode", assocPtr->firstBgPtr->errorCode,
232
                TCL_GLOBAL_ONLY);
233
 
234
        /*
235
         * Create and invoke the bgerror command.
236
         */
237
 
238
        argv[0] = "bgerror";
239
        argv[1] = assocPtr->firstBgPtr->errorMsg;
240
        command = Tcl_Merge(2, argv);
241
        Tcl_AllowExceptions(interp);
242
        Tcl_Preserve((ClientData) interp);
243
        code = Tcl_GlobalEval(interp, command);
244
        ckfree(command);
245
        if (code == TCL_ERROR) {
246
 
247
            /*
248
             * If the interpreter is safe, we look for a hidden command
249
             * named "bgerror" and call that with the error information.
250
             * Otherwise, simply ignore the error. The rationale is that
251
             * this could be an error caused by a malicious applet trying
252
             * to cause an infinite barrage of error messages. The hidden
253
             * "bgerror" command can be used by a security policy to
254
             * interpose on such attacks and e.g. kill the applet after a
255
             * few attempts.
256
             */
257
 
258
            if (Tcl_IsSafe(interp)) {
259
                Tcl_HashTable *hTblPtr;
260
                Tcl_HashEntry *hPtr;
261
 
262
                hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp,
263
                        "tclHiddenCmds", NULL);
264
                if (hTblPtr == (Tcl_HashTable *) NULL) {
265
                    goto doneWithInterp;
266
                }
267
                hPtr = Tcl_FindHashEntry(hTblPtr, "bgerror");
268
                if (hPtr == (Tcl_HashEntry *) NULL) {
269
                    goto doneWithInterp;
270
                }
271
 
272
                /*
273
                 * OK, the hidden command "bgerror" exists, invoke it.
274
                 */
275
 
276
                argv[0] = "bgerror";
277
                argv[1] = ckalloc((unsigned)
278
                        strlen(assocPtr->firstBgPtr->errorMsg));
279
                strcpy(argv[1], assocPtr->firstBgPtr->errorMsg);
280
                (void) TclInvoke(interp, 2, argv, TCL_INVOKE_HIDDEN);
281
                ckfree(argv[1]);
282
 
283
                goto doneWithInterp;
284
            }
285
 
286
            /*
287
             * We have to get the error output channel at the latest possible
288
             * time, because the eval (above) might have changed the channel.
289
             */
290
 
291
            errChannel = Tcl_GetStdChannel(TCL_STDERR);
292
            if (errChannel != (Tcl_Channel) NULL) {
293
                if (strcmp(interp->result,
294
           "\"bgerror\" is an invalid command name or ambiguous abbreviation")
295
                        == 0) {
296
                    Tcl_Write(errChannel, assocPtr->firstBgPtr->errorInfo, -1);
297
                    Tcl_Write(errChannel, "\n", -1);
298
                } else {
299
                    Tcl_Write(errChannel,
300
                            "bgerror failed to handle background error.\n",
301
                            -1);
302
                    Tcl_Write(errChannel, "    Original error: ", -1);
303
                    Tcl_Write(errChannel, assocPtr->firstBgPtr->errorMsg,
304
                            -1);
305
                    Tcl_Write(errChannel, "\n", -1);
306
                    Tcl_Write(errChannel, "    Error in bgerror: ", -1);
307
                    Tcl_Write(errChannel, interp->result, -1);
308
                    Tcl_Write(errChannel, "\n", -1);
309
                }
310
                Tcl_Flush(errChannel);
311
            }
312
        } else if (code == TCL_BREAK) {
313
 
314
            /*
315
             * Break means cancel any remaining error reports for this
316
             * interpreter.
317
             */
318
 
319
            for (errPtr = assocPtr->firstBgPtr; errPtr != NULL;
320
                    errPtr = errPtr->nextPtr) {
321
                if (errPtr->interp == interp) {
322
                    errPtr->interp = NULL;
323
                }
324
            }
325
        }
326
 
327
        /*
328
         * Discard the command and the information about the error report.
329
         */
330
 
331
doneWithInterp:
332
 
333
        if (assocPtr->firstBgPtr) {
334
            ckfree(assocPtr->firstBgPtr->errorMsg);
335
            ckfree(assocPtr->firstBgPtr->errorInfo);
336
            ckfree(assocPtr->firstBgPtr->errorCode);
337
            errPtr = assocPtr->firstBgPtr->nextPtr;
338
            ckfree((char *) assocPtr->firstBgPtr);
339
            assocPtr->firstBgPtr = errPtr;
340
        }
341
 
342
        if (interp != NULL) {
343
            Tcl_Release((ClientData) interp);
344
        }
345
    }
346
    assocPtr->lastBgPtr = NULL;
347
 
348
    Tcl_Release((ClientData) assocPtr);
349
}
350
 
351
/*
352
 *----------------------------------------------------------------------
353
 *
354
 * BgErrorDeleteProc --
355
 *
356
 *      This procedure is associated with the "tclBgError" assoc data
357
 *      for an interpreter;  it is invoked when the interpreter is
358
 *      deleted in order to free the information assoicated with any
359
 *      pending error reports.
360
 *
361
 * Results:
362
 *      None.
363
 *
364
 * Side effects:
365
 *      Background error information is freed: if there were any
366
 *      pending error reports, they are cancelled.
367
 *
368
 *----------------------------------------------------------------------
369
 */
370
 
371
static void
372
BgErrorDeleteProc(clientData, interp)
373
    ClientData clientData;      /* Pointer to ErrAssocData structure. */
374
    Tcl_Interp *interp;         /* Interpreter being deleted. */
375
{
376
    ErrAssocData *assocPtr = (ErrAssocData *) clientData;
377
    BgError *errPtr;
378
 
379
    while (assocPtr->firstBgPtr != NULL) {
380
        errPtr = assocPtr->firstBgPtr;
381
        assocPtr->firstBgPtr = errPtr->nextPtr;
382
        ckfree(errPtr->errorMsg);
383
        ckfree(errPtr->errorInfo);
384
        ckfree(errPtr->errorCode);
385
        ckfree((char *) errPtr);
386
    }
387
    Tcl_CancelIdleCall(HandleBgErrors, (ClientData) assocPtr);
388
    Tcl_EventuallyFree((ClientData) assocPtr, TCL_DYNAMIC);
389
}
390
 
391
/*
392
 *----------------------------------------------------------------------
393
 *
394
 * Tcl_CreateExitHandler --
395
 *
396
 *      Arrange for a given procedure to be invoked just before the
397
 *      application exits.
398
 *
399
 * Results:
400
 *      None.
401
 *
402
 * Side effects:
403
 *      Proc will be invoked with clientData as argument when the
404
 *      application exits.
405
 *
406
 *----------------------------------------------------------------------
407
 */
408
 
409
void
410
Tcl_CreateExitHandler(proc, clientData)
411
    Tcl_ExitProc *proc;         /* Procedure to invoke. */
412
    ClientData clientData;      /* Arbitrary value to pass to proc. */
413
{
414
    ExitHandler *exitPtr;
415
 
416
    exitPtr = (ExitHandler *) ckalloc(sizeof(ExitHandler));
417
    exitPtr->proc = proc;
418
    exitPtr->clientData = clientData;
419
    exitPtr->nextPtr = firstExitPtr;
420
    firstExitPtr = exitPtr;
421
}
422
 
423
/*
424
 *----------------------------------------------------------------------
425
 *
426
 * Tcl_DeleteExitHandler --
427
 *
428
 *      This procedure cancels an existing exit handler matching proc
429
 *      and clientData, if such a handler exits.
430
 *
431
 * Results:
432
 *      None.
433
 *
434
 * Side effects:
435
 *      If there is an exit handler corresponding to proc and clientData
436
 *      then it is cancelled;  if no such handler exists then nothing
437
 *      happens.
438
 *
439
 *----------------------------------------------------------------------
440
 */
441
 
442
void
443
Tcl_DeleteExitHandler(proc, clientData)
444
    Tcl_ExitProc *proc;         /* Procedure that was previously registered. */
445
    ClientData clientData;      /* Arbitrary value to pass to proc. */
446
{
447
    ExitHandler *exitPtr, *prevPtr;
448
 
449
    for (prevPtr = NULL, exitPtr = firstExitPtr; exitPtr != NULL;
450
            prevPtr = exitPtr, exitPtr = exitPtr->nextPtr) {
451
        if ((exitPtr->proc == proc)
452
                && (exitPtr->clientData == clientData)) {
453
            if (prevPtr == NULL) {
454
                firstExitPtr = exitPtr->nextPtr;
455
            } else {
456
                prevPtr->nextPtr = exitPtr->nextPtr;
457
            }
458
            ckfree((char *) exitPtr);
459
            return;
460
        }
461
    }
462
}
463
 
464
/*
465
 *----------------------------------------------------------------------
466
 *
467
 * Tcl_Exit --
468
 *
469
 *      This procedure is called to terminate the application.
470
 *
471
 * Results:
472
 *      None.
473
 *
474
 * Side effects:
475
 *      All existing exit handlers are invoked, then the application
476
 *      ends.
477
 *
478
 *----------------------------------------------------------------------
479
 */
480
 
481
void
482
Tcl_Exit(status)
483
    int status;                 /* Exit status for application;  typically
484
                                 * 0 for normal return, 1 for error return. */
485
{
486
    Tcl_Finalize();
487
#ifdef TCL_MEM_DEBUG
488
    if (tclMemDumpFileName != NULL) {
489
        Tcl_DumpActiveMemory(tclMemDumpFileName);
490
    }
491
#endif
492
    TclPlatformExit(status);
493
}
494
 
495
/*
496
 *----------------------------------------------------------------------
497
 *
498
 * Tcl_Finalize --
499
 *
500
 *      Runs the exit handlers to allow Tcl to clean up its state prior
501
 *      to being unloaded. Called by Tcl_Exit and when Tcl was dynamically
502
 *      loaded and is now being unloaded.
503
 *
504
 * Results:
505
 *      None.
506
 *
507
 * Side effects:
508
 *      Whatever the exit handlers do. Also frees up storage associated
509
 *      with the Tcl object type table.
510
 *
511
 *----------------------------------------------------------------------
512
 */
513
 
514
void
515
Tcl_Finalize()
516
{
517
    ExitHandler *exitPtr;
518
 
519
    /*
520
     * Invoke exit handler first.
521
     */
522
 
523
    tclInExit = 1;
524
    for (exitPtr = firstExitPtr; exitPtr != NULL; exitPtr = firstExitPtr) {
525
        /*
526
         * Be careful to remove the handler from the list before invoking
527
         * its callback.  This protects us against double-freeing if the
528
         * callback should call Tcl_DeleteExitHandler on itself.
529
         */
530
 
531
        firstExitPtr = exitPtr->nextPtr;
532
        (*exitPtr->proc)(exitPtr->clientData);
533
        ckfree((char *) exitPtr);
534
    }
535
 
536
    /*
537
     * Now finalize the Tcl execution environment.  Note that this must be done
538
     * after the exit handlers, because there are order dependencies.
539
     */
540
 
541
    TclFinalizeCompExecEnv();
542
    TclFinalizeEnvironment();
543
    TclpFinalize();
544
    firstExitPtr = NULL;
545
    tclInExit = 0;
546
}
547
 
548
/*
549
 *----------------------------------------------------------------------
550
 *
551
 * TclInExit --
552
 *
553
 *      Determines if we are in the middle of exit-time cleanup.
554
 *
555
 * Results:
556
 *      If we are in the middle of exiting, 1, otherwise 0.
557
 *
558
 * Side effects:
559
 *      None.
560
 *
561
 *----------------------------------------------------------------------
562
 */
563
 
564
int
565
TclInExit()
566
{
567
    return tclInExit;
568
}
569
 
570
/*
571
 *----------------------------------------------------------------------
572
 *
573
 * Tcl_VwaitCmd --
574
 *
575
 *      This procedure is invoked to process the "vwait" Tcl command.
576
 *      See the user documentation for details on what it does.
577
 *
578
 * Results:
579
 *      A standard Tcl result.
580
 *
581
 * Side effects:
582
 *      See the user documentation.
583
 *
584
 *----------------------------------------------------------------------
585
 */
586
 
587
        /* ARGSUSED */
588
int
589
Tcl_VwaitCmd(clientData, interp, argc, argv)
590
    ClientData clientData;      /* Not used. */
591
    Tcl_Interp *interp;         /* Current interpreter. */
592
    int argc;                   /* Number of arguments. */
593
    char **argv;                /* Argument strings. */
594
{
595
    int done, foundEvent;
596
 
597
    if (argc != 2) {
598
        Tcl_AppendResult(interp, "wrong # args: should be \"",
599
                argv[0], " name\"", (char *) NULL);
600
        return TCL_ERROR;
601
    }
602
    if (Tcl_TraceVar(interp, argv[1],
603
            TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
604
            VwaitVarProc, (ClientData) &done) != TCL_OK) {
605
        return TCL_ERROR;
606
    };
607
    done = 0;
608
    foundEvent = 1;
609
    while (!done && foundEvent) {
610
        foundEvent = Tcl_DoOneEvent(TCL_ALL_EVENTS);
611
    }
612
    Tcl_UntraceVar(interp, argv[1],
613
            TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
614
            VwaitVarProc, (ClientData) &done);
615
 
616
    /*
617
     * Clear out the interpreter's result, since it may have been set
618
     * by event handlers.
619
     */
620
 
621
    Tcl_ResetResult(interp);
622
    if (!foundEvent) {
623
        Tcl_AppendResult(interp, "can't wait for variable \"", argv[1],
624
                "\":  would wait forever", (char *) NULL);
625
        return TCL_ERROR;
626
    }
627
    return TCL_OK;
628
}
629
 
630
        /* ARGSUSED */
631
static char *
632
VwaitVarProc(clientData, interp, name1, name2, flags)
633
    ClientData clientData;      /* Pointer to integer to set to 1. */
634
    Tcl_Interp *interp;         /* Interpreter containing variable. */
635
    char *name1;                /* Name of variable. */
636
    char *name2;                /* Second part of variable name. */
637
    int flags;                  /* Information about what happened. */
638
{
639
    int *donePtr = (int *) clientData;
640
 
641
    *donePtr = 1;
642
    return (char *) NULL;
643
}
644
 
645
/*
646
 *----------------------------------------------------------------------
647
 *
648
 * Tcl_UpdateCmd --
649
 *
650
 *      This procedure is invoked to process the "update" Tcl command.
651
 *      See the user documentation for details on what it does.
652
 *
653
 * Results:
654
 *      A standard Tcl result.
655
 *
656
 * Side effects:
657
 *      See the user documentation.
658
 *
659
 *----------------------------------------------------------------------
660
 */
661
 
662
        /* ARGSUSED */
663
int
664
Tcl_UpdateCmd(clientData, interp, argc, argv)
665
    ClientData clientData;      /* Not used. */
666
    Tcl_Interp *interp;         /* Current interpreter. */
667
    int argc;                   /* Number of arguments. */
668
    char **argv;                /* Argument strings. */
669
{
670
    int flags;
671
 
672
    if (argc == 1) {
673
        flags = TCL_ALL_EVENTS|TCL_DONT_WAIT;
674
    } else if (argc == 2) {
675
        if (strncmp(argv[1], "idletasks", strlen(argv[1])) != 0) {
676
            Tcl_AppendResult(interp, "bad option \"", argv[1],
677
                    "\": must be idletasks", (char *) NULL);
678
            return TCL_ERROR;
679
        }
680
        flags = TCL_WINDOW_EVENTS|TCL_IDLE_EVENTS|TCL_DONT_WAIT;
681
    } else {
682
        Tcl_AppendResult(interp, "wrong # args: should be \"",
683
                argv[0], " ?idletasks?\"", (char *) NULL);
684
        return TCL_ERROR;
685
    }
686
 
687
    while (Tcl_DoOneEvent(flags) != 0) {
688
        /* Empty loop body */
689
    }
690
 
691
    /*
692
     * Must clear the interpreter's result because event handlers could
693
     * have executed commands.
694
     */
695
 
696
    Tcl_ResetResult(interp);
697
    return TCL_OK;
698
}

powered by: WebSVN 2.1.0

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