Mercurial > emacs
diff src/emacs.c @ 284:03e467a3d92a
Initial revision
author | Jim Blandy <jimb@redhat.com> |
---|---|
date | Thu, 23 May 1991 23:18:53 +0000 |
parents | |
children | 17ca8766781a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/emacs.c Thu May 23 23:18:53 1991 +0000 @@ -0,0 +1,751 @@ +/* Fully extensible Emacs, running on Unix, intended for GNU. + Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include <signal.h> +#include <errno.h> + +#include "config.h" +#include <stdio.h> + +#include <sys/types.h> +#include <sys/file.h> + +#ifdef VMS +#include <ssdef.h> +#endif + +#ifdef USG5 +#include <fcntl.h> +#endif + +#ifdef BSD +#include <sys/ioctl.h> +#endif + +#ifdef APOLLO +#ifndef APOLLO_SR10 +#include <default_acl.h> +#endif +#endif + +#undef NULL +#include "lisp.h" +#include "commands.h" + +#ifndef O_RDWR +#define O_RDWR 2 +#endif + +#define PRIO_PROCESS 0 + +/* Command line args from shell, as list of strings */ +Lisp_Object Vcommand_line_args; + +/* Set nonzero after Emacs has started up the first time. + Prevents reinitialization of the Lisp world and keymaps + on subsequent starts. */ +int initialized; + +/* Variable whose value is symbol giving operating system type */ +Lisp_Object Vsystem_type; + +/* 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; + +#ifdef HAVE_X_WINDOWS +/* If non-zero, -d was specified, meaning we're using some window system. */ +int display_arg; +#endif + +/* An address near the bottom of the stack. + Tells GC how to save a copy of the stack. */ +char *stack_bottom; + +#ifdef HAVE_X_WINDOWS +extern Lisp_Object Vwindow_system; +#endif /* HAVE_X_WINDOWS */ + +#ifdef USG_SHARED_LIBRARIES +/* If nonzero, this is the place to put the end of the writable segment + at startup. */ + +unsigned int bss_end = 0; +#endif + +/* Nonzero means running Emacs without interactive terminal. */ + +int noninteractive; + +/* Value of Lisp variable `noninteractive'. + Normally same as C variable `noninteractive' + but nothing terrible happens if user sets this one. */ + +int noninteractive1; + +/* Signal code for the fatal signal that was received */ +int fatal_error_code; + +/* Nonzero if handling a fatal error already */ +int fatal_error_in_progress; + +/* Handle bus errors, illegal instruction, etc. */ +fatal_error_signal (sig) + int sig; +{ +#ifdef BSD + int tpgrp; +#endif /* BSD */ + + fatal_error_code = sig; + signal (sig, SIG_DFL); + + /* If fatal error occurs in code below, avoid infinite recursion. */ + if (fatal_error_in_progress) + kill (getpid (), fatal_error_code); + + fatal_error_in_progress = 1; + + /* If we are controlling the terminal, reset terminal modes */ +#ifdef BSD + if (ioctl(0, TIOCGPGRP, &tpgrp) == 0 + && tpgrp == getpgrp (0)) +#endif /* BSD */ + { + reset_sys_modes (); + if (sig != SIGTERM) + fprintf (stderr, "Fatal error (%d).", sig); + } + + /* Clean up */ +#ifdef subprocesses + kill_buffer_processes (Qnil); +#endif + Fdo_auto_save (Qt, Qnil); + +#ifdef CLASH_DETECTION + unlock_all_files (); +#endif /* CLASH_DETECTION */ + +#ifdef VMS + kill_vms_processes (); + LIB$STOP (SS$_ABORT); +#else + /* Signal the same code; this time it will really be fatal. */ + kill (getpid (), fatal_error_code); +#endif /* not VMS */ +} + +/* Code for dealing with Lisp access to the Unix command line */ + +static +init_cmdargs (argc, argv, skip_args) + int argc; + char **argv; + int skip_args; +{ + register int i; + + Vcommand_line_args = Qnil; + + for (i = argc - 1; i >= 0; i--) + { + if (i == 0 || i > skip_args) + Vcommand_line_args + = Fcons (build_string (argv[i]), Vcommand_line_args); + } +} + +#ifdef VMS +#ifdef LINK_CRTL_SHARE +#ifdef SHAREABLE_LIB_BUG +extern noshare char **environ; +#endif /* SHAREABLE_LIB_BUG */ +#endif /* LINK_CRTL_SHARE */ +#endif /* VMS */ + +/* ARGSUSED */ +main (argc, argv, envp) + int argc; + char **argv; + char **envp; +{ + char stack_bottom_variable; + 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 + if (argc > 1 && !strcmp (argv[1], "-nl")) + { + map_in_data (0); + /* The shared memory was just restored, which clobbered this. */ + skip_args = 1; + } + else + { + map_in_data (1); + /* The shared memory was just restored, which clobbered this. */ + skip_args = 0; + } +#endif + +#ifdef HAVE_X_WINDOWS + /* Stupid kludge to catch command-line display spec. ask jla */ + { + int i; + + for (i = 1; (i < argc && ! display_arg); i++) + if (!strcmp (argv[i], "-d")) + 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]); + } + +#ifdef LINK_CRTL_SHARE +#ifdef SHAREABLE_LIB_BUG + /* Bletcherous shared libraries! */ + if (!stdin) + stdin = fdopen (0, "r"); + if (!stdout) + stdout = fdopen (1, "w"); + if (!stderr) + stderr = fdopen (2, "w"); + if (!environ) + environ = envp; +#endif /* SHAREABLE_LIB_BUG */ +#endif /* LINK_CRTL_SHARE */ +#endif /* VMS */ + + /* Record (approximately) where the stack begins. */ + stack_bottom = &stack_bottom_variable; + +#ifdef RUN_TIME_REMAP + if (initialized) + run_time_remap (argv[0]); +#endif + +#ifdef USG_SHARED_LIBRARIES + if (bss_end) + brk (bss_end); +#endif + + clearerr (stdin); +#ifdef BSD + setpgrp (0, getpid ()); +#endif + +#ifdef APOLLO +#ifndef APOLLO_SR10 + /* If USE_DOMAIN_ACLS environment variable exists, + use ACLs rather than UNIX modes. */ + if (egetenv ("USE_DOMAIN_ACLS")) + default_acl (USE_DEFACL); +#endif +#endif /* APOLLO */ + +#ifndef SYSTEM_MALLOC + if (! initialized) + malloc_init (0, malloc_warning); +#endif /* not SYSTEM_MALLOC */ + +#ifdef HIGHPRI + setpriority (PRIO_PROCESS, getpid (), HIGHPRI); + setuid (getuid ()); +#endif /* HIGHPRI */ + +#ifdef BSD + /* interrupt_input has trouble if we aren't in a separate process group. */ + setpgrp (getpid (), getpid ()); +#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]); +#ifdef HAVE_X_WINDOWS + inhibit_window_system = 1; /* -t => -nw */ +#endif + } + + if (skip_args + 1 < argc + && (!strcmp (argv[skip_args + 1], "-nw"))) + { + skip_args += 1; + inhibit_window_system = 1; + } + +/* Handle the -batch switch, which means don't do interactive display. */ + noninteractive = 0; + if (skip_args + 1 < argc && !strcmp (argv[skip_args + 1], "-batch")) + { + skip_args += 1; + noninteractive = 1; + } + + if ( +#ifndef CANNOT_DUMP + ! noninteractive || initialized +#else + 1 +#endif + ) + { + /* Don't catch these signals in batch mode if not initialized. + On some machines, this sets static data that would make + signal fail to work right when the dumped Emacs is run. */ + signal (SIGHUP, fatal_error_signal); + signal (SIGQUIT, fatal_error_signal); + signal (SIGILL, fatal_error_signal); + signal (SIGTRAP, fatal_error_signal); + signal (SIGIOT, fatal_error_signal); +#ifdef SIGEMT + signal (SIGEMT, fatal_error_signal); +#endif + signal (SIGFPE, fatal_error_signal); + signal (SIGBUS, fatal_error_signal); + signal (SIGSEGV, fatal_error_signal); + signal (SIGSYS, fatal_error_signal); + signal (SIGTERM, fatal_error_signal); +#ifdef SIGXCPU + signal (SIGXCPU, fatal_error_signal); +#endif +#ifdef SIGXFSZ + 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); + signal (SIGAIO, fatal_error_signal); + signal (SIGPTY, fatal_error_signal); + signal (SIGIOINT, fatal_error_signal); + signal (SIGGRANT, fatal_error_signal); + signal (SIGRETRACT, fatal_error_signal); + signal (SIGSOUND, fatal_error_signal); + signal (SIGMSG, fatal_error_signal); +#endif /* AIX */ + } + + noninteractive1 = noninteractive; + +/* Perform basic initializations (not merely interning symbols) */ + + if (!initialized) + { + init_alloc_once (); + init_obarray (); + init_eval_once (); + init_syntax_once (); /* Create standard syntax table. */ + /* Must be done before init_buffer */ + init_casetab_once (); + init_buffer_once (); /* Create buffer table and some buffers */ + init_minibuf_once (); /* Create list of minibuffers */ + /* Must precede init_window_once */ + init_window_once (); /* Init the window system */ + } + + init_alloc (); +#ifdef MAINTAIN_ENVIRONMENT + init_environ (); +#endif + init_eval (); + init_data (); + init_read (); + + init_cmdargs (argc, argv, skip_args); /* Create list Vcommand_line_args */ + init_buffer (); /* Init default directory of main buffer */ + if (!noninteractive) + { +#ifdef VMS + init_vms_input ();/* init_display calls get_screen_size, that needs this */ +#endif /* VMS */ + 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 */ + init_sys_modes (); /* Init system terminal modes (RAW or CBREAK, etc.) */ + init_xdisp (); + init_macros (); + init_editfns (); +#ifdef LISP_FLOAT_TYPE + init_floatfns (); +#endif +#ifdef VMS + init_vmsfns (); +#endif /* VMS */ +#ifdef subprocesses + init_process (); +#endif /* subprocesses */ + +/* Intern the names of all standard functions and variables; define standard keys */ + + if (!initialized) + { + /* The basic levels of Lisp must come first */ + /* And data must come first of all + for the sake of symbols like error-message */ + syms_of_data (); + syms_of_alloc (); +#ifdef MAINTAIN_ENVIRONMENT + syms_of_environ (); +#endif /* MAINTAIN_ENVIRONMENT */ + syms_of_read (); + syms_of_print (); + syms_of_eval (); + syms_of_fns (); +#ifdef LISP_FLOAT_TYPE + syms_of_floatfns (); +#endif + + syms_of_abbrev (); + syms_of_buffer (); + syms_of_bytecode (); + syms_of_callint (); + syms_of_casefiddle (); + syms_of_casetab (); + syms_of_callproc (); + syms_of_cmds (); +#ifndef NO_DIR_LIBRARY + syms_of_dired (); +#endif /* not NO_DIR_LIBRARY */ + syms_of_display (); + syms_of_doc (); + syms_of_editfns (); + syms_of_emacs (); + syms_of_fileio (); +#ifdef CLASH_DETECTION + syms_of_filelock (); +#endif /* CLASH_DETECTION */ + syms_of_indent (); + syms_of_keyboard (); + syms_of_keymap (); + syms_of_macros (); + syms_of_marker (); + syms_of_minibuf (); + syms_of_mocklisp (); +#ifdef subprocesses + syms_of_process (); +#endif /* subprocesses */ + syms_of_search (); +#ifdef MULTI_SCREEN + syms_of_screen (); +#endif + syms_of_syntax (); + syms_of_undo (); +#ifdef VMS + syms_of_vmsproc (); +#endif /* VMS */ + syms_of_window (); + syms_of_xdisp (); +#ifdef HAVE_X_WINDOWS + syms_of_xfns (); +#ifdef HAVE_X_MENU + syms_of_xmenu (); +#endif /* HAVE_X_MENU */ +#endif /* HAVE_X_WINDOWS */ + +#ifdef SYMS_SYSTEM + SYMS_SYSTEM; +#endif + +#ifdef SYMS_MACHINE + SYMS_MACHINE; +#endif + + keys_of_casefiddle (); + keys_of_cmds (); + keys_of_buffer (); + keys_of_keyboard (); + keys_of_keymap (); + keys_of_macros (); + keys_of_minibuf (); + keys_of_window (); + } + + if (!initialized) + { + /* Handle -l loadup-and-dump, args passed by Makefile. */ + if (argc > 2 + skip_args && !strcmp (argv[1 + skip_args], "-l")) + Vtop_level = Fcons (intern ("load"), + Fcons (build_string (argv[2 + skip_args]), 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"))) + Vtop_level = Fcons (intern ("load"), + Fcons (build_string ("loadup.el"), Qnil)); +#endif /* CANNOT_DUMP */ + } + + initialized = 1; + + /* Enter editor command loop. This never returns. */ + Frecursive_edit (); + /* NOTREACHED */ +} + +DEFUN ("kill-emacs", Fkill_emacs, Skill_emacs, 0, 1, "P", + "Exit the Emacs job and kill it. Ask for confirmation, without argument.\n\ +If ARG is an integer, return ARG as the exit program code.\n\ +If ARG is a string, stuff it as keyboard input.\n\n\ +The value of `kill-emacs-hook', if not void,\n\ +is a list of functions (of no args),\n\ +all of which are called before Emacs is actually killed.") + (arg) + Lisp_Object arg; +{ + Lisp_Object hook, hook1; + int i; + struct gcpro gcpro1; + + GCPRO1 (arg); + + if (feof (stdin)) + arg = Qt; + + if (!NULL (Vrun_hooks) && !noninteractive) + call1 (Vrun_hooks, intern ("kill-emacs-hook")); + +#ifdef subprocesses + kill_buffer_processes (Qnil); +#endif /* subprocesses */ + +#ifdef VMS + kill_vms_processes (); +#endif /* VMS */ + + Fdo_auto_save (Qt, Qnil); + +#ifdef CLASH_DETECTION + unlock_all_files (); +#endif /* CLASH_DETECTION */ + + fflush (stdout); + reset_sys_modes (); + +#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 + when we are going to exit anyway? */ +/* #ifdef VMS + stop_vms_input (); + #endif */ + stuff_buffered_input (arg); +#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. */ + unrequest_sigio (); + signal (SIGIO, SIG_IGN); +#endif + exit ((XTYPE (arg) == Lisp_Int) ? XINT (arg) +#ifdef VMS + : 1 +#else + : 0 +#endif + ); + /* NOTREACHED */ +} + +#ifndef CANNOT_DUMP +/* Nothing like this can be implemented on an Apollo. + What a loss! */ + +#ifdef HAVE_SHM + +DEFUN ("dump-emacs-data", Fdump_emacs_data, Sdump_emacs_data, 1, 1, 0, + "Dump current state of Emacs into data file FILENAME.\n\ +This function exists on systems that use HAVE_SHM.") + (intoname) + Lisp_Object intoname; +{ + extern int my_edata; + Lisp_Object tem; + extern void malloc_warning (); + + CHECK_STRING (intoname, 0); + intoname = Fexpand_file_name (intoname, Qnil); + + tem = Vpurify_flag; + Vpurify_flag = Qnil; + + fflush (stdout); + /* Tell malloc where start of impure now is */ + /* Also arrange for warnings when nearly out of space. */ +#ifndef SYSTEM_MALLOC + malloc_init (&my_edata, malloc_warning); +#endif + map_out_data (XSTRING (intoname)->data); + + Vpurify_flag = tem; + + return Qnil; +} + +#else /* not HAVE_SHM */ + +DEFUN ("dump-emacs", Fdump_emacs, Sdump_emacs, 2, 2, 0, + "Dump current state of Emacs into executable file FILENAME.\n\ +Take symbols from SYMFILE (presumably the file you executed to run Emacs).\n\ +This is used in the file `loadup.el' when building Emacs.\n\ +\n\ +Bind `command-line-processed' to nil before dumping,\n\ +if you want the dumped Emacs to process its command line\n\ +and announce itself normally when it is run.") + (intoname, symname) + Lisp_Object intoname, symname; +{ + extern int my_edata; + Lisp_Object tem; + extern void malloc_warning (); + + CHECK_STRING (intoname, 0); + intoname = Fexpand_file_name (intoname, Qnil); + if (!NULL (symname)) + { + CHECK_STRING (symname, 0); + if (XSTRING (symname)->size) + symname = Fexpand_file_name (symname, Qnil); + } + + tem = Vpurify_flag; + Vpurify_flag = Qnil; + + fflush (stdout); +#ifdef VMS + mapout_data (XSTRING (intoname)->data); +#else + /* Tell malloc where start of impure now is */ + /* Also arrange for warnings when nearly out of space. */ +#ifndef SYSTEM_MALLOC + malloc_init (&my_edata, malloc_warning); +#endif + unexec (XSTRING (intoname)->data, + !NULL (symname) ? XSTRING (symname)->data : 0, &my_edata, 0, 0); +#endif /* not VMS */ + + Vpurify_flag = tem; + + return Qnil; +} + +#endif /* not HAVE_SHM */ + +#endif /* not CANNOT_DUMP */ + +#ifdef VMS +#define SEPCHAR ',' +#else +#define SEPCHAR ':' +#endif + +Lisp_Object +decode_env_path (evarname, defalt) + char *evarname, *defalt; +{ + register char *path, *p; + extern char *index (); + + Lisp_Object lpath; + + path = (char *) egetenv (evarname); + if (!path) + path = defalt; + lpath = Qnil; + while (1) + { + p = index (path, SEPCHAR); + if (!p) p = path + strlen (path); + lpath = Fcons (p - path ? make_string (path, p - path) : Qnil, + lpath); + if (*p) + path = p + 1; + else + break; + } + return Fnreverse (lpath); +} + +syms_of_emacs () +{ +#ifdef HAVE_SHM + defsubr (&Sdump_emacs_data); +#else + defsubr (&Sdump_emacs); +#endif + + defsubr (&Skill_emacs); + + DEFVAR_LISP ("command-line-args", &Vcommand_line_args, + "Args passed by shell to Emacs, as a list of strings."); + + DEFVAR_LISP ("system-type", &Vsystem_type, + "Value is symbol indicating type of operating system you are using."); + Vsystem_type = intern (SYSTEM_TYPE); + + DEFVAR_BOOL ("noninteractive", &noninteractive1, + "Non-nil means Emacs is running without interactive terminal."); +}