~ubuntu-branches/ubuntu/dapper/tk8.0/dapper-updates

« back to all changes in this revision

Viewing changes to generic/tkConsole.c

  • Committer: Bazaar Package Importer
  • Author(s): Mike Markley
  • Date: 2001-07-24 21:57:40 UTC
  • Revision ID: james.westby@ubuntu.com-20010724215740-r70t25rtmbqjil2h
Tags: upstream-8.0.5
ImportĀ upstreamĀ versionĀ 8.0.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 * tkConsole.c --
 
3
 *
 
4
 *      This file implements a Tcl console for systems that may not
 
5
 *      otherwise have access to a console.  It uses the Text widget
 
6
 *      and provides special access via a console command.
 
7
 *
 
8
 * Copyright (c) 1995-1996 Sun Microsystems, Inc.
 
9
 *
 
10
 * See the file "license.terms" for information on usage and redistribution
 
11
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 
12
 *
 
13
 * RCS: @(#) $Id: tkConsole.c,v 1.3 1999/02/04 20:51:36 stanton Exp $
 
14
 */
 
15
 
 
16
#include "tk.h"
 
17
#include <string.h>
 
18
 
 
19
/*
 
20
 * A data structure of the following type holds information for each console
 
21
 * which a handler (i.e. a Tcl command) has been defined for a particular
 
22
 * top-level window.
 
23
 */
 
24
 
 
25
typedef struct ConsoleInfo {
 
26
    Tcl_Interp *consoleInterp;  /* Interpreter for the console. */
 
27
    Tcl_Interp *interp;         /* Interpreter to send console commands. */
 
28
} ConsoleInfo;
 
29
 
 
30
static Tcl_Interp *gStdoutInterp = NULL;
 
31
 
 
32
/*
 
33
 * Forward declarations for procedures defined later in this file:
 
34
 *
 
35
 * The first three will be used in the tk app shells...
 
36
 */
 
37
 
 
38
void    TkConsoleCreate _ANSI_ARGS_((void));
 
39
int     TkConsoleInit _ANSI_ARGS_((Tcl_Interp *interp));
 
40
void    TkConsolePrint _ANSI_ARGS_((Tcl_Interp *interp,
 
41
                            int devId, char *buffer, long size));
 
42
 
 
43
static int      ConsoleCmd _ANSI_ARGS_((ClientData clientData,
 
44
                    Tcl_Interp *interp, int argc, char **argv));
 
45
static void     ConsoleDeleteProc _ANSI_ARGS_((ClientData clientData));
 
46
static void     ConsoleEventProc _ANSI_ARGS_((ClientData clientData,
 
47
                    XEvent *eventPtr));
 
48
static int      InterpreterCmd _ANSI_ARGS_((ClientData clientData,
 
49
                    Tcl_Interp *interp, int argc, char **argv));
 
50
 
 
51
static int      ConsoleInput _ANSI_ARGS_((ClientData instanceData,
 
52
                    char *buf, int toRead, int *errorCode));
 
53
static int      ConsoleOutput _ANSI_ARGS_((ClientData instanceData,
 
54
                    char *buf, int toWrite, int *errorCode));
 
55
static int      ConsoleClose _ANSI_ARGS_((ClientData instanceData,
 
56
                    Tcl_Interp *interp));
 
57
static void     ConsoleWatch _ANSI_ARGS_((ClientData instanceData,
 
58
                    int mask));
 
59
static int      ConsoleHandle _ANSI_ARGS_((ClientData instanceData,
 
60
                    int direction, ClientData *handlePtr));
 
61
 
 
62
/*
 
63
 * This structure describes the channel type structure for file based IO:
 
64
 */
 
65
 
 
66
static Tcl_ChannelType consoleChannelType = {
 
67
    "console",                  /* Type name. */
 
68
    NULL,                       /* Always non-blocking.*/
 
69
    ConsoleClose,               /* Close proc. */
 
70
    ConsoleInput,               /* Input proc. */
 
71
    ConsoleOutput,              /* Output proc. */
 
72
    NULL,                       /* Seek proc. */
 
73
    NULL,                       /* Set option proc. */
 
74
    NULL,                       /* Get option proc. */
 
75
    ConsoleWatch,               /* Watch for events on console. */
 
76
    ConsoleHandle,              /* Get a handle from the device. */
 
77
};
 
78
 
 
79
/*
 
80
 *----------------------------------------------------------------------
 
81
 *
 
82
 * TkConsoleCreate --
 
83
 *
 
84
 *      Create the console channels and install them as the standard
 
85
 *      channels.  All I/O will be discarded until TkConsoleInit is
 
86
 *      called to attach the console to a text widget.
 
87
 *
 
88
 * Results:
 
89
 *      None.
 
90
 *
 
91
 * Side effects:
 
92
 *      Creates the console channel and installs it as the standard
 
93
 *      channels.
 
94
 *
 
95
 *----------------------------------------------------------------------
 
96
 */
 
97
 
 
98
void
 
99
TkConsoleCreate()
 
100
{
 
101
    Tcl_Channel consoleChannel;
 
102
 
 
103
    consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console0",
 
104
            (ClientData) TCL_STDIN, TCL_READABLE);
 
105
    if (consoleChannel != NULL) {
 
106
        Tcl_SetChannelOption(NULL, consoleChannel, "-translation", "lf");
 
107
        Tcl_SetChannelOption(NULL, consoleChannel, "-buffering", "none");
 
108
    }
 
109
    Tcl_SetStdChannel(consoleChannel, TCL_STDIN);
 
110
    consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console1",
 
111
            (ClientData) TCL_STDOUT, TCL_WRITABLE);
 
112
    if (consoleChannel != NULL) {
 
113
        Tcl_SetChannelOption(NULL, consoleChannel, "-translation", "lf");
 
114
        Tcl_SetChannelOption(NULL, consoleChannel, "-buffering", "none");
 
115
    }
 
116
    Tcl_SetStdChannel(consoleChannel, TCL_STDOUT);
 
117
    consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console2",
 
118
            (ClientData) TCL_STDERR, TCL_WRITABLE);
 
119
    if (consoleChannel != NULL) {
 
120
        Tcl_SetChannelOption(NULL, consoleChannel, "-translation", "lf");
 
121
        Tcl_SetChannelOption(NULL, consoleChannel, "-buffering", "none");
 
122
    }
 
123
    Tcl_SetStdChannel(consoleChannel, TCL_STDERR);
 
124
}
 
125
 
 
126
/*
 
127
 *----------------------------------------------------------------------
 
128
 *
 
129
 * TkConsoleInit --
 
130
 *
 
131
 *      Initialize the console.  This code actually creates a new
 
132
 *      application and associated interpreter.  This effectivly hides
 
133
 *      the implementation from the main application.
 
134
 *
 
135
 * Results:
 
136
 *      None.
 
137
 *
 
138
 * Side effects:
 
139
 *      A new console it created.
 
140
 *
 
141
 *----------------------------------------------------------------------
 
142
 */
 
143
 
 
144
int 
 
145
TkConsoleInit(interp)
 
146
    Tcl_Interp *interp;                 /* Interpreter to use for prompting. */
 
147
{
 
148
    Tcl_Interp *consoleInterp;
 
149
    ConsoleInfo *info;
 
150
    Tk_Window mainWindow = Tk_MainWindow(interp);
 
151
#ifdef MAC_TCL
 
152
    static char initCmd[] = "source -rsrc {Console}";
 
153
#else
 
154
    static char initCmd[] = "source $tk_library/console.tcl";
 
155
#endif
 
156
    
 
157
    consoleInterp = Tcl_CreateInterp();
 
158
    if (consoleInterp == NULL) {
 
159
        goto error;
 
160
    }
 
161
    
 
162
    /*
 
163
     * Initialized Tcl and Tk.
 
164
     */
 
165
 
 
166
    if (Tcl_Init(consoleInterp) != TCL_OK) {
 
167
        goto error;
 
168
    }
 
169
    if (Tk_Init(consoleInterp) != TCL_OK) {
 
170
        goto error;
 
171
    }
 
172
    gStdoutInterp = interp;
 
173
    
 
174
    /* 
 
175
     * Add console commands to the interp 
 
176
     */
 
177
    info = (ConsoleInfo *) ckalloc(sizeof(ConsoleInfo));
 
178
    info->interp = interp;
 
179
    info->consoleInterp = consoleInterp;
 
180
    Tcl_CreateCommand(interp, "console", ConsoleCmd, (ClientData) info,
 
181
            (Tcl_CmdDeleteProc *) ConsoleDeleteProc);
 
182
    Tcl_CreateCommand(consoleInterp, "consoleinterp", InterpreterCmd,
 
183
            (ClientData) info, (Tcl_CmdDeleteProc *) NULL);
 
184
 
 
185
    Tk_CreateEventHandler(mainWindow, StructureNotifyMask, ConsoleEventProc,
 
186
            (ClientData) info);
 
187
 
 
188
    Tcl_Preserve((ClientData) consoleInterp);
 
189
    if (Tcl_Eval(consoleInterp, initCmd) == TCL_ERROR) {
 
190
        /* goto error; -- no problem for now... */
 
191
        printf("Eval error: %s", consoleInterp->result);
 
192
    }
 
193
    Tcl_Release((ClientData) consoleInterp);
 
194
    return TCL_OK;
 
195
    
 
196
    error:
 
197
    if (consoleInterp != NULL) {
 
198
        Tcl_DeleteInterp(consoleInterp);
 
199
    }
 
200
    return TCL_ERROR;
 
201
}
 
202
 
 
203
/*
 
204
 *----------------------------------------------------------------------
 
205
 *
 
206
 * ConsoleOutput--
 
207
 *
 
208
 *      Writes the given output on the IO channel. Returns count of how
 
209
 *      many characters were actually written, and an error indication.
 
210
 *
 
211
 * Results:
 
212
 *      A count of how many characters were written is returned and an
 
213
 *      error indication is returned in an output argument.
 
214
 *
 
215
 * Side effects:
 
216
 *      Writes output on the actual channel.
 
217
 *
 
218
 *----------------------------------------------------------------------
 
219
 */
 
220
 
 
221
static int
 
222
ConsoleOutput(instanceData, buf, toWrite, errorCode)
 
223
    ClientData instanceData;            /* Indicates which device to use. */
 
224
    char *buf;                          /* The data buffer. */
 
225
    int toWrite;                        /* How many bytes to write? */
 
226
    int *errorCode;                     /* Where to store error code. */
 
227
{
 
228
    *errorCode = 0;
 
229
    Tcl_SetErrno(0);
 
230
 
 
231
    if (gStdoutInterp != NULL) {
 
232
        TkConsolePrint(gStdoutInterp, (int) instanceData, buf, toWrite);
 
233
    }
 
234
    
 
235
    return toWrite;
 
236
}
 
237
 
 
238
/*
 
239
 *----------------------------------------------------------------------
 
240
 *
 
241
 * ConsoleInput --
 
242
 *
 
243
 *      Read input from the console.  Not currently implemented.
 
244
 *
 
245
 * Results:
 
246
 *      Always returns EOF.
 
247
 *
 
248
 * Side effects:
 
249
 *      None.
 
250
 *
 
251
 *----------------------------------------------------------------------
 
252
 */
 
253
 
 
254
        /* ARGSUSED */
 
255
static int
 
256
ConsoleInput(instanceData, buf, bufSize, errorCode)
 
257
    ClientData instanceData;            /* Unused. */
 
258
    char *buf;                          /* Where to store data read. */
 
259
    int bufSize;                        /* How much space is available
 
260
                                         * in the buffer? */
 
261
    int *errorCode;                     /* Where to store error code. */
 
262
{
 
263
    return 0;                   /* Always return EOF. */
 
264
}
 
265
 
 
266
/*
 
267
 *----------------------------------------------------------------------
 
268
 *
 
269
 * ConsoleClose --
 
270
 *
 
271
 *      Closes the IO channel.
 
272
 *
 
273
 * Results:
 
274
 *      Always returns 0 (success).
 
275
 *
 
276
 * Side effects:
 
277
 *      Frees the dummy file associated with the channel.
 
278
 *
 
279
 *----------------------------------------------------------------------
 
280
 */
 
281
 
 
282
        /* ARGSUSED */
 
283
static int
 
284
ConsoleClose(instanceData, interp)
 
285
    ClientData instanceData;    /* Unused. */
 
286
    Tcl_Interp *interp;         /* Unused. */
 
287
{
 
288
    return 0;
 
289
}
 
290
 
 
291
/*
 
292
 *----------------------------------------------------------------------
 
293
 *
 
294
 * ConsoleWatch --
 
295
 *
 
296
 *      Called by the notifier to set up the console device so that
 
297
 *      events will be noticed. Since there are no events on the
 
298
 *      console, this routine just returns without doing anything.
 
299
 *
 
300
 * Results:
 
301
 *      None.
 
302
 *
 
303
 * Side effects:
 
304
 *      None.
 
305
 *
 
306
 *----------------------------------------------------------------------
 
307
 */
 
308
 
 
309
        /* ARGSUSED */
 
310
static void
 
311
ConsoleWatch(instanceData, mask)
 
312
    ClientData instanceData;            /* Device ID for the channel. */
 
313
    int mask;                           /* OR-ed combination of
 
314
                                         * TCL_READABLE, TCL_WRITABLE and
 
315
                                         * TCL_EXCEPTION, for the events
 
316
                                         * we are interested in. */
 
317
{
 
318
}
 
319
 
 
320
/*
 
321
 *----------------------------------------------------------------------
 
322
 *
 
323
 * ConsoleHandle --
 
324
 *
 
325
 *      Invoked by the generic IO layer to get a handle from a channel.
 
326
 *      Because console channels are not devices, this function always
 
327
 *      fails.
 
328
 *
 
329
 * Results:
 
330
 *      Always returns TCL_ERROR.
 
331
 *
 
332
 * Side effects:
 
333
 *      None.
 
334
 *
 
335
 *----------------------------------------------------------------------
 
336
 */
 
337
 
 
338
        /* ARGSUSED */
 
339
static int
 
340
ConsoleHandle(instanceData, direction, handlePtr)
 
341
    ClientData instanceData;    /* Device ID for the channel. */
 
342
    int direction;              /* TCL_READABLE or TCL_WRITABLE to indicate
 
343
                                 * which direction of the channel is being
 
344
                                 * requested. */
 
345
    ClientData *handlePtr;      /* Where to store handle */
 
346
{
 
347
    return TCL_ERROR;
 
348
}
 
349
 
 
350
/*
 
351
 *----------------------------------------------------------------------
 
352
 *
 
353
 * ConsoleCmd --
 
354
 *
 
355
 *      The console command implements a Tcl interface to the various console
 
356
 *      options.
 
357
 *
 
358
 * Results:
 
359
 *      None.
 
360
 *
 
361
 * Side effects:
 
362
 *      None.
 
363
 *
 
364
 *----------------------------------------------------------------------
 
365
 */
 
366
 
 
367
static int
 
368
ConsoleCmd(clientData, interp, argc, argv)
 
369
    ClientData clientData;              /* Not used. */
 
370
    Tcl_Interp *interp;                 /* Current interpreter. */
 
371
    int argc;                           /* Number of arguments. */
 
372
    char **argv;                        /* Argument strings. */
 
373
{
 
374
    ConsoleInfo *info = (ConsoleInfo *) clientData;
 
375
    char c;
 
376
    int length;
 
377
    int result;
 
378
    Tcl_Interp *consoleInterp;
 
379
 
 
380
    if (argc < 2) {
 
381
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
 
382
                " option ?arg arg ...?\"", (char *) NULL);
 
383
        return TCL_ERROR;
 
384
    }
 
385
    
 
386
    c = argv[1][0];
 
387
    length = strlen(argv[1]);
 
388
    result = TCL_OK;
 
389
    consoleInterp = info->consoleInterp;
 
390
    Tcl_Preserve((ClientData) consoleInterp);
 
391
    if ((c == 't') && (strncmp(argv[1], "title", length)) == 0) {
 
392
        Tcl_DString dString;
 
393
        
 
394
        Tcl_DStringInit(&dString);
 
395
        Tcl_DStringAppend(&dString, "wm title . ", -1);
 
396
        if (argc == 3) {
 
397
            Tcl_DStringAppendElement(&dString, argv[2]);
 
398
        }
 
399
        Tcl_Eval(consoleInterp, Tcl_DStringValue(&dString));
 
400
        Tcl_DStringFree(&dString);
 
401
    } else if ((c == 'h') && (strncmp(argv[1], "hide", length)) == 0) {
 
402
        Tcl_Eval(consoleInterp, "wm withdraw .");
 
403
    } else if ((c == 's') && (strncmp(argv[1], "show", length)) == 0) {
 
404
        Tcl_Eval(consoleInterp, "wm deiconify .");
 
405
    } else if ((c == 'e') && (strncmp(argv[1], "eval", length)) == 0) {
 
406
        if (argc == 3) {
 
407
            result = Tcl_Eval(consoleInterp, argv[2]);
 
408
            Tcl_AppendResult(interp, Tcl_GetStringResult(consoleInterp),
 
409
                    (char *) NULL);
 
410
        } else {
 
411
            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
 
412
                    " eval command\"", (char *) NULL);
 
413
            return TCL_ERROR;
 
414
        }
 
415
    } else {
 
416
        Tcl_AppendResult(interp, "bad option \"", argv[1],
 
417
                "\": should be hide, show, or title",
 
418
                (char *) NULL);
 
419
        result = TCL_ERROR;
 
420
    }
 
421
    Tcl_Release((ClientData) consoleInterp);
 
422
    return result;
 
423
}
 
424
 
 
425
/*
 
426
 *----------------------------------------------------------------------
 
427
 *
 
428
 * InterpreterCmd --
 
429
 *
 
430
 *      This command allows the console interp to communicate with the
 
431
 *      main interpreter.
 
432
 *
 
433
 * Results:
 
434
 *      None.
 
435
 *
 
436
 * Side effects:
 
437
 *      None.
 
438
 *
 
439
 *----------------------------------------------------------------------
 
440
 */
 
441
 
 
442
static int
 
443
InterpreterCmd(clientData, interp, argc, argv)
 
444
    ClientData clientData;              /* Not used. */
 
445
    Tcl_Interp *interp;                 /* Current interpreter. */
 
446
    int argc;                           /* Number of arguments. */
 
447
    char **argv;                        /* Argument strings. */
 
448
{
 
449
    ConsoleInfo *info = (ConsoleInfo *) clientData;
 
450
    char c;
 
451
    int length;
 
452
    int result;
 
453
    Tcl_Interp *otherInterp;
 
454
 
 
455
    if (argc < 2) {
 
456
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
 
457
                " option ?arg arg ...?\"", (char *) NULL);
 
458
        return TCL_ERROR;
 
459
    }
 
460
    
 
461
    c = argv[1][0];
 
462
    length = strlen(argv[1]);
 
463
    otherInterp = info->interp;
 
464
    Tcl_Preserve((ClientData) otherInterp);
 
465
    if ((c == 'e') && (strncmp(argv[1], "eval", length)) == 0) {
 
466
        result = Tcl_GlobalEval(otherInterp, argv[2]);
 
467
        Tcl_AppendResult(interp, otherInterp->result, (char *) NULL);
 
468
    } else if ((c == 'r') && (strncmp(argv[1], "record", length)) == 0) {
 
469
        Tcl_RecordAndEval(otherInterp, argv[2], TCL_EVAL_GLOBAL);
 
470
        result = TCL_OK;
 
471
        Tcl_ResetResult(interp);
 
472
        Tcl_AppendResult(interp, otherInterp->result, (char *) NULL);
 
473
    } else {
 
474
        Tcl_AppendResult(interp, "bad option \"", argv[1],
 
475
                "\": should be eval or record",
 
476
                (char *) NULL);
 
477
        result = TCL_ERROR;
 
478
    }
 
479
    Tcl_Release((ClientData) otherInterp);
 
480
    return result;
 
481
}
 
482
 
 
483
/*
 
484
 *----------------------------------------------------------------------
 
485
 *
 
486
 * ConsoleDeleteProc --
 
487
 *
 
488
 *      If the console command is deleted we destroy the console window
 
489
 *      and all associated data structures.
 
490
 *
 
491
 * Results:
 
492
 *      None.
 
493
 *
 
494
 * Side effects:
 
495
 *      A new console it created.
 
496
 *
 
497
 *----------------------------------------------------------------------
 
498
 */
 
499
 
 
500
void 
 
501
ConsoleDeleteProc(clientData) 
 
502
    ClientData clientData;
 
503
{
 
504
    ConsoleInfo *info = (ConsoleInfo *) clientData;
 
505
 
 
506
    Tcl_DeleteInterp(info->consoleInterp);
 
507
    info->consoleInterp = NULL;
 
508
}
 
509
 
 
510
/*
 
511
 *----------------------------------------------------------------------
 
512
 *
 
513
 * ConsoleEventProc --
 
514
 *
 
515
 *      This event procedure is registered on the main window of the
 
516
 *      slave interpreter.  If the user or a running script causes the
 
517
 *      main window to be destroyed, then we need to inform the console
 
518
 *      interpreter by invoking "tkConsoleExit".
 
519
 *
 
520
 * Results:
 
521
 *      None.
 
522
 *
 
523
 * Side effects:
 
524
 *      Invokes the "tkConsoleExit" procedure in the console interp.
 
525
 *
 
526
 *----------------------------------------------------------------------
 
527
 */
 
528
 
 
529
static void
 
530
ConsoleEventProc(clientData, eventPtr)
 
531
    ClientData clientData;
 
532
    XEvent *eventPtr;
 
533
{
 
534
    ConsoleInfo *info = (ConsoleInfo *) clientData;
 
535
    Tcl_Interp *consoleInterp;
 
536
    
 
537
    if (eventPtr->type == DestroyNotify) {
 
538
        consoleInterp = info->consoleInterp;
 
539
 
 
540
        /*
 
541
         * It is possible that the console interpreter itself has
 
542
         * already been deleted. In that case the consoleInterp
 
543
         * field will be set to NULL. If the interpreter is already
 
544
         * gone, we do not have to do any work here.
 
545
         */
 
546
        
 
547
        if (consoleInterp == (Tcl_Interp *) NULL) {
 
548
            return;
 
549
        }
 
550
        Tcl_Preserve((ClientData) consoleInterp);
 
551
        Tcl_Eval(consoleInterp, "tkConsoleExit");
 
552
        Tcl_Release((ClientData) consoleInterp);
 
553
    }
 
554
}
 
555
 
 
556
/*
 
557
 *----------------------------------------------------------------------
 
558
 *
 
559
 * TkConsolePrint --
 
560
 *
 
561
 *      Prints to the give text to the console.  Given the main interp
 
562
 *      this functions find the appropiate console interp and forwards
 
563
 *      the text to be added to that console.
 
564
 *
 
565
 * Results:
 
566
 *      None.
 
567
 *
 
568
 * Side effects:
 
569
 *      None.
 
570
 *
 
571
 *----------------------------------------------------------------------
 
572
 */
 
573
 
 
574
void
 
575
TkConsolePrint(interp, devId, buffer, size)
 
576
    Tcl_Interp *interp;         /* Main interpreter. */
 
577
    int devId;                  /* TCL_STDOUT for stdout, TCL_STDERR for
 
578
                                 * stderr. */
 
579
    char *buffer;               /* Text buffer. */
 
580
    long size;                  /* Size of text buffer. */
 
581
{
 
582
    Tcl_DString command, output;
 
583
    Tcl_CmdInfo cmdInfo;
 
584
    char *cmd;
 
585
    ConsoleInfo *info;
 
586
    Tcl_Interp *consoleInterp;
 
587
    int result;
 
588
 
 
589
    if (interp == NULL) {
 
590
        return;
 
591
    }
 
592
    
 
593
    if (devId == TCL_STDERR) {
 
594
        cmd = "tkConsoleOutput stderr ";
 
595
    } else {
 
596
        cmd = "tkConsoleOutput stdout ";
 
597
    }
 
598
    
 
599
    result = Tcl_GetCommandInfo(interp, "console", &cmdInfo);
 
600
    if (result == 0) {
 
601
        return;
 
602
    }
 
603
    info = (ConsoleInfo *) cmdInfo.clientData;
 
604
    
 
605
    Tcl_DStringInit(&output);
 
606
    Tcl_DStringAppend(&output, buffer, size);
 
607
 
 
608
    Tcl_DStringInit(&command);
 
609
    Tcl_DStringAppend(&command, cmd, strlen(cmd));
 
610
    Tcl_DStringAppendElement(&command, output.string);
 
611
 
 
612
    consoleInterp = info->consoleInterp;
 
613
    Tcl_Preserve((ClientData) consoleInterp);
 
614
    Tcl_Eval(consoleInterp, command.string);
 
615
    Tcl_Release((ClientData) consoleInterp);
 
616
    
 
617
    Tcl_DStringFree(&command);
 
618
    Tcl_DStringFree(&output);
 
619
}