home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / maths / plplot / plplot_2 / drivers / tk / plserver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-25  |  8.9 KB  |  308 lines

  1. /* $Id: plserver.c,v 1.29 1994/08/25 04:00:27 mjl Exp $
  2.  * $Log: plserver.c,v $
  3.  * Revision 1.29  1994/08/25  04:00:27  mjl
  4.  * Fixed some error output; elminates spurious <RET> at end.
  5.  *
  6.  * Revision 1.28  1994/07/19  22:31:43  mjl
  7.  * All device drivers: enabling macro renamed to PLD_<driver>, where <driver>
  8.  * is xwin, ps, etc.  See plDevs.h for more detail.  All internal header file
  9.  * inclusion changed to /not/ use a search path so that it will work better
  10.  * with makedepend.
  11.  *
  12.  * Revision 1.27  1994/06/30  18:45:02  mjl
  13.  * Minor changes to pass gcc -Wall without warnings and other cleaning up.
  14.  *
  15.  * Revision 1.26  1994/06/23  22:33:53  mjl
  16.  * Fixed bug introduced in last update concerning exit handling for DP style
  17.  * communication.
  18.  *
  19.  * Revision 1.25  1994/06/16  19:04:32  mjl
  20.  * Massively restructured.  Is now just a front-end to the pltkMain()
  21.  * function.  Structured along the preferred lines for extended wish'es.
  22. */
  23.  
  24. /* 
  25.  * plserver.c
  26.  * Maurice LeBrun
  27.  * 30-Apr-93
  28.  *
  29.  * Plplot graphics server.
  30.  *
  31.  * Just a front-end to the pltkMain() function.  Structured along the
  32.  * preferred lines for extended wish'es.  Is typically run as a child
  33.  * process from the plplot TK driver to render output.  Can use either TK
  34.  * send or Tcl-DP RPC for communication, depending on how it is invoked.
  35.  *
  36.  * Note that plserver can be used the same way as wish or dpwish, as it
  37.  * contains the functionality of each of these (except the -notk Tcl-DP
  38.  * command-line option is not supported).  
  39.  */
  40. /*
  41. #define DEBUG
  42. */
  43.  
  44. #include "plserver.h"
  45.  
  46. /* Application-specific command-line options */
  47. /* Variable declarations */
  48.  
  49. static char *client_name;    /* Name of client main window */
  50. static char *auto_path;        /* addition to auto_path */
  51. static int child;        /* set if child of TK driver */
  52. static int dp;            /* set if using Tcl-DP to communicate */
  53. static char *client_host;    /* Host id for client */
  54. static char *client_port;    /* Communications port id for client */
  55.  
  56. static Tk_ArgvInfo argTable[] = {
  57.     {"-client_name", TK_ARGV_STRING, (char *) NULL, (char *) &client_name,
  58.      "Client main window name to connect to"},
  59.     {"-client_host", TK_ARGV_STRING, (char *) NULL, (char *) &client_host,
  60.      "Client host to connect to"},
  61.     {"-client_port", TK_ARGV_STRING, (char *) NULL, (char *) &client_port,
  62.      "Client port (Tcl-DP) to connect to"},
  63.     {"-auto_path", TK_ARGV_STRING, (char *) NULL, (char *) &auto_path,
  64.      "Additional directory(s) to autoload"},
  65.     {"-child", TK_ARGV_CONSTANT, (char *) 1, (char *) &child,
  66.      "Set ONLY when child of plplot TK driver"},
  67.     {(char *) NULL, TK_ARGV_END, (char *) NULL, (char *) NULL,
  68.      (char *) NULL}
  69. };
  70.  
  71. /* PLplot/Tk extension command -- handle exit. */
  72.  
  73. static int
  74. plExitCmd(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
  75.  
  76. /* Evals the specified command, aborting on an error. */
  77.  
  78. static void
  79. tcl_cmd(Tcl_Interp *interp, char *cmd);
  80.  
  81. /*----------------------------------------------------------------------*\
  82.  * main --
  83.  *
  84.  * Just a stub routine to call pltkMain.  The latter is nice to have
  85.  * when building extended wishes, since then you don't have to rely on
  86.  * sucking the Tk main out of libtk (which doesn't work correctly on all
  87.  * systems/compilers/linkers/etc).  Hopefully in the future Tk will
  88.  * supply a sufficiently capable tkMain() type function that can be used
  89.  * instead. 
  90. \*----------------------------------------------------------------------*/
  91.  
  92. int
  93. main(int argc, char **argv)
  94. {
  95.     int i, myargc = argc;
  96.     char *myargv[20];
  97.     Tcl_Interp *interp;
  98.     char *helpmsg = "Command-specific options:";
  99.  
  100. #ifdef DEBUG
  101.     fprintf(stderr, "Program %s called with arguments :\n", argv[0]);
  102.     for (i = 1; i < argc; i++) 
  103.     fprintf(stderr, "%s ", argv[i]);
  104.     fprintf(stderr, "\n");
  105. #endif
  106.  
  107. /* Create interpreter just for argument parsing */
  108.  
  109.     interp = Tcl_CreateInterp();
  110.  
  111. /* Save arglist to get around tk_ParseArgv limitations */
  112.  
  113.     for (i = 0; i < argc; i++)
  114.     myargv[i] = argv[i];
  115.  
  116. /* Parse args */
  117. /* Examine the result string to see if an error return is really an error */
  118.  
  119.     if (Tk_ParseArgv(interp, (Tk_Window) NULL, &argc, argv, argTable, 
  120.              TK_ARGV_NO_DEFAULTS) != TCL_OK) {
  121.     fprintf(stderr, "\n(plserver) %s\n\n", interp->result);
  122.     fprintf(stderr, "\
  123. The client_<xxx> and -child options should not be used except via the\n\
  124. Plplot/Tk driver.\n\n(wish) ");
  125.     if (strncmp(interp->result, helpmsg, strlen(helpmsg)))
  126.         exit(1);
  127.     }
  128.  
  129. /* No longer need interpreter */
  130.  
  131.     Tcl_DeleteInterp(interp);
  132.  
  133. /* Call pltkMain() with original argc/argv list, to make sure -h is seen */
  134. /* Does not return until program exit */
  135.  
  136.     exit(pltkMain(myargc, myargv));
  137. }
  138.  
  139.  
  140. /*
  141.  *----------------------------------------------------------------------
  142.  *
  143.  * Tcl_AppInit --
  144.  *
  145.  *    This procedure performs application-specific initialization.
  146.  *    Most applications, especially those that incorporate additional
  147.  *    packages, will have their own version of this procedure.
  148.  *
  149.  * Results:
  150.  *    Returns a standard Tcl completion code, and leaves an error
  151.  *    message in interp->result if an error occurs.
  152.  *
  153.  * Side effects:
  154.  *    Depends on the startup script.
  155.  *
  156.  *----------------------------------------------------------------------
  157.  */
  158.  
  159. int
  160. Tcl_AppInit(interp)
  161.     Tcl_Interp *interp;        /* Interpreter for application. */
  162. {
  163.     Tk_Window main;
  164.  
  165.     main = Tk_MainWindow(interp);
  166.  
  167.     /*
  168.      * Call the init procedures for included packages.  Each call should
  169.      * look like this:
  170.      *
  171.      * if (Mod_Init(interp) == TCL_ERROR) {
  172.      *     return TCL_ERROR;
  173.      * }
  174.      *
  175.      * where "Mod" is the name of the module.
  176.      */
  177.  
  178.     if (Tcl_Init(interp) == TCL_ERROR) {
  179.     return TCL_ERROR;
  180.     }
  181.     if (main && Tk_Init(interp) == TCL_ERROR) {
  182.     return TCL_ERROR;
  183.     }
  184. #ifdef PLD_dp
  185.     if (Tdp_Init(interp) == TCL_ERROR) {
  186.     return TCL_ERROR;
  187.     }
  188. #endif
  189.     if (Pltk_Init(interp) == TCL_ERROR) {
  190.     return TCL_ERROR;
  191.     }
  192.  
  193. /* Application-specific startup.  That means: for use in plserver ONLY. */
  194.  
  195. /* Pass child variable to interpreter if set. */
  196.  
  197.     if (child != 0)
  198.     Tcl_SetVar(interp, "child", "1", 0);
  199.  
  200. /* If client_name is set, TK send is being used to communicate. */
  201. /* If client_port is set, Tcl-DP RPC is being used to communicate. */
  202. /* The "dp" variable determines which style communication is used */
  203.  
  204.     if (client_name != NULL) {
  205.     Tcl_SetVar(interp, "client_name", client_name, 0);
  206.     dp = 0; tcl_cmd(interp, "set dp 0");
  207.     }
  208.     else if (client_port != NULL) {
  209. #ifdef PLD_dp
  210.     Tcl_SetVar(interp, "client_port", client_port, 0);
  211.     if (client_host != NULL)
  212.         Tcl_SetVar(interp, "client_host", client_host, 0);
  213.     dp = 1; tcl_cmd(interp, "set dp 1");
  214. #else
  215.     Tcl_AppendResult(interp,
  216.              "no Tcl-DP support in this version of plserver",
  217.              (char *) NULL);
  218.     return TCL_ERROR;
  219. #endif
  220.     }
  221.  
  222. /* Add user-specified directory(s) to auto_path */
  223.  
  224.     if (auto_path != NULL) {
  225.     Tcl_SetVar(interp, "dir", auto_path, 0);
  226.     tcl_cmd(interp, "set auto_path \"$dir $auto_path\"");
  227.     }
  228.  
  229. /* Rename "exit" to "tkexit", and insert custom exit handler */
  230.  
  231.     tcl_cmd(interp, "rename exit tkexit");
  232.  
  233.     Tcl_CreateCommand(interp, "exit", plExitCmd,
  234.                       (ClientData) main, (void (*)(ClientData)) NULL);
  235.  
  236.     return TCL_OK;
  237. }
  238.  
  239. /*----------------------------------------------------------------------*\
  240.  * plExitCmd
  241.  *
  242.  * PLplot/Tk extension command -- handle exit.
  243.  * The reason for overriding the normal exit command is so we can tell the
  244.  * client to abort.
  245. \*----------------------------------------------------------------------*/
  246.  
  247. static int
  248. plExitCmd(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
  249. {
  250.     int value = 0;
  251.  
  252. /* Print error message if one given */
  253.  
  254.     if (interp->result != NULL && interp->result[0] != '\0')
  255.     fprintf(stderr, "%s\n", interp->result);
  256.  
  257. /* Best to check the syntax before proceeding */
  258.  
  259.     if ((argc != 1) && (argc != 2)) {
  260.     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
  261.              " ?returnCode?\"", (char *) NULL);
  262.     return TCL_ERROR;
  263.     }
  264.     if ((argc != 1) && (Tcl_GetInt(interp, argv[1], &value) != TCL_OK)) {
  265.     Tcl_AppendResult(interp, "non-integer return code: \"", argv[1],
  266.              "\"", (char *) NULL);
  267.     return TCL_ERROR;
  268.     }
  269.  
  270. /* If client exists, tell it to self destruct */
  271.  
  272.     if (client_name != NULL) {
  273.     client_name = NULL;
  274.     Tcl_VarEval(interp, "send $client after 1 abort", (char **) NULL);
  275.     }
  276.     else if (client_port != NULL) {
  277.     client_port = NULL;
  278.     Tcl_VarEval(interp, "dp_RDO $client abort", (char **) NULL);
  279.     }
  280.  
  281. /* Now really exit */
  282.  
  283.     return Tcl_VarEval(interp, "tkexit", argv[1], (char **) NULL);
  284. }
  285.  
  286. /*----------------------------------------------------------------------*\
  287. * tcl_cmd
  288. *
  289. * Evals the specified command, aborting on an error.
  290. \*----------------------------------------------------------------------*/
  291.  
  292. static void
  293. tcl_cmd(Tcl_Interp *interp, char *cmd)
  294. {
  295.     int result;
  296.  
  297.     dbug_enter("tcl_cmd");
  298. #ifdef DEBUG_ENTER
  299.     fprintf(stderr, "plserver: evaluating command %s\n", cmd);
  300. #endif
  301.  
  302.     result = Tcl_VarEval(interp, cmd, (char **) NULL);
  303.     if (result != TCL_OK) {
  304.     Tcl_Eval(interp, "exit");
  305.     exit(1);
  306.     }
  307. }
  308.