PLplot 5.15.0
Loading...
Searching...
No Matches
tkMain.c
Go to the documentation of this file.
1// Modified version of tkMain.c, from Tk 3.6.
2// Maurice LeBrun
3// 23-Jun-1994
4//
5// Copyright (C) 2004 Joao Cardoso
6//
7// This file is part of PLplot.
8//
9// PLplot is free software; you can redistribute it and/or modify
10// it under the terms of the GNU Library General Public License as published
11// by the Free Software Foundation; either version 2 of the License, or
12// (at your option) any later version.
13//
14// PLplot is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17// GNU Library General Public License for more details.
18//
19// You should have received a copy of the GNU Library General Public License
20// along with PLplot; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23//
24// Modifications include:
25// 1. main() changed to pltkMain().
26// 2. tcl_RcFileName -> RcFileName, now passed in through the argument list.
27// 3. Tcl_AppInit -> AppInit, now passed in through the argument list.
28// 4. Support for -e <script> startup option
29//
30// The original notes follow.
31//
32
33//
34// main.c --
35//
36// This file contains the main program for "wish", a windowing
37// shell based on Tk and Tcl. It also provides a template that
38// can be used as the basis for main programs for other Tk
39// applications.
40//
41// Copyright (c) 1990-1993 The Regents of the University of California.
42// All rights reserved.
43//
44// Permission is hereby granted, without written agreement and without
45// license or royalty fees, to use, copy, modify, and distribute this
46// software and its documentation for any purpose, provided that the
47// above copyright notice and the following two paragraphs appear in
48// all copies of this software.
49//
50// IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
51// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
52// OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
53// CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54//
55// THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
56// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
57// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
58// ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
59// PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
60//
61
62#include "plplotP.h"
63#include "pltkd.h"
64#include <stdio.h>
65#include <stdlib.h>
66#include <tcl.h>
67#include <tk.h>
68#ifdef HAVE_ITCL
69# ifndef HAVE_ITCLDECLS_H
70# define RESOURCE_INCLUDED
71# endif
72# include <itcl.h>
73#endif
74
75// itk.h includes itclInt.h which includes tclInt.h ...disaster -mjl
76// #ifdef HAVE_ITK
77// #include <itk.h>
78// #endif
79
80// From itkDecls.h
81
82EXTERN int Itk_Init ( Tcl_Interp * interp );
83
84// From tclIntDecls.h
85
86//#ifndef Tcl_Import_TCL_DECLARED
87#if 0
88EXTERN int Tcl_Import ( Tcl_Interp * interp,
89 Tcl_Namespace * nsPtr, char * pattern,
90 int allowOverwrite );
91#endif
92
93#ifndef Tcl_GetGlobalNamespace_TCL_DECLARE
94EXTERN Tcl_Namespace * Tcl_GetGlobalNamespace ( Tcl_Interp * interp );
95#endif
96
97//
98// Declarations for various library procedures and variables (don't want
99// to include tkInt.h or tkConfig.h here, because people might copy this
100// file out of the Tk source directory to make their own modified versions).
101//
102
103// these are defined in unistd.h, included by plplotP.h
104// extern void exit (int status);
105// extern int isatty (int fd);
106// extern int read (int fd, char *buf, size_t size);
107//
108#if defined ( _WIN32 )
109// On Windows we do not have a convenient console to work with
110#define isatty( a ) 0
111#endif
112
113//
114// Global variables used by the main program:
115//
116
117static Tcl_Interp *interp; // Interpreter for this application.
118static Tcl_DString command; // Used to assemble lines of terminal input
119 // into Tcl commands.
120static int tty; // Non-zero means standard input is a
121 // terminal-like device. Zero means it's
122 // a file.
123static char errorExitCmd[] = "exit 1";
124
125//
126// Command-line options:
127//
128
129static int synchronize = 0;
130static const char *script = NULL;
131static const char *fileName = NULL;
132static const char *name = NULL;
133static const char *display = NULL;
134static const char *geometry = NULL;
135
136static Tk_ArgvInfo argTable[] = {
137 { "-file", TK_ARGV_STRING, (char *) NULL, (char *) &fileName,
138 "File from which to read commands" },
139 { "-e", TK_ARGV_STRING, (char *) NULL, (char *) &script,
140 "Script to execute on startup" },
141 { "-geometry", TK_ARGV_STRING, (char *) NULL, (char *) &geometry,
142 "Initial geometry for window" },
143 { "-display", TK_ARGV_STRING, (char *) NULL, (char *) &display,
144 "Display to use" },
145 { "-name", TK_ARGV_STRING, (char *) NULL, (char *) &name,
146 "Name to use for application" },
147 { "-sync", TK_ARGV_CONSTANT, (char *) 1, (char *) &synchronize,
148 "Use synchronous mode for display server" },
149 { (char *) NULL, TK_ARGV_END, (char *) NULL, (char *) NULL,
150 (char *) NULL }
151};
152
153//
154// Forward declarations for procedures defined later in this file:
155//
156
157static void Prompt ( Tcl_Interp * interploc, int partial );
158static void StdinProc ( ClientData clientData, int mask );
159
160//
161//--------------------------------------------------------------------------
162//
163// main --
164//
165// Main program for Wish.
166//
167// Results:
168// None. This procedure never returns (it exits the process when
169// it's done
170//
171// Side effects:
172// This procedure initializes the wish world and then starts
173// interpreting commands; almost anything could happen, depending
174// on the script being interpreted.
175//
176//--------------------------------------------------------------------------
177//
178
179int
180pltkMain( int argc, const char **argv, char *RcFileName,
181 int ( *AppInit )( Tcl_Interp *interp ) )
182{
183 char *args;
184 const char *msg, *p;
185 char buf[20];
186 int code;
187
188#ifdef PL_HAVE_PTHREAD
189 XInitThreads();
190#endif
191
192 Tcl_FindExecutable( argv[0] );
193 interp = Tcl_CreateInterp();
194#ifdef TCL_MEM_DEBUG
195 Tcl_InitMemory( interp );
196#endif
197
198 //
199 // Parse command-line arguments.
200 //
201 //fprintf( stderr, "Before Tk_ParseArgv\n" );
202
203 if ( Tk_ParseArgv( interp, (Tk_Window) NULL, &argc, argv, argTable, 0 )
204 != TCL_OK )
205 {
206 fprintf( stderr, "%s\n", Tcl_GetStringResult( interp ) );
207 exit( 1 );
208 }
209 //fprintf( stderr, "After Tk_ParseArgv\n" );
210 if ( name == NULL )
211 {
212 if ( fileName != NULL )
213 {
214 p = fileName;
215 }
216 else
217 {
218 p = argv[0];
219 }
220 name = strrchr( p, '/' );
221 if ( name != NULL )
222 {
223 name++;
224 }
225 else
226 {
227 name = p;
228 }
229 }
230
231 //
232 // If a display was specified, put it into the DISPLAY
233 // environment variable so that it will be available for
234 // any sub-processes created by us.
235 //
236
237 if ( display != NULL )
238 {
239 Tcl_SetVar2( interp, "env", "DISPLAY", display, TCL_GLOBAL_ONLY );
240 }
241
242 //
243 // Initialize the Tk application.
244 //
245
246 //
247 // This must be setup *before* calling Tk_Init,
248 // and `name' has already been setup above
249 //
250
251 Tcl_SetVar( interp, "argv0", name, TCL_GLOBAL_ONLY );
252
253 if ( Tcl_Init( interp ) == TCL_ERROR )
254 {
255 fprintf( stderr, "Tcl initialisation failed: %s\n", Tcl_GetStringResult( interp ) );
256 return TCL_ERROR;
257 }
258 if ( Tk_Init( interp ) == TCL_ERROR )
259 {
260 fprintf( stderr, "Tk initialisation failed: %s\n", Tcl_GetStringResult( interp ) );
261 return TCL_ERROR;
262 }
263#ifdef HAVE_ITCL
264 if ( Itcl_Init( interp ) == TCL_ERROR )
265 {
266 fprintf( stderr, "Itcl initialisation failed: %s\n", Tcl_GetStringResult( interp ) );
267 return TCL_ERROR;
268 }
269#endif
270#ifdef HAVE_ITK
271 if ( Itk_Init( interp ) == TCL_ERROR )
272 {
273 fprintf( stderr, "Itk initialisation failed: %s\n", Tcl_GetStringResult( interp ) );
274 return TCL_ERROR;
275 }
276
277//
278// Pulled in this next section from itkwish in itcl3.0.1.
279//
280
281 //
282 // This is itkwish, so import all [incr Tcl] commands by
283 // default into the global namespace. Fix up the autoloader
284 // to do the same.
285 //
286 if ( Tcl_Import( interp, Tcl_GetGlobalNamespace( interp ),
287 "::itk::*", /* allowOverwrite */ 1 ) != TCL_OK )
288 {
289 fprintf( stderr, "Itk initialisation failed: %s\n", Tcl_GetStringResult( interp ) );
290 return TCL_ERROR;
291 }
292
293 if ( Tcl_Import( interp, Tcl_GetGlobalNamespace( interp ),
294 "::itcl::*", /* allowOverwrite */ 1 ) != TCL_OK )
295 {
296 fprintf( stderr, "Itk initialisation failed: %s\n", Tcl_GetStringResult( interp ) );
297 return TCL_ERROR;
298 }
299
300 if ( Tcl_Eval( interp, "auto_mkindex_parser::slavehook { _%@namespace import -force ::itcl::* ::itk::* }" ) != TCL_OK )
301 {
302 fprintf( stderr, "Itk initialisation failed: %s\n", Tcl_GetStringResult( interp ) );
303 return TCL_ERROR;
304 }
305#endif
306
307 //
308 // Make command-line arguments available in the Tcl variables "argc"
309 // and "argv". Also set the "geometry" variable from the geometry
310 // specified on the command line.
311 //
312 //fprintf( stderr, "Before Tcl_Merge\n" );
313
314 args = Tcl_Merge( argc - 1, ( const char * const * )argv + 1 );
315 Tcl_SetVar( interp, "argv", args, TCL_GLOBAL_ONLY );
316 ckfree( args );
317 sprintf( buf, "%d", argc - 1 );
318 Tcl_SetVar( interp, "argc", buf, TCL_GLOBAL_ONLY );
319
320 //fprintf( stderr, "After Tcl_Merge\n" );
321 if ( geometry != NULL )
322 {
323 Tcl_SetVar( interp, "geometry", geometry, TCL_GLOBAL_ONLY );
324 }
325
326 //
327 // Set the "tcl_interactive" variable.
328 //
329
330 tty = isatty( 0 );
331 Tcl_SetVar( interp, "tcl_interactive",
332 ( ( fileName == NULL ) && tty ) ? "1" : "0", TCL_GLOBAL_ONLY );
333
334 //
335 // Add a few application-specific commands to the application's
336 // interpreter.
337 //
338
339 //
340 // Invoke application-specific initialization.
341 //
342 //fprintf( stderr, "Before AppInit\n" );
343
344 if ( ( *AppInit )( interp ) != TCL_OK )
345 {
346 fprintf( stderr, "(*AppInit) failed: %s\n", Tcl_GetStringResult( interp ) );
347 return TCL_ERROR;
348 }
349
350 //
351 // Set the geometry of the main window, if requested.
352 //
353
354 if ( geometry != NULL )
355 {
356 code = Tcl_VarEval( interp, "wm geometry . ", geometry, (char *) NULL );
357 if ( code != TCL_OK )
358 {
359 fprintf( stderr, "%s\n", Tcl_GetStringResult( interp ) );
360 }
361 }
362
363 //
364 // Process the startup script, if any.
365 //
366 //fprintf( stderr, "Before startup\n" );
367
368 if ( script != NULL )
369 {
370 code = Tcl_VarEval( interp, script, (char *) NULL );
371 if ( code != TCL_OK )
372 {
373 goto error;
374 }
375 tty = 0;
376 }
377
378 //
379 // Invoke the script specified on the command line, if any.
380 //
381 //fprintf( stderr, "Before source\n" );
382
383 if ( fileName != NULL )
384 {
385 code = Tcl_VarEval( interp, "source \"", fileName, "\"", (char *) NULL );
386 if ( code != TCL_OK )
387 {
388 goto error;
389 }
390 tty = 0;
391 }
392 else
393 {
394 //
395 // Commands will come from standard input, so set up an event
396 // handler for standard input. Evaluate the .rc file, if one
397 // has been specified, set up an event handler for standard
398 // input, and print a prompt if the input device is a
399 // terminal.
400 //
401
402 if ( RcFileName != NULL )
403 {
404 Tcl_DString buffer;
405 char *fullName;
406 FILE *f;
407
408 fullName = Tcl_TranslateFileName( interp, RcFileName, &buffer );
409 if ( fullName == NULL )
410 {
411 fprintf( stderr, "%s\n", Tcl_GetStringResult( interp ) );
412 }
413 else
414 {
415 f = fopen( fullName, "r" );
416 if ( f != NULL )
417 {
418 code = Tcl_EvalFile( interp, fullName );
419 if ( code != TCL_OK )
420 {
421 fprintf( stderr, "%s\n", Tcl_GetStringResult( interp ) );
422 }
423 fclose( f );
424 }
425 }
426 Tcl_DStringFree( &buffer );
427 }
428// Exclude UNIX-only feature
429#if !defined ( MAC_TCL ) && !defined ( _WIN32 )
430#if defined( TCL_MAJOR_VERSION ) && TCL_MAJOR_VERSION >= 9
431 Tcl_CreateFileHandler( 0, TCL_READABLE, StdinProc, (void *) 0 );
432#else
433 Tcl_CreateFileHandler( 0, TCL_READABLE, StdinProc, (ClientData) 0 );
434#endif
435#endif
436 if ( tty )
437 {
438 Prompt( interp, 0 );
439 }
440 }
441 fflush( stdout );
442 Tcl_DStringInit( &command );
443
444 //
445 // Loop infinitely, waiting for commands to execute. When there
446 // are no windows left, Tk_MainLoop returns and we exit.
447 //
448
449 //fprintf( stderr, "Before Tk_MainLoop\n" );
450 Tk_MainLoop();
451
452 //
453 // Don't exit directly, but rather invoke the Tcl "exit" command.
454 // This gives the application the opportunity to redefine "exit"
455 // to do additional cleanup.
456 //
457
458 Tcl_Eval( interp, "exit" );
459 exit( 1 );
460
461error:
462 msg = Tcl_GetVar( interp, "errorInfo", TCL_GLOBAL_ONLY );
463 if ( msg == NULL )
464 {
465 msg = Tcl_GetStringResult( interp );
466 }
467 fprintf( stderr, "%s\n", msg );
468 Tcl_Eval( interp, errorExitCmd );
469 return 1; // Needed only to prevent compiler warnings.
470}
471
472//
473//--------------------------------------------------------------------------
474//
475// StdinProc --
476//
477// This procedure is invoked by the event dispatcher whenever
478// standard input becomes readable. It grabs the next line of
479// input characters, adds them to a command being assembled, and
480// executes the command if it's complete.
481//
482// Results:
483// None.
484//
485// Side effects:
486// Could be almost arbitrary, depending on the command that's
487// typed.
488//
489//--------------------------------------------------------------------------
490//
491
492// ARGSUSED
493static void
494StdinProc( ClientData PL_UNUSED( clientData ), int PL_UNUSED( mask ) )
495{
496#define BUFFER_SIZE 4000
497 char input[BUFFER_SIZE + 1];
498 static int gotPartial = 0;
499 char *cmd;
500 int code, count;
501 const char *res;
502
503#if !defined ( _WIN32 )
504 count = (int) read( fileno( stdin ), input, BUFFER_SIZE );
505#else
506 count = fread( input, BUFFER_SIZE, sizeof ( char ), stdin );
507#endif
508 if ( count <= 0 )
509 {
510 if ( !gotPartial )
511 {
512 if ( tty )
513 {
514 Tcl_Eval( interp, "exit" );
515 exit( 1 );
516 }
517 else
518 {
519#if !defined ( MAC_TCL ) && !defined ( _WIN32 )
520 Tcl_DeleteFileHandler( 0 );
521#endif
522 }
523 return;
524 }
525 else
526 {
527 count = 0;
528 }
529 }
530 cmd = Tcl_DStringAppend( &command, input, count );
531 if ( count != 0 )
532 {
533 if ( ( input[count - 1] != '\n' ) && ( input[count - 1] != ';' ) )
534 {
535 gotPartial = 1;
536 goto prompt;
537 }
538 if ( !Tcl_CommandComplete( cmd ) )
539 {
540 gotPartial = 1;
541 goto prompt;
542 }
543 }
544 gotPartial = 0;
545
546 //
547 // Disable the stdin file handler while evaluating the command;
548 // otherwise if the command re-enters the event loop we might
549 // process commands from stdin before the current command is
550 // finished. Among other things, this will trash the text of the
551 // command being evaluated.
552 //
553#if !defined ( MAC_TCL ) && !defined ( _WIN32 )
554#if defined( TCL_MAJOR_VERSION ) && TCL_MAJOR_VERSION >= 9
555 Tcl_CreateFileHandler( 0, 0, StdinProc, (void *) 0 );
556#else
557 Tcl_CreateFileHandler( 0, 0, StdinProc, (ClientData) 0 );
558#endif
559#endif
560 code = Tcl_RecordAndEval( interp, cmd, 0 );
561#if !defined ( MAC_TCL ) && !defined ( _WIN32 )
562#if defined( TCL_MAJOR_VERSION ) && TCL_MAJOR_VERSION >= 9
563 Tcl_CreateFileHandler( 0, TCL_READABLE, StdinProc, (void *) 0 );
564#else
565 Tcl_CreateFileHandler( 0, TCL_READABLE, StdinProc, (ClientData) 0 );
566#endif
567#endif
568 Tcl_DStringFree( &command );
569 res = Tcl_GetStringResult( interp );
570 if ( *res != 0 )
571 {
572 if ( ( code != TCL_OK ) || ( tty ) )
573 {
574 printf( "%s\n", res );
575 }
576 }
577
578 //
579 // Output a prompt.
580 //
581
582prompt:
583 if ( tty )
584 {
585 Prompt( interp, gotPartial );
586 }
587}
588
589//
590//--------------------------------------------------------------------------
591//
592// Prompt --
593//
594// Issue a prompt on standard output, or invoke a script
595// to issue the prompt.
596//
597// Results:
598// None.
599//
600// Side effects:
601// A prompt gets output, and a Tcl script may be evaluated
602// in interp.
603//
604//--------------------------------------------------------------------------
605//
606
607static void
608Prompt( interploc, partial )
609Tcl_Interp * interploc; // Interpreter to use for prompting.
610int partial; // Non-zero means there already
611 // exists a partial command, so use
612 // the secondary prompt.
613{
614 const char *promptCmd;
615 int code;
616
617 promptCmd = Tcl_GetVar( interploc,
618 partial ? "tcl_prompt2" : "tcl_prompt1", TCL_GLOBAL_ONLY );
619 if ( promptCmd == NULL )
620 {
621defaultPrompt:
622 if ( !partial )
623 {
624 fputs( "% ", stdout );
625 }
626 }
627 else
628 {
629 code = Tcl_Eval( interploc, promptCmd );
630 if ( code != TCL_OK )
631 {
632 Tcl_AddErrorInfo( interploc,
633 "\n (script that generates prompt)" );
634 fprintf( stderr, "%s\n", Tcl_GetStringResult( interploc ) );
635 goto defaultPrompt;
636 }
637 }
638 fflush( stdout );
639}
static int error
Definition plcont.c:61
#define BUFFER_SIZE
Definition plcore.c:94
static PLINT * buffer
Definition plfill.c:74
#define PL_UNUSED(x)
Definition plplot.h:138
static Tk_ArgvInfo argTable[]
Definition plserver.c:52
static int AppInit(Tcl_Interp *interp)
Definition pltcl.c:134
static int argc
Definition qt.cpp:48
static char ** argv
Definition qt.cpp:49
static char buf[200]
Definition tclAPI.c:879
int isatty(int fd)
static Tcl_Interp * interp
Definition tkMain.c:117
static char errorExitCmd[]
Definition tkMain.c:123
static const char * fileName
Definition tkMain.c:131
static int tty
Definition tkMain.c:120
static void StdinProc(ClientData clientData, int mask)
static const char * geometry
Definition tkMain.c:134
static Tcl_DString command
Definition tkMain.c:118
EXTERN Tcl_Namespace * Tcl_GetGlobalNamespace(Tcl_Interp *interp)
static void Prompt(Tcl_Interp *interploc, int partial)
Definition tkMain.c:608
static int synchronize
Definition tkMain.c:129
static const char * script
Definition tkMain.c:130
int pltkMain(int argc, const char **argv, char *RcFileName, int(*AppInit)(Tcl_Interp *interp))
Definition tkMain.c:180
static const char * name
Definition tkMain.c:132
static const char * display
Definition tkMain.c:133
EXTERN int Itk_Init(Tcl_Interp *interp)