PLplot  5.10.0
plserver.c
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines