diff src/emacs.c @ 16:0293115a14e9 r19-15b91

Import from CVS: tag r19-15b91
author cvs
date Mon, 13 Aug 2007 08:49:20 +0200
parents 9ee227acff29
children 859a2309aef8
line wrap: on
line diff
--- a/src/emacs.c	Mon Aug 13 08:48:43 2007 +0200
+++ b/src/emacs.c	Mon Aug 13 08:49:20 2007 +0200
@@ -140,6 +140,8 @@
 char **initial_argv;
 int initial_argc;
 
+static void sort_args (int argc, char **argv);
+
 extern int always_gc;           /* hack */
 
 Lisp_Object Qkill_emacs_hook;
@@ -279,7 +281,7 @@
   for (i = argc - 1; i >= 0; i--)
     {
       if (i == 0 || i > skip_args)
-	result = Fcons (build_ext_string (argv [i], FORMAT_OS), result);
+	result = Fcons (build_ext_string (argv [i], FORMAT_FILENAME), result);
     }
   return result;
 }
@@ -343,6 +345,14 @@
   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);
+}
+
 
 #ifdef I18N4
 				/* #### - don't know why I18N4 on SunOS/JLE
@@ -351,6 +361,69 @@
 # undef RUN_TIME_REMAP
 #endif
 
+/* 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 (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 = strchr (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;
+    }
+}
+
 static DOESNT_RETURN
 main_1 (int argc, char **argv, char **envp)
 {
@@ -359,6 +432,8 @@
   Lisp_Object load_me;
   int inhibit_window_system;
 
+  noninteractive = 0;
+
 #ifdef NeXT
   extern int malloc_cookie;
   
@@ -369,8 +444,7 @@
    * work with dumping.  But malloc_jumpstart() and malloc_freezedry() in
    * unexnext.c are both completely undocumented, even in NS header files!
    * But hey, it solves all NS related memory problems, so who's
-   * complaining?
-   */
+   * complaining? */
   if (initialized)
     if (malloc_jumpstart (malloc_cookie) != 0)
       printf ("malloc jumpstart failed!\n");
@@ -383,9 +457,11 @@
 #endif
 #endif
 
+  sort_args (argc, argv);
+
   /* 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.  */
@@ -397,7 +473,7 @@
       /* The shared memory was just restored, which clobbered this.  */
       skip_args = 0;
     }
-#endif
+#endif /* HAVE_SHM */
 
 #ifdef VMS
   /* If -map specified, map the data file in */
@@ -456,19 +532,16 @@
 #endif /* HAVE_SOCKS */
 
 #ifndef SYSTEM_MALLOC
-
   if (!initialized)
-    {
-      /* Arrange to get warning messages as memory fills up.  */
-      memory_warnings (0, malloc_warning);
-    }
+    /* Arrange to get warning messages as memory fills up.  */
+    memory_warnings (0, malloc_warning);
 #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;
+  (stdin) ->_flag &= ~_IOTEXT;
   (stdout)->_flag &= ~_IOTEXT;
   (stderr)->_flag &= ~_IOTEXT;
 #endif /* MSDOS */
@@ -490,56 +563,42 @@
 #endif
 
   /* Handle the -t switch, which specifies filename to use as terminal */
-  if (skip_args + 2 < argc && !strcmp (argv[skip_args + 1], "-t"))
-    {
-      int result;
+  {
+    char *term;
+    if (argmatch (argv, argc, "-t", "--terminal", 4, &term, &skip_args))
+      {
+	close (0);
+	close (1);
+	if (open (term, O_RDWR, 2) < 0)
+	  fatal ("%s: %s", term, strerror (errno));
+	dup (0);
+	if (! isatty (0))
+	  fatal ("%s: not a tty", term);
 
-      skip_args += 2;
-      close (0);
-      close (1);
-      result = open (argv[skip_args], O_RDWR, 2 );
-      if (result < 0)
-	{
-	  fatal ("%s: %s", argv[skip_args], strerror (errno));
-	}
-      dup (0);
-      if (! isatty (0))
-	fatal ("%s: not a tty", argv[skip_args]);
+	stderr_out ("Using %s", ttyname (0));
+	inhibit_window_system = 1;	/* -t => -nw */
+      }
+  }
 
-      stderr_out ("Using %s", ttyname (0));
-#if 0
-      stderr_out ("Using %s", argv[skip_args]);
-#endif
-      inhibit_window_system = 1;	/* -t => -nw */
-    }
-
-  if (skip_args + 1 < argc
-      && (!strcmp (argv[skip_args + 1], "-nw")))
-    {
-      skip_args += 1;
-      inhibit_window_system = 1;
-    }
+  /* Handle -nw switch */
+  if (argmatch (argv, argc, "-nw", "--no-windows", 6, NULL, &skip_args))
+    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") ||
-       !strcmp (argv[skip_args + 1], "--batch")))
-    {
-      skip_args += 1;
-      noninteractive = 1;
-    }
-
+  if (argmatch (argv, argc, "-batch", "--batch", 5, NULL, &skip_args))
+    noninteractive = 1;
+ 
   /* Partially handle the -version and -help switches: they imply -batch,
-     but are not removed from the list.
-   */
-  if (skip_args + 1 < argc &&
-      (!strcmp (argv[skip_args + 1], "-version") ||
-       !strcmp (argv[skip_args + 1], "--version") ||
-       !strcmp (argv[skip_args + 1], "-help") ||
-       !strcmp (argv[skip_args + 1], "--help")))
-    noninteractive = 1;
+     but are not removed from the list. */
+  if (argmatch (argv, argc, "-help", "--help",   3, NULL, &skip_args) ||
+      argmatch (argv, argc, "-?",     0,         2, NULL, &skip_args) ||
+      argmatch (argv, argc, "-flags", "--flags", 6, NULL, &skip_args))
+    noninteractive = 1, skip_args--;
 
+  if (argmatch (argv, argc, "-version", "--version", 3, NULL, &skip_args) ||
+      argmatch (argv, argc, "-V",    0,              2, NULL, &skip_args))
+      noninteractive = 1, skip_args--;
+  
   /* Now, figure out which type of console is our first console. */
 
   display_arg = 0;
@@ -556,42 +615,62 @@
 
 #ifdef HAVE_WINDOW_SYSTEM
   /* 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
+     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.  */
   if (!inhibit_window_system && !noninteractive)
     {
-      int i;
-      char *disp;
+#ifdef HAVE_X_WINDOWS
+      char *dpy = 0;
+      int count_before = skip_args;
       
-      for (i = 1; (i < argc && !display_arg); i++)
+      if (argmatch (argv, argc, "-d", "--display", 3, &dpy, &skip_args) ||
+	  argmatch (argv, argc, "-display", 0,     3, &dpy, &skip_args))
+	{
+	  display_arg = 1;
+	  display_use = "x";
+	}
+      /* If we have the form --display=NAME,
+	 convert it into  -d name.
+	 This requires inserting a new element into argv.  */
+      if (dpy != 0 && skip_args - count_before == 1)
 	{
-#ifdef HAVE_X_WINDOWS
-	  if (!strcmp (argv[i], "-d") || !strcmp (argv[i], "-display"))
-	    {
-	      display_arg = 1;
-	      display_use = "x";
-	    }
-#endif /* HAVE_X_WINDOWS */
-#ifdef HAVE_NEXTSTEP
-	  if (!strcmp (argv[i], "-NXHost") || !strcmp (argv[i], "-MachLaunch"))
-	    {
-	      display_arg = 1;
-	      display_use = "ns";
-	    }
-#endif /* HAVE_NEXTSTEP */
+	  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] = dpy;
+	  for (j = count_before + 2; j <argc; j++)
+	    new[j + 1] = argv[j];
+	  argv = new;
+	  argc++;
 	}
-      
-#ifdef HAVE_X_WINDOWS
-      disp = getenv ("DISPLAY");
+      /* Change --display to -d, when its arg is separate.  */
+      else if (dpy != 0 && skip_args > count_before
+	       && argv[count_before + 1][1] == '-')
+	argv[count_before + 1] = "-d";
 
-      /* null string doesn't count as a display */
-      if (disp && disp[0])
+      /* Don't actually discard this arg.  */
+      skip_args = count_before;
+
+      /* If there is a non-empty environment var DISPLAY, set
+         `display_use', but not `display_arg', which is only to be set
+         if the display was specified on the command line. */
+      if ((dpy = getenv ("DISPLAY")) && dpy[0])
 	display_use = "x";
 
-      /* Do not set display_arg here.  It is only to be set if the display
-	 was specified on the command line. */
-#endif
+#endif /* HAVE_X_WINDOWS */
+
+#ifdef HAVE_NEXTSTEP
+      if (argmatch (argv, argc, "-NXHost",     0, 6, 0, &skip_args) ||
+	  argmatch (argv, argc, "-MachLaunch", 0, 9, 0, &skip_args))
+	{
+	  display_arg = 1;
+	  display_use = "ns";
+	}
+#endif /* HAVE_NEXTSTEP */
     }
 #endif /* HAVE_WINDOW_SYSTEM */
 
@@ -648,7 +727,7 @@
 	 is call one of the following three functions:
 
 	 defsymbol()
-	 defsubr()
+	 defsubr() (i.e. DEFSUBR)
 	 deferror()
 	 defkeyword()
 
@@ -1293,7 +1372,7 @@
     {
       /* Handle -l loadup-and-dump, args passed by Makefile. */
       if (argc > 2 + skip_args && !strcmp (argv[1 + skip_args], "-l"))
-        load_me = build_string (argv[2 + skip_args]);
+	load_me = build_string (argv[2 + skip_args]);
 #ifdef CANNOT_DUMP
       /* Unless next switch is -nl, load "loadup.el" first thing.  */
       if (!(argc > 1 + skip_args && !strcmp (argv[1 + skip_args], "-nl")))
@@ -1313,6 +1392,217 @@
   /* NOTREACHED */
 }
 
+
+/* 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
+{
+  CONST char * CONST name;
+  CONST char * CONST longname;
+  int priority;
+  int nargs;
+};
+
+static struct standard_args standard_args[] =
+{
+  /* Handled by main_1 above: */
+  { "-nl", "--no-shared-memory", 100, 0 },
+#ifdef VMS
+  { "-map", "--map-data", 100, 0 },
+#endif
+  { "-t", "--terminal", 95, 1 },
+  { "-nw", "--no-windows", 90, 0 },
+  { "-batch", "--batch", 85, 0 },
+  { "-help", "--help", 80, 0 },
+  { "-flags", "--flags", 80, 0 },
+  { "-h", 0, 80, 0 },
+  { "-?", 0, 80, 0 },
+  { "-version", "--version", 75, 0 },
+  { "-V", 0, 75, 0 },
+  { "-d", "--display", 80, 1 },
+  { "-display", 0, 80, 1 },
+  { "-NXHost",  0, 79, 0 },
+  { "-MachLaunch", 0, 79, 0},
+
+  /* Handled by command-line-early in startup.el: */
+  { "-q", "--no-init-file", 50, 0 },
+  { "-unmapped", 0, 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 },
+
+  /* Xt options: */
+  { "-i", "--icon-type", 15, 0 },
+  { "-itype", 0, 15, 0 },
+  { "-iconic", "--iconic", 15, 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 },
+  { "-title", 0, 10, 1 },
+  { "-name", "--name", 10, 1 },
+  { "-xrm", "--xrm", 10, 1 },
+  { "-r", "--reverse-video", 5, 0 },
+  { "-rv", 0, 5, 0 },
+  { "-reverse", 0, 5, 0 },
+  { "-hb", "--horizontal-scroll-bars", 5, 0 },
+  { "-vb", "--vertical-scroll-bars", 5, 0 },
+
+  /* These have the same priority as ordinary file name args,
+     so they are not reordered with respect to those.  */
+  { "-L", "--directory", 0, 1 },
+  { "-directory", 0, 0, 1 },
+  { "-l", "--load", 0, 1 },
+  { "-load", 0, 0, 1 },
+  { "-f", "--funcall", 0, 1 },
+  { "-funcall", 0, 0, 1 },
+  { "-eval", "--eval", 0, 1 },
+  { "-insert", "--insert", 0, 1 },
+  /* This should be processed after ordinary file name args and the like.  */
+  { "-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 (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;
+  int end_of_options_p = 0;
+
+  /* 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;
+      /* Pseudo options "--" and "run-temacs" indicate end of options */
+      if (!strcmp (argv[from], "--") ||
+	  !strcmp (argv[from], "run-temacs"))
+	end_of_options_p = 1;
+      if (!end_of_options_p && argv[from][0] == '-')
+	{
+	  int match, thislen;
+	  char *equals;
+
+	  /* Look for a match with a known old-fashioned option.  */
+	  for (i = 0; i < countof (standard_args); i++)
+	    if (!strcmp (argv[from], standard_args[i].name))
+	      {
+		options[from]  = standard_args[i].nargs;
+		priority[from] = standard_args[i].priority;
+		if (from + standard_args[i].nargs >= argc)
+		  fatal ("Option `%s' requires an argument\n", argv[from]);
+		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 = strchr (argv[from], '=');
+	      if (equals != 0)
+		thislen = equals - argv[from];
+
+	      for (i = 0; i < countof (standard_args); i++)
+		if (standard_args[i].longname
+		    && !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;
+		  if (from + options[from] >= argc)
+		    fatal ("Option `%s' requires an argument\n", argv[from]);
+		  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 = -9999;
+
+      /* 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;
+    }
+
+  memcpy (argv, new, sizeof (char *) * argc);
+}
+
 static JMP_BUF run_temacs_catch;
 
 static int run_temacs_argc;
@@ -1407,6 +1697,9 @@
 DOESNT_RETURN
 main (int argc, char **argv, char **envp)
 {
+  int     volatile vol_argc = argc;
+  char ** volatile vol_argv = argv;
+  char ** volatile vol_envp = envp;
 #ifdef QUANTIFY
   quantify_stop_recording_data ();
   quantify_clear_data ();
@@ -1415,45 +1708,42 @@
   suppress_early_backtrace = 0;
   lim_data = 0; /* force reinitialization of this variable */
 
-  if (sizeof (Lisp_Object) != sizeof (void *))
-    abort (); /* Lisp_Object must fit in a word;
-		 check VALBITS and GCTYPEBITS */
+  /* Lisp_Object must fit in a word; check VALBITS and GCTYPEBITS */
+  assert (sizeof (Lisp_Object) == sizeof (void *));
+
   if (!initialized)
-  {
-    run_temacs_argc = 0;
-    if (! SETJMP (run_temacs_catch))
-      main_1 (argc, argv, envp);
-    /* run-emacs-from-temacs called */
-    argc = run_temacs_argc;
-    run_temacs_argc = 0;
-    argv = run_temacs_argv;
+    {
+      run_temacs_argc = 0;
+      if (! SETJMP (run_temacs_catch))
+	main_1 (vol_argc, vol_argv, vol_envp);
+      /* run-emacs-from-temacs called */
+      vol_argc = run_temacs_argc;
+      vol_argv = run_temacs_argv;
 #ifdef _SCO_DS
-    /*
-    This makes absolutely no sense to anyone involved.
-    There are several people using this stuff.  We've
-    compared versions on everything we can think of.  We
-    can find no difference.  However, on both my systems
-    environ is a plain old global variable initialized to
-    zero.  _environ is the one that contains pointers to
-    the actual environment.
-    Since we can't figure out the difference (and we're
-    hours away from a release), this takes a very cowardly
-    approach and is bracketed with both a system specific
-    preprocessor test and a runtime "do you have this
-    problem" test
-    06/20/96 robertl@dgii.com
-    */
-    {
-    extern char *_environ ;
-    if ((unsigned) environ == 0)
-      environ=_environ;
+      /* This makes absolutely no sense to anyone involved.  There are
+	 several people using this stuff.  We've compared versions on
+	 everything we can think of.  We can find no difference.
+	 However, on both my systems environ is a plain old global
+	 variable initialized to zero.  _environ is the one that
+	 contains pointers to the actual environment.
+
+	 Since we can't figure out the difference (and we're hours
+	 away from a release), this takes a very cowardly approach and
+	 is bracketed with both a system specific preprocessor test
+	 and a runtime "do you have this problem" test
+
+	 06/20/96 robertl@dgii.com */
+      {
+	extern char *_environ;
+	if ((unsigned) environ == 0)
+	  environ=_environ;
+      }
+#endif /* _SCO_DS */
+      vol_envp = environ;
     }
-#endif
-    envp = environ;
-  }
   run_temacs_argc = -1;
 
-  main_1 (argc, argv, envp);
+  main_1 (vol_argc, vol_argv, vol_envp);
 }
 
 
@@ -1883,6 +2173,7 @@
   defsubr (&Srun_emacs_from_temacs);
   defsubr (&Srunning_temacs_p);
   defsubr (&Sinvocation_name);
+  defsubr (&Sinvocation_directory);
   defsubr (&Skill_emacs);
   defsubr (&Snoninteractive);