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

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [generic/] [tkMain.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
 * tkMain.c --
3
 *
4
 *      This file contains a generic main program for Tk-based applications.
5
 *      It can be used as-is for many applications, just by supplying a
6
 *      different appInitProc procedure for each specific application.
7
 *      Or, it can be used as a template for creating new main programs
8
 *      for Tk applications.
9
 *
10
 * Copyright (c) 1990-1994 The Regents of the University of California.
11
 * Copyright (c) 1994-1996 Sun Microsystems, Inc.
12
 *
13
 * See the file "license.terms" for information on usage and redistribution
14
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15
 *
16
 * RCS: @(#) $Id: tkMain.c,v 1.1.1.1 2002-01-16 10:25:52 markom Exp $
17
 */
18
 
19
#include <ctype.h>
20
#include <stdio.h>
21
#include <string.h>
22
#include <tcl.h>
23
#include <tk.h>
24
#ifdef NO_STDLIB_H
25
#   include "../compat/stdlib.h"
26
#else
27
#   include <stdlib.h>
28
#endif
29
 
30
/*
31
 * Declarations for various library procedures and variables (don't want
32
 * to include tkInt.h or tkPort.h here, because people might copy this
33
 * file out of the Tk source directory to make their own modified versions).
34
 * Note: don't declare "exit" here even though a declaration is really
35
 * needed, because it will conflict with a declaration elsewhere on
36
 * some systems.
37
 */
38
 
39
extern int              isatty _ANSI_ARGS_((int fd));
40
#if !defined(__WIN32__) && !defined(_WIN32)
41
extern char *           strrchr _ANSI_ARGS_((CONST char *string, int c));
42
#endif
43
extern void             TkpDisplayWarning _ANSI_ARGS_((char *msg,
44
                            char *title));
45
 
46
/*
47
 * Global variables used by the main program:
48
 */
49
 
50
static Tcl_Interp *interp;      /* Interpreter for this application. */
51
static Tcl_DString command;     /* Used to assemble lines of terminal input
52
                                 * into Tcl commands. */
53
static Tcl_DString line;        /* Used to read the next line from the
54
                                 * terminal input. */
55
static int tty;                 /* Non-zero means standard input is a
56
                                 * terminal-like device.  Zero means it's
57
                                 * a file. */
58
 
59
/*
60
 * Forward declarations for procedures defined later in this file.
61
 */
62
 
63
static void             Prompt _ANSI_ARGS_((Tcl_Interp *interp, int partial));
64
static void             StdinProc _ANSI_ARGS_((ClientData clientData,
65
                            int mask));
66
 
67
/*
68
 *----------------------------------------------------------------------
69
 *
70
 * Tk_Main --
71
 *
72
 *      Main program for Wish and most other Tk-based applications.
73
 *
74
 * Results:
75
 *      None. This procedure never returns (it exits the process when
76
 *      it's done.
77
 *
78
 * Side effects:
79
 *      This procedure initializes the Tk world and then starts
80
 *      interpreting commands;  almost anything could happen, depending
81
 *      on the script being interpreted.
82
 *
83
 *----------------------------------------------------------------------
84
 */
85
 
86
void
87
Tk_Main(argc, argv, appInitProc)
88
    int argc;                           /* Number of arguments. */
89
    char **argv;                        /* Array of argument strings. */
90
    Tcl_AppInitProc *appInitProc;       /* Application-specific initialization
91
                                         * procedure to call after most
92
                                         * initialization but before starting
93
                                         * to execute commands. */
94
{
95
    char *args, *fileName;
96
    char buf[20];
97
    int code;
98
    size_t length;
99
    Tcl_Channel inChannel, outChannel;
100
 
101
    Tcl_FindExecutable(argv[0]);
102
    interp = Tcl_CreateInterp();
103
#ifdef TCL_MEM_DEBUG
104
    Tcl_InitMemory(interp);
105
#endif
106
 
107
    /*
108
     * Parse command-line arguments.  A leading "-file" argument is
109
     * ignored (a historical relic from the distant past).  If the
110
     * next argument doesn't start with a "-" then strip it off and
111
     * use it as the name of a script file to process.
112
     */
113
 
114
    fileName = NULL;
115
    if (argc > 1) {
116
        length = strlen(argv[1]);
117
        if ((length >= 2) && (strncmp(argv[1], "-file", length) == 0)) {
118
            argc--;
119
            argv++;
120
        }
121
    }
122
    if ((argc > 1) && (argv[1][0] != '-')) {
123
        fileName = argv[1];
124
        argc--;
125
        argv++;
126
    }
127
 
128
    /*
129
     * Make command-line arguments available in the Tcl variables "argc"
130
     * and "argv".
131
     */
132
 
133
    args = Tcl_Merge(argc-1, argv+1);
134
    Tcl_SetVar(interp, "argv", args, TCL_GLOBAL_ONLY);
135
    ckfree(args);
136
    sprintf(buf, "%d", argc-1);
137
    Tcl_SetVar(interp, "argc", buf, TCL_GLOBAL_ONLY);
138
    Tcl_SetVar(interp, "argv0", (fileName != NULL) ? fileName : argv[0],
139
            TCL_GLOBAL_ONLY);
140
 
141
    /*
142
     * Set the "tcl_interactive" variable.
143
     */
144
 
145
    /*
146
     * For now, under Windows, we assume we are not running as a console mode
147
     * app, so we need to use the GUI console.  In order to enable this, we
148
     * always claim to be running on a tty.  This probably isn't the right
149
     * way to do it.
150
     */
151
 
152
#ifdef __WIN32__
153
    tty = 1;
154
#else
155
    tty = isatty(0);
156
#endif
157
    Tcl_SetVar(interp, "tcl_interactive",
158
            ((fileName == NULL) && tty) ? "1" : "0", TCL_GLOBAL_ONLY);
159
 
160
    /*
161
     * Invoke application-specific initialization.
162
     */
163
 
164
    if ((*appInitProc)(interp) != TCL_OK) {
165
        TkpDisplayWarning(interp->result, "Application initialization failed");
166
    }
167
 
168
    /*
169
     * Invoke the script specified on the command line, if any.
170
     */
171
 
172
    if (fileName != NULL) {
173
        code = Tcl_EvalFile(interp, fileName);
174
        if (code != TCL_OK) {
175
            /*
176
             * The following statement guarantees that the errorInfo
177
             * variable is set properly.
178
             */
179
 
180
            Tcl_AddErrorInfo(interp, "");
181
            TkpDisplayWarning(Tcl_GetVar(interp, "errorInfo",
182
                    TCL_GLOBAL_ONLY), "Error in startup script");
183
            Tcl_DeleteInterp(interp);
184
            Tcl_Exit(1);
185
        }
186
        tty = 0;
187
    } else {
188
 
189
        /*
190
         * Evaluate the .rc file, if one has been specified.
191
         */
192
 
193
        Tcl_SourceRCFile(interp);
194
 
195
        /*
196
         * Establish a channel handler for stdin.
197
         */
198
 
199
        inChannel = Tcl_GetStdChannel(TCL_STDIN);
200
        if (inChannel) {
201
            Tcl_CreateChannelHandler(inChannel, TCL_READABLE, StdinProc,
202
                    (ClientData) inChannel);
203
        }
204
        if (tty) {
205
            Prompt(interp, 0);
206
        }
207
    }
208
 
209
    outChannel = Tcl_GetStdChannel(TCL_STDOUT);
210
    if (outChannel) {
211
        Tcl_Flush(outChannel);
212
    }
213
    Tcl_DStringInit(&command);
214
    Tcl_DStringInit(&line);
215
    Tcl_ResetResult(interp);
216
 
217
    /*
218
     * Loop infinitely, waiting for commands to execute.  When there
219
     * are no windows left, Tk_MainLoop returns and we exit.
220
     */
221
 
222
    Tk_MainLoop();
223
    Tcl_DeleteInterp(interp);
224
    Tcl_Exit(0);
225
}
226
 
227
/*
228
 *----------------------------------------------------------------------
229
 *
230
 * StdinProc --
231
 *
232
 *      This procedure is invoked by the event dispatcher whenever
233
 *      standard input becomes readable.  It grabs the next line of
234
 *      input characters, adds them to a command being assembled, and
235
 *      executes the command if it's complete.
236
 *
237
 * Results:
238
 *      None.
239
 *
240
 * Side effects:
241
 *      Could be almost arbitrary, depending on the command that's
242
 *      typed.
243
 *
244
 *----------------------------------------------------------------------
245
 */
246
 
247
    /* ARGSUSED */
248
static void
249
StdinProc(clientData, mask)
250
    ClientData clientData;              /* Not used. */
251
    int mask;                           /* Not used. */
252
{
253
    static int gotPartial = 0;
254
    char *cmd;
255
    int code, count;
256
    Tcl_Channel chan = (Tcl_Channel) clientData;
257
 
258
    count = Tcl_Gets(chan, &line);
259
 
260
    if (count < 0) {
261
        if (!gotPartial) {
262
            if (tty) {
263
                Tcl_Exit(0);
264
            } else {
265
                Tcl_DeleteChannelHandler(chan, StdinProc, (ClientData) chan);
266
            }
267
            return;
268
        }
269
    }
270
 
271
    (void) Tcl_DStringAppend(&command, Tcl_DStringValue(&line), -1);
272
    cmd = Tcl_DStringAppend(&command, "\n", -1);
273
    Tcl_DStringFree(&line);
274
    if (!Tcl_CommandComplete(cmd)) {
275
        gotPartial = 1;
276
        goto prompt;
277
    }
278
    gotPartial = 0;
279
 
280
    /*
281
     * Disable the stdin channel handler while evaluating the command;
282
     * otherwise if the command re-enters the event loop we might
283
     * process commands from stdin before the current command is
284
     * finished.  Among other things, this will trash the text of the
285
     * command being evaluated.
286
     */
287
 
288
    Tcl_CreateChannelHandler(chan, 0, StdinProc, (ClientData) chan);
289
    code = Tcl_RecordAndEval(interp, cmd, TCL_EVAL_GLOBAL);
290
 
291
    chan = Tcl_GetStdChannel(TCL_STDIN);
292
    if (chan) {
293
        Tcl_CreateChannelHandler(chan, TCL_READABLE, StdinProc,
294
                (ClientData) chan);
295
    }
296
    Tcl_DStringFree(&command);
297
    if (*interp->result != 0) {
298
        if ((code != TCL_OK) || (tty)) {
299
            /*
300
             * The statement below used to call "printf", but that resulted
301
             * in core dumps under Solaris 2.3 if the result was very long.
302
             *
303
             * NOTE: This probably will not work under Windows either.
304
             */
305
 
306
            puts(interp->result);
307
        }
308
    }
309
 
310
    /*
311
     * Output a prompt.
312
     */
313
 
314
    prompt:
315
    if (tty) {
316
        Prompt(interp, gotPartial);
317
    }
318
    Tcl_ResetResult(interp);
319
}
320
 
321
/*
322
 *----------------------------------------------------------------------
323
 *
324
 * Prompt --
325
 *
326
 *      Issue a prompt on standard output, or invoke a script
327
 *      to issue the prompt.
328
 *
329
 * Results:
330
 *      None.
331
 *
332
 * Side effects:
333
 *      A prompt gets output, and a Tcl script may be evaluated
334
 *      in interp.
335
 *
336
 *----------------------------------------------------------------------
337
 */
338
 
339
static void
340
Prompt(interp, partial)
341
    Tcl_Interp *interp;                 /* Interpreter to use for prompting. */
342
    int partial;                        /* Non-zero means there already
343
                                         * exists a partial command, so use
344
                                         * the secondary prompt. */
345
{
346
    char *promptCmd;
347
    int code;
348
    Tcl_Channel outChannel, errChannel;
349
 
350
    promptCmd = Tcl_GetVar(interp,
351
        partial ? "tcl_prompt2" : "tcl_prompt1", TCL_GLOBAL_ONLY);
352
    if (promptCmd == NULL) {
353
defaultPrompt:
354
        if (!partial) {
355
 
356
            /*
357
             * We must check that outChannel is a real channel - it
358
             * is possible that someone has transferred stdout out of
359
             * this interpreter with "interp transfer".
360
             */
361
 
362
            outChannel = Tcl_GetChannel(interp, "stdout", NULL);
363
            if (outChannel != (Tcl_Channel) NULL) {
364
                Tcl_Write(outChannel, "% ", 2);
365
            }
366
        }
367
    } else {
368
        code = Tcl_Eval(interp, promptCmd);
369
        if (code != TCL_OK) {
370
            Tcl_AddErrorInfo(interp,
371
                    "\n    (script that generates prompt)");
372
            /*
373
             * We must check that errChannel is a real channel - it
374
             * is possible that someone has transferred stderr out of
375
             * this interpreter with "interp transfer".
376
             */
377
 
378
            errChannel = Tcl_GetChannel(interp, "stderr", NULL);
379
            if (errChannel != (Tcl_Channel) NULL) {
380
                Tcl_Write(errChannel, interp->result, -1);
381
                Tcl_Write(errChannel, "\n", 1);
382
            }
383
            goto defaultPrompt;
384
        }
385
    }
386
    outChannel = Tcl_GetChannel(interp, "stdout", NULL);
387
    if (outChannel != (Tcl_Channel) NULL) {
388
        Tcl_Flush(outChannel);
389
    }
390
}

powered by: WebSVN 2.1.0

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