PLplot 5.15.0
Loading...
Searching...
No Matches
plserver.c
Go to the documentation of this file.
1// Copyright 1993, 1994, 1995
2// Maurice LeBrun mjl@dino.ph.utexas.edu
3// Institute for Fusion Studies University of Texas at Austin
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//
25// PLplot graphics server.
26//
27// Just a front-end to the pltkMain() function. Structured along the
28// preferred lines for extended wish'es. Is typically run as a child
29// process from the PLplot TK driver to render output. Can use either TK
30// send or Tcl-DP RPC for communication, depending on how it is invoked.
31//
32// Note that plserver can be used the same way as wish or dpwish, as it
33// contains the functionality of each of these (except the -notk Tcl-DP
34// command-line option is not supported).
35//
36
37#define NEED_PLDEBUG
38#include "plserver.h"
39
40// Application-specific command-line options
41// Variable declarations
42
43static char *client_name; // Name of client main window
44static char *auto_path; // addition to auto_path
45static int child; // set if child of TK driver
46#ifdef PLD_dp
47static int dp; // set if using Tcl-DP to communicate
48#endif
49static char *client_host; // Host id for client
50static char *client_port; // Communications port id for client
51
52static Tk_ArgvInfo argTable[] = {
53 { "-client_name", TK_ARGV_STRING, (char *) NULL, (char *) &client_name,
54 "Client main window name to connect to" },
55 { "-client_host", TK_ARGV_STRING, (char *) NULL, (char *) &client_host,
56 "Client host to connect to" },
57 { "-client_port", TK_ARGV_STRING, (char *) NULL, (char *) &client_port,
58 "Client port (Tcl-DP) to connect to" },
59 { "-auto_path", TK_ARGV_STRING, (char *) NULL, (char *) &auto_path,
60 "Additional directory(s) to autoload" },
61 { "-child", TK_ARGV_CONSTANT, (char *) 1, (char *) &child,
62 "Set ONLY when child of PLplot TK driver" },
63 { (char *) NULL, TK_ARGV_END, (char *) NULL, (char *) NULL,
64 (char *) NULL }
65};
66
67// PLplot/Tk extension command -- handle exit.
68
69static int
70plExitCmd( ClientData clientData, Tcl_Interp *interp, int argc, char **argv );
71
72// Evals the specified command, aborting on an error.
73
74static void
75tcl_cmd( Tcl_Interp *interp, const char *cmd );
76
77// Application-specific startup
78
79static int
80AppInit( Tcl_Interp *interp );
81
82//--------------------------------------------------------------------------
83// main --
84//
85// Just a stub routine to call pltkMain. The latter is nice to have
86// when building extended wishes, since then you don't have to rely on
87// sucking the Tk main out of libtk (which doesn't work correctly on all
88// systems/compilers/linkers/etc). Hopefully in the future Tk will
89// supply a sufficiently capable tkMain() type function that can be used
90// instead.
91//--------------------------------------------------------------------------
92
93int
94main( int argc, const char **argv )
95{
96 int i, myargc = argc;
97 const char **myargv;
98 Tcl_Interp *interp;
99 const char *helpmsg = "Command-specific options:";
100
101#ifdef DEBUG
102 fprintf( stderr, "Program %s called with arguments :\n", argv[0] );
103 for ( i = 1; i < argc; i++ )
104 {
105 fprintf( stderr, "%s ", argv[i] );
106 }
107 fprintf( stderr, "\n" );
108#endif
109
110// Create interpreter just for argument parsing
111
112 interp = Tcl_CreateInterp();
113
114// Save arglist to get around Tk_ParseArgv limitations
115
116#ifdef DEBUG
117 fprintf( stderr, "Before myargv\n" );
118#endif
119
120 // According to both Linux and Windows documentation,
121 // argv is actually argc+1 in length with the last element set to
122 // the NULL value. So leave room for that last element.
123 myargv = (const char **) malloc( ( argc + 1 ) * sizeof ( char * ) );
124 for ( i = 0; i < argc + 1; i++ )
125 {
126 myargv[i] = argv[i];
127 }
128
129#ifdef DEBUG
130 fprintf( stderr, "After myargv\n" );
131#endif
132
133// Parse args
134// Examine the result string to see if an error return is really an error
135
136 if ( Tk_ParseArgv( interp, (Tk_Window) NULL, &argc, argv,
137 argTable, TK_ARGV_NO_DEFAULTS ) != TCL_OK )
138 {
139#ifdef DEBUG
140 fprintf( stderr, "Error in Tk_ParseArgv\n" );
141#endif
142 fprintf( stderr, "\n(plserver) %s\n\n", Tcl_GetStringResult( interp ) );
143 fprintf( stderr, "\
144The client_<xxx> and -child options should not be used except via the\n\
145PLplot/Tk driver.\n\n(wish) " );
146#ifdef DEBUG
147 fprintf( stderr, "Before Tcl_SetResult\n" );
148#endif
149 Tcl_SetResult( interp, (char *) helpmsg, TCL_VOLATILE );
150 }
151
152#ifdef DEBUG
153 fprintf( stderr, "After Tk_ParseArgv\n" );
154#endif
155
156// No longer need interpreter
157
158#if TCL_MAJOR_VERSION < 7 || ( TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION < 5 )
159 Tcl_DeleteInterp( interp );
160#endif
161
162// Call pltkMain() with original argc/argv list, to make sure -h is seen
163// Does not return until program exit
164
165 exit( pltkMain( myargc, myargv, NULL, AppInit ) );
166}
167
168
169//
170//--------------------------------------------------------------------------
171//
172// AppInit --
173//
174// This procedure performs application-specific initialization.
175// Most applications, especially those that incorporate additional
176// packages, will have their own version of this procedure.
177//
178// Results:
179// Returns a standard Tcl completion code, and leaves an error
180// message in interp->result if an error occurs.
181//
182// Side effects:
183// Depends on the startup script.
184//
185//--------------------------------------------------------------------------
186//
187
188static int
189AppInit( Tcl_Interp *interp )
190{
191 Tk_Window mainWindow = Tk_MainWindow( interp );
192
193//
194// Call the init procedures for included packages. Each call should
195// look like this:
196//
197// if (Mod_Init(interp) == TCL_ERROR) {
198// return TCL_ERROR;
199// }
200//
201// where "Mod" is the name of the module.
202//
203 if ( Pltk_Init( interp ) == TCL_ERROR )
204 {
205 return TCL_ERROR;
206 }
207
208// Application-specific startup. That means: for use in plserver ONLY.
209
210// Pass child variable to interpreter if set.
211
212 if ( child != 0 )
213 Tcl_SetVar( interp, "child", "1", 0 );
214
215// If client_name is set, TK send is being used to communicate.
216// If client_port is set, Tcl-DP RPC is being used to communicate.
217// The "dp" variable determines which style communication is used
218
219 if ( client_name != NULL )
220 {
221 Tcl_SetVar( interp, "client_name", client_name, 0 );
222 tcl_cmd( interp, "set dp 0" );
223#ifdef PLD_dp
224 dp = 0;
225#endif
226 }
227 else if ( client_port != NULL )
228 {
229#ifdef PLD_dp
230 Tcl_SetVar( interp, "client_port", client_port, 0 );
231 if ( client_host != NULL )
232 Tcl_SetVar( interp, "client_host", client_host, 0 );
233 dp = 1; tcl_cmd( interp, "set dp 1" );
234#else
235 Tcl_AppendResult( interp,
236 "no Tcl-DP support in this version of plserver",
237 (char *) NULL );
238 return TCL_ERROR;
239#endif
240 }
241
242// Add user-specified directory(s) to auto_path
243
244 if ( auto_path != NULL )
245 {
246 Tcl_SetVar( interp, "dir", auto_path, 0 );
247 tcl_cmd( interp, "lappend auto_path $dir" );
248 }
249
250// Rename "exit" to "tkexit", and insert custom exit handler
251
252 tcl_cmd( interp, "rename exit tkexit" );
253
254 Tcl_CreateCommand( interp, "exit", (Tcl_CmdProc *) plExitCmd,
255 (ClientData) mainWindow, (Tcl_CmdDeleteProc *) NULL );
256
257 return TCL_OK;
258}
259
260//--------------------------------------------------------------------------
261// plExitCmd
262//
263// PLplot/Tk extension command -- handle exit.
264// The reason for overriding the normal exit command is so we can tell the
265// client to abort.
266//--------------------------------------------------------------------------
267
268static int
269plExitCmd( ClientData PL_UNUSED( clientData ), Tcl_Interp *interp, int argc, char **argv )
270{
271 int value = 0;
272 const char *res;
273
274// Print error message if one given
275
276 res = Tcl_GetStringResult( interp );
277 if ( res[0] != '\0' )
278 fprintf( stderr, "%s\n", res );
279
280// Best to check the syntax before proceeding
281
282 if ( ( argc != 1 ) && ( argc != 2 ) )
283 {
284 Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
285 " ?returnCode?\"", (char *) NULL );
286 return TCL_ERROR;
287 }
288 if ( ( argc != 1 ) && ( Tcl_GetInt( interp, argv[1], &value ) != TCL_OK ) )
289 {
290 Tcl_AppendResult( interp, "non-integer return code: \"", argv[1],
291 "\"", (char *) NULL );
292 return TCL_ERROR;
293 }
294
295// If client exists, tell it to self destruct
296
297 Tcl_VarEval( interp, "plserver_link_end", (char **) NULL );
298
299// Now really exit
300// (Note: this function is actually deprecated, but as it is only used here
301// at the end of the program, let's leave it.)
302
303 if ( argc == 1 )
304 {
305 return Tcl_VarEval( interp, "tkexit", (char **) NULL );
306 }
307 else
308 {
309 return Tcl_VarEval( interp, "tkexit", argv[1], (char **) NULL );
310 }
311}
312
313//--------------------------------------------------------------------------
314// tcl_cmd
315//
316// Evals the specified command, aborting on an error.
317//--------------------------------------------------------------------------
318
319static void
320tcl_cmd( Tcl_Interp *interp, const char *cmd )
321{
322 int result;
323
324 dbug_enter( "tcl_cmd" );
325 pldebug( "tcl_cmd", "evaluating command %s\n", cmd );
326
327 result = Tcl_VarEval( interp, cmd, (char **) NULL );
328 if ( result != TCL_OK )
329 {
330 Tcl_Eval( interp, "exit" );
331 exit( 1 );
332 }
333}
int main()
Definition cdexpert.c:35
static PLFLT value(double n1, double n2, double hue)
Definition plctrl.c:1219
#define PL_UNUSED(x)
Definition plplot.h:138
static void tcl_cmd(Tcl_Interp *interp, const char *cmd)
Definition plserver.c:320
static int child
Definition plserver.c:45
static char * auto_path
Definition plserver.c:44
static int AppInit(Tcl_Interp *interp)
Definition plserver.c:189
static int plExitCmd(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
static Tk_ArgvInfo argTable[]
Definition plserver.c:52
static char * client_host
Definition plserver.c:49
static char * client_name
Definition plserver.c:43
static char * client_port
Definition plserver.c:50
static int AppInit(Tcl_Interp *interp)
Definition pltcl.c:134
static int plExitCmd(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
Definition pltcl.c:66
EXTERN PLDLLIMPEXP_TCLTK int Pltk_Init(Tcl_Interp *interp)
Definition Pltk_Init.c:51
EXTERN PLDLLIMPEXP_TCLTK int pltkMain(int argc, const char **argv, char *RcFileName, int(*AppInit)(Tcl_Interp *interp))
Definition tkMain.c:184
static int argc
Definition qt.cpp:48
static char ** argv
Definition qt.cpp:49
#define dbug_enter(a)
Definition tclMatrix.c:59
static Tcl_Interp * interp
Definition tkMain.c:120