PLplot
5.15.0
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
43
static
char
*
client_name
;
// Name of client main window
44
static
char
*
auto_path
;
// addition to auto_path
45
static
int
child
;
// set if child of TK driver
46
#ifdef PLD_dp
47
static
int
dp;
// set if using Tcl-DP to communicate
48
#endif
49
static
char
*
client_host
;
// Host id for client
50
static
char
*
client_port
;
// Communications port id for client
51
52
static
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
69
static
int
70
plExitCmd
( ClientData clientData, Tcl_Interp *
interp
,
int
argc
,
char
**
argv
);
71
72
// Evals the specified command, aborting on an error.
73
74
static
void
75
tcl_cmd
( Tcl_Interp *
interp
,
const
char
*cmd );
76
77
// Application-specific startup
78
79
static
int
80
AppInit
( 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
93
int
94
main
(
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,
"\
144
The client_<xxx> and -child options should not be used except via the\n\
145
PLplot/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
188
static
int
189
AppInit
( 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
268
static
int
269
plExitCmd
( 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
319
static
void
320
tcl_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
}
argc
static int argc
Definition:
qt.cpp:48
plserver.h
PL_UNUSED
#define PL_UNUSED(x)
Definition:
plplot.h:138
value
static PLFLT value(double n1, double n2, double hue)
Definition:
plctrl.c:1219
main
int main(int argc, const char **argv)
Definition:
plserver.c:94
pltkMain
EXTERN PLDLLIMPEXP_TCLTK int pltkMain(int argc, const char **argv, char *RcFileName, int(*AppInit)(Tcl_Interp *interp))
Definition:
tkMain.c:184
AppInit
static int AppInit(Tcl_Interp *interp)
Definition:
plserver.c:189
plExitCmd
static int plExitCmd(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
argv
static char ** argv
Definition:
qt.cpp:49
child
static int child
Definition:
plserver.c:45
interp
static Tcl_Interp * interp
Definition:
tkMain.c:120
Pltk_Init
EXTERN PLDLLIMPEXP_TCLTK int Pltk_Init(Tcl_Interp *interp)
Definition:
Pltk_Init.c:51
dbug_enter
#define dbug_enter(a)
Definition:
tclMatrix.c:59
client_host
static char * client_host
Definition:
plserver.c:49
argTable
static Tk_ArgvInfo argTable[]
Definition:
plserver.c:52
tcl_cmd
static void tcl_cmd(Tcl_Interp *interp, const char *cmd)
Definition:
plserver.c:320
client_port
static char * client_port
Definition:
plserver.c:50
auto_path
static char * auto_path
Definition:
plserver.c:44
client_name
static char * client_name
Definition:
plserver.c:43
bindings
tk
plserver.c
Generated on Thu Nov 7 2019 00:00:00 for PLplot by
1.8.16