home *** CD-ROM | disk | FTP | other *** search
/ Education Sampler 1992 [NeXTSTEP] / Education_1992_Sampler.iso / Programming / Source / winterp-1.13 / src-server / winterp.c.orig < prev    next >
Encoding:
Text File  |  1991-10-05  |  53.3 KB  |  1,374 lines

  1. /* -*-C-*-
  2. ********************************************************************************
  3. *
  4. * File:         winterp.c
  5. * RCS:          $Header: winterp.c,v 1.13 91/04/17 19:44:34 mayer Exp $
  6. * Description:  WINTERP main() file.
  7. * Author:       Niels Mayer, HPLabs
  8. * Created:      Sat Jun 10 02:15:35 1989
  9. * Modified:     Fri Oct  4 20:21:05 1991 (Niels Mayer) mayer@hplnpm
  10. * Language:     C
  11. * Package:      N/A
  12. * Status:       X11r5 contrib tape release
  13. *
  14. * WINTERP Copyright 1989, 1990, 1991 Hewlett-Packard Company (by Niels Mayer).
  15. * XLISP version 2.1, Copyright (c) 1989, by David Betz.
  16. *
  17. * Permission to use, copy, modify, distribute, and sell this software and its
  18. * documentation for any purpose is hereby granted without fee, provided that
  19. * the above copyright notice appear in all copies and that both that
  20. * copyright notice and this permission notice appear in supporting
  21. * documentation, and that the name of Hewlett-Packard and David Betz not be
  22. * used in advertising or publicity pertaining to distribution of the software
  23. * without specific, written prior permission.  Hewlett-Packard and David Betz
  24. * make no representations about the suitability of this software for any
  25. * purpose. It is provided "as is" without express or implied warranty.
  26. *
  27. * HEWLETT-PACKARD AND DAVID BETZ DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
  28. * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  29. * IN NO EVENT SHALL HEWLETT-PACKARD NOR DAVID BETZ BE LIABLE FOR ANY SPECIAL,
  30. * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  31. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  32. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  33. * PERFORMANCE OF THIS SOFTWARE.
  34. *
  35. * See ./winterp/COPYRIGHT for information on contacting the authors.
  36. * Please send modifications, improvements and bugfixes to mayer@hplabs.hp.com
  37. * Post XLISP-specific questions/information to the newsgroup comp.lang.lisp.x
  38. *
  39. ********************************************************************************
  40. */
  41. static char rcs_identity[] = "@(#)$Header: winterp.c,v 1.13 91/04/17 19:44:34 mayer Exp $";
  42.  
  43. #include <stdio.h>
  44. #include <stdlib.h>        /* for unlink(), getenv(), etc */
  45. #include <ctype.h>
  46.  
  47. #include "../src-server/config.h" /* define DEFAULT_UNIX_SOCKET_FILEPATH DEFAULT_UNIX_SOCKET_FILEPATH_ENVVAR, etc */
  48.  
  49. #if (defined(WINTERP_WANT_INET_SERVER) || defined(WINTERP_WANT_UNIX_SERVER))
  50. #include <sys/types.h>
  51. #include <sys/socket.h>
  52. #endif                /* (defined(WINTERP_WANT_INET_SERVER) || defined(WINTERP_WANT_UNIX_SERVER)) */
  53.  
  54. #ifdef WINTERP_WANT_INET_SERVER
  55. #include <netinet/in.h>
  56. #include <netdb.h>
  57. #endif                /* WINTERP_WANT_INET_SERVER */
  58.  
  59. #ifdef WINTERP_WANT_UNIX_SERVER
  60. #include <sys/un.h> /* for AF_UNIX sockets */
  61. #endif                /* WINTERP_WANT_UNIX_SERVER */
  62.  
  63. #include <X11/Intrinsic.h>
  64. #include <X11/Shell.h>
  65. #include <Xm/Xm.h>
  66.  
  67. #include "winterp.h"
  68.  
  69. /* this must come after winterp.h since WINTERP_MOTIF_11 may be def'd there */
  70. #ifdef WINTERP_MOTIF_11
  71. #include <Xm/Protocols.h>    /* <Xm/Protocols.h> location seems to have moved in 1.1 */
  72. #else
  73. #include <X11/Protocols.h>
  74. #endif                /* WINTERP_MOTIF_11 */
  75.  
  76. #include "user_prefs.h"
  77. #include "xlisp/xlisp.h"
  78.  
  79.  
  80. /* forward declarations */
  81. static void Read_Eval_Print();
  82. static int  Read_From_Stream_Eval_And_Print();
  83. #ifdef WINTERP_WANT_INET_SERVER
  84. static void AF_INET_Read_Eval_Print();
  85. static int  Initialize_AF_INET_Server_Socket();
  86. #endif                /* WINTERP_WANT_INET_SERVER */
  87. #ifdef WINTERP_WANT_UNIX_SERVER
  88. static void AF_UNIX_Read_Eval_Print();
  89. static int  Initialize_AF_UNIX_Server_Socket();
  90. #endif                /* WINTERP_WANT_UNIX_SERVER */
  91. static void Winterp_Xtoolkit_Error_Handler();
  92. static void Winterp_Xtoolkit_Warning_Handler();
  93. static int  Winterp_Xlib_Error_Handler();
  94. void        Winterp_Application_Shell_WMDelete_Callback();
  95.  
  96. /* global variables */
  97. jmp_buf        top_level;
  98. CONTEXT        cntxt;
  99. int        read_eval_print_just_called;
  100. int        lisp_reader_hit_eof;
  101. char*        app_name = NULL;
  102. char*        app_class = NULL;
  103. #ifdef WINTERP_WANT_INET_SERVER
  104. static int    client_AF_INET_listen_socket = NULL;
  105. #endif                /* WINTERP_WANT_INET_SERVER */
  106. #ifdef WINTERP_WANT_UNIX_SERVER
  107. static int    client_AF_UNIX_listen_socket = NULL;
  108. #endif                /* WINTERP_WANT_UNIX_SERVER */
  109. Widget        toplevel_Wgt = NULL;
  110. XtAppContext    app_context = NULL;
  111. Display*    display;
  112. Window        root_win;
  113. Screen*        screen;
  114. Colormap    colormap;
  115. Atom        wm_delete_atom;
  116. Pixel        default_foreground_pixel, default_background_pixel;
  117. USER_PREFS_DATA user_prefs;    /* extern declared in user_prefs.h, really here */
  118. char        temptext[BUFSIZ]; /* a temporary text buffer, for sprintf() */
  119. Arg        _args[10];    /* for XtSetArg() macros in winterp.h */
  120. int        _num_args;    /* for XtSetArg() macros in winterp.h */
  121.  
  122. /* 
  123.  * Data on how user-customization resources are interpreted:
  124.  * this must be kept up to date with data structure USER_PREFS_DATA_PTR 
  125.  * in user_prefs.h
  126.  */
  127. static XtResource resources[] = {
  128.   /*
  129.    * The name of the file to load to initialize xlisp.
  130.    */
  131.   {"lispInitFile", "LispInitFile",
  132.      XmRString, sizeof(String),
  133.      XtOffset(USER_PREFS_DATA_PTR, lisp_init_file),
  134.      XmRString, (XtPointer) DEFAULT_LISP_INIT_FILE},
  135.  
  136.   /*
  137.    * The name of the file to output lisp transactions.
  138.    */
  139.   {"lispTranscriptFile", "LispTranscriptFile",
  140.      XmRString, sizeof(String),
  141.      XtOffset(USER_PREFS_DATA_PTR, lisp_transcript_file),
  142.      XmRString, (XtPointer) DEFAULT_LISP_TRANSCRIPT_FILE},
  143.  
  144.   /*
  145.    * The name of the default directory for 'load'. This is only
  146.    * used in cases where 'load' wasn't supplied a full
  147.    * filepath (i.e. a path beginning with '/' or '.').
  148.    *
  149.    * Note that "lispLibDir" should be the path to an existing directory with
  150.    * a trailing '/', e.g. "/usr/local/winterp/lisp-lib/". The default is
  151.    * "./" so as to simulate Xlisp's default load behavior.
  152.    * (See also w_utils.c:Wut_Prim_LOAD()).
  153.    */
  154.   {"lispLibDir", "LisplibDir",
  155.      XmRString, sizeof(String),
  156.      XtOffset(USER_PREFS_DATA_PTR, lisp_lib_dir),
  157.      XmRString, (XtPointer) DEFAULT_LISP_LIB_DIR},
  158.   
  159.   /*
  160.    * Setting this boolean to FALSE will allow WINTERP to startup
  161.    * without printing lots of output.
  162.    */
  163.   {"enableInitMsgs", "EnableInitMsgs",
  164.      XmRBoolean, sizeof(Boolean),
  165.      XtOffset(USER_PREFS_DATA_PTR, enable_init_msgs),
  166.      XmRImmediate, (XtPointer) DEFAULT_ENABLE_INIT_MSGS},
  167.  
  168. #ifdef WINTERP_WANT_INET_SERVER
  169.   /*
  170.    * The port number of the widget interpreter lisp server.
  171.    */
  172.   {"servicePort", "ServicePort",
  173.      XmRInt, sizeof(int),
  174.      XtOffset(USER_PREFS_DATA_PTR, service_port),
  175.      XmRImmediate, (XtPointer) DEFAULT_INET_SERVICE_PORT},
  176.  
  177.   /*
  178.    * The service name of the widget interpreter lisp server.
  179.    */
  180.   {"serviceName", "ServiceName",
  181.      XmRString, sizeof(String),
  182.      XtOffset(USER_PREFS_DATA_PTR, service_name),
  183.      XmRString, (XtPointer) DEFAULT_INET_SERVICE_NAME},
  184.  
  185.   /*
  186.    * Setting this boolean to TRUE will start up WINTERP so that
  187.    * it will accept input from its INET Domain Server. Those worried about
  188.    * security when running winterp-based applications will want to
  189.    * set this to FALSE in the application defaults file for the application.
  190.    */
  191.   {"enableInetServer", "enableInetServer",
  192.      XmRBoolean, sizeof(Boolean),
  193.      XtOffset(USER_PREFS_DATA_PTR, enable_AF_INET_server),
  194.      XmRImmediate, (XtPointer) DEFAULT_ENABLE_INET_SERVER},
  195. #endif                /* WINTERP_WANT_INET_SERVER */
  196.  
  197. #ifdef WINTERP_WANT_UNIX_SERVER
  198.   /*
  199.    * Setting this boolean to FALSE will start up WINTERP without
  200.    * it's Unix Domain server. Those worried about security when running
  201.    * winterp-based applications on a multi-user machine will want
  202.    * to set this in the  application defaults file for the application.
  203.    */
  204.   {"enableUnixServer", "enableUnixServer",
  205.      XmRBoolean, sizeof(Boolean),
  206.      XtOffset(USER_PREFS_DATA_PTR, enable_AF_UNIX_server),
  207.      XmRImmediate, (XtPointer) DEFAULT_ENABLE_UNIX_SERVER},
  208.  
  209.   /*
  210.    * This is set to the full pathname for the AF_UNIX domain socket-file
  211.    */
  212.   {"unixSocketFilepath", "UnixSocketFilepath",
  213.      XmRString, sizeof(String),
  214.      XtOffset(USER_PREFS_DATA_PTR, unix_socket_filepath),
  215.      XmRString, (XtPointer) DEFAULT_UNIX_SOCKET_FILEPATH},
  216. #endif                /* WINTERP_WANT_UNIX_SERVER */
  217.  
  218.   /*
  219.    * Setting this boolean to FALSE will start up WINTERP
  220.    * with the Xtoolkit's default XtError handler -- any XtErrors
  221.    * will cause WINTERP to exit. By default, this is TRUE,
  222.    * which means that a lisp error will be signalled, and the
  223.    * call-sequence (or callback) that caused the error will
  224.    * terminate, however WINTERP will be able to execute other callbacks,
  225.    * input from the XLISP eval-server, etc. For interactive
  226.    * use, I suggest leaving this resource at the default TRUE;
  227.    * for delivered applications, you probably want to set this to
  228.    * FALSE.
  229.    */
  230.   {"enableXtErrorBreak", "EnableXtErrorBreak",
  231.      XmRBoolean, sizeof(Boolean),
  232.      XtOffset(USER_PREFS_DATA_PTR, enable_XtError_break),
  233.      XmRImmediate, (XtPointer) DEFAULT_ENABLE_XT_ERROR_BREAK},
  234.  
  235.   /*
  236.    * Setting this boolean to FALSE will start up WINTERP
  237.    * with the Xtoolkit's default XtWarning handler -- any XtWarnings
  238.    * will just cause a message to be printed, execution will continue.
  239.    * By default, this is FALSE which means that a warning message will get
  240.    * printed, but Lisp will not break. This is set to FALSE by default
  241.    * because some XtWarnings were not meant to be broken out of and can
  242.    * leave Motif in a weird state, causing possible subsequent core-dumps.
  243.    * If you know don't know what you're doing I suggest leaving this
  244.    * resource at the default FALSE value.
  245.    */
  246.   {"enableXtWarningBreak", "EnableXtWarningBreak",
  247.      XmRBoolean, sizeof(Boolean),
  248.      XtOffset(USER_PREFS_DATA_PTR, enable_XtWarning_break),
  249.      XmRImmediate, (XtPointer) DEFAULT_ENABLE_XT_WARNING_BREAK},
  250.  
  251.   /*
  252.    * Setting this boolean to FALSE will start up WINTERP
  253.    * with the Xlib's default Error handler -- any XErrors
  254.    * will cause WINTERP to exit. By default, this is TRUE,
  255.    * which means that a lisp error will be signalled, and the
  256.    * call-sequence (or callback) that caused the error will
  257.    * terminate, however WINTERP will be able to execute other callbacks,
  258.    * input from the XLISP eval-server, etc. For interactive
  259.    * use, I suggest leaving this resource at the default TRUE;
  260.    * for delivered applications, you probably want to set this to
  261.    * FALSE.
  262.    */
  263.   {"enableXErrorBreak", "EnableXErrorBreak",
  264.      XmRBoolean, sizeof(Boolean),
  265.      XtOffset(USER_PREFS_DATA_PTR, enable_XError_break),
  266.      XmRImmediate, (XtPointer) DEFAULT_ENABLE_X_ERROR_BREAK}
  267. };
  268.  
  269. /*
  270.  * Table indicating how to set-from-the-command-line the application-specific
  271.  * resources specified in resources[] above.
  272.  */
  273. static XrmOptionDescRec commandline_options_table[] = {
  274.   {"-init_file",    ".lispInitFile",    XrmoptionSepArg, NULL},
  275.   {"-transcript_file",    ".lispTranscriptFile",    XrmoptionSepArg, NULL},
  276.   {"-lib_dir",        ".lispLibDir",        XrmoptionSepArg, NULL},
  277.   {"-no_init_msgs",    ".enableInitMsgs",    XrmoptionNoArg, "false"},
  278.   {"-enable_init_msgs",    ".enableInitMsgs",    XrmoptionNoArg, "true"},
  279. #ifdef WINTERP_WANT_INET_SERVER
  280.   {"-serv_port",    ".servicePort",        XrmoptionSepArg, NULL},
  281.   {"-serv_name",    ".serviceName",        XrmoptionSepArg, NULL},
  282.   {"-no_inet_server",    ".enableInetServer",    XrmoptionNoArg, "false"},
  283.   {"-enable_inet_server",".enableInetServer",    XrmoptionNoArg, "true"},
  284. #endif                /* WINTERP_WANT_INET_SERVER */
  285. #ifdef WINTERP_WANT_UNIX_SERVER
  286.   {"-no_unix_server",    ".enableUnixServer",    XrmoptionNoArg, "false"},
  287.   {"-enable_unix_server",".enableUnixServer",    XrmoptionNoArg, "true"},
  288.   {"-unix_socket_file",    ".unixSocketFilepath",    XrmoptionSepArg, NULL},
  289. #endif                /* WINTERP_WANT_UNIX_SERVER */
  290.   {"-no_xterr_brk",    ".enableXtErrorBreak",    XrmoptionNoArg, "false"},
  291.   {"-enable_xterr_brk",    ".enableXtErrorBreak",    XrmoptionNoArg, "true"},
  292.   {"-no_xtwarn_brk",    ".enableXtWarningBreak",XrmoptionNoArg, "false"},
  293.   {"-enable_xtwarn_brk",".enableXtWarningBreak",XrmoptionNoArg, "true"},
  294.   {"-no_xerr_brk",    ".enableXErrorBreak",    XrmoptionNoArg, "false"},
  295.   {"-enable_xerr_brk",    ".enableXErrorBreak",    XrmoptionNoArg, "true"}
  296. };
  297.  
  298. /*
  299.  * Setup an action table for winterp. Note that action procedure "Lisp"
  300.  * is a special action procedure that calls the lisp evaluator on the
  301.  * parameters of the action. A translation like
  302.  * "Ctrl<Key>K: Lisp(quack 1 2 3)" will evaluate '(quack 1 2 3)'
  303.  */
  304. extern void Wtx_Winterp_Lisp_Action_Proc(); /* w_txlations.c */
  305. static XtActionsRec winterp_action_table[] = {
  306.   {"Lisp", Wtx_Winterp_Lisp_Action_Proc}
  307. };
  308.  
  309.  
  310. /*******************************************************************************
  311.  * main - the main routine
  312.  ******************************************************************************/
  313. main(argc,argv)
  314.   int argc; char *argv[];
  315. {
  316.   extern LVAL true;        /* from xlisp/xlglob.c */
  317.   extern LVAL s_evalhook,s_applyhook; /* from xlisp/xlglob.c */
  318.   extern FILE* osaopen();    /* from xlisp/unixstuff.c */
  319.   extern FILE *tfp;        /* from xlisp/xlglob.c */
  320.   extern int xldebug;        /* from xlisp/xlglob.c */
  321.   extern int xltrcindent;    /* from xlisp/xlglob.c */
  322.   extern LVAL Wshl_WidgetID_To_WIDGETOBJ(); /* wc_SHELL.c */
  323.   extern void Wfu_Sanity_Check(); /* w_funtab.c */
  324.   char** original_argv;
  325.   int    original_argc;
  326.   XEvent event;
  327.  
  328.  
  329.   /*
  330.    * Trim directory path off of program name.
  331.    */
  332.   if ((app_name = rindex(argv[0], '/')) == NULL)
  333.     app_name = argv[0];
  334.   else
  335.     app_name++;
  336.  
  337.   /*
  338.    * Trim "Login Shell" from the program name
  339.    */
  340.   if (*app_name == '-')
  341.     app_name++;
  342.  
  343.   /*
  344.    * sanity check to ensure that the number of pointers to funtab entries in
  345.    * w_funtab.h correspond to the number of entries in w_funtab.c:funtab[].
  346.    */
  347.   Wfu_Funtab_Sanity_Check();
  348.  
  349.   /* 
  350.    * Make a copy of argv,argc to pass into
  351.    * 'toplevel_Wgt = XtAppCreateShell(...applicationShellWidgetClass...)'
  352.    * This is used by session managers so as to provide arguments to restart
  353.    * the application with the same arguments as the current invocation.
  354.    * We must make a copy here because XtOpenDisplay() modifies argv and argc
  355.    * and we twiddle argc/argv below.
  356.    */
  357.   original_argv = (char**) XtMalloc((unsigned) (argc + 1) * sizeof(char*));
  358.   for (original_argc = 0 ; original_argc < argc ; original_argc++)
  359.     original_argv[original_argc] = argv[original_argc];
  360.   original_argv[original_argc] = NULL;
  361.   
  362.   /*
  363.    * Special case the first argument on the command line... 
  364.    * If it is "-class <classname>", then use the next argument <classname> as the
  365.    * application class.  This kludge allows us to run winterp using a variable
  366.    * application class name, thus allowing us to use specify variable APP-DEFAULT
  367.    * files. (Hack submitted by Eric Blossom of HP Western Response Center Labs.)
  368.    */
  369.   app_class = "Winterp";
  370.   if ((argc >= 3) && (strcmp(argv[1], "-class") == 0)) {
  371.     app_class = argv[2];
  372.     argv[2] = argv[0];
  373.     argv += 2;
  374.     argc -= 2;
  375.   }
  376.  
  377.   /* 
  378.    * Initialize the toolkit
  379.    */
  380.   XtToolkitInitialize();
  381.  
  382.   /* 
  383.    * Initialize Resource converters: normally, these functions are called 
  384.    * from XtCreateWidget(), XtCreateManagedWidget(),  XtCreatePopupShell(), and
  385.    * XtAppCreateShell(); they only get called the first time you create a
  386.    * widget of class Primitive or Manager because they're called from the 
  387.    * ClassInitialize() procedure. With the way WINTERP's automatic resource
  388.    * converters work, you can end up asking for a resource conversion to occur
  389.    * before any ClassInitialize() procs are called, and that would cause errors
  390.    * like "X Toolkit Warning: No type converter registered for 'String' to ..."
  391.    */
  392.   XmRegisterConverters();    /* from Xm/ResConvert.c -- used in Manager, Primitive and Vendor ClassInitialize() */
  393.   _XmRegisterPixmapConverters(); /* from Xm/Visual.c -- used in Manager, Primitive and Vendor ClassInitialize() */
  394.  
  395.   /*
  396.    * Sanity check to ensure that the version of the Motif toolkit libraries
  397.    * used correspond to the Motif toolkit header <Xm/Xm.h>. This test is only valid
  398.    * after XmRegisterConverters() has been called.
  399.    */
  400.   if (xmUseVersion != XmVersion) { /* XmVersion def'd and xmUseVersion externed in <Xm/Xm.h> */
  401.     (void) fprintf(stderr, "%s: Fatal error: application must be recompiled with <Xm/Xm.h> matching libXm.a\n", app_name);
  402.     (void) fprintf(stderr, "\t\t(header version == %d, library version == %d)\n", XmVersion, xmUseVersion);
  403.     exit(1);
  404.   }
  405.  
  406.   app_context = XtCreateApplicationContext();
  407.   display = XtOpenDisplay(app_context, (String) NULL, app_name, app_class,
  408.               commandline_options_table, XtNumber(commandline_options_table),
  409.               &argc, argv);
  410.   if (!display)
  411.     xlfatal("Can't open display -- XtOpenDisplay() failed.");
  412.  
  413.   if (argc > 1) {        /* if argc!=0, then there are invalid arguments that didn't get parsed by XtOpenDisplay() */
  414.     (void) fprintf (stderr, "usage: %s [-class <classname>] [-init_file <file.lsp>]\n", app_name);
  415.     (void) fprintf (stderr, "\t[-transcript_file <file.out>] [-lib_dir <path-to-load-dir>]\n");
  416.     (void) fprintf (stderr, "\t[-no_init_msgs] [-enable_init_msgs]\n");
  417. #ifdef WINTERP_WANT_INET_SERVER
  418.     (void) fprintf (stderr, "\t[-serv_port <portnum>] [-serv_name <servname>]\n");
  419.     (void) fprintf (stderr, "\t[-no_inet_server] [-enable_inet_server]\n");
  420. #endif                /* WINTERP_WANT_INET_SERVER */
  421. #ifdef WINTERP_WANT_UNIX_SERVER
  422.     (void) fprintf (stderr, "\t[-no_unix_server] [-enable_unix_server]\n");
  423.     (void) fprintf (stderr, "\t[-unix_socket_file <socket-filepath>]\n");
  424. #endif                /* WINTERP_WANT_UNIX_SERVER */
  425.     (void) fprintf (stderr, "\t[-no_xterr_brk] [-enable_xterr_brk]\n");
  426.     (void) fprintf (stderr, "\t[-no_xtwarn_brk] [-enable_xtwarn_brk]\n");
  427.     (void) fprintf (stderr, "\t[-no_xerr_brk] [-enable_xerr_brk]\n");
  428.     (void) fprintf (stderr, "\t[... Xtoolkit options ...]\n");
  429.     (void) fprintf (stderr, "\tNote: if you wish to use the -class option it must be the\n");
  430.     (void) fprintf (stderr, "\tfirst argument following %s.\n", app_name);
  431.     xlfatal("Invalid command-line arguments.");
  432.   }
  433.  
  434.   /* 
  435.    * Set close-on-exec on file descriptor of display connection. Otherwise, any
  436.    * child processes started up by WINTERP will inherit the file-descriptor, and
  437.    * windows will not disappear after WINTERP is killed while child processes remain.
  438.    */
  439.   fcntl(ConnectionNumber(display), F_SETFD, 1);
  440.  
  441.   /*
  442.    * initialize some global variables used throughout this program.
  443.    * NOTE: if winterp ever gets changed to use application contexts enabling
  444.    * multiple displays, screens, etc, then we'll have to make some major changes
  445.    * here, and to any primitives that use these values.
  446.    */
  447.   root_win = DefaultRootWindow(display);
  448.   screen = DefaultScreenOfDisplay(display);
  449.   colormap = XDefaultColormapOfScreen(screen);
  450.   wm_delete_atom = XmInternAtom(display, "WM_DELETE_WINDOW", FALSE);
  451.  
  452.   /*
  453.    * Setup action table for accelerators and translations.
  454.    */
  455.   XtAppAddActions(app_context, winterp_action_table, XtNumber(winterp_action_table));
  456.   
  457.   /* 
  458.    * We need toplevel_Wgt so that we can have around a "default" set of X
  459.    * structures (colors, graphics contexts etc) for use by XtConvert()...
  460.    * this is a kludge. We also need this widget around in order to set
  461.    * Winterp-specific application resources in structure user_prefs.
  462.    *
  463.    * So as not to bother people with an uneccesary window, we create the
  464.    * window at location +1+1, then unmap it.
  465.    */
  466.   ARGLIST_RESET();
  467.   ARGLIST_ADD(XmNdeleteResponse, XmDO_NOTHING);    /* we handle wm deletion (f.kill) w/ XmAddWMProtocolCallback() below. */
  468.   ARGLIST_ADD(XmNscreen, (XtArgVal) screen);
  469.   ARGLIST_ADD(XmNargc, (XtArgVal) original_argc);
  470.   ARGLIST_ADD(XmNargv, (XtArgVal) original_argv);
  471.   ARGLIST_ADD(XmNgeometry, (XtArgVal) "10x10+1+1"); /* we don't want user to have to place this window, so give it a location; giving size prevents "Error: Shell widget winterp has zero width and/or height" */
  472.   toplevel_Wgt = XtAppCreateShell(app_name, app_class, applicationShellWidgetClass, display, ARGLIST());
  473.   XmAddWMProtocolCallback(toplevel_Wgt, wm_delete_atom, Winterp_Application_Shell_WMDelete_Callback, NULL);
  474.   XtGetApplicationResources(toplevel_Wgt, &user_prefs, resources, XtNumber(resources), NULL, 0); /* place application resources in user_prefs global struct. */
  475.   XtRealizeWidget(toplevel_Wgt); /* give the order to create the windows, etc. */
  476.   XmUpdateDisplay(toplevel_Wgt); /* after this executes, the widget will get realized, windows created, etc. */
  477.   XtUnmapWidget(toplevel_Wgt);    /* once the windows are created by XtRealizeWidget()/XmUpdateDisplay(), we may hide the window by unmapping */
  478.   XtFree((char*) original_argv); /* Motif makes a copy of this upon setting XmNargv resource however, if this is placed after XtAppCreateShell() call, you get a coredump... */
  479.  
  480.   /*
  481.    * Get Xtoolkit's default foreground and background Pixels, set globals
  482.    * to these values.
  483.    */
  484.   {
  485.     XrmValue from, to;
  486.  
  487.     from.size = (unsigned int) strlen(XtDefaultForeground) + 1;
  488.     from.addr = (XtPointer) XtDefaultForeground;
  489.     to.size = (unsigned int) sizeof(Pixel);
  490.     to.addr = (XtPointer) &default_foreground_pixel;
  491.     XtConvert(toplevel_Wgt, XmRString, &from, XmRPixel, &to);
  492.     if (to.addr == NULL)    /* error if conversion failed */
  493.       xlfatal("XtConvert() couldn't convert XtDefaultForeground to XmRPixel.");
  494.  
  495.     from.size = (unsigned int) strlen(XtDefaultBackground) + 1;
  496.     from.addr = (XtPointer) XtDefaultBackground;
  497.     to.size = (unsigned int) sizeof(Pixel);
  498.     to.addr = (XtPointer) &default_background_pixel;
  499.     XtConvert(toplevel_Wgt, XmRString, &from, XmRPixel, &to);
  500.     if (to.addr == NULL)    /* error if conversion failed */
  501.       xlfatal("XtConvert() couldn't convert XtDefaultBackground to XmRPixel.");
  502.   }
  503.  
  504. #ifdef WINTERP_WANT_INET_SERVER
  505.   if (user_prefs.enable_AF_INET_server) {
  506.     /*
  507.      * get a socket to listen on. when it's selected, call AF_INET_Read_Eval_Print()
  508.      * to open a connection socket, process the client request, and close the socket
  509.      */
  510.     client_AF_INET_listen_socket = Initialize_AF_INET_Server_Socket();
  511.     (void) XtAppAddInput(app_context, client_AF_INET_listen_socket, XtInputReadMask,
  512.              AF_INET_Read_Eval_Print, NULL);
  513.   }
  514. #endif                /* WINTERP_WANT_INET_SERVER */
  515.  
  516. #ifdef WINTERP_WANT_UNIX_SERVER
  517.   if (user_prefs.enable_AF_UNIX_server) {
  518.     /*
  519.      * get a socket to listen on. when it's selected, call AF_UNIX_Read_Eval_Print()
  520.      * to open a connection socket, process the client request, and close the socket
  521.      */
  522.     client_AF_UNIX_listen_socket = Initialize_AF_UNIX_Server_Socket();
  523.     (void) XtAppAddInput(app_context, client_AF_UNIX_listen_socket, XtInputReadMask,
  524.              AF_UNIX_Read_Eval_Print, NULL);
  525.   }
  526. #endif                /* WINTERP_WANT_UNIX_SERVER */
  527.  
  528.  
  529.   /*
  530.    * Setup Xlib and Xtoolkit warning and error handlers so that errors inside
  531.    * the Xtoolkit will call xlerror().
  532.    */
  533.   if (user_prefs.enable_XtError_break)
  534.     (void) XtAppSetErrorHandler(app_context, Winterp_Xtoolkit_Error_Handler);
  535.   if (user_prefs.enable_XtWarning_break)
  536.     (void) XtAppSetWarningHandler(app_context, Winterp_Xtoolkit_Warning_Handler);
  537.   if (user_prefs.enable_XError_break)
  538.     XSetErrorHandler(Winterp_Xlib_Error_Handler);
  539.  
  540.   if (user_prefs.enable_init_msgs) {
  541.     (void) printf("================================================================================\n");
  542. #ifdef WINTERP_MOTIF_113
  543.     (void) printf("WINTERP -- Motif 1.1.3 Widget INTERPreter\n");
  544. #else /* !defined(WINTERP_MOTIF_113) */
  545. #ifdef WINTERP_MOTIF_111
  546.     (void) printf("WINTERP -- Motif 1.1.1 Widget INTERPreter\n");
  547. #else /* !defined(WINTERP_MOTIF_111) --> Plain old 1.0 or 1.1 */
  548.     (void) printf("WINTERP -- Motif %d.%d Widget INTERPreter\n", XmVERSION, XmREVISION); /* from <Xm/Xm.h> */
  549. #endif /* WINTERP_MOTIF_111 */
  550. #endif /* WINTERP_MOTIF_113 */
  551.     (void) printf("\tby Niels P. Mayer (mayer@hplabs.hp.com).\n");
  552.     (void) printf("\tWINTERP version %d.%d, Copyright (c) 1989-1991 Hewlett-Packard Company\n",
  553.           WINTERP_VERSION_INT, WINTERP_REVISION_INT); /* from winterp.h */
  554.     (void) printf("\tXLISP version %d.%d, Copyright (c) 1985-1989, by David Betz\n\n",
  555.           XLISP_VERSION_INT, XLISP_REVISION_INT); /* from xlisp/xlisp.h */
  556.   }
  557.  
  558.   /* 
  559.    * Startup XLISP
  560.    */
  561.   if (user_prefs.enable_init_msgs)
  562.     osinit("Initializing ...\n");
  563.   else 
  564.     osinit("");
  565.  
  566.   /* setup initialization error handler */
  567.   xlbegin(&cntxt, CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL, (LVAL)1);
  568.   if (setjmp(cntxt.c_jmpbuf))
  569.     xlfatal("Fatal XLISP initialization error.");
  570.   if (setjmp(top_level))
  571.     xlfatal("XLISP RESTORE not allowed during initialization.");
  572.  
  573.   /* initialize xlisp */
  574.   xlinit();            /* xlisp/xlinit.c */
  575.  
  576.   /* initialize WINTERP modules */
  577.   Wso_Init();            /* w_savedobjs.c */
  578.   Wres_Init();            /* w_resources.c */
  579.   Wxms_Init();            /* w_XmString.c */
  580.   Wcb_Init();            /* w_callbacks.c */
  581.   Wto_Init();            /* w_timeouts.c */
  582.   Wtx_Init();            /* w_txlations.c */
  583.   Weh_Init();            /* w_evnthndlr.c */
  584.   Wxm_Init();            /* w_libXm.c */
  585.  
  586.   /* 
  587.    * The following create interfaces to all the motif widget-classes via
  588.    * xlisp classes, by calling Wcls_Create_Subclass_Of_WIDGET_CLASS()
  589.    * with o_WIDGET_CLASS (def'd in Wc_WIDGET_Init()) as their superclass.
  590.    * Methods on the specific widget classes correspond to 
  591.    * special operations pertaining to that class, and not to others. 
  592.    * These derived classes may override the 'Widget_Class' :isnew method 
  593.    * for cases where motif "convenience" functions are used to create the 
  594.    * widget. Additionally, since different classes generate different callback
  595.    * structures, certain widgetclasses may override the metaclass' :set_callback
  596.    * and :add_callback methods so as to allow dereferencing of the appropriate
  597.    * callback structure elements.
  598.    */
  599.   Wc_WIDGET_Init();        /* WIDGET_CLASS metaclass */
  600.   Wc_SHELL_Init();        /* SHELL and POPUP_SHELL metaclasses */
  601.   Wc_ArrowB_Init();
  602.   Wc_BulletinB_Init();
  603.   Wc_CascadeB_Init();
  604.   Wc_Command_Init();
  605.   Wc_DrawingA_Init();
  606.   Wc_DrawnB_Init();
  607.   Wc_FileSB_Init();
  608.   Wc_Form_Init();
  609.   Wc_Frame_Init();
  610.   Wc_Label_Init();
  611.   Wc_List_Init();
  612.   Wc_MainW_Init();
  613.   Wc_MessageB_Init();
  614.   Wc_PanewW_Init();
  615.   Wc_PushB_Init();
  616.   Wc_RowColumn_Init();
  617.   Wc_Scale_Init();
  618.   Wc_ScrollBar_Init();
  619.   Wc_ScrolledW_Init();
  620.   Wc_SelectioB_Init();
  621.   Wc_Separator_Init();
  622.   Wc_Text_Init();
  623.   Wc_ToggleB_Init();
  624. #ifdef HP_GRAPH_WIDGET
  625.   Wc_XmGraph_Init();
  626. #endif                /* HP_GRAPH_WIDGET */
  627.  
  628.   {
  629.     LVAL sym;
  630.  
  631.     /*
  632.      * Make the toplevel_Wgt accessible from lisp as global *TOPLEVEL_WIDGET*.
  633.      * This code must occur after calling Wc_SHELL_Init(), and preferably after
  634.      * every WINTERP widget class initializer is called.
  635.      */
  636.     sym = xlenter("*TOPLEVEL_WIDGET*");
  637.     setvalue(sym, Wshl_WidgetID_To_WIDGETOBJ(toplevel_Wgt));
  638.  
  639.     /*
  640.      * Make XLISP, WINTERP, and MOTIF version info available within interpreter.
  641.      */
  642.     sym = xlenter("*XLISP_VERSION*");
  643.     setvalue(sym, cvfixnum((FIXTYPE) XLISP_VERSION_INT)); /* XLISP_VERSION_INT from xlisp/xlisp.h */
  644.     sym = xlenter("*XLISP_REVISION*");
  645.     setvalue(sym, cvfixnum((FIXTYPE) XLISP_REVISION_INT)); /* XLISP_REVISION_INT from xlisp/xlisp.h */
  646.     sym = xlenter("*MOTIF_VERSION*");
  647.     setvalue(sym, cvfixnum((FIXTYPE) XmVERSION)); /* XmVERSION from <Xm/Xm.h> */
  648.     sym = xlenter("*MOTIF_REVISION*");
  649.     setvalue(sym, cvfixnum((FIXTYPE) XmREVISION)); /* XmREVISION from <Xm/Xm.h> */
  650.     sym = xlenter("*WINTERP_VERSION*");
  651.     setvalue(sym, cvfixnum((FIXTYPE) WINTERP_VERSION_INT)); /* WINTERP_VERSION_INT from winterp.h */
  652.     sym = xlenter("*WINTERP_REVISION*");
  653.     setvalue(sym, cvfixnum((FIXTYPE) WINTERP_REVISION_INT)); /* WINTERP_REVISION_INT from winterp.h  */
  654.   }
  655.  
  656.   xlend(&cntxt);
  657.  
  658.   /* reset the error handler */
  659.   xlbegin(&cntxt, CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL, true);
  660.  
  661.   /* open the transcript file */
  662.   if (user_prefs.lisp_transcript_file && (tfp = osaopen(user_prefs.lisp_transcript_file, "w")) == NULL) {
  663.     (void) sprintf(temptext, "error: can't open transcript file: \"%s\"",
  664.            user_prefs.lisp_transcript_file);
  665.     stdputstr(temptext);
  666.   }
  667.  
  668.   /* load file specified by resource "lispInitFile" (defaults to "initialize.lsp") */
  669.   if (setjmp(cntxt.c_jmpbuf) == 0) {
  670.     if (!xlload(user_prefs.lisp_init_file, user_prefs.enable_init_msgs, FALSE)) {
  671.       (void) sprintf(temptext,
  672.              "WINTERP warning -- couldn't load initialization file: \"%s\"\n\t\
  673. Check command-line argument \"-init_file\" or Xresource \".lispInitFile\"\n",
  674.              user_prefs.lisp_init_file);
  675.       stdputstr(temptext);
  676.     }
  677.   }
  678.  
  679.   if (user_prefs.enable_init_msgs) {
  680.  
  681. #ifdef WINTERP_WANT_INET_SERVER
  682.     if (user_prefs.enable_AF_INET_server) {
  683.       (void) printf("\nXLisp INET Domain eval-server ready for input");
  684.       if (user_prefs.service_port)
  685.     (void) printf(" on port %d .\n", user_prefs.service_port);
  686.       else
  687.     (void) printf(" using service=%s .\n", user_prefs.service_name);
  688.     }
  689. #endif                /* WINTERP_WANT_INET_SERVER */
  690.  
  691. #ifdef WINTERP_WANT_UNIX_SERVER
  692.     if (user_prefs.enable_AF_UNIX_server)
  693.       (void) printf("\nXLisp Unix Domain eval-server ready for input on socket %s .\n",
  694.             user_prefs.unix_socket_filepath);
  695. #endif                /* WINTERP_WANT_UNIX_SERVER */
  696.  
  697. #if (defined(WINTERP_WANT_INET_SERVER) && !defined(WINTERP_WANT_UNIX_SERVER))
  698.     if (user_prefs.enable_AF_INET_server)
  699.       (void) printf("Note: INPUT TO XLISP EVALUATOR CANNOT BE ENTERED HERE!! (see winterp.doc)\n");
  700. #endif
  701. #if (!defined(WINTERP_WANT_INET_SERVER) && defined(WINTERP_WANT_UNIX_SERVER))
  702.     if (user_prefs.enable_AF_UNIX_server)
  703.       (void) printf("Note: INPUT TO XLISP EVALUATOR CANNOT BE ENTERED HERE!! (see winterp.doc)\n");
  704. #endif
  705. #if (defined(WINTERP_WANT_INET_SERVER) && defined(WINTERP_WANT_UNIX_SERVER))
  706.     if ((user_prefs.enable_AF_INET_server) || (user_prefs.enable_AF_UNIX_server))
  707.       (void) printf("Note: INPUT TO XLISP EVALUATOR CANNOT BE ENTERED HERE!! (see winterp.doc)\n");
  708. #endif
  709.  
  710.     (void) printf("================================================================================\n");
  711.   }
  712.   
  713.   /* setup longjmp target for restore */
  714.   if (setjmp(top_level))
  715.     xlbegin(&cntxt, CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL, true);
  716.  
  717.   read_eval_print_just_called = TRUE; /* special initial cond */
  718.   lisp_reader_hit_eof = FALSE;
  719.  
  720.   /* Process X Events and Lisp client requests forever */
  721.   for (;;) {
  722.     /* 
  723.      * We need to setup a new error return only after each time that an XLISP 
  724.      * evaluation occurs. Therefore, we check for read_eval_print_just_called 
  725.      * (which is set by Read_Eval_Print()) and then clear it once the setjmp() 
  726.      * has been done. This avoids setting up an error return for each X event
  727.      * being processed in this loop. 
  728.      */
  729.     if (read_eval_print_just_called) {
  730.       read_eval_print_just_called = FALSE;
  731.       if (lisp_reader_hit_eof) 
  732.     break;
  733.       if (setjmp(cntxt.c_jmpbuf)) { /* longjmp target for error return */
  734.     setvalue(s_evalhook, NIL);
  735.     setvalue(s_applyhook, NIL);
  736.     xltrcindent = 0;
  737.     xldebug = 0;
  738.         xlflush();        /* needed if using (read)/(read-line) from stdin */ 
  739.       }
  740.       if (user_prefs.enable_init_msgs)
  741.     stdputstr("Xlisp-Eval-Result> "); /* use this to separate results of different evaluations */
  742.       fflush(stdout); fflush(stderr); /* otherwise output won't happen while blocked in XtAppNextEvent() */
  743.     }
  744.  
  745.     /*
  746.      * XtAppNextEvent() waits for Xevents, and while it is waiting, it will
  747.      * process inputs added via XtAppAddInput() or XtAppAddWorkProc(). Lisp 
  748.      * server input will cause Read_Eval_Print() to get called, and that
  749.      * procedure sets the globals lisp_reader_hit_eof and 
  750.      * read_eval_print_just_called. Read_Eval_Print() sends a bogus 
  751.      * XAnyEvent (event.type == 0) so as to force XtAppNextEvent() to return; 
  752.      * otherwise it would only return if a lisp evaluation caused X events 
  753.      * to be generated, which means that XLISP error returns for non-X 
  754.      * evaluations wouldn't get set up properly.
  755.      *
  756.      * XtDispatchEvent() will dispatch the actions from the events gathered
  757.      * by XtAppNextEvent(). Note that XtDispatchEvent() ignores the aforementioned
  758.      * bogus events: "if (event->type == 0) return;"
  759.      */
  760.     XtAppNextEvent(app_context, &event);
  761.     XtDispatchEvent(&event);
  762.   }
  763.   wrapup();            /* this is also called if we eval expr (quit) */
  764. }
  765.  
  766.  
  767. #ifdef WINTERP_WANT_INET_SERVER
  768. /******************************************************************************
  769.  * initialize AF_INET server, returning a socket that can be listened on.
  770.  ******************************************************************************/
  771. static int Initialize_AF_INET_Server_Socket()
  772. {
  773.   int                ls;    /* socket descriptor */
  774.   struct servent    *sp;    /* pointer to service information */
  775.   struct sockaddr_in myaddr_in;    /* for local socket address */
  776.   char* portenv;
  777.  
  778.   /* clear out address structure */
  779.   memset ((char *)&myaddr_in, 0, sizeof(struct sockaddr_in));
  780.   
  781.   /* Set up address structure for the listen socket. */
  782.   myaddr_in.sin_family = AF_INET;
  783.   myaddr_in.sin_addr.s_addr = INADDR_ANY;
  784.   
  785.   /* Find the information for the server to get the needed port number. */
  786.   if (portenv = getenv(DEFAULT_INET_PORT_ENVVAR)) { /* env var for port specification */
  787.     user_prefs.service_port = (int) strtol(portenv, (char **) NULL, 0);    /* environment var overrides Xresource setting */
  788.     myaddr_in.sin_port = htons((u_short) user_prefs.service_port);
  789.   }
  790.   else if (user_prefs.service_port != NULL)
  791.     myaddr_in.sin_port = htons((u_short) user_prefs.service_port);
  792.   else {
  793.     if ((sp = getservbyname(user_prefs.service_name, "tcp")) == NULL)
  794.       xlfatal("Unable to getservbyname() for INET Domain Socket.");
  795.     myaddr_in.sin_port = sp->s_port;
  796.   }
  797.   
  798.   /* Create the listen socket. */
  799.   if ((ls = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  800.     perror(app_name);
  801.     xlfatal("Unable to create INET Domain Socket().");
  802.   }
  803.   
  804.   /* Bind the listen address to the socket. */
  805.   if (bind(ls, &myaddr_in, sizeof(struct sockaddr_in)) == -1) {
  806.     perror(app_name);
  807.     xlfatal("Unable to bind() INET Domain Socket.");
  808.   }
  809.  
  810.   /* Initiate the listen on the socket so remote users
  811.    * can connect.  The listen backlog is set to 5, which
  812.    * is the largest currently supported.
  813.    */
  814.   if (listen(ls,5) == -1) {
  815.     perror(app_name);
  816.     xlfatal("Unable to listen() on INET Domain Socket.");
  817.   }
  818.   
  819.   setpgrp();
  820.  
  821.   fcntl(ls, F_SETFD, 1);    /* set close-on-exec for the client listener socket */
  822.   
  823.   return (ls);
  824. }
  825. #endif                /* WINTERP_WANT_INET_SERVER */
  826.  
  827.  
  828. #ifdef WINTERP_WANT_UNIX_SERVER
  829. /******************************************************************************
  830.  * initialize AF_UNIX server, returning a socket that can be listened on.
  831.  * This code contributed by Victor Kan <kan@DG-RTP.DG.COM> and modified by 
  832.  * Niels Mayer.
  833.  ******************************************************************************/
  834. static int Initialize_AF_UNIX_Server_Socket()
  835. {
  836.   int ls;            /* socket descriptor */
  837.   struct sockaddr_un myaddr_un;
  838.   char* socket_path;
  839.  
  840.   memset((char *) &myaddr_un, 0, sizeof(struct sockaddr_un));
  841.   myaddr_un.sun_family = AF_UNIX;
  842.  
  843.   if (socket_path = getenv(DEFAULT_UNIX_SOCKET_FILEPATH_ENVVAR)) /* env var for port specification */
  844.     user_prefs.unix_socket_filepath = socket_path;
  845.   /* else user_prefs.unix_socket_filepath is set to DEFAULT_UNIX_SOCKET_FILEPATH value above */
  846.  
  847. #ifndef SOCKADDR_UN_MAXLEN
  848. #define SOCKADDR_UN_MAXLEN 108    /* can't find SOCKADDR_UN_MAXLEN on hpux 7.0, however "char sun_path[108];" */ 
  849. #endif
  850.   if (strlen(user_prefs.unix_socket_filepath) > (SOCKADDR_UN_MAXLEN - 1)) {
  851.     (void) fprintf(stderr, "%s: Error -- socket path %s must be shorter than %d bytes.\n",
  852.            app_name,
  853.            user_prefs.unix_socket_filepath,
  854.            SOCKADDR_UN_MAXLEN - 1);
  855.     exit(1);
  856.   }
  857.   else
  858.     strcpy(myaddr_un.sun_path, user_prefs.unix_socket_filepath);
  859.   
  860.   /*
  861.    * Create the listen socket.
  862.    */
  863.   if ((ls = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
  864.     perror(app_name);
  865.     (void) sprintf(temptext, "socket() failed to create Unix Domain socket %s .\n",
  866.            user_prefs.unix_socket_filepath);
  867.     xlfatal(temptext);
  868.   }
  869.  
  870.   /*
  871.    * Bind the listen address to the socket.
  872.    */
  873.   if (bind(ls, &myaddr_un, sizeof(myaddr_un.sun_family) + strlen(myaddr_un.sun_path)) == -1) {
  874.     perror(app_name);
  875.     (void) sprintf(temptext,
  876.            "Unable to bind() Unix Domain socket \"%s\".\n\t\
  877. Note: you may need to do \"rm %s\" if a previous\n\t\
  878. %s terminated incorrectly. Alternately, another\n\t\
  879. invocation of %s may be running, in which case you need\n\t\
  880. to specify a different UnixDomain Socket file by setting\n\t\
  881. environment variable %s, or by setting\n\t\
  882. resource %s.unixSocketFilepath .\n",
  883.            user_prefs.unix_socket_filepath,
  884.            user_prefs.unix_socket_filepath,
  885.            app_name,
  886.            app_name,
  887.            DEFAULT_UNIX_SOCKET_FILEPATH_ENVVAR,
  888.            app_name);
  889.     xlfatal(temptext);
  890.   }
  891.  
  892.   /*
  893.    * Initiate the listen on the socket so remote users
  894.    * can connect.  The listen backlog is set to 5, which
  895.    * is the largest currently supported.
  896.    */
  897.   if (listen(ls,5) == -1) {
  898.     perror(app_name);
  899.     (void) sprintf(temptext, "Unable to listen() on Unix Domain socket %s .",
  900.            user_prefs.unix_socket_filepath);
  901.     xlfatal(temptext);
  902.   }
  903.   
  904.   setpgrp();
  905.  
  906.   fcntl(ls, F_SETFD, 1);    /* set close-on-exec for the client listener socket */
  907.  
  908.   return (ls);
  909. }
  910. #endif                /* WINTERP_WANT_UNIX_SERVER */
  911.  
  912.  
  913. #ifdef WINTERP_WANT_INET_SERVER
  914. /******************************************************************************
  915.  * Accept the request on client_AF_INET_listen_socket, and open a socket for
  916.  * reading, rdsock. rdsock will be closed by Read_Eval_Print().
  917.  ******************************************************************************/
  918. static int Accept_AF_INET_Server_Request(client_listen_socket)
  919.      int client_listen_socket;
  920.   int rdsock;
  921.   int addrlen = sizeof(struct sockaddr_in);
  922.   struct sockaddr_in peeraddr_in; /* for peer socket address */
  923. #ifdef hpux            
  924.   long lingerOpt = 1L;        /* NOTE: necessary while hpux-version < 8.0 (???) */
  925. #else
  926.   struct linger lingerOpt;
  927.   lingerOpt.l_onoff  = 1;
  928.   lingerOpt.l_linger = 10000;
  929. #endif
  930.  
  931.   memset((char *)&peeraddr_in, 0, sizeof(struct sockaddr_in));
  932.   if ((rdsock = accept(client_listen_socket, &peeraddr_in, &addrlen)) == -1) {
  933.     perror(app_name);
  934.     xlfatal("Unable to accept() on INET Domain Socket."); /* CLEANUP & EXIT */
  935.   }
  936.   if (setsockopt(rdsock, SOL_SOCKET, SO_LINGER, (char *) &lingerOpt,
  937. #ifdef hpux
  938.          sizeof(long)    /* NOTE: necessary while hpux-version < 8.0 (???) */
  939. #else
  940.          sizeof(struct linger)
  941. #endif
  942.          ) == -1) {
  943.     perror(app_name);
  944.     xlfatal("Unable to setsockopt() on INET Domain Socket."); /* CLEANUP & EXIT */
  945.   }
  946.  
  947.   fcntl(rdsock, F_SETFD, 1);    /* set close-on-exec for the client read socket */
  948.  
  949.   return (rdsock);
  950. }
  951. #endif                /* WINTERP_WANT_INET_SERVER */
  952.  
  953.  
  954. #ifdef WINTERP_WANT_UNIX_SERVER
  955. /******************************************************************************
  956.  * Accept the request on client_AF_UNIX_listen_socket, and open a socket for
  957.  * reading, rdsock. rdsock will be closed by Read_Eval_Print().
  958.  * This code contributed by Victor Kan <kan@DG-RTP.DG.COM> and modified by 
  959.  * Niels Mayer.
  960.  ******************************************************************************/
  961. static int Accept_AF_UNIX_Server_Request(client_listen_socket)
  962.      int client_listen_socket;
  963.   int rdsock;
  964.   struct sockaddr_un peeraddr_un;
  965.   int addrlen = sizeof (struct sockaddr_un);
  966.   memset ((char *) &peeraddr_un, 0, sizeof (struct sockaddr_un));
  967.  
  968.   if ((rdsock = accept(client_listen_socket, &peeraddr_un, &addrlen)) == -1) {
  969.     perror(app_name);
  970.     xlfatal("Unable to accept() on Unix Domain socket."); /* cleanup and exit */
  971.   }
  972.  
  973.   fcntl(rdsock, F_SETFD, 1);    /* set close-on-exec for the client read socket */
  974.  
  975.   return (rdsock);
  976. }
  977. #endif                /* WINTERP_WANT_UNIX_SERVER */
  978.  
  979.  
  980. #ifdef WINTERP_WANT_INET_SERVER
  981. /******************************************************************************
  982.  * This procedure is called (indirectly, via XtAppAddInput() callback) from 
  983.  * XtAppNextEvent() in main() and from XtAppNextEvent() in 
  984.  * xldbug.c:breakloop(). This callback will be called whenever new input 
  985.  * appears on client_AF_INET_listen_socket indicating that a new connection has been 
  986.  * requested and that another s-expression is ready to be evaluated by Xlisp. 
  987.  * This procedure will accept that connection and read all the data from the 
  988.  * client and send it off to the XLisp reader, and the Xlisp evaluator. 
  989.  * The results of the evaluation are printed.
  990.  ******************************************************************************/
  991. static void AF_INET_Read_Eval_Print(client_data, source_fildes, id)
  992.      XtPointer  client_data;
  993.      int*       source_fildes;
  994.      XtInputId* id;
  995. {
  996.   Read_Eval_Print(Accept_AF_INET_Server_Request(client_AF_INET_listen_socket));
  997. }
  998. #endif                /* WINTERP_WANT_INET_SERVER */
  999.  
  1000. #ifdef WINTERP_WANT_UNIX_SERVER
  1001. /******************************************************************************
  1002.  * This procedure is called (indirectly, via AtAppAddInput() callback) from 
  1003.  * XtAppNextEvent() in main() and from XtAppNextEvent() in 
  1004.  * xldbug.c:breakloop(). This callback will be called whenever new input 
  1005.  * appears on client_AF_UNIX_listen_socket indicating that a new connection has been 
  1006.  * requested and that another s-expression is ready to be evaluated by Xlisp. 
  1007.  * This procedure will accept that connection and read all the data from the 
  1008.  * client and send it off to the XLisp reader, and the Xlisp evaluator. 
  1009.  * The results of the evaluation are printed.
  1010.  ******************************************************************************/
  1011. static void AF_UNIX_Read_Eval_Print(client_data, source_fildes, id)
  1012.      XtPointer  client_data;
  1013.      int*       source_fildes;
  1014.      XtInputId* id;
  1015. {
  1016.   Read_Eval_Print(Accept_AF_UNIX_Server_Request(client_AF_UNIX_listen_socket));
  1017. }
  1018. #endif                /* WINTERP_WANT_UNIX_SERVER */
  1019.  
  1020.  
  1021. /******************************************************************************
  1022.  * This procedure is called from AF_UNIX_Read_Eval_Print() or
  1023.  * AF_INET_Read_Eval_Print(). Those procedures will accept the connections
  1024.  * requested on client_AF_UNIX_listen_socket or client_AF_INET_listen_socket
  1025.  * and return a read-socket <rdsock> from which this procedure will
  1026.  * read all the data from the client and send it off to the XLisp reader,
  1027.  * and the Xlisp evaluator.  The results of the evaluation are printed.
  1028.  ******************************************************************************/
  1029. static void Read_Eval_Print(rdsock)
  1030.      int rdsock;
  1031. {
  1032.   static char rdbuf[BUFSIZ];
  1033.   int len, i;
  1034.   LVAL sexp_stream, new_elt, last_elt = NIL;
  1035.  
  1036.   /* 
  1037.    * set this global flag so that main() and breakloop() will set up an error 
  1038.    * handler for the next call to the lisp evaluator.
  1039.    */
  1040.   read_eval_print_just_called = TRUE; 
  1041.  
  1042.   /*
  1043.    * Read the sexpression from the socket -- note assumption that entire
  1044.    * sexpression is sent in one "packet" and then the socket is closed.
  1045.    */
  1046.  
  1047.   xlsave1(sexp_stream);        /* protect from gc */
  1048.   sexp_stream = newustream();    /* note - stream obj has ptrs for head and tail*/
  1049.  
  1050.   while (len = recv(rdsock, rdbuf, BUFSIZ, 0)) { /* read len characters into rdbuf */
  1051.     if (len < 0) {
  1052.       perror(app_name);
  1053.       xlfatal("Unable to recv() on read socket."); /* CLEANUP & EXIT */
  1054.     }
  1055.  
  1056.     /* foreach character received, stuff it into an xlisp unnamed stream */
  1057.     for (i = 0; i < len; i++) {
  1058.       new_elt = cons(cvchar(rdbuf[i]), NIL);
  1059.       if (last_elt) {        /* if we've already created the head of the stream */
  1060.     rplacd(last_elt, new_elt); /* add new_elt to the tail of the list */
  1061.     last_elt = new_elt;    /* increment last_elt pointer */
  1062.       }
  1063.       else {            /* else create the head of the stream */
  1064.     sethead(sexp_stream, new_elt);
  1065.     last_elt = new_elt;
  1066.       }
  1067.     }
  1068.   }
  1069.   close(rdsock);        /* we've finished reading from the socket */
  1070.     
  1071.   if (last_elt)
  1072.     settail(sexp_stream, last_elt); /* streams are cdr-coded -- give ptr to tail */
  1073.   else            
  1074.     sexp_stream = NIL;        /* loop never executed, no characters read. */
  1075.   lisp_reader_hit_eof = !(Read_From_Stream_Eval_And_Print(sexp_stream));
  1076.   xlpop();            /*sexp_stream*/
  1077.  
  1078.  
  1079.   /* TODO -- 
  1080.      (1) make the client program, wl, wait until the evaluation is done. This will
  1081.      ensure that we don't get into a "race condition" with gnumeacs' winterp-mode --
  1082.      It is possible that winterp will still be reading winterp-mode's tempfile
  1083.      as gnuemacs writes another copy of this file. This can happen when a user
  1084.      is giving the gnuemacs winterp-send-defun command faster than winterp can
  1085.      read the files being sent to it.
  1086.      
  1087.      (2) send the results of the evaluation back to the client program wl, 
  1088.      have it print the results on stdout. Furthermore, if the form sent to
  1089.      winterp by wl results in a lisp error, wl should return a nonzero exitstatus. 
  1090.      
  1091.      This would be trivial, except that we'd want to send stdout and stderr
  1092.      back as well. If we were to use only the xlisp xlio.c routiunes for printing
  1093.      We could conceivably set the lisp symbols *standard-output* *debug-output*
  1094.      and *trace-output* so that they print to a stream, and just shove these
  1095.      streams back at the client.
  1096.      */
  1097.  
  1098.   /*
  1099.    * HACK CAUSED BY LAME IMPLEMENTATION OF XtMainLoop/XtAppNextEvent:
  1100.    * This creates a bogus event so as to force XtAppNextEvent to return, even if
  1101.    * the lisp evaluation didn't result in any new events being generated. 
  1102.    * The problem was that XtAppAddInput callbacks were being handled entirely 
  1103.    * within XtAppNextEvent(). Thus, once this procedure exited, XtAppNextEvent() 
  1104.    * would block waiting for a "real event", and never exit until an XEvent 
  1105.    * occured. XLISP requires that a new setjmp/longjmp error return be setup 
  1106.    * before each new lisp evaluation, and that couldn't happen unless 
  1107.    * XtAppNextEvent exited and allowed a new execution context to be created.
  1108.    *
  1109.    * Although I could do a call to XEventsQueued(display, QueuedAfterFlush)
  1110.    * in order to determine whether a bogus event needs to be sent, my hunch
  1111.    * is that the extra XFlush() caused by that operation would be more 
  1112.    * inefficient than processing/discarding the extra bogus event each time
  1113.    * a sexp is sent to the lisp server.
  1114.    */
  1115.   {
  1116.     XEvent bogus_event;
  1117.     bogus_event.type = 0;    /* XAnyEvent type --> ignored by XtDispatchEvent() */
  1118.     bogus_event.xany.display = display;
  1119.     bogus_event.xany.window  = XtWindow(toplevel_Wgt);;
  1120.     XPutBackEvent(display, &bogus_event);
  1121.   }
  1122. }
  1123.  
  1124.  
  1125. /*******************************************************************************
  1126.  * This fn reads from its input, which is assumed to be a xlisp stream.
  1127.  * returns false if EOF hit during read.
  1128.  ******************************************************************************/
  1129. static int Read_From_Stream_Eval_And_Print(sexp_stream)
  1130.      LVAL sexp_stream;        /* make sure this is a stream, and not other LVAL */
  1131. {
  1132.   extern int xldebug;
  1133.   extern LVAL s_1plus,s_2plus,s_3plus,s_1star,s_2star,s_3star,s_minus;
  1134.   LVAL rep_expr;
  1135.   int read_result;
  1136.  
  1137.   xlprot1(sexp_stream);        /* protect against GC */
  1138.     
  1139.   /* Read Evaluate and Print the expression in sexp_stream */
  1140.   if ((read_result = xlread(sexp_stream, &rep_expr, FALSE))) {
  1141.  
  1142.     /* save the last expression returned by the reader */
  1143.     setvalue(s_3plus, getvalue(s_2plus));
  1144.     setvalue(s_2plus, getvalue(s_1plus));
  1145.     setvalue(s_1plus, getvalue(s_minus));
  1146.     setvalue(s_minus, rep_expr);
  1147.  
  1148.     /* evaluate the expression returned by the reader */
  1149.     rep_expr = xleval(rep_expr);
  1150.  
  1151.     /* save the last expression returned by the evaluator */
  1152.     setvalue(s_3star,getvalue(s_2star));
  1153.     setvalue(s_2star,getvalue(s_1star));
  1154.     setvalue(s_1star,rep_expr);
  1155.  
  1156.     if (xldebug)        /* print eval results */
  1157.       dbgprint(rep_expr);
  1158.     else
  1159.       stdprint(rep_expr);
  1160.   }
  1161.  
  1162.   else {            /* if reader hit EOF, just print a new line */
  1163.     if (xldebug)
  1164.       dbgputstr("\n");   
  1165.     else
  1166.       stdputstr("\n");
  1167.   }
  1168.   xlpop(/*sexp_stream*/);
  1169.   return (read_result);        /* return FALSE if hit EOF */
  1170. }
  1171.  
  1172.  
  1173. /*******************************************************************************
  1174.  * xlfatal - print a fatal error message and exit
  1175.  ******************************************************************************/
  1176. xlfatal(msg)
  1177.   char *msg;
  1178. {
  1179.   extern FILE *tfp;
  1180.  
  1181.   (void) fprintf(stderr, "%s -- error: %s\n", app_name, msg);
  1182.  
  1183. #ifdef WINTERP_WANT_INET_SERVER
  1184.   if (client_AF_INET_listen_socket)
  1185.     close(client_AF_INET_listen_socket);
  1186. #endif                /* WINTERP_WANT_INET_SERVER */
  1187.  
  1188. #ifdef WINTERP_WANT_UNIX_SERVER
  1189.   if (client_AF_UNIX_listen_socket) {
  1190.     close(client_AF_UNIX_listen_socket);
  1191.     unlink(user_prefs.unix_socket_filepath);
  1192.   }
  1193. #endif                /* WINTERP_WANT_UNIX_SERVER */
  1194.  
  1195.   if (tfp)
  1196.     fclose(tfp);
  1197.  
  1198.   if (app_context)
  1199.     XtDestroyApplicationContext(app_context);
  1200.  
  1201.   exit(1);
  1202. }
  1203.  
  1204.  
  1205. /*******************************************************************************
  1206.  * wrapup - clean up and exit to the operating system. 
  1207.  * This is also called in xlsys.c:xexit().
  1208.  ******************************************************************************/
  1209. wrapup()
  1210. {
  1211.   extern FILE *tfp;
  1212.  
  1213.   stdputstr("\n");
  1214.  
  1215. #ifdef WINTERP_WANT_INET_SERVER
  1216.   if (client_AF_INET_listen_socket)
  1217.     close(client_AF_INET_listen_socket);
  1218. #endif                /* WINTERP_WANT_INET_SERVER */
  1219.  
  1220. #ifdef WINTERP_WANT_UNIX_SERVER
  1221.   if (client_AF_UNIX_listen_socket) {
  1222.     close(client_AF_UNIX_listen_socket);
  1223.     unlink(user_prefs.unix_socket_filepath);
  1224.   }
  1225. #endif                /* WINTERP_WANT_UNIX_SERVER */
  1226.  
  1227.   if (tfp)
  1228.     fclose(tfp);
  1229.  
  1230.   if (app_context)
  1231.     XtDestroyApplicationContext(app_context);
  1232.  
  1233.   exit(0);
  1234. }
  1235.  
  1236. /*******************************************************************************
  1237.  * This is the protocol callback for application shells created in WINTERP.
  1238.  * see toplevel_Wgt above, and also APPLICATION_SHELL_WIDGET_CLASS in
  1239.  * wc_SHELL.c.
  1240.  ******************************************************************************/
  1241. void Winterp_Application_Shell_WMDelete_Callback(shell, closure, call_data)
  1242.      Widget shell;
  1243.      XtPointer closure;
  1244.      XtPointer call_data;
  1245. {
  1246.   wrapup();
  1247. }
  1248.  
  1249. /*******************************************************************************
  1250.  * This handles fatal errors from the Xtoolkit. According to the Xtoolkit
  1251.  * docs, such a handler should terminate the application. In this case,
  1252.  * however, we suggest to the user that the application be terminated, but
  1253.  * don't actually do it. This may allow the user to figure out what went 
  1254.  * wrong by poking around inside the lisp environment.
  1255.  *
  1256.  * This is set up in main() via XtAppSetErrorHandler(). Note that the default
  1257.  * error handler is _XtDefaultError().
  1258.  ******************************************************************************/
  1259. static void Winterp_Xtoolkit_Error_Handler(message)
  1260.      String message;
  1261. {
  1262.   (void) sprintf(temptext,
  1263.          "X Toolkit Fatal Error -- PLEASE QUIT AND RESTART THIS APPLICATION:\n\t%s\n",
  1264.          message);
  1265.   xlfail(temptext);
  1266. }
  1267.  
  1268.  
  1269. /*******************************************************************************
  1270.  * This handles nonfatal errors from the Xtoolkit.
  1271.  *
  1272.  * This is set up in main() via XtAppSetWarningHandler(). Note that the default
  1273.  * error handler is _XtDefaultWarning().
  1274.  ******************************************************************************/
  1275. static void Winterp_Xtoolkit_Warning_Handler(message)
  1276.      String message;
  1277. {
  1278.   (void) sprintf(temptext,
  1279.          "X Toolkit Warning:\n\t%s\n",
  1280.          message);
  1281.   xlfail(temptext);
  1282. }
  1283.  
  1284.  
  1285. /*******************************************************************************
  1286.  * The following code is from X11r4:mit/lib/X/XlibInt.c.
  1287.  * Copyright    Massachusetts Institute of Technology    1985, 1986, 1987.
  1288.  ******************************************************************************/
  1289. static int Winterp_XPrintDefaultError (dpy, event, fp)
  1290.     Display *dpy;
  1291.     XErrorEvent *event;
  1292.     FILE *fp;
  1293. {
  1294.     char buffer[BUFSIZ];
  1295.     char mesg[BUFSIZ];
  1296.     char number[32];
  1297.     char *mtype = "XlibMessage";
  1298.     register _XExtension *ext = (_XExtension *)NULL;
  1299.     XGetErrorText(dpy, event->error_code, buffer, BUFSIZ);
  1300.     XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ);
  1301.     (void) fprintf(fp, "%s:  %s\n  ", mesg, buffer);
  1302.     XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d", 
  1303.     mesg, BUFSIZ);
  1304.     (void) fprintf(fp, mesg, event->request_code);
  1305.     if (event->request_code < 128) {
  1306.     sprintf(number, "%d", event->request_code);
  1307.     XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ);
  1308.     } else {
  1309.     for (ext = dpy->ext_procs;
  1310.          ext && (ext->codes.major_opcode != event->request_code);
  1311.          ext = ext->next)
  1312.       ;
  1313.     if (ext)
  1314.         strcpy(buffer, ext->name);
  1315.     else
  1316.         buffer[0] = '\0';
  1317.     }
  1318.     (void) fprintf(fp, " (%s)\n  ", buffer);
  1319.     XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d",
  1320.     mesg, BUFSIZ);
  1321.     (void) fprintf(fp, mesg, event->minor_code);
  1322.     if (ext) {
  1323.     sprintf(mesg, "%s.%d", ext->name, event->minor_code);
  1324.     XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ);
  1325.     (void) fprintf(fp, " (%s)", buffer);
  1326.     }
  1327.     fputs("\n  ", fp);
  1328.     XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
  1329.     mesg, BUFSIZ);
  1330.     (void) fprintf(fp, mesg, event->resourceid);
  1331.     fputs("\n  ", fp);
  1332.     XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d", 
  1333.     mesg, BUFSIZ);
  1334.     (void) fprintf(fp, mesg, event->serial);
  1335.     fputs("\n  ", fp);
  1336.     XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d",
  1337.     mesg, BUFSIZ);
  1338.     (void) fprintf(fp, mesg, dpy->request);
  1339.     fputs("\n", fp);
  1340.     if (event->error_code == BadImplementation) return 0;
  1341.     return 1;
  1342. }
  1343.  
  1344.  
  1345. /*******************************************************************************
  1346.  * This handles errors from Xlib. It is set up in main() via XSetErrorHandler().
  1347.  *
  1348.  * By default, the Xlib error handler is:
  1349.  *
  1350.  * int _XDefaultError(dpy, event)
  1351.  *     Display *dpy;
  1352.  *     XErrorEvent *event;
  1353.  * {
  1354.  *     if (_XPrintDefaultError (dpy, event, stderr) == 0) return 0;
  1355.  *     exit(1);
  1356.  * }
  1357.  *
  1358.  * However for WINTERP, we don't want to have exit() called on such errors,
  1359.  * rather we call xlfail() to indicate an error occured and to throw us into
  1360.  * the debug loop.
  1361.  ******************************************************************************/
  1362. static int Winterp_Xlib_Error_Handler(dpy, event)
  1363.      Display*     dpy;
  1364.      XErrorEvent* event;
  1365. {
  1366.  
  1367.   (void) Winterp_XPrintDefaultError (dpy, event, stderr);
  1368.   xlfail("Xlib error detected.");
  1369.   return (0);
  1370. }
  1371.