PLplot
5.10.0
|
00001 // Copyright 1993, 1994, 1995 00002 // Maurice LeBrun mjl@dino.ph.utexas.edu 00003 // Institute for Fusion Studies University of Texas at Austin 00004 // 00005 // Copyright (C) 2004 Joao Cardoso 00006 // 00007 // This file is part of PLplot. 00008 // 00009 // PLplot is free software; you can redistribute it and/or modify 00010 // it under the terms of the GNU Library General Public License as published 00011 // by the Free Software Foundation; either version 2 of the License, or 00012 // (at your option) any later version. 00013 // 00014 // PLplot is distributed in the hope that it will be useful, 00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 // GNU Library General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU Library General Public License 00020 // along with PLplot; if not, write to the Free Software 00021 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00022 // 00023 //-------------------------------------------------------------------------- 00024 // 00025 // PLplot graphics server. 00026 // 00027 // Just a front-end to the pltkMain() function. Structured along the 00028 // preferred lines for extended wish'es. Is typically run as a child 00029 // process from the PLplot TK driver to render output. Can use either TK 00030 // send or Tcl-DP RPC for communication, depending on how it is invoked. 00031 // 00032 // Note that plserver can be used the same way as wish or dpwish, as it 00033 // contains the functionality of each of these (except the -notk Tcl-DP 00034 // command-line option is not supported). 00035 // 00036 00037 #define NEED_PLDEBUG 00038 #include "plserver.h" 00039 00040 // Application-specific command-line options 00041 // Variable declarations 00042 00043 static char *client_name; // Name of client main window 00044 static char *auto_path; // addition to auto_path 00045 static int child; // set if child of TK driver 00046 #ifdef PLD_dp 00047 static int dp; // set if using Tcl-DP to communicate 00048 #endif 00049 static char *client_host; // Host id for client 00050 static char *client_port; // Communications port id for client 00051 00052 static Tk_ArgvInfo argTable[] = { 00053 { "-client_name", TK_ARGV_STRING, (char *) NULL, (char *) &client_name, 00054 "Client main window name to connect to" }, 00055 { "-client_host", TK_ARGV_STRING, (char *) NULL, (char *) &client_host, 00056 "Client host to connect to" }, 00057 { "-client_port", TK_ARGV_STRING, (char *) NULL, (char *) &client_port, 00058 "Client port (Tcl-DP) to connect to" }, 00059 { "-auto_path", TK_ARGV_STRING, (char *) NULL, (char *) &auto_path, 00060 "Additional directory(s) to autoload" }, 00061 { "-child", TK_ARGV_CONSTANT, (char *) 1, (char *) &child, 00062 "Set ONLY when child of PLplot TK driver" }, 00063 { (char *) NULL, TK_ARGV_END, (char *) NULL, (char *) NULL, 00064 (char *) NULL } 00065 }; 00066 00067 // PLplot/Tk extension command -- handle exit. 00068 00069 static int 00070 plExitCmd( ClientData clientData, Tcl_Interp *interp, int argc, char **argv ); 00071 00072 // Evals the specified command, aborting on an error. 00073 00074 static void 00075 tcl_cmd( Tcl_Interp *interp, const char *cmd ); 00076 00077 // Application-specific startup 00078 00079 static int 00080 AppInit( Tcl_Interp *interp ); 00081 00082 //-------------------------------------------------------------------------- 00083 // main -- 00084 // 00085 // Just a stub routine to call pltkMain. The latter is nice to have 00086 // when building extended wishes, since then you don't have to rely on 00087 // sucking the Tk main out of libtk (which doesn't work correctly on all 00088 // systems/compilers/linkers/etc). Hopefully in the future Tk will 00089 // supply a sufficiently capable tkMain() type function that can be used 00090 // instead. 00091 //-------------------------------------------------------------------------- 00092 00093 int 00094 main( int argc, const char **argv ) 00095 { 00096 int i, myargc = argc; 00097 const char **myargv; 00098 Tcl_Interp *interp; 00099 const char *helpmsg = "Command-specific options:"; 00100 00101 #ifdef DEBUG 00102 fprintf( stderr, "Program %s called with arguments :\n", argv[0] ); 00103 for ( i = 1; i < argc; i++ ) 00104 { 00105 fprintf( stderr, "%s ", argv[i] ); 00106 } 00107 fprintf( stderr, "\n" ); 00108 #endif 00109 00110 // Create interpreter just for argument parsing 00111 00112 interp = Tcl_CreateInterp(); 00113 00114 // Save arglist to get around Tk_ParseArgv limitations 00115 00116 #ifdef DEBUG 00117 fprintf( stderr, "Before myargv\n" ); 00118 #endif 00119 00120 // According to both Linux and Windows documentation, 00121 // argv is actually argc+1 in length with the last element set to 00122 // the NULL value. So leave room for that last element. 00123 myargv = (const char **) malloc( ( argc + 1 ) * sizeof ( char * ) ); 00124 for ( i = 0; i < argc + 1; i++ ) 00125 { 00126 myargv[i] = argv[i]; 00127 } 00128 00129 #ifdef DEBUG 00130 fprintf( stderr, "After myargv\n" ); 00131 #endif 00132 00133 // Parse args 00134 // Examine the result string to see if an error return is really an error 00135 00136 if ( Tk_ParseArgv( interp, (Tk_Window) NULL, &argc, argv, 00137 argTable, TK_ARGV_NO_DEFAULTS ) != TCL_OK ) 00138 { 00139 #ifdef DEBUG 00140 fprintf( stderr, "Error in Tk_ParseArgv\n" ); 00141 #endif 00142 fprintf( stderr, "\n(plserver) %s\n\n", Tcl_GetStringResult( interp ) ); 00143 fprintf( stderr, "\ 00144 The client_<xxx> and -child options should not be used except via the\n\ 00145 PLplot/Tk driver.\n\n(wish) " ); 00146 #ifdef DEBUG 00147 fprintf( stderr, "Before Tcl_SetResult\n" ); 00148 #endif 00149 Tcl_SetResult( interp, (char *) helpmsg, TCL_VOLATILE ); 00150 } 00151 00152 #ifdef DEBUG 00153 fprintf( stderr, "After Tk_ParseArgv\n" ); 00154 #endif 00155 00156 // No longer need interpreter 00157 00158 #if TCL_MAJOR_VERSION < 7 || ( TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION < 5 ) 00159 Tcl_DeleteInterp( interp ); 00160 #endif 00161 00162 // Call pltkMain() with original argc/argv list, to make sure -h is seen 00163 // Does not return until program exit 00164 00165 exit( pltkMain( myargc, myargv, NULL, AppInit ) ); 00166 } 00167 00168 00169 // 00170 //-------------------------------------------------------------------------- 00171 // 00172 // AppInit -- 00173 // 00174 // This procedure performs application-specific initialization. 00175 // Most applications, especially those that incorporate additional 00176 // packages, will have their own version of this procedure. 00177 // 00178 // Results: 00179 // Returns a standard Tcl completion code, and leaves an error 00180 // message in interp->result if an error occurs. 00181 // 00182 // Side effects: 00183 // Depends on the startup script. 00184 // 00185 //-------------------------------------------------------------------------- 00186 // 00187 00188 static int 00189 AppInit( Tcl_Interp *interp ) 00190 { 00191 Tk_Window mainWindow = Tk_MainWindow( interp ); 00192 00193 // 00194 // Call the init procedures for included packages. Each call should 00195 // look like this: 00196 // 00197 // if (Mod_Init(interp) == TCL_ERROR) { 00198 // return TCL_ERROR; 00199 // } 00200 // 00201 // where "Mod" is the name of the module. 00202 // 00203 if ( Pltk_Init( interp ) == TCL_ERROR ) 00204 { 00205 return TCL_ERROR; 00206 } 00207 00208 // Application-specific startup. That means: for use in plserver ONLY. 00209 00210 // Pass child variable to interpreter if set. 00211 00212 if ( child != 0 ) 00213 Tcl_SetVar( interp, "child", "1", 0 ); 00214 00215 // If client_name is set, TK send is being used to communicate. 00216 // If client_port is set, Tcl-DP RPC is being used to communicate. 00217 // The "dp" variable determines which style communication is used 00218 00219 if ( client_name != NULL ) 00220 { 00221 Tcl_SetVar( interp, "client_name", client_name, 0 ); 00222 tcl_cmd( interp, "set dp 0" ); 00223 #ifdef PLD_dp 00224 dp = 0; 00225 #endif 00226 } 00227 else if ( client_port != NULL ) 00228 { 00229 #ifdef PLD_dp 00230 Tcl_SetVar( interp, "client_port", client_port, 0 ); 00231 if ( client_host != NULL ) 00232 Tcl_SetVar( interp, "client_host", client_host, 0 ); 00233 dp = 1; tcl_cmd( interp, "set dp 1" ); 00234 #else 00235 Tcl_AppendResult( interp, 00236 "no Tcl-DP support in this version of plserver", 00237 (char *) NULL ); 00238 return TCL_ERROR; 00239 #endif 00240 } 00241 00242 // Add user-specified directory(s) to auto_path 00243 00244 if ( auto_path != NULL ) 00245 { 00246 Tcl_SetVar( interp, "dir", auto_path, 0 ); 00247 tcl_cmd( interp, "lappend auto_path $dir" ); 00248 } 00249 00250 // Rename "exit" to "tkexit", and insert custom exit handler 00251 00252 tcl_cmd( interp, "rename exit tkexit" ); 00253 00254 Tcl_CreateCommand( interp, "exit", (Tcl_CmdProc *) plExitCmd, 00255 (ClientData) mainWindow, (Tcl_CmdDeleteProc *) NULL ); 00256 00257 return TCL_OK; 00258 } 00259 00260 //-------------------------------------------------------------------------- 00261 // plExitCmd 00262 // 00263 // PLplot/Tk extension command -- handle exit. 00264 // The reason for overriding the normal exit command is so we can tell the 00265 // client to abort. 00266 //-------------------------------------------------------------------------- 00267 00268 static int 00269 plExitCmd( ClientData PL_UNUSED( clientData ), Tcl_Interp *interp, int argc, char **argv ) 00270 { 00271 int value = 0; 00272 const char *res; 00273 00274 // Print error message if one given 00275 00276 res = Tcl_GetStringResult( interp ); 00277 if ( res[0] != '\0' ) 00278 fprintf( stderr, "%s\n", res ); 00279 00280 // Best to check the syntax before proceeding 00281 00282 if ( ( argc != 1 ) && ( argc != 2 ) ) 00283 { 00284 Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0], 00285 " ?returnCode?\"", (char *) NULL ); 00286 return TCL_ERROR; 00287 } 00288 if ( ( argc != 1 ) && ( Tcl_GetInt( interp, argv[1], &value ) != TCL_OK ) ) 00289 { 00290 Tcl_AppendResult( interp, "non-integer return code: \"", argv[1], 00291 "\"", (char *) NULL ); 00292 return TCL_ERROR; 00293 } 00294 00295 // If client exists, tell it to self destruct 00296 00297 Tcl_VarEval( interp, "plserver_link_end", (char **) NULL ); 00298 00299 // Now really exit 00300 // (Note: this function is actually deprecated, but as it is only used here 00301 // at the end of the program, let's leave it.) 00302 00303 if ( argc == 1 ) 00304 { 00305 return Tcl_VarEval( interp, "tkexit", (char **) NULL ); 00306 } 00307 else 00308 { 00309 return Tcl_VarEval( interp, "tkexit", argv[1], (char **) NULL ); 00310 } 00311 } 00312 00313 //-------------------------------------------------------------------------- 00314 // tcl_cmd 00315 // 00316 // Evals the specified command, aborting on an error. 00317 //-------------------------------------------------------------------------- 00318 00319 static void 00320 tcl_cmd( Tcl_Interp *interp, const char *cmd ) 00321 { 00322 int result; 00323 00324 dbug_enter( "tcl_cmd" ); 00325 pldebug( "tcl_cmd", "evaluating command %s\n", cmd ); 00326 00327 result = Tcl_VarEval( interp, cmd, (char **) NULL ); 00328 if ( result != TCL_OK ) 00329 { 00330 Tcl_Eval( interp, "exit" ); 00331 exit( 1 ); 00332 } 00333 }