~ubuntu-branches/ubuntu/quantal/gclcvs/quantal

« back to all changes in this revision

Viewing changes to gcl-tk/tkXshell.c

  • Committer: Bazaar Package Importer
  • Author(s): Camm Maguire
  • Date: 2004-06-24 15:13:46 UTC
  • Revision ID: james.westby@ubuntu.com-20040624151346-xh0xaaktyyp7aorc
Tags: 2.7.0-26
C_GC_OFFSET is 2 on m68k-linux

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * tkXshell.c
 
3
 *
 
4
 * Version of Tk main that is modified to build a wish shell with the Extended
 
5
 * Tcl command set and libraries.  This makes it easier to use a different
 
6
 * main.
 
7
 *-----------------------------------------------------------------------------
 
8
 * Copyright 1991-1993 Karl Lehenbauer and Mark Diekhans.
 
9
 *
 
10
 * Permission to use, copy, modify, and distribute this software and its
 
11
 * documentation for any purpose and without fee is hereby granted, provided
 
12
 * that the above copyright notice appear in all copies.  Karl Lehenbauer and
 
13
 * Mark Diekhans make no representations about the suitability of this
 
14
 * software for any purpose.  It is provided "as is" without express or
 
15
 * implied warranty.
 
16
 *-----------------------------------------------------------------------------
 
17
 * $Id: tkXshell.c,v 3.1 1993/11/19 08:21:29 markd Exp $
 
18
 *-----------------------------------------------------------------------------
 
19
 */
 
20
 
 
21
/* 
 
22
 * main.c --
 
23
 *
 
24
 *      This file contains the main program for "wish", a windowing
 
25
 *      shell based on Tk and Tcl.  It also provides a template that
 
26
 *      can be used as the basis for main programs for other Tk
 
27
 *      applications.
 
28
 *
 
29
 * Copyright (c) 1990-1993 The Regents of the University of California.
 
30
 * All rights reserved.
 
31
 *
 
32
 * Permission is hereby granted, without written agreement and without
 
33
 * license or royalty fees, to use, copy, modify, and distribute this
 
34
 * software and its documentation for any purpose, provided that the
 
35
 * above copyright notice and the following two paragraphs appear in
 
36
 * all copies of this software.
 
37
 * 
 
38
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 
39
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 
40
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 
41
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
42
 *
 
43
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 
44
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 
45
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 
46
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 
47
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 
48
 */
 
49
 
 
50
#ifdef __cplusplus
 
51
#    include "tcl++.h"
 
52
#    include <unistd.h>
 
53
#else
 
54
#    include "tclExtend.h"
 
55
#endif
 
56
 
 
57
#include "tk.h"
 
58
 
 
59
/*-------------------------------------------------------------------*/
 
60
#include <unistd.h>
 
61
#include <sys/types.h>
 
62
#include <signal.h>
 
63
 
 
64
int sock_write( int connection, const char *text, int length );
 
65
int sock_read( int connection, char *buffer, int max_len );
 
66
 
 
67
extern int hdl;
 
68
extern pid_t parent;
 
69
/*-------------------------------------------------------------------*/
 
70
 
 
71
/*
 
72
 * Declarations for various library procedures and variables (don't want
 
73
 * to include tkInt.h or tkConfig.h here, because people might copy this
 
74
 * file out of the Tk source directory to make their own modified versions).
 
75
 */
 
76
 
 
77
extern void             exit _ANSI_ARGS_((int status));
 
78
extern int              isatty _ANSI_ARGS_((int fd));
 
79
/*
 
80
extern int              read _ANSI_ARGS_((int fd, char *buf, size_t size));
 
81
*/
 
82
extern char *           strrchr _ANSI_ARGS_((CONST char *string, int c));
 
83
 
 
84
/*
 
85
 * Global variables used by the main program:
 
86
 */
 
87
 
 
88
static Tk_Window mainWindow;    /* The main window for the application.  If
 
89
                                 * NULL then the application no longer
 
90
                                 * exists. */
 
91
static Tcl_Interp *interp;      /* Interpreter for this application. */
 
92
char *tcl_RcFileName ;          /* Name of a user-specific startup script
 
93
                                 * to source if the application is being run
 
94
                                 * interactively (e.g. "~/.wishrc").  Set
 
95
                                 * by Tcl_AppInit.  NULL means don't source
 
96
                                 * anything ever. */
 
97
static Tcl_DString command;     /* Used to assemble lines of terminal input
 
98
                                 * into Tcl commands. */
 
99
static int gotPartial = 0;      /* Partial command in buffer. */
 
100
static int tty;                 /* Non-zero means standard input is a
 
101
                                 * terminal-like device.  Zero means it's
 
102
                                 * a file. */
 
103
static char exitCmd[] = "exit";
 
104
static char errorExitCmd[] = "exit 1";
 
105
 
 
106
/*
 
107
 * Command-line options:
 
108
 */
 
109
 
 
110
static int synchronize = 0;
 
111
static char *fileName = NULL;
 
112
static char *name = NULL;
 
113
static char *display = NULL;
 
114
static char *geometry = NULL;
 
115
 
 
116
static Tk_ArgvInfo argTable[] = {
 
117
    {"-file", TK_ARGV_STRING, (char *) NULL, (char *) &fileName,
 
118
        "File from which to read commands"},
 
119
    {"-geometry", TK_ARGV_STRING, (char *) NULL, (char *) &geometry,
 
120
        "Initial geometry for window"},
 
121
    {"-display", TK_ARGV_STRING, (char *) NULL, (char *) &display,
 
122
        "Display to use"},
 
123
    {"-name", TK_ARGV_STRING, (char *) NULL, (char *) &name,
 
124
        "Name to use for application"},
 
125
    {"-sync", TK_ARGV_CONSTANT, (char *) 1, (char *) &synchronize,
 
126
        "Use synchronous mode for display server"},
 
127
    {(char *) NULL, TK_ARGV_END, (char *) NULL, (char *) NULL,
 
128
        (char *) NULL}
 
129
};
 
130
 
 
131
/*
 
132
 * Forward declarations for procedures defined later in this file:
 
133
 */
 
134
 
 
135
static void             StdinProc _ANSI_ARGS_((ClientData clientData,
 
136
                            int mask));
 
137
static void             SignalProc _ANSI_ARGS_((int signalNum));
 
138
 
 
139
/*
 
140
 *----------------------------------------------------------------------
 
141
 *
 
142
 * TkX_Wish --
 
143
 *
 
144
 *      Main program for Wish.
 
145
 *
 
146
 * Results:
 
147
 *      None. This procedure never returns (it exits the process when
 
148
 *      it's done
 
149
 *
 
150
 * Side effects:
 
151
 *      This procedure initializes the wish world and then starts
 
152
 *      interpreting commands;  almost anything could happen, depending
 
153
 *      on the script being interpreted.
 
154
 *
 
155
 *----------------------------------------------------------------------
 
156
 */
 
157
 
 
158
void
 
159
TkX_Wish (argc, argv)
 
160
    int argc;                           /* Number of arguments. */
 
161
    char **argv;                        /* Array of argument strings. */
 
162
{
 
163
    char *args, *p, *msg;
 
164
    char buf[20];
 
165
    int code;
 
166
 
 
167
    interp = Tcl_CreateInterp();
 
168
#ifdef TCL_MEM_DEBUG
 
169
    Tcl_InitMemory(interp);
 
170
#endif
 
171
 
 
172
    /*
 
173
     * Parse command-line arguments.
 
174
     */
 
175
 
 
176
    if (Tk_ParseArgv(interp, (Tk_Window) NULL, &argc, argv, argTable, 0)
 
177
            != TCL_OK) {
 
178
        fprintf(stderr, "%s\n", interp->result);
 
179
        exit(1);
 
180
    }
 
181
    if (name == NULL) {
 
182
        if (fileName != NULL) {
 
183
            p = fileName;
 
184
        } else {
 
185
            p = argv[0];
 
186
        }
 
187
        name = strrchr(p, '/');
 
188
        if (name != NULL) {
 
189
            name++;
 
190
        } else {
 
191
            name = p;
 
192
        }
 
193
    }
 
194
 
 
195
    /*
 
196
     * If a display was specified, put it into the DISPLAY
 
197
     * environment variable so that it will be available for
 
198
     * any sub-processes created by us.
 
199
     */
 
200
 
 
201
    if (display != NULL) {
 
202
        Tcl_SetVar2(interp, "env", "DISPLAY", display, TCL_GLOBAL_ONLY);
 
203
    }
 
204
 
 
205
    /*
 
206
     * Set the "tcl_interactive" variable.
 
207
     */
 
208
    tty = isatty(hdl);
 
209
    Tcl_SetVar(interp, "tcl_interactive",
 
210
            ((fileName == NULL) && tty) ? "1" : "0", TCL_GLOBAL_ONLY);
 
211
 
 
212
    tty = isatty(hdl);
 
213
 
 
214
    /*
 
215
     * Initialize the Tk application.
 
216
     */
 
217
 
 
218
    mainWindow = Tk_CreateMainWindow(interp, display, name, "Tk");
 
219
    if (mainWindow == NULL) {
 
220
        fprintf(stderr, "%s\n", interp->result);
 
221
        exit(1);
 
222
    }
 
223
    Tk_SetClass(mainWindow, "Tk");
 
224
    if (synchronize) {
 
225
        XSynchronize(Tk_Display(mainWindow), True);
 
226
    }
 
227
    Tk_GeometryRequest(mainWindow, 200, 200);
 
228
 
 
229
    /*
 
230
     * Make command-line arguments available in the Tcl variables "argc"
 
231
     * and "argv".  Also set the "geometry" variable from the geometry
 
232
     * specified on the command line.
 
233
     */
 
234
 
 
235
    args = Tcl_Merge(argc-1, argv+1);
 
236
    Tcl_SetVar(interp, "argv", args, TCL_GLOBAL_ONLY);
 
237
    ckfree(args);
 
238
    sprintf(buf, "%d", argc-1);
 
239
    Tcl_SetVar(interp, "argc", buf, TCL_GLOBAL_ONLY);
 
240
    Tcl_SetVar(interp, "argv0", (fileName != NULL) ? fileName : argv[0],
 
241
            TCL_GLOBAL_ONLY);
 
242
    if (geometry != NULL) {
 
243
        Tcl_SetVar(interp, "geometry", geometry, TCL_GLOBAL_ONLY);
 
244
    }
 
245
 
 
246
    /*
 
247
     * Invoke application-specific initialization.
 
248
     */
 
249
 
 
250
    if (Tcl_AppInit(interp) != TCL_OK) {
 
251
        TclX_ErrorExit (interp, 255);
 
252
    }
 
253
 
 
254
    /*
 
255
     * Set the geometry of the main window, if requested.
 
256
     */
 
257
 
 
258
    if (geometry != NULL) {
 
259
        code = Tcl_VarEval(interp, "wm geometry . ", geometry, (char *) NULL);
 
260
        if (code != TCL_OK) {
 
261
            fprintf(stderr, "%s\n", interp->result);
 
262
        }
 
263
    }
 
264
 
 
265
    /*
 
266
     * Invoke the script specified on the command line, if any.
 
267
     */
 
268
 
 
269
    if (fileName != NULL) {
 
270
        code = Tcl_VarEval(interp, "source ", fileName, (char *) NULL);
 
271
        if (code != TCL_OK) {
 
272
            goto error;
 
273
        }
 
274
        tty = 0;
 
275
    } else {
 
276
        TclX_EvalRCFile (interp);
 
277
 
 
278
        /*
 
279
         * Commands will come from standard input.  Set up a handler
 
280
         * to receive those characters and print a prompt if the input
 
281
         * device is a terminal.
 
282
         */
 
283
        tclErrorSignalProc = SignalProc;
 
284
        Tk_CreateFileHandler(hdl, TK_READABLE, StdinProc, (ClientData) 0);
 
285
        if (tty) {
 
286
            TclX_OutputPrompt (interp, 1);
 
287
        }
 
288
    }
 
289
    tclSignalBackgroundError = Tk_BackgroundError;
 
290
 
 
291
    fflush(stdout);
 
292
    Tcl_DStringInit(&command);
 
293
 
 
294
    /*
 
295
     * Loop infinitely, waiting for commands to execute.  When there
 
296
     * are no windows left, Tk_MainLoop returns and we exit.
 
297
     */
 
298
 
 
299
    Tk_MainLoop();
 
300
 
 
301
    /*
 
302
     * Don't exit directly, but rather invoke the Tcl "exit" command.
 
303
     * This gives the application the opportunity to redefine "exit"
 
304
     * to do additional cleanup.
 
305
     */
 
306
 
 
307
    Tcl_GlobalEval(interp, exitCmd);
 
308
    exit(1);
 
309
 
 
310
error:
 
311
    msg = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
 
312
    if (msg == NULL) {
 
313
        msg = interp->result;
 
314
    }
 
315
    fprintf(stderr, "%s\n", msg);
 
316
    Tcl_GlobalEval(interp, errorExitCmd);
 
317
    exit (1);
 
318
}
 
319
 
 
320
/*
 
321
 *----------------------------------------------------------------------
 
322
 *
 
323
 * SignalProc --
 
324
 *
 
325
 *      Function called on a signal generating an error to clear the stdin
 
326
 *      buffer.
 
327
 *----------------------------------------------------------------------
 
328
 */
 
329
 
 
330
static void
 
331
SignalProc (signalNum)
 
332
    int  signalNum;
 
333
{
 
334
    tclGotErrorSignal = 0;
 
335
    Tcl_DStringFree (&command);
 
336
    gotPartial = 0;
 
337
    if (tty) {
 
338
        fputc ('\n', stdout);
 
339
        TclX_OutputPrompt (interp, !gotPartial);
 
340
    }
 
341
}
 
342
 
 
343
/*
 
344
 *----------------------------------------------------------------------
 
345
 *
 
346
 * StdinProc --
 
347
 *
 
348
 *      This procedure is invoked by the event dispatcher whenever
 
349
 *      standard input becomes readable.  It grabs the next line of
 
350
 *      input characters, adds them to a command being assembled, and
 
351
 *      executes the command if it's complete.
 
352
 *
 
353
 * Results:
 
354
 *      None.
 
355
 *
 
356
 * Side effects:
 
357
 *      Could be almost arbitrary, depending on the command that's
 
358
 *      typed.
 
359
 *
 
360
 *----------------------------------------------------------------------
 
361
 */
 
362
 
 
363
#define BUFFER_SIZE 4000
 
364
 
 
365
static void
 
366
StdinProc(clientData, mask)
 
367
    ClientData clientData;              /* Not used. */
 
368
    int mask;                           /* Not used. */
 
369
{
 
370
  char input[BUFFER_SIZE+1];
 
371
  char *cmd;
 
372
  int code, count;
 
373
  
 
374
  count = read(hdl, input, BUFFER_SIZE);
 
375
  if (count <= 0)
 
376
    {
 
377
      if (!gotPartial)
 
378
        {
 
379
          if (tty)
 
380
            {
 
381
              Tcl_VarEval(interp, "exit", (char *) NULL);
 
382
              exit(1);
 
383
            }
 
384
          else 
 
385
            {
 
386
              Tk_DeleteFileHandler(hdl);
 
387
            }
 
388
          return;
 
389
        }
 
390
      else
 
391
        {
 
392
          count = 0;
 
393
        }
 
394
    }
 
395
  cmd = Tcl_DStringAppend(&command, input, count);
 
396
 
 
397
  fprintf(stderr, "TK command : %s\n", cmd);
 
398
  fflush(stderr);
 
399
 
 
400
  if (count != 0)
 
401
    {
 
402
      if ((input[count-1] != '\n') && (input[count-1] != ';'))
 
403
        {
 
404
          gotPartial = 1;
 
405
          goto exitPoint;
 
406
        }
 
407
      if (!Tcl_CommandComplete(cmd))
 
408
        {
 
409
          fprintf(stderr, "Partial command\n", cmd);
 
410
          fflush(stderr);
 
411
          
 
412
          gotPartial = 1;
 
413
          goto exitPoint;
 
414
        }
 
415
    }
 
416
  gotPartial = 0;
 
417
 
 
418
/*
 
419
* Disable the stdin file handler;  otherwise if the command
 
420
* re-enters the event loop we might process commands from
 
421
* stdin before the current command is finished.  Among other
 
422
* things, this will trash the text of the command being evaluated.
 
423
*/
 
424
 
 
425
  Tk_CreateFileHandler(hdl, 0, StdinProc, (ClientData) 0);
 
426
  code = Tcl_RecordAndEval(interp, cmd, 0);
 
427
  Tk_CreateFileHandler(hdl, TK_READABLE, StdinProc, (ClientData) 0);
 
428
  if (tty)
 
429
    TclX_PrintResult (interp, code, cmd);
 
430
  else
 
431
    {
 
432
      char buf[1024];
 
433
      sprintf(buf, "%d %s", code, interp->result);
 
434
      sock_write(hdl, buf, strlen(buf));
 
435
      kill(parent, SIGUSR1);
 
436
    }
 
437
  Tcl_DStringFree(&command);
 
438
  
 
439
 exitPoint:
 
440
  if (tty)
 
441
    {
 
442
      TclX_OutputPrompt (interp, !gotPartial);
 
443
    }
 
444
}
 
445