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

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [generic/] [tkConsole.c] - Blame information for rev 1780

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
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.1.1.1 2002-01-16 10:25:51 markom 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(info->consoleInterp, "wm withdraw .");
403
    } else if ((c == 's') && (strncmp(argv[1], "show", length)) == 0) {
404
        Tcl_Eval(info->consoleInterp, "wm deiconify .");
405
    } else if ((c == 'e') && (strncmp(argv[1], "eval", length)) == 0) {
406
        if (argc == 3) {
407
            Tcl_Eval(info->consoleInterp, argv[2]);
408
        } else {
409
            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
410
                    " eval command\"", (char *) NULL);
411
            return TCL_ERROR;
412
        }
413
    } else {
414
        Tcl_AppendResult(interp, "bad option \"", argv[1],
415
                "\": should be hide, show, or title",
416
                (char *) NULL);
417
        result = TCL_ERROR;
418
    }
419
    Tcl_Release((ClientData) consoleInterp);
420
    return result;
421
}
422
 
423
/*
424
 *----------------------------------------------------------------------
425
 *
426
 * InterpreterCmd --
427
 *
428
 *      This command allows the console interp to communicate with the
429
 *      main interpreter.
430
 *
431
 * Results:
432
 *      None.
433
 *
434
 * Side effects:
435
 *      None.
436
 *
437
 *----------------------------------------------------------------------
438
 */
439
 
440
static int
441
InterpreterCmd(clientData, interp, argc, argv)
442
    ClientData clientData;              /* Not used. */
443
    Tcl_Interp *interp;                 /* Current interpreter. */
444
    int argc;                           /* Number of arguments. */
445
    char **argv;                        /* Argument strings. */
446
{
447
    ConsoleInfo *info = (ConsoleInfo *) clientData;
448
    char c;
449
    int length;
450
    int result;
451
    Tcl_Interp *otherInterp;
452
 
453
    if (argc < 2) {
454
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
455
                " option ?arg arg ...?\"", (char *) NULL);
456
        return TCL_ERROR;
457
    }
458
 
459
    c = argv[1][0];
460
    length = strlen(argv[1]);
461
    otherInterp = info->interp;
462
    Tcl_Preserve((ClientData) otherInterp);
463
    if ((c == 'e') && (strncmp(argv[1], "eval", length)) == 0) {
464
        result = Tcl_GlobalEval(otherInterp, argv[2]);
465
        Tcl_AppendResult(interp, otherInterp->result, (char *) NULL);
466
    } else if ((c == 'r') && (strncmp(argv[1], "record", length)) == 0) {
467
        Tcl_RecordAndEval(otherInterp, argv[2], TCL_EVAL_GLOBAL);
468
        result = TCL_OK;
469
        Tcl_AppendResult(interp, otherInterp->result, (char *) NULL);
470
    } else {
471
        Tcl_AppendResult(interp, "bad option \"", argv[1],
472
                "\": should be eval or record",
473
                (char *) NULL);
474
        result = TCL_ERROR;
475
    }
476
    Tcl_Release((ClientData) otherInterp);
477
    return result;
478
}
479
 
480
/*
481
 *----------------------------------------------------------------------
482
 *
483
 * ConsoleDeleteProc --
484
 *
485
 *      If the console command is deleted we destroy the console window
486
 *      and all associated data structures.
487
 *
488
 * Results:
489
 *      None.
490
 *
491
 * Side effects:
492
 *      A new console it created.
493
 *
494
 *----------------------------------------------------------------------
495
 */
496
 
497
void
498
ConsoleDeleteProc(clientData)
499
    ClientData clientData;
500
{
501
    ConsoleInfo *info = (ConsoleInfo *) clientData;
502
 
503
    Tcl_DeleteInterp(info->consoleInterp);
504
    info->consoleInterp = NULL;
505
}
506
 
507
/*
508
 *----------------------------------------------------------------------
509
 *
510
 * ConsoleEventProc --
511
 *
512
 *      This event procedure is registered on the main window of the
513
 *      slave interpreter.  If the user or a running script causes the
514
 *      main window to be destroyed, then we need to inform the console
515
 *      interpreter by invoking "tkConsoleExit".
516
 *
517
 * Results:
518
 *      None.
519
 *
520
 * Side effects:
521
 *      Invokes the "tkConsoleExit" procedure in the console interp.
522
 *
523
 *----------------------------------------------------------------------
524
 */
525
 
526
static void
527
ConsoleEventProc(clientData, eventPtr)
528
    ClientData clientData;
529
    XEvent *eventPtr;
530
{
531
    ConsoleInfo *info = (ConsoleInfo *) clientData;
532
    Tcl_Interp *consoleInterp;
533
 
534
    if (eventPtr->type == DestroyNotify) {
535
        consoleInterp = info->consoleInterp;
536
 
537
        /*
538
         * It is possible that the console interpreter itself has
539
         * already been deleted. In that case the consoleInterp
540
         * field will be set to NULL. If the interpreter is already
541
         * gone, we do not have to do any work here.
542
         */
543
 
544
        if (consoleInterp == (Tcl_Interp *) NULL) {
545
            return;
546
        }
547
        Tcl_Preserve((ClientData) consoleInterp);
548
        Tcl_Eval(consoleInterp, "tkConsoleExit");
549
        Tcl_Release((ClientData) consoleInterp);
550
    }
551
}
552
 
553
/*
554
 *----------------------------------------------------------------------
555
 *
556
 * TkConsolePrint --
557
 *
558
 *      Prints to the give text to the console.  Given the main interp
559
 *      this functions find the appropiate console interp and forwards
560
 *      the text to be added to that console.
561
 *
562
 * Results:
563
 *      None.
564
 *
565
 * Side effects:
566
 *      None.
567
 *
568
 *----------------------------------------------------------------------
569
 */
570
 
571
void
572
TkConsolePrint(interp, devId, buffer, size)
573
    Tcl_Interp *interp;         /* Main interpreter. */
574
    int devId;                  /* TCL_STDOUT for stdout, TCL_STDERR for
575
                                 * stderr. */
576
    char *buffer;               /* Text buffer. */
577
    long size;                  /* Size of text buffer. */
578
{
579
    Tcl_DString command, output;
580
    Tcl_CmdInfo cmdInfo;
581
    char *cmd;
582
    ConsoleInfo *info;
583
    Tcl_Interp *consoleInterp;
584
    int result;
585
 
586
    if (interp == NULL) {
587
        return;
588
    }
589
 
590
    if (devId == TCL_STDERR) {
591
        cmd = "tkConsoleOutput stderr ";
592
    } else {
593
        cmd = "tkConsoleOutput stdout ";
594
    }
595
 
596
    result = Tcl_GetCommandInfo(interp, "console", &cmdInfo);
597
    if (result == 0) {
598
        return;
599
    }
600
    info = (ConsoleInfo *) cmdInfo.clientData;
601
 
602
    Tcl_DStringInit(&output);
603
    Tcl_DStringAppend(&output, buffer, size);
604
 
605
    Tcl_DStringInit(&command);
606
    Tcl_DStringAppend(&command, cmd, strlen(cmd));
607
    Tcl_DStringAppendElement(&command, output.string);
608
 
609
    consoleInterp = info->consoleInterp;
610
    Tcl_Preserve((ClientData) consoleInterp);
611
    Tcl_Eval(consoleInterp, command.string);
612
    Tcl_Release((ClientData) consoleInterp);
613
 
614
    Tcl_DStringFree(&command);
615
    Tcl_DStringFree(&output);
616
}

powered by: WebSVN 2.1.0

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