Unspecified location of chown for Linux (Linux doesn't put chown in /etc).
[bpt/emacs.git] / src / emacs.c
index 68d0ce3..56d4ecf 100644 (file)
@@ -1,5 +1,5 @@
 /* Fully extensible Emacs, running on Unix, intended for GNU.
-   Copyright (C) 1985, 1986, 1987, 1992, 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>
@@ -35,10 +35,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <sys/ioctl.h>
 #endif
 
-#ifdef HAVE_TERMIOS
-#include <termios.h>
-#endif
-
 #ifdef APOLLO
 #ifndef APOLLO_SR10
 #include <default_acl.h>
@@ -51,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;
@@ -65,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;
 
@@ -73,8 +79,11 @@ 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;
   
 /* 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 */
@@ -85,6 +94,11 @@ int inhibit_window_system;
    priority; Those functions have their own extern declaration.  */
 int emacs_priority;
 
+#ifdef BSD_PGRPS
+/* See sysdep.c.  */
+extern int inherited_pgroup;
+#endif
+
 #ifdef HAVE_X_WINDOWS
 /* If non-zero, -d was specified, meaning we're using some window system. */
 int display_arg;
@@ -134,7 +148,7 @@ fatal_error_signal (sig)
     {
       fatal_error_in_progress = 1;
 
-      shut_down_emacs (sig);
+      shut_down_emacs (sig, 0, Qnil);
     }
 
 #ifdef VMS
@@ -144,10 +158,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 */
 
@@ -158,8 +190,77 @@ init_cmdargs (argc, argv, skip_args)
      int skip_args;
 {
   register int i;
+  Lisp_Object name, dir;
 
   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 = tem;
+             dir = Ffile_name_directory (name);
+           }
+         else
+           break;
+       }
+    }
 
   Vcommand_line_args = Qnil;
 
@@ -179,6 +280,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
@@ -194,14 +303,19 @@ 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__ */
@@ -217,8 +331,6 @@ main (argc, argv, envp)
   int skip_args = 0;
   extern int errno;
   extern sys_nerr;
-  extern char *sys_errlist[];
-  extern void malloc_warning ();
 
 /* Map in shared memory, if we are using that.  */
 #ifdef HAVE_SHM
@@ -296,9 +408,19 @@ main (argc, argv, envp)
 #endif
 
   clearerr (stdin);
-#ifdef BSD
-  setpgrp (0, getpid ());
+
+#ifdef BSD_PGRPS
+  if (initialized)
+    {
+      inherited_pgroup = EMACS_GETPGRP (0);
+      setpgrp (0, getpid ());
+    }
+#else
+#if defined (USG5) && defined (INTERRUPT_INPUT)
+  setpgrp ();
 #endif
+#endif
+
 
 #ifdef APOLLO
 #ifndef APOLLO_SR10
@@ -321,15 +443,23 @@ main (argc, argv, envp)
     }
 #endif /* not SYSTEM_MALLOC */
 
+#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 PRIO_PROCESS
   if (emacs_priority)
     nice (emacs_priority);
   setuid (getuid ());
 #endif /* PRIO_PROCESS */
 
-#ifdef BSD
-  /* interrupt_input has trouble if we aren't in a separate process group.  */
-  setpgrp (getpid (), getpid ());
+#ifdef EXTRA_INITIALIZE
+  EXTRA_INITIALIZE;
 #endif
 
   inhibit_window_system = 0;
@@ -344,12 +474,7 @@ main (argc, argv, envp)
       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";
+         char *errstring = strerror (errno);
          fprintf (stderr, "emacs: %s: %s\n", argv[skip_args], errstring);
          exit (1);
        }
@@ -407,9 +532,13 @@ main (argc, argv, envp)
       signal (SIGEMT, fatal_error_signal);
 #endif
       signal (SIGFPE, fatal_error_signal);
+#ifdef SIGBUS
       signal (SIGBUS, fatal_error_signal);
+#endif
       signal (SIGSEGV, fatal_error_signal);
+#ifdef SIGSYS
       signal (SIGSYS, fatal_error_signal);
+#endif
       signal (SIGTERM, fatal_error_signal);
 #ifdef SIGXCPU
       signal (SIGXCPU, fatal_error_signal);
@@ -418,18 +547,17 @@ 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
       signal (SIGGRANT, fatal_error_signal);
       signal (SIGRETRACT, fatal_error_signal);
       signal (SIGSOUND, fatal_error_signal);
@@ -459,15 +587,31 @@ main (argc, argv, envp)
   init_eval ();
   init_data ();
 
+#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
@@ -476,7 +620,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 */
@@ -508,9 +651,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 ();
@@ -542,6 +683,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 */
@@ -598,14 +740,14 @@ 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) */
 
   /* Enter editor command loop.  This never returns.  */
   Frecursive_edit ();
@@ -634,11 +776,6 @@ all of which are called before Emacs is actually killed.")
   if (!NILP (Vrun_hooks) && !noninteractive)
     call1 (Vrun_hooks, intern ("kill-emacs-hook"));
 
-#ifdef HAVE_X_WINDOWS
-  if (!noninteractive && EQ (Vwindow_system, intern ("x")))
-    Fx_close_current_connection ();
-#endif /* HAVE_X_WINDOWS */
-
   UNGCPRO;
 
 /* Is it really necessary to do this deassign
@@ -646,9 +783,8 @@ all of which are called before Emacs is actually killed.")
 /* #ifdef VMS
   stop_vms_input ();
  #endif  */
-  stuff_buffered_input (arg);
 
-  shut_down_emacs (0);
+  shut_down_emacs (0, 0, STRINGP (arg) ? arg : Qnil);
 
   exit ((XTYPE (arg) == Lisp_Int) ? XINT (arg)
 #ifdef VMS
@@ -671,16 +807,23 @@ all of which are called before Emacs is actually killed.")
 
    This is called by fatal signal handlers, X protocol error handlers,
    and Fkill_emacs.  */
+
 void
-shut_down_emacs (sig)
-     int sig;
+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 ();
@@ -693,6 +836,8 @@ shut_down_emacs (sig)
   reset_sys_modes ();
 #endif
 
+  stuff_buffered_input (stuff);
+
   kill_buffer_processes (Qnil);
   Fdo_auto_save (Qt, Qnil);
 
@@ -704,6 +849,11 @@ shut_down_emacs (sig)
   kill_vms_processes ();
 #endif
 
+#ifdef HAVE_X_WINDOWS
+  if (!noninteractive && EQ (Vwindow_system, intern ("x")) && ! no_x)
+    Fx_close_current_connection ();
+#endif /* HAVE_X_WINDOWS */
+
 #ifdef SIGIO
   /* There is a tendency for a SIGIO signal to arrive within exit,
      and cause a SIGHUP because the input descriptor is already closed.  */
@@ -728,7 +878,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);
@@ -764,7 +913,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);
@@ -809,7 +957,6 @@ decode_env_path (evarname, defalt)
      char *evarname, *defalt;
 {
   register char *path, *p;
-  extern char *index ();
 
   Lisp_Object lpath;
 
@@ -839,15 +986,18 @@ decode_env_path (evarname, defalt)
 
 syms_of_emacs ()
 {
+#ifndef CANNOT_DUMP
 #ifdef HAVE_SHM
   defsubr (&Sdump_emacs_data);
 #else
   defsubr (&Sdump_emacs);
+#endif
 #endif
 
   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.");
@@ -856,6 +1006,10 @@ 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 (CONFIGURATION);
+
   DEFVAR_BOOL ("noninteractive", &noninteractive1,
     "Non-nil means Emacs is running without interactive terminal.");
 
@@ -863,16 +1017,30 @@ syms_of_emacs ()
     "Hook to be run whenever kill-emacs is called.\n\
 Since kill-emacs may be invoked when the terminal is disconnected (or\n\
 in other similar situations), functions placed on this hook should not\n\
-not expect to be able to interact with the user.");
+expect to be able to interact with the user.");
   Vkill_emacs_hook = Qnil;
 
   DEFVAR_INT ("emacs-priority", &emacs_priority,
     "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 PRIO_PROCESS 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;
 }