(x_bitmap_icon): Fix test for unallocated icon bitmap.
[bpt/emacs.git] / src / emacs.c
index f00860f..ac32633 100644 (file)
@@ -98,6 +98,10 @@ int inhibit_window_system;
    priority; Those functions have their own extern declaration.  */
 int emacs_priority;
 
+/* 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;
@@ -136,6 +140,8 @@ 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;
@@ -341,9 +347,11 @@ __main ()
 
    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, sstr, lstr, minlen, valptr, skipptr)
+argmatch (argv, argc, sstr, lstr, minlen, valptr, skipptr)
      char **argv;
+     int argc;
      char *sstr;
      char *lstr;
      int minlen;
@@ -352,7 +360,13 @@ argmatch (argv, sstr, lstr, minlen, valptr, skipptr)
 {
   char *p;
   int arglen;
-  char *arg = argv[*skipptr+1];
+  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)
@@ -368,7 +382,7 @@ argmatch (argv, sstr, lstr, minlen, valptr, skipptr)
     }
   arglen = (valptr != NULL && (p = index (arg, '=')) != NULL
            ? p - arg : strlen (arg));
-  if (arglen < minlen || strncmp (arg, lstr, arglen) != 0)
+  if (lstr == 0 || arglen < minlen || strncmp (arg, lstr, arglen) != 0)
     return 0;
   else if (valptr == NULL)
     {
@@ -404,9 +418,27 @@ main (argc, argv, envp)
   extern int errno;
   extern sys_nerr;
 
+  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 (argmatch (argv, "-nl", "--no-shared-memory", 6, NULL, &skip_args))
+  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.  */
@@ -429,27 +461,11 @@ 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;
-
-    /* We don't check for a long option --display here, since the X code
-       won't be able to recognize that form anyway.  */
-    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 */
   {
     char *file;
-    if (argmatch (argv, "-map", "--map-data", 3, &mapin_file, &skip_args))
+    if (argmatch (argv, argc, "-map", "--map-data", 3, &mapin_file, &skip_args))
       mapin_data (file);
   }
 
@@ -528,7 +544,7 @@ main (argc, argv, envp)
   /* Handle the -t switch, which specifies filename to use as terminal */
   {
     char *term;
-    if (argmatch (argv, "-t", "--terminal", 4, &term, &skip_args))
+    if (argmatch (argv, argc, "-t", "--terminal", 4, &term, &skip_args))
       {
        int result;
        close (0);
@@ -552,16 +568,16 @@ main (argc, argv, envp)
 #endif
       }
   }
-  if (argmatch (argv, "-nw", "--no-windows", 6, NULL, &skip_args))
+  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 (argmatch (argv, "-batch", "--batch", 5, NULL, &skip_args))
+  if (argmatch (argv, argc, "-batch", "--batch", 5, NULL, &skip_args))
     noninteractive = 1;
 
   /* Handle the --help option, which gives a usage message..  */
-  if (argmatch (argv, "-help", "--help", 3, NULL, &skip_args))
+  if (argmatch (argv, argc, "-help", "--help", 3, NULL, &skip_args))
     {
       printf ("\
 Usage: %s [-t term] [--terminal term]  [-nw] [--no-windows]  [--batch]\n\
@@ -572,6 +588,48 @@ Usage: %s [-t term] [--terminal term]  [-nw] [--no-windows]  [--batch]\n\
       exit (0);
     }
 
+#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)
     {
 #ifdef BSD_PGRPS
@@ -606,6 +664,27 @@ Usage: %s [-t term] [--terminal term]  [-nw] [--no-windows]  [--batch]\n\
       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);
@@ -668,6 +747,7 @@ Usage: %s [-t term] [--terminal term]  [-nw] [--no-windows]  [--batch]\n\
   init_alloc ();
   init_eval ();
   init_data ();
+  running_asynch_code = 0;
 
 #ifdef MSDOS
   /* Call early 'cause init_environment needs it.  */
@@ -787,6 +867,11 @@ Usage: %s [-t term] [--terminal term]  [-nw] [--no-windows]  [--batch]\n\
 #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
@@ -810,12 +895,12 @@ Usage: %s [-t term] [--terminal term]  [-nw] [--no-windows]  [--batch]\n\
     {
       char *file;
       /* Handle -l loadup-and-dump, args passed by Makefile. */
-      if (argmatch (argv, "-l", "--load", 3, &file, &skip_args))
+      if (argmatch (argv, argc, "-l", "--load", 3, &file, &skip_args))
        Vtop_level = Fcons (intern ("load"),
                            Fcons (build_string (file), Qnil));
 #ifdef CANNOT_DUMP
       /* Unless next switch is -nl, load "loadup.el" first thing.  */
-      if (!argmatch (argv, "-nl", "--no-loadup", 6, NULL, &skip_args))
+      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 */
@@ -833,7 +918,7 @@ Usage: %s [-t term] [--terminal term]  [-nw] [--no-windows]  [--batch]\n\
 #endif /* defined (sun) || defined (LOCALTIME_CACHE) */
 
   /* Handle the GNU standard option --version.  */
-  if (argmatch (argv, "-version", "--version", 3, NULL, &skip_args))
+  if (argmatch (argv, argc, "-version", "--version", 3, NULL, &skip_args))
     {
       Lisp_Object ver;
       ver = call0 (intern ("emacs-version"));
@@ -847,6 +932,184 @@ Usage: %s [-t term] [--terminal term]  [-nw] [--no-windows]  [--batch]\n\
   /* 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\
@@ -1032,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);