1 /* Fully extensible Emacs, running on Unix, intended for GNU.
2    Copyright (C) 1985, 1986, 1987, 1990 Free Software Foundation, Inc.
3 
4 This file is part of GNU Emacs.
5 
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
10 
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING.  If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
19 
20 
21 #include <signal.h>
22 #include <errno.h>
23 
24 #include "config.h"
25 #include <stdio.h>
26 #undef NULL
27 #include "lisp.h"
28 #include "commands.h"
29 
30 #include <sys/types.h>
31 #include <sys/file.h>
32 
33 #ifdef VMS
34 #include <ssdef.h>
35 #endif
36 
37 #ifdef USG5
38 #include <fcntl.h>
39 #endif
40 
41 #ifdef BSD
42 #include <sys/ioctl.h>
43 #endif
44 
45 #ifdef APOLLO
46 #ifndef APOLLO_SR10
47 #include <default_acl.h>
48 #endif
49 #endif
50 
51 #ifndef O_RDWR
52 #define O_RDWR 2
53 #endif
54 
55 #define PRIO_PROCESS 0
56 
57 /* Command line args from shell, as list of strings */
58 Lisp_Object Vcommand_line_args;
59 
60 /* Hook run by `kill-emacs' before it does really anything.  */
61 Lisp_Object Vkill_emacs_hook;
62 
63 /* Set nonzero after Emacs has started up the first time.
64   Prevents reinitialization of the Lisp world and keymaps
65   on subsequent starts.  */
66 int initialized;
67 
68 /* Variable whose value is symbol giving operating system type */
69 Lisp_Object Vsystem_type;
70 
71 /* If non-zero, emacs should not attempt to use an window-specific code,
72    but instead should use the virtual terminal under which it was started */
73 int inhibit_window_system;
74 
75 #ifdef HAVE_X_WINDOWS
76 /* If -d option is used, this variable points to the name of
77    the display to use.  */
78 char *alternate_display;
79 char **xargv;
80 int xargc;
81 #endif /* HAVE_X_WINDOWS */
82 
83 #ifdef USG_SHARED_LIBRARIES
84 /* If nonzero, this is the place to put the end of the writable segment
85    at startup.  */
86 
87 unsigned int bss_end = 0;
88 #endif
89 
90 /* Nonzero means running Emacs without interactive terminal.  */
91 
92 int noninteractive;
93 
94 /* Value of Lisp variable `noninteractive'.
95    Normally same as C variable `noninteractive'
96    but nothing terrible happens if user sets this one.  */
97 
98 int noninteractive1;
99 
100 /* Signal code for the fatal signal that was received */
101 int fatal_error_code;
102 
103 /* Nonzero if handling a fatal error already */
104 int fatal_error_in_progress;
105 
106 /* Handle bus errors, illegal instruction, etc. */
107 fatal_error_signal (sig)
108      int sig;
109 {
110 #ifdef BSD
111   int tpgrp;
112 #endif /* BSD */
113 
114   fatal_error_code = sig;
115   signal (sig, SIG_DFL);
116 
117   /* If fatal error occurs in code below, avoid infinite recursion.  */
118   if (fatal_error_in_progress)
119     kill (getpid (), fatal_error_code);
120 
121   fatal_error_in_progress = 1;
122 
123   /* If we are controlling the terminal, reset terminal modes */
124 #ifdef BSD
125   if (ioctl(0, TIOCGPGRP, &tpgrp) == 0
126       && tpgrp == getpgrp (0))
127 #endif /* BSD */
128     {
129       reset_sys_modes ();
130       if (sig != SIGTERM)
131 	fprintf (stderr, "Fatal error (%d).", sig);
132     }
133 
134   /* Clean up */
135 #ifdef subprocesses
136   kill_buffer_processes (Qnil);
137 #endif
138   Fdo_auto_save (Qt);
139 
140 #ifdef CLASH_DETECTION
141   unlock_all_files ();
142 #endif /* CLASH_DETECTION */
143 
144 #ifdef VMS
145   kill_vms_processes ();
146   LIB$STOP (SS$_ABORT);
147 #else
148   /* Signal the same code; this time it will really be fatal.  */
149   kill (getpid (), fatal_error_code);
150 #endif /* not VMS */
151 }
152 
153 /* Code for dealing with Lisp access to the Unix command line */
154 
155 static
156 init_cmdargs (argc, argv, skip_args)
157      int argc;
158      char **argv;
159      int skip_args;
160 {
161   register int i;
162 
163   Vcommand_line_args = Qnil;
164 
165   for (i = argc - 1; i >= 0; i--)
166     {
167       if (i == 0 || i > skip_args)
168 	Vcommand_line_args
169 	  = Fcons (build_string (argv[i]), Vcommand_line_args);
170     }
171 }
172 
173 #ifdef VMS
174 #ifdef LINK_CRTL_SHARE
175 #ifdef SHAREABLE_LIB_BUG
176 extern noshare char **environ;
177 #endif /* SHAREABLE_LIB_BUG */
178 #endif /* LINK_CRTL_SHARE */
179 #endif /* VMS */
180 
181 /* ARGSUSED */
182 main (argc, argv, envp)
183      int argc;
184      char **argv;
185      char **envp;
186 {
187   int skip_args = 0;
188   extern int errno;
189   extern void malloc_warning ();
190 
191 /* Map in shared memory, if we are using that.  */
192 #ifdef HAVE_SHM
193   if (argc > 1 && !strcmp (argv[1], "-nl"))
194     {
195       map_in_data (0);
196       /* The shared momory was just restored, which clobbered this.  */
197       skip_args = 1;
198     }
199   else
200     {
201       map_in_data (1);
202       /* The shared momory was just restored, which clobbered this.  */
203       skip_args = 0;
204     }
205 #endif
206 
207 #ifdef VMS
208   /* If -map specified, map the data file in */
209   if (argc > 2 && ! strcmp (argv[1], "-map"))
210     {
211       skip_args = 2;
212       mapin_data (argv[2]);
213     }
214 
215 #ifdef LINK_CRTL_SHARE
216 #ifdef SHAREABLE_LIB_BUG
217   /* Bletcherous shared libraries! */
218   if (!stdin)
219     stdin = fdopen (0, "r");
220   if (!stdout)
221     stdout = fdopen (1, "w");
222   if (!stderr)
223     stderr = fdopen (2, "w");
224   if (!environ)
225     environ = envp;
226 #endif /* SHAREABLE_LIB_BUG */
227 #endif /* LINK_CRTL_SHARE */
228 #endif /* VMS */
229 
230 #ifdef USG_SHARED_LIBRARIES
231   if (bss_end)
232     brk (bss_end);
233 #endif
234 
235   clearerr (stdin);
236 
237 #ifdef APOLLO
238 #ifndef APOLLO_SR10
239   /* If USE_DOMAIN_ACLS environment variable exists,
240      use ACLs rather than UNIX modes. */
241   if (egetenv ("USE_DOMAIN_ACLS"))
242     default_acl (USE_DEFACL);
243 #endif
244 #endif /* APOLLO */
245 
246 #ifndef SYSTEM_MALLOC
247   /* Arrange for warnings when nearly out of space.  */
248   malloc_init (0, malloc_warning);
249 #endif
250 
251 #ifdef HIGHPRI
252   setpriority (PRIO_PROCESS, getpid (), HIGHPRI);
253   setuid (getuid ());
254 #endif HIGHPRI
255 
256   inhibit_window_system = 0;
257 
258 #ifdef HAVE_X_WINDOWS
259   xargv = argv;
260   xargc = argc;
261 #endif
262 
263 /* Handle the -t switch, which specifies filename to use as terminal */
264   if (skip_args + 2 < argc && !strcmp (argv[skip_args + 1], "-t"))
265     {
266       skip_args += 2;
267       close (0);
268       close (1);
269       open (argv[skip_args], O_RDWR, 2 );
270       dup (0);
271       fprintf (stderr, "Using %s\n", argv[skip_args]);
272 #ifdef HAVE_X_WINDOWS
273       inhibit_window_system = 1;	/* -t => -nw */
274 #endif
275     }
276 #ifdef HAVE_X_WINDOWS
277 /* Handle the -d switch, which means use a different display for X */
278   if (skip_args + 2 < argc && (!strcmp (argv[skip_args + 1], "-d") ||
279 			       !strcmp (argv[skip_args + 1], "-display")))
280     {
281       skip_args += 2;
282       alternate_display = argv[skip_args];
283     }
284   else
285     alternate_display = 0;
286 #endif	/* HAVE_X_WINDOWS */
287 
288   if (skip_args + 1 < argc
289       && (!strcmp (argv[skip_args + 1], "-nw")))
290     {
291       skip_args += 1;
292       inhibit_window_system = 1;
293     }
294 
295 /* Handle the -batch switch, which means don't do interactive display.  */
296   noninteractive = 0;
297   if (skip_args + 1 < argc && !strcmp (argv[skip_args + 1], "-batch"))
298     {
299       skip_args += 1;
300       noninteractive = 1;
301     }
302 
303   if (
304 #ifndef CANNOT_DUMP
305       ! noninteractive || initialized
306 #else
307       1
308 #endif
309       )
310     {
311       /* Don't catch these signals in batch mode if not initialized.
312 	 On some machines, this sets static data that would make
313 	 signal fail to work right when the dumped Emacs is run.  */
314       signal (SIGHUP, fatal_error_signal);
315       signal (SIGQUIT, fatal_error_signal);
316       signal (SIGILL, fatal_error_signal);
317       signal (SIGTRAP, fatal_error_signal);
318       signal (SIGIOT, fatal_error_signal);
319 #ifdef SIGEMT
320       signal (SIGEMT, fatal_error_signal);
321 #endif
322       signal (SIGFPE, fatal_error_signal);
323       signal (SIGBUS, fatal_error_signal);
324       signal (SIGSEGV, fatal_error_signal);
325       signal (SIGSYS, fatal_error_signal);
326       signal (SIGTERM, fatal_error_signal);
327 #ifdef SIGXCPU
328       signal (SIGXCPU, fatal_error_signal);
329 #endif
330 #ifdef SIGXFSZ
331       signal (SIGXFSZ, fatal_error_signal);
332 #endif SIGXFSZ
333 
334 #ifdef AIX
335       signal (SIGDANGER, fatal_error_signal);
336       signal (20, fatal_error_signal);
337       signal (21, fatal_error_signal);
338       signal (22, fatal_error_signal);
339       signal (23, fatal_error_signal);
340       signal (24, fatal_error_signal);
341       signal (SIGAIO, fatal_error_signal);
342       signal (SIGPTY, fatal_error_signal);
343       signal (SIGIOINT, fatal_error_signal);
344       signal (SIGGRANT, fatal_error_signal);
345       signal (SIGRETRACT, fatal_error_signal);
346       signal (SIGSOUND, fatal_error_signal);
347       signal (SIGMSG, fatal_error_signal);
348 #endif /* AIX */
349     }
350 
351   noninteractive1 = noninteractive;
352 
353 /* Perform basic initializations (not merely interning symbols) */
354 
355   if (!initialized)
356     {
357       init_alloc_once ();
358       init_obarray ();
359       init_eval_once ();
360       init_syntax_once ();	/* Create standard syntax table.  */
361 		      /* Must be done before init_buffer */
362       init_buffer_once ();	/* Create buffer table and some buffers */
363       init_minibuf_once ();	/* Create list of minibuffers */
364 			      /* Must precede init_window_once */
365       init_window_once ();	/* Init the window system */
366     }
367 
368   init_alloc ();
369 #ifdef MAINTAIN_ENVIRONMENT
370   init_environ ();
371 #endif
372   init_eval ();
373   init_data ();
374   init_read ();
375 
376   init_cmdargs (argc, argv, skip_args);	/* Create list Vcommand_line_args */
377   init_buffer ();	/* Init default directory of main buffer */
378   if (!noninteractive)
379     {
380 #ifdef VMS
381       init_vms_input ();/* init_display calls get_screen_size, that needs this */
382 #endif /* VMS */
383       init_display ();	/* Determine terminal type.  init_sys_modes uses results */
384     }
385   init_keyboard ();	/* This too must precede init_sys_modes */
386   init_callproc ();	/* And this too. */
387   init_sys_modes ();	/* Init system terminal modes (RAW or CBREAK, etc.) */
388   init_xdisp ();
389   init_macros ();
390   init_editfns ();
391 #ifdef VMS
392   init_vmsfns ();
393 #endif /* VMS */
394 #ifdef subprocesses
395   init_process ();
396 #endif /* subprocesses */
397 
398 /* Intern the names of all standard functions and variables; define standard keys */
399 
400   if (!initialized)
401     {
402       /* The basic levels of Lisp must come first */
403       /* And data must come first of all
404 	 for the sake of symbols like error-message */
405       syms_of_data ();
406       syms_of_alloc ();
407 #ifdef MAINTAIN_ENVIRONMENT
408       syms_of_environ ();
409 #endif MAINTAIN_ENVIRONMENT
410       syms_of_read ();
411       syms_of_print ();
412       syms_of_eval ();
413       syms_of_fns ();
414 
415       syms_of_abbrev ();
416       syms_of_buffer ();
417       syms_of_bytecode ();
418       syms_of_callint ();
419       syms_of_casefiddle ();
420       syms_of_callproc ();
421       syms_of_cmds ();
422 #ifndef NO_DIR_LIBRARY
423       syms_of_dired ();
424 #endif /* not NO_DIR_LIBRARY */
425       syms_of_display ();
426       syms_of_doc ();
427       syms_of_editfns ();
428       syms_of_emacs ();
429       syms_of_fileio ();
430 #ifdef CLASH_DETECTION
431       syms_of_filelock ();
432 #endif /* CLASH_DETECTION */
433       syms_of_indent ();
434       syms_of_keyboard ();
435       syms_of_keymap ();
436       syms_of_macros ();
437       syms_of_marker ();
438       syms_of_minibuf ();
439       syms_of_mocklisp ();
440 #ifdef subprocesses
441       syms_of_process ();
442 #endif /* subprocesses */
443       syms_of_search ();
444       syms_of_syntax ();
445       syms_of_undo ();
446       syms_of_window ();
447       syms_of_xdisp ();
448 #ifdef HAVE_X_WINDOWS
449       syms_of_xfns ();
450 #ifdef HAVE_X_MENU
451       syms_of_xmenu ();
452 #endif /* HAVE_X_MENU */
453 #endif /* HAVE_X_WINDOWS */
454 
455 #ifdef SYMS_SYSTEM
456       SYMS_SYSTEM;
457 #endif
458 
459 #ifdef SYMS_MACHINE
460       SYMS_MACHINE;
461 #endif
462 
463       keys_of_casefiddle ();
464       keys_of_cmds ();
465       keys_of_buffer ();
466       keys_of_keyboard ();
467       keys_of_keymap ();
468       keys_of_macros ();
469       keys_of_minibuf ();
470       keys_of_window ();
471     }
472 
473   if (!initialized)
474     {
475       /* Handle -l loadup-and-dump, args passed by Makefile. */
476       if (argc > 2 + skip_args && !strcmp (argv[1 + skip_args], "-l"))
477 	Vtop_level = Fcons (intern ("load"),
478 			    Fcons (build_string (argv[2 + skip_args]), Qnil));
479 #ifdef CANNOT_DUMP
480       /* Unless next switch is -nl, load "loadup.el" first thing.  */
481       if (!(argc > 1 + skip_args && !strcmp (argv[1 + skip_args], "-nl")))
482 	Vtop_level = Fcons (intern ("load"),
483 			    Fcons (build_string ("loadup.el"), Qnil));
484 #endif /* CANNOT_DUMP */
485     }
486 
487   initialized = 1;
488 
489   /* Enter editor command loop.  This never returns.  */
490   Frecursive_edit ();
491   /* NOTREACHED */
492 }
493 
494 DEFUN ("kill-emacs", Fkill_emacs, Skill_emacs, 0, 1, "P",
495   "Exit the Emacs job and kill it.  ARG means no query.\n\
496 If emacs is running noninteractively and ARG is an integer,\n\
497 return ARG as the exit program code.")
498   (arg)
499      Lisp_Object arg;
500 {
501   Lisp_Object answer;
502   int i;
503   struct gcpro gcpro1;
504 
505   GCPRO1 (arg);
506 
507   if (!NULL (Vkill_emacs_hook))
508     call0 (Vkill_emacs_hook);
509 
510   if (feof (stdin))
511     arg = Qt;
512 
513 #ifdef subprocesses
514   kill_buffer_processes (Qnil);
515 #endif /* subprocesses */
516 
517 #ifdef VMS
518   kill_vms_processes ();
519 #endif /* VMS */
520 
521   Fdo_auto_save (Qt);
522 
523 #ifdef CLASH_DETECTION
524   unlock_all_files ();
525 #endif /* CLASH_DETECTION */
526 
527   fflush (stdout);
528   reset_sys_modes ();
529   UNGCPRO;
530 
531 /* Is it really necessary to do this deassign
532    when we are going to exit anyway?  */
533 /* #ifdef VMS
534   stop_vms_input ();
535  #endif  */
536   stuff_buffered_input (arg);
537 #ifdef SIGIO
538   /* There is a tendency for a SIGIO signal to arrive within exit,
539      and cause a SIGHUP because the input descriptor is already closed.  */
540   unrequest_sigio ();
541   signal (SIGIO, SIG_IGN);
542 #endif
543   exit ((XTYPE (arg) == Lisp_Int) ? XINT (arg)
544 #ifdef VMS
545 	: 1
546 #else
547 	: 0
548 #endif
549 	);
550   /* NOTREACHED */
551 }
552 
553 #ifndef CANNOT_DUMP
554 /* Nothing like this can be implemented on an Apollo.
555    What a loss!  */
556 
557 #ifdef HAVE_SHM
558 
559 DEFUN ("dump-emacs-data", Fdump_emacs_data, Sdump_emacs_data, 1, 1, 0,
560   "Dump current state of Emacs into data file FILENAME.\n\
561 This function exists on systems that use HAVE_SHM.")
562   (intoname)
563      Lisp_Object intoname;
564 {
565   extern int my_edata;
566   Lisp_Object tem;
567   extern void malloc_warning ();
568 
569   CHECK_STRING (intoname, 0);
570   intoname = Fexpand_file_name (intoname, Qnil);
571 
572   tem = Vpurify_flag;
573   Vpurify_flag = Qnil;
574 
575   fflush (stdout);
576   /* Tell malloc where start of impure now is */
577   /* Also arrange for warnings when nearly out of space.  */
578 #ifndef SYSTEM_MALLOC
579   malloc_init (&my_edata, malloc_warning);
580 #endif
581   map_out_data (XSTRING (intoname)->data);
582 
583   Vpurify_flag = tem;
584 
585   return Qnil;
586 }
587 
588 #else /* not HAVE_SHM */
589 
590 DEFUN ("dump-emacs", Fdump_emacs, Sdump_emacs, 2, 2, 0,
591   "Dump current state of Emacs into executable file FILENAME.\n\
592 Take symbols from SYMFILE (presumably the file you executed to run Emacs).")
593   (intoname, symname)
594      Lisp_Object intoname, symname;
595 {
596   extern int my_edata;
597   Lisp_Object tem;
598   extern void malloc_warning ();
599 
600   CHECK_STRING (intoname, 0);
601   intoname = Fexpand_file_name (intoname, Qnil);
602   if (!NULL (symname))
603     {
604       CHECK_STRING (symname, 0);
605       if (XSTRING (symname)->size)
606 	symname = Fexpand_file_name (symname, Qnil);
607     }
608 
609   tem = Vpurify_flag;
610   Vpurify_flag = Qnil;
611 
612   fflush (stdout);
613 #ifdef VMS
614   mapout_data (XSTRING (intoname)->data);
615 #else
616   /* Tell malloc where start of impure now is */
617   /* Also arrange for warnings when nearly out of space.  */
618 #ifndef SYSTEM_MALLOC
619   malloc_init (&my_edata, malloc_warning);
620 #endif
621   unexec (XSTRING (intoname)->data,
622 	  !NULL (symname) ? XSTRING (symname)->data : 0, &my_edata, 0, 0);
623 #endif /* not VMS */
624 
625   Vpurify_flag = tem;
626 
627   return Qnil;
628 }
629 
630 #endif /* not HAVE_SHM */
631 
632 #endif /* not CANNOT_DUMP */
633 
634 #ifdef VMS
635 #define SEPCHAR ','
636 #else
637 #define SEPCHAR ':'
638 #endif
639 
640 Lisp_Object
641 decode_env_path (evarname, defalt)
642      char *evarname, *defalt;
643 {
644   register char *path, *p;
645   extern char *index ();
646 
647   Lisp_Object lpath;
648 
649   path = (char *) egetenv (evarname);
650   if (!path)
651     path = defalt;
652   lpath = Qnil;
653   while (1)
654     {
655       p = index (path, SEPCHAR);
656       if (!p) p = path + strlen (path);
657       lpath = Fcons (p - path ? make_string (path, p - path) : Qnil,
658 		     lpath);
659       if (*p)
660 	path = p + 1;
661       else
662 	break;
663     }
664   return Fnreverse (lpath);
665 }
666 
667 syms_of_emacs ()
668 {
669 #ifndef CANNOT_DUMP
670 #ifdef HAVE_SHM
671   defsubr (&Sdump_emacs_data);
672 #else
673   defsubr (&Sdump_emacs);
674 #endif
675 #endif /* not CANNOT_DUMP */
676 
677   defsubr (&Skill_emacs);
678 
679   DEFVAR_LISP ("command-line-args", &Vcommand_line_args,
680     "Args passed by shell to Emacs, as a list of strings.");
681 
682   DEFVAR_LISP ("system-type", &Vsystem_type,
683     "Symbol indicating type of operating system you are using.");
684   Vsystem_type = intern (SYSTEM_TYPE);
685 
686   DEFVAR_BOOL ("noninteractive", &noninteractive1,
687     "Non-nil means Emacs is running without interactive terminal.");
688 
689   Vkill_emacs_hook = Qnil;
690 
691   DEFVAR_LISP ("kill-emacs-hook", &Vkill_emacs_hook,
692     "Function called, if non-nil, whenever kill-emacs is called.");
693 }
694