(x_bitmap_icon): Fix test for unallocated icon bitmap.
[bpt/emacs.git] / src / emacs.c
index c38811f..ac32633 100644 (file)
@@ -1,5 +1,5 @@
 /* Fully extensible Emacs, running on Unix, intended for GNU.
-   Copyright (C) 1985, 1986, 1987, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1993, 1994 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -21,7 +21,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <signal.h>
 #include <errno.h>
 
-#include "config.h"
+#include <config.h>
 #include <stdio.h>
 
 #include <sys/types.h>
@@ -47,12 +47,15 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "systty.h"
 #include "syssignal.h"
+#include "process.h"
 
 #ifndef O_RDWR
 #define O_RDWR 2
 #endif
 
-#define PRIO_PROCESS 0
+extern void malloc_warning ();
+extern char *index ();
+extern char *strerror ();
 
 /* Command line args from shell, as list of strings */
 Lisp_Object Vcommand_line_args;
@@ -61,6 +64,13 @@ Lisp_Object Vcommand_line_args;
    names discarded.  */
 Lisp_Object Vinvocation_name;
 
+/* The directory name from which Emacs was invoked.  */
+Lisp_Object Vinvocation_directory;
+
+/* The directory name in which to find subdirs such as lisp and etc.
+   nil means get them only from PATH_LOADSEARCH.  */
+Lisp_Object Vinstallation_directory;
+
 /* Hook run by `kill-emacs' before it does really anything.  */
 Lisp_Object Vkill_emacs_hook;
 
@@ -69,9 +79,16 @@ Lisp_Object Vkill_emacs_hook;
   on subsequent starts.  */
 int initialized;
 
-/* Variable whose value is symbol giving operating system type */
+/* Variable whose value is symbol giving operating system type */
 Lisp_Object Vsystem_type;
-  
+
+/* Variable whose value is string giving configuration built for.  */
+Lisp_Object Vsystem_configuration;
+
+/* Variable whose value is string giving configuration options,
+   for use when reporting bugs.  */
+Lisp_Object Vsystem_configuration_options;
+
 /* If non-zero, emacs should not attempt to use an window-specific code,
    but instead should use the virtual terminal under which it was started */
 int inhibit_window_system;
@@ -81,7 +98,11 @@ int inhibit_window_system;
    priority; Those functions have their own extern declaration.  */
 int emacs_priority;
 
-#ifdef BSD
+/* If non-zero a filter or a sentinel is running.  Tested to save the match
+   data on the first attempt to change it inside asynchronous code. */
+int running_asynch_code;
+
+#ifdef BSD_PGRPS
 /* See sysdep.c.  */
 extern int inherited_pgroup;
 #endif
@@ -115,6 +136,12 @@ int noninteractive;
    but nothing terrible happens if user sets this one.  */
 
 int noninteractive1;
+
+/* Save argv and argc.  */
+char **initial_argv;
+int initial_argc;
+
+static void sort_args ();
 \f
 /* Signal code for the fatal signal that was received */
 int fatal_error_code;
@@ -145,10 +172,28 @@ fatal_error_signal (sig)
      Remember that since we're in a signal handler, the signal we're
      going to send is probably blocked, so we have to unblock it if we
      want to really receive it.  */
+#ifndef MSDOS
   sigunblock (sigmask (fatal_error_code));
+#endif
   kill (getpid (), fatal_error_code);
 #endif /* not VMS */
 }
+
+#ifdef SIGDANGER
+
+/* Handler for SIGDANGER.  */
+SIGTYPE
+memory_warning_signal (sig)
+     int sig;
+{
+  signal (sig, memory_warning_signal);
+
+  malloc_warning ("Operating system warns that virtual memory is running low.\n");
+
+  /* It might be unsafe to call do_auto_save now.  */
+  force_auto_save_soon ();
+}
+#endif
 \f
 /* Code for dealing with Lisp access to the Unix command line */
 
@@ -159,8 +204,80 @@ init_cmdargs (argc, argv, skip_args)
      int skip_args;
 {
   register int i;
+  Lisp_Object name, dir;
+
+  initial_argv = argv;
+  initial_argc = argc;
 
   Vinvocation_name = Ffile_name_nondirectory (build_string (argv[0]));
+  Vinvocation_directory = Ffile_name_directory (build_string (argv[0]));
+  /* If we got no directory in argv[0], search PATH to find where
+     Emacs actually came from.  */
+  if (NILP (Vinvocation_directory))
+    {
+      Lisp_Object found;
+      int yes = openp (Vexec_path, Vinvocation_name,
+                      EXEC_SUFFIXES, &found, 1);
+      if (yes == 1)
+       Vinvocation_directory = Ffile_name_directory (found);
+    }
+
+  Vinstallation_directory = Qnil;
+
+  if (!NILP (Vinvocation_directory))
+    {
+      dir = Vinvocation_directory;
+      name = Fexpand_file_name (Vinvocation_name, dir);
+      while (1)
+       {
+         Lisp_Object tem, lib_src_exists;
+         Lisp_Object etc_exists, info_exists;
+
+         /* See if dir contains subdirs for use by Emacs.
+            Check for the ones that would exist in a build directory,
+            not including lisp and info.  */
+         tem = Fexpand_file_name (build_string ("lib-src"), dir);
+         lib_src_exists = Ffile_exists_p (tem);
+         if (!NILP (lib_src_exists))
+           {
+             tem = Fexpand_file_name (build_string ("etc"), dir);
+             etc_exists = Ffile_exists_p (tem);
+             if (!NILP (etc_exists))
+               {
+                 Vinstallation_directory
+                   = Ffile_name_as_directory (dir);
+                 break;
+               }
+           }
+
+         /* See if dir's parent contains those subdirs.  */
+         tem = Fexpand_file_name (build_string ("../lib-src"), dir);
+         lib_src_exists = Ffile_exists_p (tem);
+         if (!NILP (lib_src_exists))
+           {
+             tem = Fexpand_file_name (build_string ("../etc"), dir);
+             etc_exists = Ffile_exists_p (tem);
+             if (!NILP (etc_exists))
+               {
+                 tem = Fexpand_file_name (build_string (".."), dir);
+                 Vinstallation_directory
+                   = Ffile_name_as_directory (tem);
+                 break;
+               }
+           }
+
+         /* If the Emacs executable is actually a link,
+            next try the dir that the link points into.  */
+         tem = Ffile_symlink_p (name);
+         if (!NILP (tem))
+           {
+             name = Fexpand_file_name (tem, dir);
+             dir = Ffile_name_directory (name);
+           }
+         else
+           break;
+       }
+    }
 
   Vcommand_line_args = Qnil;
 
@@ -180,6 +297,14 @@ Any directory names are omitted.")
   return Fcopy_sequence (Vinvocation_name);
 }
 
+DEFUN ("invocation-directory", Finvocation_directory, Sinvocation_directory,
+  0, 0, 0,
+  "Return the directory name in which the Emacs executable was located")
+  ()
+{
+  return Fcopy_sequence (Vinvocation_directory);
+}
+
 \f
 #ifdef VMS
 #ifdef LINK_CRTL_SHARE
@@ -195,19 +320,93 @@ extern noshare char **environ;
    Provide dummy definitions to avoid error.
    (We don't have any real constructors or destructors.)  */
 #ifdef __GNUC__
+#ifndef GCC_CTORS_IN_LIBC
 __do_global_ctors ()
 {}
 __do_global_ctors_aux ()
 {}
 __do_global_dtors ()
 {}
+/* Linux has a bug in its library; avoid an error.  */
+#ifndef LINUX
 char * __CTOR_LIST__[2] = { (char *) (-1), 0 };
+#endif
 char * __DTOR_LIST__[2] = { (char *) (-1), 0 };
+#endif /* GCC_CTORS_IN_LIBC */
 __main ()
 {}
 #endif /* __GNUC__ */
 #endif /* ORDINARY_LINK */
 
+/* Test whether the next argument in ARGV matches SSTR or a prefix of
+   LSTR (at least MINLEN characters).  If so, then if VALPTR is non-null
+   (the argument is supposed to have a value) store in *VALPTR either
+   the next argument or the portion of this one after the equal sign.
+   ARGV is read starting at position *SKIPPTR; this index is advanced
+   by the number of arguments used.
+
+   Too bad we can't just use getopt for all of this, but we don't have
+   enough information to do it right.  */
+
+static int
+argmatch (argv, argc, sstr, lstr, minlen, valptr, skipptr)
+     char **argv;
+     int argc;
+     char *sstr;
+     char *lstr;
+     int minlen;
+     char **valptr;
+     int *skipptr;
+{
+  char *p;
+  int arglen;
+  char *arg;
+
+  /* Don't access argv[argc]; give up in advance.  */
+  if (argc <= *skipptr + 1)
+    return 0;
+
+  arg = argv[*skipptr+1];
+  if (arg == NULL)
+    return 0;
+  if (strcmp (arg, sstr) == 0)
+    {
+      if (valptr != NULL)
+       {
+         *valptr = argv[*skipptr+2];
+         *skipptr += 2;
+       }
+      else
+       *skipptr += 1;
+      return 1;
+    }
+  arglen = (valptr != NULL && (p = index (arg, '=')) != NULL
+           ? p - arg : strlen (arg));
+  if (lstr == 0 || arglen < minlen || strncmp (arg, lstr, arglen) != 0)
+    return 0;
+  else if (valptr == NULL)
+    {
+      *skipptr += 1;
+      return 1;
+    }
+  else if (p != NULL)
+    {
+      *valptr = p+1;
+      *skipptr += 1;
+      return 1;
+    }
+  else if (argv[*skipptr+2] != NULL)
+    {
+      *valptr = argv[*skipptr+2];
+      *skipptr += 2;
+      return 1;
+    }
+  else
+    {
+      return 0;
+    }
+}
+
 /* ARGSUSED */
 main (argc, argv, envp)
      int argc;
@@ -218,12 +417,28 @@ main (argc, argv, envp)
   int skip_args = 0;
   extern int errno;
   extern sys_nerr;
-  extern char *sys_errlist[];
-  extern void malloc_warning ();
+
+  sort_args (argc, argv);
+
+  if (argmatch (argv, argc, "-version", "--version", 3, NULL, &skip_args))
+    {
+      Lisp_Object tem;
+      tem = Fsymbol_value (intern ("emacs-version"));
+      if (!STRINGP (tem))
+       {
+         fprintf (stderr, "Invalid value of `emacs-version'\n");
+         exit (1);
+       }
+      else
+       {
+         printf ("%s\n", XSTRING (tem)->data);
+         exit (0);
+       }
+    }
 
 /* Map in shared memory, if we are using that.  */
 #ifdef HAVE_SHM
-  if (argc > 1 && !strcmp (argv[1], "-nl"))
+  if (argmatch (argv, argc, "-nl", "--no-shared-memory", 6, NULL, &skip_args))
     {
       map_in_data (0);
       /* The shared memory was just restored, which clobbered this.  */
@@ -246,27 +461,13 @@ main (argc, argv, envp)
       printf ("malloc jumpstart failed!\n");
 #endif /* NeXT */
 
-#ifdef HAVE_X_WINDOWS
-  /* Stupid kludge to catch command-line display spec.  We can't
-     handle this argument entirely in window system dependent code
-     because we don't even know which window system dependent code
-     to run until we've recognized this argument.  */
-  {
-    int i;
-
-    for (i = 1; (i < argc && ! display_arg); i++)
-      if (!strcmp (argv[i], "-d") || !strcmp (argv[i], "-display"))
-       display_arg = 1;
-  }
-#endif
-
 #ifdef VMS
   /* If -map specified, map the data file in */
-  if (argc > 2 && ! strcmp (argv[1], "-map"))
-    {
-      skip_args = 2;
-      mapin_data (argv[2]);
-    }
+  {
+    char *file;
+    if (argmatch (argv, argc, "-map", "--map-data", 3, &mapin_file, &skip_args))
+      mapin_data (file);
+  }
 
 #ifdef LINK_CRTL_SHARE
 #ifdef SHAREABLE_LIB_BUG
@@ -298,14 +499,6 @@ main (argc, argv, envp)
 
   clearerr (stdin);
 
-#ifdef BSD
-  {
-    inherited_pgroup = getpgrp (0);
-    setpgrp (0, getpid ());
-  }
-#endif
-
-
 #ifdef APOLLO
 #ifndef APOLLO_SR10
   /* If USE_DOMAIN_ACLS environment variable exists,
@@ -327,58 +520,129 @@ main (argc, argv, envp)
     }
 #endif /* not SYSTEM_MALLOC */
 
-#ifdef PRIO_PROCESS
+#ifdef MSDOS
+  /* We do all file input/output as binary files.  When we need to translate
+     newlines, we do that manually.  */
+  _fmode = O_BINARY;
+  (stdin)->_flag &= ~_IOTEXT;
+  (stdout)->_flag &= ~_IOTEXT;
+  (stderr)->_flag &= ~_IOTEXT;
+#endif /* MSDOS */
+
+#ifdef SET_EMACS_PRIORITY
   if (emacs_priority)
     nice (emacs_priority);
   setuid (getuid ());
-#endif /* PRIO_PROCESS */
+#endif /* SET_EMACS_PRIORITY */
+
+#ifdef EXTRA_INITIALIZE
+  EXTRA_INITIALIZE;
+#endif
 
   inhibit_window_system = 0;
 
   /* Handle the -t switch, which specifies filename to use as terminal */
-  if (skip_args + 2 < argc && !strcmp (argv[skip_args + 1], "-t"))
-    {
-      int result;
-      skip_args += 2;
-      close (0);
-      close (1);
-      result = open (argv[skip_args], O_RDWR, 2 );
-      if (result < 0)
-       {
-         char *errstring;
-
-         if (errno >= 0 && errno < sys_nerr)
-           errstring = sys_errlist[errno];
-         else
-           errstring = "undocumented error code";
-         fprintf (stderr, "emacs: %s: %s\n", argv[skip_args], errstring);
-         exit (1);
-       }
-      dup (0);
-      if (! isatty (0))
-       {
-         fprintf (stderr, "emacs: %s: not a tty\n", argv[skip_args]);
-         exit (1);
-       }
-      fprintf (stderr, "Using %s\n", argv[skip_args]);
+  {
+    char *term;
+    if (argmatch (argv, argc, "-t", "--terminal", 4, &term, &skip_args))
+      {
+       int result;
+       close (0);
+       close (1);
+       result = open (term, O_RDWR, 2 );
+       if (result < 0)
+         {
+           char *errstring = strerror (errno);
+           fprintf (stderr, "emacs: %s: %s\n", term, errstring);
+           exit (1);
+         }
+       dup (0);
+       if (! isatty (0))
+         {
+           fprintf (stderr, "emacs: %s: not a tty\n", term);
+           exit (1);
+         }
+       fprintf (stderr, "Using %s\n", term);
 #ifdef HAVE_X_WINDOWS
-      inhibit_window_system = 1;       /* -t => -nw */
+       inhibit_window_system = 1; /* -t => -nw */
 #endif
-    }
+      }
+  }
+  if (argmatch (argv, argc, "-nw", "--no-windows", 6, NULL, &skip_args))
+    inhibit_window_system = 1;
 
-  if (skip_args + 1 < argc
-      && (!strcmp (argv[skip_args + 1], "-nw")))
+  /* Handle the -batch switch, which means don't do interactive display.  */
+  noninteractive = 0;
+  if (argmatch (argv, argc, "-batch", "--batch", 5, NULL, &skip_args))
+    noninteractive = 1;
+
+  /* Handle the --help option, which gives a usage message..  */
+  if (argmatch (argv, argc, "-help", "--help", 3, NULL, &skip_args))
     {
-      skip_args += 1;
-      inhibit_window_system = 1;
+      printf ("\
+Usage: %s [-t term] [--terminal term]  [-nw] [--no-windows]  [--batch]\n\
+      [-q] [--no-init-file]  [-u user] [--user user]  [--debug-init]\n\
+\(Arguments above this line must be first; those below may be in any order)\n\
+      [-f func] [--funcall func]  [-l file] [--load file]  [--insert file]\n\
+      file-to-visit  [--kill]\n", argv[0]);
+      exit (0);
     }
 
-/* Handle the -batch switch, which means don't do interactive display.  */
-  noninteractive = 0;
-  if (skip_args + 1 < argc && !strcmp (argv[skip_args + 1], "-batch"))
+#ifdef HAVE_X_WINDOWS
+  /* Stupid kludge to catch command-line display spec.  We can't
+     handle this argument entirely in window system dependent code
+     because we don't even know which window system dependent code
+     to run until we've recognized this argument.  */
+  {
+    char *displayname;
+    int i;
+    int count_before = skip_args;
+
+    if (argmatch (argv, argc, "-d", "--display", 3, &displayname, &skip_args))
+      display_arg = 1;
+    else if (argmatch (argv, argc, "-display", 0, 3, &displayname, &skip_args))
+      display_arg = 1;
+
+    /* If we have the form --display=NAME,
+       convert it into  -d name.
+       This requires inserting a new element into argv.  */
+    if (displayname != 0 && skip_args - count_before == 1)
+      {
+       char **new = (char **) xmalloc (sizeof (char *) * (argc + 2));
+       int j;
+
+       for (j = 0; j < count_before + 1; j++)
+         new[j] = argv[j];
+       new[count_before + 1] = "-d";
+       new[count_before + 2] = displayname;
+       for (j = count_before + 2; j <argc; j++)
+         new[j + 1] = argv[j];
+       argv = new;
+       argc++;
+      }
+    /* Change --display to -d, when its arg is separate.  */
+    else if (displayname != 0 && skip_args > count_before
+            && argv[count_before + 1][1] == '-')
+      argv[count_before] = "-d";
+
+    /* Don't actually discard this arg.  */
+    skip_args = count_before;
+  }
+#endif
+
+  if (! noninteractive)
     {
-      skip_args += 1;
-      noninteractive = 1;
+#ifdef BSD_PGRPS
+      if (initialized)
+       {
+         inherited_pgroup = EMACS_GETPGRP (0);
+         setpgrp (0, getpid ());
+       }
+#else
+#if defined (USG5) && defined (INTERRUPT_INPUT)
+      setpgrp ();
+#endif
+#endif
     }
 
 #ifdef POSIX_SIGNALS
@@ -400,6 +664,27 @@ main (argc, argv, envp)
       signal (SIGQUIT, fatal_error_signal);
       signal (SIGILL, fatal_error_signal);
       signal (SIGTRAP, fatal_error_signal);
+#ifdef SIGABRT
+      signal (SIGABRT, fatal_error_signal);
+#endif
+#ifdef SIGHWE
+      signal (SIGHWE, fatal_error_signal);
+#endif
+#ifdef SIGPRE
+      signal (SIGPRE, fatal_error_signal);
+#endif
+#ifdef SIGORE
+      signal (SIGORE, fatal_error_signal);
+#endif
+#ifdef SIGUME
+      signal (SIGUME, fatal_error_signal);
+#endif
+#ifdef SIGDLK
+      signal (SIGDLK, fatal_error_signal);
+#endif
+#ifdef SIGCPULIM
+      signal (SIGCPULIM, fatal_error_signal);
+#endif
 #ifdef SIGIOT
       /* This is missing on some systems - OS/2, for example.  */
       signal (SIGIOT, fatal_error_signal);
@@ -423,17 +708,14 @@ main (argc, argv, envp)
       signal (SIGXFSZ, fatal_error_signal);
 #endif /* SIGXFSZ */
 
-#ifdef AIX
-      signal (SIGDANGER, fatal_error_signal);
-      signal (20, fatal_error_signal);
-      signal (21, fatal_error_signal);
-      signal (22, fatal_error_signal);
-      signal (23, fatal_error_signal);
-      signal (24, fatal_error_signal);
-#ifdef SIGIO
-      signal (SIGAIO, fatal_error_signal);
-      signal (SIGPTY, fatal_error_signal);
+#ifdef SIGDANGER
+      /* This just means available memory is getting low.  */
+      signal (SIGDANGER, memory_warning_signal);
 #endif
+
+#ifdef AIX
+/* 20 is SIGCHLD, 21 is SIGTTIN, 22 is SIGTTOU.  */
+      signal (SIGXCPU, fatal_error_signal);
 #ifndef _I386
       signal (SIGIOINT, fatal_error_signal);
 #endif
@@ -465,16 +747,33 @@ main (argc, argv, envp)
   init_alloc ();
   init_eval ();
   init_data ();
+  running_asynch_code = 0;
+
+#ifdef MSDOS
+  /* Call early 'cause init_environment needs it.  */
+  init_dosfns ();
+  /* Set defaults for several environment variables.  */
+  if (initialized) init_environment (argc, argv, skip_args);
+#endif
 
   /* egetenv is a pretty low-level facility, which may get called in
      many circumstances; it seems flimsy to put off initializing it
      until calling init_callproc.  */
   set_process_environment ();
+  /* AIX crashes are reported in system versions 3.2.3 and 3.2.4
+     if this is not done.  Do it after set_process_environment so that we
+     don't pollute Vprocess_environment.  */
+#ifdef AIX
+  putenv ("LANG=C");
+#endif
+
+  init_buffer ();      /* Init default directory of main buffer */
 
+  init_callproc_1 ();  /* Must precede init_cmdargs and init_sys_modes.  */
+  init_cmdargs (argc, argv, skip_args);        /* Must precede init_lread.  */
+  init_callproc ();    /* Must follow init_cmdargs but not init_sys_modes.  */
   init_lread ();
 
-  init_cmdargs (argc, argv, skip_args);        /* Create list Vcommand_line_args */
-  init_buffer ();      /* Init default directory of main buffer */
   if (!noninteractive)
     {
 #ifdef VMS
@@ -483,7 +782,6 @@ main (argc, argv, envp)
       init_display (); /* Determine terminal type.  init_sys_modes uses results */
     }
   init_keyboard ();    /* This too must precede init_sys_modes */
-  init_callproc ();    /* And this too. */
 #ifdef VMS
   init_vmsproc ();     /* And this too. */
 #endif /* VMS */
@@ -515,9 +813,7 @@ main (argc, argv, envp)
       syms_of_print ();
       syms_of_eval ();
       syms_of_fns ();
-#ifdef LISP_FLOAT_TYPE
       syms_of_floatfns ();
-#endif
 
       syms_of_abbrev ();
       syms_of_buffer ();
@@ -549,6 +845,7 @@ main (argc, argv, envp)
       syms_of_search ();
       syms_of_frame ();
       syms_of_syntax ();
+      syms_of_term ();
       syms_of_undo ();
 
       /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
@@ -570,6 +867,11 @@ main (argc, argv, envp)
 #endif /* HAVE_X_MENU */
 #endif /* HAVE_X_WINDOWS */
 
+#if defined (MSDOS) && !defined (HAVE_X_WINDOWS)
+      syms_of_xfaces ();
+      syms_of_xmenu ();
+#endif
+
 #ifdef SYMS_SYSTEM
       SYMS_SYSTEM;
 #endif
@@ -591,13 +893,14 @@ main (argc, argv, envp)
 
   if (!initialized)
     {
+      char *file;
       /* Handle -l loadup-and-dump, args passed by Makefile. */
-      if (argc > 2 + skip_args && !strcmp (argv[1 + skip_args], "-l"))
+      if (argmatch (argv, argc, "-l", "--load", 3, &file, &skip_args))
        Vtop_level = Fcons (intern ("load"),
-                           Fcons (build_string (argv[2 + skip_args]), Qnil));
+                           Fcons (build_string (file), Qnil));
 #ifdef CANNOT_DUMP
       /* Unless next switch is -nl, load "loadup.el" first thing.  */
-      if (!(argc > 1 + skip_args && !strcmp (argv[1 + skip_args], "-nl")))
+      if (!argmatch (argv, argc, "-nl", "--no-loadup", 6, NULL, &skip_args))
        Vtop_level = Fcons (intern ("load"),
                            Fcons (build_string ("loadup.el"), Qnil));
 #endif /* CANNOT_DUMP */
@@ -605,20 +908,208 @@ main (argc, argv, envp)
 
   initialized = 1;
 
-#ifdef sun
-  /* sun's localtime() has a bug.  it caches the value of the time
+#if defined (sun) || defined (LOCALTIME_CACHE)
+  /* sun's localtime has a bug.  it caches the value of the time
      zone rather than looking it up every time.  Since localtime() is
      called to bolt the undumping time into the undumped emacs, this
-     results in localtime() ignoring the TZ environment variable.
-     This flushes the new TZ value into localtime(). */
-  tzset();
-#endif /* sun */
+     results in localtime ignoring the TZ environment variable.
+     This flushes the new TZ value into localtime. */
+  tzset ();
+#endif /* defined (sun) || defined (LOCALTIME_CACHE) */
+
+  /* Handle the GNU standard option --version.  */
+  if (argmatch (argv, argc, "-version", "--version", 3, NULL, &skip_args))
+    {
+      Lisp_Object ver;
+      ver = call0 (intern ("emacs-version"));
+      if (STRINGP (ver))
+       printf ("%s\n", XSTRING (ver)->data);
+      exit (0);
+    }
 
   /* Enter editor command loop.  This never returns.  */
   Frecursive_edit ();
   /* NOTREACHED */
 }
 \f
+/* Sort the args so we can find the most important ones
+   at the beginning of argv.  */
+
+/* First, here's a table of all the standard options.  */
+
+struct standard_args
+{
+  char *name;
+  char *longname;
+  int priority;
+  int nargs;
+};
+
+struct standard_args standard_args[] =
+{
+  { "-nl", "--no-shared-memory", 100, 0 },
+  { "-map", "--map-data", 100, 0 },
+  { "-t", "--terminal", 90, 1 },
+  { "-d", "--display", 80, 1 },
+  { "-display", 0, 80, 1 },
+  { "-nw", "--no-windows", 70, 0 },
+  { "-batch", "--batch", 60, 0 },
+  { "-q", "--no-init-file", 50, 0 },
+  { "-no-init-file", 0, 50, 0 },
+  { "-no-site-file", "--no-site-file", 40, 0 },
+  { "-u", "--user", 30, 1 },
+  { "-user", 0, 30, 1 },
+  { "-debug-init", "--debug-init", 20, 0 },
+  { "-bg", "--background-color", 10, 1 },
+  { "-background", 0, 10, 1 },
+  { "-fg", "--foreground-color", 10, 1 },
+  { "-foreground", 0, 10, 1 },
+  { "-bd", "--border-color", 10, 1 },
+  { "-bw", "--border-width", 10, 1 },
+  { "-ib", "--internal-border", 10, 1 },
+  { "-ms", "--mouse-color", 10, 1 },
+  { "-cr", "--cursor-color", 10, 1 },
+  { "-fn", "--font", 10, 1 },
+  { "-font", 0, 10, 1 },
+  { "-g", "--geometry", 10, 1 },
+  { "-geometry", 0, 10, 1 },
+  { "-T", "--title", 10, 1 },
+  { "-i", "--icon-type", 10, 1 },
+  { "-itype", 0, 10, 1 },
+  { "-name", "--name", 10, 1 },
+  { "-xrm", "--xrm", 10, 1 },
+  { "-r", "--reverse-video", 5, 0 },
+  { "-rv", 0, 5, 0 },
+  { "-reverse", 0, 5, 0 },
+  { "-vb", "--vertical-scroll-bars", 5, 0 },
+  { "-iconic", "--iconic", 5, 0 },
+  /* These have the same priority as ordinary file name args,
+     so they are not reordered with respect to those.  */
+  { "-l", "--load", 0, 1 },
+  { "-load", 0, 0, 1 },
+  { "-f", "--funcall", 0, 1 },
+  { "-funcall", 0, 0, 1 },
+  { "-insert", "--insert", 0, 1 },
+  { "-kill", "--kill", -10, 0 },
+};
+
+/* Reorder the elements of ARGV (assumed to have ARGC elements)
+   so that the highest priority ones come first.
+   Do not change the order of elements of equal priority.
+   If an option takes an argument, keep it and its argument together.  */
+
+static void
+sort_args (argc, argv)
+     int argc;
+     char **argv;
+{
+  char **new = (char **) xmalloc (sizeof (char *) * argc);
+  /* For each element of argv,
+     the corresponding element of options is:
+     0 for an option that takes no arguments,
+     1 for an option that takes one argument, etc.
+     -1 for an ordinary non-option argument.  */
+  int *options = (int *) xmalloc (sizeof (int) * argc);
+  int *priority = (int *) xmalloc (sizeof (int) * argc);
+  int to = 1;
+  int from;
+  int i;
+
+  /* Categorize all the options,
+     and figure out which argv elts are option arguments.  */
+  for (from = 1; from < argc; from++)
+    {
+      options[from] = -1;
+      priority[from] = 0;
+      if (argv[from][0] == '-')
+       {
+         int match, thislen;
+         char *equals;
+
+         /* Look for a match with a known old-fashioned option.  */
+         for (i = 0; i < sizeof (standard_args) / sizeof (standard_args[0]); i++)
+           if (!strcmp (argv[from], standard_args[i].name))
+             {
+               options[from] = standard_args[i].nargs;
+               priority[from] = standard_args[i].priority;
+               from += standard_args[i].nargs;
+               goto done;
+             }
+
+         /* Look for a match with a known long option.
+            MATCH is -1 if no match so far, -2 if two or more matches so far,
+            >= 0 (the table index of the match) if just one match so far.  */
+         if (argv[from][1] == '-')
+           {
+             match = -1;
+             thislen = strlen (argv[from]);
+             equals = index (argv[from], '=');
+             if (equals != 0)
+               thislen = equals - argv[from];
+
+             for (i = 0; i < sizeof (standard_args) / sizeof (standard_args[0]); i++)
+               if (!strncmp (argv[from], standard_args[i].longname, thislen))
+                 {
+                   if (match == -1)
+                     match = i;
+                   else
+                     match = -2;
+                 }
+
+             /* If we found exactly one match, use that.  */
+             if (match >= 0)
+               {
+                 options[from] = standard_args[match].nargs;
+                 priority[from] = standard_args[match].priority;
+                 /* If --OPTION=VALUE syntax is used,
+                    this option uses just one argv element.  */
+                 if (equals != 0)
+                   options[from] = 0;
+                 from += options[from];
+               }
+           }
+       done: ;
+       }
+    }
+
+  /* Copy the arguments, in order of decreasing priority, to NEW.  */
+  new[0] = argv[0];
+  while (to < argc)
+    {
+      int best = -1;
+      int best_priority = -2;
+
+      /* Find the highest priority remaining option.
+        If several have equal priority, take the first of them.  */
+      for (from = 1; from < argc; from++)
+       {
+         if (argv[from] != 0 && priority[from] > best_priority)
+           {
+             best_priority = priority[from];
+             best = from;
+           }
+         /* Skip option arguments--they are tied to the options.  */
+         if (options[from] > 0)
+           from += options[from];
+       }
+           
+      if (best < 0)
+       abort ();
+
+      /* Copy the highest priority remaining option, with its args, to NEW.  */
+      new[to++] = argv[best];
+      for (i = 0; i < options[best]; i++)
+       new[to++] = argv[best + i + 1];
+
+      /* Clear out this option in ARGV.  */
+      argv[best] = 0;
+      for (i = 0; i < options[best]; i++)
+       argv[best + i + 1] = 0;
+    }
+
+  bcopy (new, argv, sizeof (char *) * argc);
+}
+\f
 DEFUN ("kill-emacs", Fkill_emacs, Skill_emacs, 0, 1, "P",
   "Exit the Emacs job and kill it.\n\
 If ARG is an integer, return ARG as the exit program code.\n\
@@ -649,9 +1140,9 @@ all of which are called before Emacs is actually killed.")
   stop_vms_input ();
  #endif  */
 
-  shut_down_emacs (0, 0);
+  shut_down_emacs (0, 0, STRINGP (arg) ? arg : Qnil);
 
-  exit ((XTYPE (arg) == Lisp_Int) ? XINT (arg)
+  exit (INTEGERP (arg) ? XINT (arg)
 #ifdef VMS
        : 1
 #else
@@ -678,12 +1169,17 @@ shut_down_emacs (sig, no_x, stuff)
      int sig, no_x;
      Lisp_Object stuff;
 {
+  /* Prevent running of hooks from now on.  */
+  Vrun_hooks = Qnil;
+
   /* If we are controlling the terminal, reset terminal modes */
 #ifdef EMACS_HAVE_TTY_PGRP
   {
+    int pgrp = EMACS_GETPGRP (0);
+
     int tpgrp;
     if (EMACS_GET_TTY_PGRP (0, &tpgrp) != -1
-       && tpgrp == getpgrp (0))
+       && tpgrp == pgrp)
       {
        fflush (stdout);
        reset_sys_modes ();
@@ -709,10 +1205,16 @@ shut_down_emacs (sig, no_x, stuff)
   kill_vms_processes ();
 #endif
 
+#if 0 /* This triggers a bug in XCloseDisplay and is not needed.  */
 #ifdef HAVE_X_WINDOWS
-  if (!noninteractive && EQ (Vwindow_system, intern ("x")) && ! no_x)
+  /* It's not safe to call intern here.  Maybe we are crashing.  */
+  if (!noninteractive && SYMBOLP (Vwindow_system)
+      && XSYMBOL (Vwindow_system)->name->size == 1
+      && XSYMBOL (Vwindow_system)->name->data[0] == 'x'
+      && ! no_x)
     Fx_close_current_connection ();
 #endif /* HAVE_X_WINDOWS */
+#endif
 
 #ifdef SIGIO
   /* There is a tendency for a SIGIO signal to arrive within exit,
@@ -738,7 +1240,6 @@ This function exists on systems that use HAVE_SHM.")
 {
   extern int my_edata;
   Lisp_Object tem;
-  extern void malloc_warning ();
 
   CHECK_STRING (intoname, 0);
   intoname = Fexpand_file_name (intoname, Qnil);
@@ -774,7 +1275,6 @@ and announce itself normally when it is run.")
 {
   extern int my_edata;
   Lisp_Object tem;
-  extern void malloc_warning ();
 
   CHECK_STRING (intoname, 0);
   intoname = Fexpand_file_name (intoname, Qnil);
@@ -795,7 +1295,11 @@ and announce itself normally when it is run.")
   /* Tell malloc where start of impure now is */
   /* Also arrange for warnings when nearly out of space.  */
 #ifndef SYSTEM_MALLOC
+#ifndef WINDOWSNT
+  /* On Windows, this was done before dumping, and that once suffices.
+     Meanwhile, my_edata is not valid on Windows.  */
   memory_warnings (&my_edata, malloc_warning);
+#endif /* not WINDOWSNT */
 #endif
   unexec (XSTRING (intoname)->data,
          !NILP (symname) ? XSTRING (symname)->data : 0, &my_edata, 0, 0);
@@ -819,7 +1323,6 @@ decode_env_path (evarname, defalt)
      char *evarname, *defalt;
 {
   register char *path, *p;
-  extern char *index ();
 
   Lisp_Object lpath;
 
@@ -860,6 +1363,7 @@ syms_of_emacs ()
   defsubr (&Skill_emacs);
 
   defsubr (&Sinvocation_name);
+  defsubr (&Sinvocation_directory);
 
   DEFVAR_LISP ("command-line-args", &Vcommand_line_args,
     "Args passed by shell to Emacs, as a list of strings.");
@@ -868,6 +1372,14 @@ syms_of_emacs ()
     "Value is symbol indicating type of operating system you are using.");
   Vsystem_type = intern (SYSTEM_TYPE);
 
+  DEFVAR_LISP ("system-configuration", &Vsystem_configuration,
+    "Value is string indicating configuration Emacs was built for.");
+  Vsystem_configuration = build_string (EMACS_CONFIGURATION);
+
+  DEFVAR_LISP ("system-configuration-options", &Vsystem_configuration_options,
+    "String containing the configuration options Emacs was built with.");
+  Vsystem_configuration_options = build_string (EMACS_CONFIG_OPTIONS);
+
   DEFVAR_BOOL ("noninteractive", &noninteractive1,
     "Non-nil means Emacs is running without interactive terminal.");
 
@@ -882,9 +1394,23 @@ expect to be able to interact with the user.");
     "Priority for Emacs to run at.\n\
 This value is effective only if set before Emacs is dumped,\n\
 and only if the Emacs executable is installed with setuid to permit\n\
-it to change priority.  (Emacs sets its uid back to the real uid.)");
+it to change priority.  (Emacs sets its uid back to the real uid.)\n\
+Currently, you need to define SET_EMACS_PRIORITY in `config.h'\n\
+before you compile Emacs, to enable the code for this feature.");
   emacs_priority = 0;
 
-  staticpro (&Vinvocation_name);
-  Vinvocation_name = Qnil;
+  DEFVAR_LISP ("invocation-name", &Vinvocation_name,
+    "The program name that was used to run Emacs.\n\
+Any directory names are omitted.");
+
+  DEFVAR_LISP ("invocation-directory", &Vinvocation_directory,
+    "The directory in which the Emacs executable was found, to run it.\n\
+The value is nil if that directory's name is not known.");
+
+  DEFVAR_LISP ("installation-directory", &Vinstallation_directory,
+    "A directory within which to look for the `lib-src' and `etc' directories.\n\
+This is non-nil when we can't find those directories in their standard\n\
+installed locations, but we can find them\n\
+near where the Emacs executable was found.");
+  Vinstallation_directory = Qnil;
 }