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