This commit was generated by cvs2svn to compensate for changes in r25, which
authortomo <tomo>
Mon, 17 May 1999 09:41:34 +0000 (09:41 +0000)
committertomo <tomo>
Mon, 17 May 1999 09:41:34 +0000 (09:41 +0000)
included commits to RCS files with non-trunk default branches.

36 files changed:
src/callint.c
src/console-msw.h
src/device-msw.c
src/device-x.c
src/device.c
src/dired.c
src/event-Xt.c
src/event-msw.c
src/extents.c
src/extents.h
src/fileio.c
src/filelock.c
src/frame-x.c
src/gif_io.c [new file with mode: 0644]
src/gifrlib.h [new file with mode: 0644]
src/glyphs-msw.c
src/glyphs-x.c
src/gui-x.c
src/insdel.h
src/keymap.c
src/line-number.c
src/macros.c
src/marker.c
src/menubar-msw.c
src/menubar-x.c
src/ntproc.c
src/process-nt.c
src/process-unix.c
src/ralloc.c
src/s/cygwin32.h
src/s/decosf4-0.h
src/s/freebsd.h
src/undo.c
src/unexalpha.c
src/unexelf.c
src/window.c

index d1cd907..dac2dfb 100644 (file)
@@ -715,7 +715,14 @@ when reading the arguments.
             }
          case 'k':             /* Key sequence (vector of events) */
            {
-             Lisp_Object tem = Fread_key_sequence (PROMPT (), Qnil, Qnil);
+             struct gcpro ngcpro1;
+             Lisp_Object tem;
+             Lisp_Object key_prompt = PROMPT ();
+
+             NGCPRO1(key_prompt);
+             tem = Fread_key_sequence (key_prompt, Qnil, Qnil);
+             NUNGCPRO;
+
              visargs[argnum] = Fkey_description (tem);
              /* The following makes `describe-key' not work with
                 extent-local keymaps and such; and anyway, it's
@@ -728,7 +735,14 @@ when reading the arguments.
          case 'K':             /* Key sequence (vector of events),
                                   no automatic downcasing */
            {
-             Lisp_Object tem = Fread_key_sequence (PROMPT (), Qnil, Qt);
+             struct gcpro ngcpro1;
+             Lisp_Object tem;
+             Lisp_Object key_prompt = PROMPT ();
+
+             NGCPRO1(key_prompt);
+             tem = Fread_key_sequence (key_prompt, Qnil, Qt);
+             NUNGCPRO;
+
              visargs[argnum] = Fkey_description (tem);
              /* The following makes `describe-key' not work with
                 extent-local keymaps and such; and anyway, it's
index c78792e..45e2561 100644 (file)
@@ -251,4 +251,6 @@ HANDLE get_nt_process_handle (struct Lisp_Process *p);
 extern Lisp_Object Vmswindows_frame_being_created;
 extern Lisp_Object mswindows_frame_being_created;
 
+void mswindows_enumerate_fonts (struct device *d);
+
 #endif /* _XEMACS_CONSOLE_MSW_H_ */
index 266c014..2b8e28e 100644 (file)
@@ -39,13 +39,6 @@ Boston, MA 02111-1307, USA.  */
 #include "frame.h"
 #include "sysdep.h"
 
-#ifndef __CYGWIN32__
-#include <commctrl.h>
-#else
-#define FONTENUMPROC FONTENUMEXPROC
-#define ntmTm ntmentm
-#endif
-
 /* win32 DDE management library globals */
 #ifdef HAVE_DRAGNDROP
 DWORD mswindows_dde_mlid;
@@ -65,77 +58,11 @@ Lisp_Object Vmswindows_get_true_file_attributes;
 
 Lisp_Object Qinit_pre_mswindows_win, Qinit_post_mswindows_win;
 
-struct font_enum_t
-{
-  HDC hdc;
-  struct device *d;
-};
-
 
 /************************************************************************/
 /*                               helpers                                */
 /************************************************************************/
 
-static int CALLBACK
-font_enum_callback_2 (ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme, 
-                     int FontType, struct font_enum_t *font_enum)
-{
-  struct mswindows_font_enum *fontlist, **fonthead;
-  char fontname[MSW_FONTSIZE];
-
-  /* The enumerated font weights are not to be trusted because:
-   *  a) lpelfe->elfStyle is only filled in for TrueType fonts.
-   *  b) Not all Bold and Italic styles of all fonts (inluding some Vector,
-   *     Truetype and Raster fonts) are enumerated.
-   * I guess that fonts for which Bold and Italic styles are generated
-   * 'on-the-fly' are not enumerated. It would be overly restrictive to
-   * disallow Bold And Italic weights for these fonts, so we just leave
-   * weights unspecified. This means that we have to weed out duplicates of
-   * those fonts that do get enumerated with different weights. */
-
-  if (FontType == 0 /*vector*/ || FontType == TRUETYPE_FONTTYPE)
-    /* Scalable, so leave pointsize blank */
-    sprintf (fontname, "%s::::%s", lpelfe->elfLogFont.lfFaceName,
-            lpelfe->elfScript);
-  else
-    /* Formula for pointsize->height from LOGFONT docs in Platform SDK */
-    sprintf (fontname, "%s::%d::%s", lpelfe->elfLogFont.lfFaceName,
-            MulDiv (lpntme->ntmTm.tmHeight - lpntme->ntmTm.tmInternalLeading,
-                    72, DEVICE_MSWINDOWS_LOGPIXELSY (font_enum->d)),
-             lpelfe->elfScript);
-
-  fonthead = &DEVICE_MSWINDOWS_FONTLIST (font_enum->d);
-  fontlist = *fonthead;
-  while (fontlist)
-    if (!strcmp (fontname, fontlist->fontname))
-      return 1;                /* found a duplicate */
-    else
-      fontlist = fontlist->next;
-
-  /* Insert entry at head */
-  fontlist = *fonthead;
-  *fonthead = xmalloc (sizeof (struct mswindows_font_enum));
-  if (*fonthead == NULL)
-    {
-      *fonthead = fontlist;
-      return 0;
-    }
-  strcpy ((*fonthead)->fontname, fontname);
-  (*fonthead)->next = fontlist;
-  return 1;
-}
-
-static int CALLBACK
-font_enum_callback_1 (ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme, 
-                     int FontType, struct font_enum_t *font_enum)
-{
-  /* This function gets called once per facename per character set.
-   * We call a second callback to enumerate the fonts in each facename */
-  return EnumFontFamiliesEx (font_enum->hdc, &lpelfe->elfLogFont,
-                            (FONTENUMPROC) font_enum_callback_2,
-                            (LPARAM) font_enum, 0);
-}
-
 static Lisp_Object
 build_syscolor_string (int index)
 {
@@ -182,8 +109,6 @@ mswindows_init_device (struct device *d, Lisp_Object props)
 {
   WNDCLASSEX wc;
   HDC hdc;
-  LOGFONT logfont;
-  struct font_enum_t font_enum;
 
   DEVICE_CLASS (d) = Qcolor;
   DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
@@ -204,17 +129,10 @@ mswindows_init_device (struct device *d, Lisp_Object props)
   DEVICE_MSWINDOWS_HORZSIZE(d) = GetDeviceCaps(hdc, HORZSIZE);
   DEVICE_MSWINDOWS_VERTSIZE(d) = GetDeviceCaps(hdc, VERTSIZE);
   DEVICE_MSWINDOWS_BITSPIXEL(d) = GetDeviceCaps(hdc, BITSPIXEL);
-
-  DEVICE_MSWINDOWS_FONTLIST (d) = NULL;
-  logfont.lfCharSet = DEFAULT_CHARSET;
-  logfont.lfFaceName[0] = '\0';
-  logfont.lfPitchAndFamily = DEFAULT_PITCH;
-  font_enum.hdc = hdc;
-  font_enum.d = d;
-  EnumFontFamiliesEx (hdc, &logfont, (FONTENUMPROC) font_enum_callback_1,
-                     (LPARAM) (&font_enum), 0);
   DeleteDC (hdc);
 
+  mswindows_enumerate_fonts (d);
+
   /* Register the main window class */
   wc.cbSize = sizeof (WNDCLASSEX);
   wc.style = CS_OWNDC; /* One DC per window */
index 6a9c7b9..b0cad36 100644 (file)
@@ -62,9 +62,6 @@ Lisp_Object Vx_app_defaults_directory;
 Lisp_Object Qx_error;
 Lisp_Object Qinit_pre_x_win, Qinit_post_x_win;
 
-/* \e$B@ZJ"\e(B, n.  Japanese ritual suicide. */
-int x_seppuku_on_epipe;
-
 /* The application class of Emacs. */
 Lisp_Object Vx_emacs_application_class;
 
@@ -880,10 +877,8 @@ x_IO_error_handler (Display *disp)
   Lisp_Object dev;
   struct device *d = get_device_from_display_1 (disp);
 
-  if (d)
-    XSETDEVICE (dev, d);
-  else
-    dev = Qnil;
+  assert (d != NULL);
+  XSETDEVICE (dev, d);
 
   if (NILP (find_nonminibuffer_frame_not_on_device (dev)))
     {
@@ -903,31 +898,24 @@ x_IO_error_handler (Display *disp)
     {
       warn_when_safe
        (Qx, Qcritical,
-        "I/O Error %d (%s) on display connection \"%s\"\n"
-        "  after %lu requests (%lu known processed) with "
-        "%d events remaining.\n",
+        "I/O Error %d (%s) on display connection\n"
+        "  \"%s\" after after %lu requests (%lu known processed)\n"
+        "  with %d events remaining.\n"
+        "  Throwing to top level.\n",
         errno, strerror (errno), DisplayString (disp),
          NextRequest (disp) - 1, LastKnownRequestProcessed (disp),
          QLength (disp));
     }
 
+  /* According to X specs, we should not return from this function, or
+     Xlib might just decide to exit().  So we mark the offending
+     console for deletion and throw to top level.  */
   if (d)
     enqueue_magic_eval_event (io_error_delete_device, dev);
+  DEVICE_X_BEING_DELETED (d) = 1;
+  Fthrow (Qtop_level, Qnil);
 
-  /* CvE, July 16, 1996, XEmacs 19.14 */
-  /* Test for broken pipe error, which indicates X-server has gone down */
-  if (errno == EPIPE && x_seppuku_on_epipe)
-    {
-      /* Most probably X-server has gone down: Avoid infinite loop by just */
-      /* exiting */
-      /* slb:  This sounds really, really dangerous to do by default, so */
-      /* I'm adding a guard to avoid doing this as default behavior */
-      stderr_out( "\n\nXEmacs exiting on broken pipe (errno %d, %s)\n",
-                 errno, strerror(errno));
-      exit(errno);
-    }
-
-  return 0;
+  RETURN_NOT_REACHED (0);
 }
 
 DEFUN ("x-debug-mode", Fx_debug_mode, 1, 2, 0, /*
@@ -1734,14 +1722,6 @@ just reside in C.
 */ );
   Vx_initial_argv_list = Qnil;
 
-  DEFVAR_BOOL ("x-seppuku-on-epipe", &x_seppuku_on_epipe /*
-When non-nil, terminate XEmacs immediately on SIGPIPE from the X server.
-XEmacs doesn't terminate properly on some systems.
-When this variable is non-nil, XEmacs will commit immediate suicide
-when it gets a sigpipe from the X Server.
-*/ );
-  x_seppuku_on_epipe = 0;
-
 #if defined(MULE) && (defined(LWLIB_MENUBARS_MOTIF) || defined(HAVE_XIM) || defined (USE_XFONTSET))
   DEFVAR_LISP ("x-app-defaults-directory", &Vx_app_defaults_directory /*
 Used by the Lisp code to communicate to the low level X initialization
index e96ff39..44d69ba 100644 (file)
@@ -817,6 +817,9 @@ delete_device_internal (struct device *d, int force,
 void
 io_error_delete_device (Lisp_Object device)
 {
+  /* Note: it's the console that should get deleted, but
+     delete_device_internal() contains a hack that also deletes the
+     console when called from this function.  */
   delete_device_internal (XDEVICE (device), 1, 0, 1);
 }
 
index b8c35f2..076e339 100644 (file)
@@ -30,6 +30,8 @@ Boston, MA 02111-1307, USA.  */
 #include "opaque.h"
 #include "sysfile.h"
 #include "sysdir.h"
+#include "systime.h"
+#include "syspwd.h"
 
 Lisp_Object Vcompletion_ignored_extensions;
 Lisp_Object Qdirectory_files;
@@ -294,11 +296,12 @@ file_name_completion_unwind (Lisp_Object locative)
   DIR *d;
   Lisp_Object obj = XCAR (locative);
 
-  if (NILP (obj))
-    return Qnil;
-  d = (DIR *)get_opaque_ptr (obj);
-  closedir (d);
-  free_opaque_ptr (obj);
+  if (!NILP (obj))
+    {
+      d = (DIR *)get_opaque_ptr (obj);
+      closedir (d);
+      free_opaque_ptr (obj);
+    }
   free_cons (XCONS (locative));
   return Qnil;
 }
@@ -528,6 +531,252 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag,
 }
 
 \f
+static Lisp_Object user_name_completion (Lisp_Object user,
+                                         int all_flag,
+                                         int *uniq);
+
+DEFUN ("user-name-completion", Fuser_name_completion, 1, 1, 0, /*
+Complete user name USER.
+
+Returns the longest string common to all user names that start
+with USER.  If there is only one and USER matches it exactly,
+returns t.  Returns nil if there is no user name starting with USER.
+*/
+       (user))
+{
+  return user_name_completion (user, 0, NULL);
+}
+
+DEFUN ("user-name-completion-1", Fuser_name_completion_1, 1, 1, 0, /*
+Complete user name USER.
+
+This function is identical to `user-name-completion', except that
+the cons of the completion and an indication of whether the
+completion was unique is returned.
+
+The car of the returned value is the longest string common to all
+user names that start with USER.  If there is only one and USER
+matches it exactly, the car is t.  The car is nil if there is no
+user name starting with USER.  The cdr of the result is non-nil
+if and only if the completion returned in the car was unique.
+*/
+       (user))
+{
+  int uniq;
+  Lisp_Object completed;
+
+  completed = user_name_completion (user, 0, &uniq);
+  return Fcons (completed, uniq ? Qt : Qnil);
+}
+
+DEFUN ("user-name-all-completions", Fuser_name_all_completions, 1, 1, 0, /*
+Return a list of all completions of user name USER.
+These are all user names which begin with USER.
+*/
+       (user))
+{
+  return user_name_completion (user, 1, NULL);
+}
+
+static Lisp_Object
+user_name_completion_unwind (Lisp_Object locative)
+{
+  Lisp_Object obj1 = XCAR (locative);
+  Lisp_Object obj2 = XCDR (locative);
+  char **cache;
+  int clen, i;
+
+
+  if (!NILP (obj1) && !NILP (obj2))
+    {
+      /* clean up if interrupted building cache */
+      cache = *(char ***)get_opaque_ptr (obj1);
+      clen  = *(int *)get_opaque_ptr (obj2);
+      free_opaque_ptr (obj1);
+      free_opaque_ptr (obj2);
+      for (i = 0; i < clen; i++)
+        free (cache[i]);
+      free (cache);
+    }
+
+  free_cons (XCONS (locative));
+  endpwent ();
+
+  return Qnil;
+}
+
+static char **user_cache;
+static int user_cache_len;
+static int user_cache_max;
+static long user_cache_time;
+
+#define  USER_CACHE_REBUILD  (24*60*60)  /* 1 day, in seconds */
+
+static Lisp_Object
+user_name_completion (Lisp_Object user, int all_flag, int *uniq)
+{
+  /* This function can GC */
+  struct passwd *pw;
+  int matchcount = 0;
+  Lisp_Object bestmatch = Qnil;
+  Charcount bestmatchsize = 0;
+  int speccount = specpdl_depth ();
+  int i, cmax, clen;
+  char **cache;
+  Charcount user_name_length;
+  Lisp_Object locative;
+  EMACS_TIME t;
+  struct gcpro gcpro1, gcpro2;
+
+  GCPRO2 (user, bestmatch);
+
+  CHECK_STRING (user);
+
+  user_name_length = XSTRING_CHAR_LENGTH (user);
+
+  /* Cache user name lookups because it tends to be quite slow.
+   * Rebuild the cache occasionally to catch changes */
+  EMACS_GET_TIME (t);
+  if (user_cache  &&
+      EMACS_SECS (t) - user_cache_time > USER_CACHE_REBUILD)
+    {
+      for (i = 0; i < user_cache_len; i++)
+        free (user_cache[i]);
+      free (user_cache);
+      user_cache = NULL;
+      user_cache_len = 0;
+      user_cache_max = 0;
+    }
+
+  if (user_cache == NULL || user_cache_max <= 0)
+    {
+      cmax  = 200;
+      clen  = 0;
+      cache = (char **) malloc (cmax*sizeof (char *));
+
+      setpwent ();
+      locative = noseeum_cons (Qnil, Qnil);
+      XCAR (locative) = make_opaque_ptr ((void *) &cache);
+      XCDR (locative) = make_opaque_ptr ((void *) &clen);
+      record_unwind_protect (user_name_completion_unwind, locative);
+      /* #### may need to slow down interrupts around call to getpwent
+       * below.  at least the call to getpwnam in Fuser_full_name
+       * is documented as needing it on irix. */
+      while ((pw = getpwent ()))
+        {
+          if (clen >= cmax)
+            {
+              cmax *= 2;
+              cache = (char **) realloc (cache, cmax*sizeof (char *));
+            }
+
+          QUIT;
+
+          cache[clen++] = strdup (pw->pw_name);
+        }
+      free_opaque_ptr (XCAR (locative));
+      free_opaque_ptr (XCDR (locative));
+      XCAR (locative) = Qnil;
+      XCDR (locative) = Qnil;
+
+      unbind_to (speccount, Qnil); /* free locative cons, endpwent() */
+
+      user_cache_max = cmax;
+      user_cache_len = clen;
+      user_cache = cache;
+      user_cache_time = EMACS_SECS (t);
+    }
+
+  for (i = 0; i < user_cache_len; i++)
+    {
+      Bytecount len;
+      /* scmp() works in chars, not bytes, so we have to compute this: */
+      Charcount cclen;
+      Bufbyte *d_name;
+
+      d_name = (Bufbyte *) user_cache[i];
+      len = strlen (d_name);
+      cclen = bytecount_to_charcount (d_name, len);
+
+      QUIT;
+
+      if (cclen < user_name_length   ||
+          0 <= scmp (d_name, XSTRING_DATA (user), user_name_length))
+        continue;
+
+      matchcount++;    /* count matching completions */
+
+      if (all_flag || NILP (bestmatch))
+        {
+          Lisp_Object name = Qnil;
+          struct gcpro ngcpro1;
+          NGCPRO1 (name);
+          /* This is a possible completion */
+          name = make_string (d_name, len);
+          if (all_flag)
+            {
+              bestmatch = Fcons (name, bestmatch);
+            }
+          else
+            {
+              bestmatch = name;
+              bestmatchsize = XSTRING_CHAR_LENGTH (name);
+            }
+          NUNGCPRO;
+        }
+      else
+        {
+          Charcount compare = min (bestmatchsize, cclen);
+          Bufbyte *p1 = XSTRING_DATA (bestmatch);
+          Bufbyte *p2 = d_name;
+          Charcount matchsize = scmp (p1, p2, compare);
+
+          if (matchsize < 0)
+            matchsize = compare;
+          if (completion_ignore_case)
+            {
+              /* If this is an exact match except for case,
+                 use it as the best match rather than one that is not
+                 an exact match.  This way, we get the case pattern
+                 of the actual match.  */
+              if ((matchsize == cclen
+                   && matchsize < XSTRING_CHAR_LENGTH (bestmatch))
+                  ||
+                  /* If there is no exact match ignoring case,
+                     prefer a match that does not change the case
+                     of the input.  */
+                  (((matchsize == cclen)
+                    ==
+                    (matchsize == XSTRING_CHAR_LENGTH (bestmatch)))
+                   /* If there is more than one exact match aside from
+                      case, and one of them is exact including case,
+                      prefer that one.  */
+                   && 0 > scmp_1 (p2, XSTRING_DATA (user),
+                                  user_name_length, 0)
+                   && 0 <= scmp_1 (p1, XSTRING_DATA (user),
+                                   user_name_length, 0)))
+                {
+                  bestmatch = make_string (d_name, len);
+                }
+            }
+
+          bestmatchsize = matchsize;
+        }
+    }
+
+  UNGCPRO;
+
+  if (uniq)
+    *uniq = (matchcount == 1);
+
+  if (all_flag || NILP (bestmatch))
+    return bestmatch;
+  if (matchcount == 1 && bestmatchsize == user_name_length)
+    return Qt;
+  return Fsubstring (bestmatch, Qzero, make_int (bestmatchsize));
+}
+
+\f
 Lisp_Object
 make_directory_hash_table (CONST char *path)
 {
@@ -689,6 +938,9 @@ syms_of_dired (void)
   DEFSUBR (Fdirectory_files);
   DEFSUBR (Ffile_name_completion);
   DEFSUBR (Ffile_name_all_completions);
+  DEFSUBR (Fuser_name_completion);
+  DEFSUBR (Fuser_name_completion_1);
+  DEFSUBR (Fuser_name_all_completions);
   DEFSUBR (Ffile_attributes);
 }
 
@@ -703,4 +955,8 @@ It is used by the functions `file-name-completion' and
 `file-name-all-completions'.
 */ );
   Vcompletion_ignored_extensions = Qnil;
+
+  user_cache = NULL;
+  user_cache_len = 0;
+  user_cache_max = 0;
 }
index e852322..5052edd 100644 (file)
@@ -658,6 +658,9 @@ void
 emacs_Xt_mapping_action (Widget w, XEvent* event)
 {
   struct device *d = get_device_from_display (event->xany.display);
+
+  if (DEVICE_X_BEING_DELETED (d))
+    return;
 #if 0
   /* nyet.  Now this is handled by Xt. */
   XRefreshKeyboardMapping (&event->xmapping);
@@ -769,7 +772,7 @@ x_to_emacs_keysym (XKeyPressedEvent *event, int simple_p)
      /* simple_p means don't try too hard (ASCII only) */
 {
   KeySym keysym = 0;
-
+  
 #ifdef HAVE_XIM
   int len;
   char buffer[64];
@@ -794,7 +797,8 @@ x_to_emacs_keysym (XKeyPressedEvent *event, int simple_p)
          than passing in 0) to avoid crashes on German IRIX */
       char dummy[256];
       XLookupString (event, dummy, 200, &keysym, 0);
-      return x_keysym_to_emacs_keysym (keysym, simple_p);
+      return (IsModifierKey (keysym) || keysym == XK_Mode_switch )
+       ? Qnil : x_keysym_to_emacs_keysym (keysym, simple_p);
     }
 #endif /* ! XIM_MOTIF */
 
@@ -843,7 +847,8 @@ x_to_emacs_keysym (XKeyPressedEvent *event, int simple_p)
     {
     case XLookupKeySym:
     case XLookupBoth:
-      return x_keysym_to_emacs_keysym (keysym, simple_p);
+      return (IsModifierKey (keysym) || keysym == XK_Mode_switch )
+       ? Qnil : x_keysym_to_emacs_keysym (keysym, simple_p);
 
     case XLookupChars:
       {
@@ -921,6 +926,10 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
   struct device *d    = get_device_from_display (display);
   struct x_device *xd = DEVICE_X_DATA (d);
 
+  if (DEVICE_X_BEING_DELETED (d))
+     /* #### Uh, is this 0 correct? */
+     return 0;
+
   set_last_server_timestamp (d, x_event);
 
   switch (x_event->type)
@@ -983,20 +992,16 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
          {
            Lisp_Object keysym;
            XKeyEvent *ev = &x_event->xkey;
-           KeyCode keycode = ev->keycode;
-
-           if (x_key_is_modifier_p (keycode, d)) /* it's a modifier key */
-             return 0;
-
            /* This used to compute the frame from the given X window and
               store it here, but we really don't care about the frame. */
            emacs_event->channel = DEVICE_CONSOLE (d);
            keysym = x_to_emacs_keysym (&x_event->xkey, 0);
 
-           /* If the emacs keysym is nil, then that means that the
-              X keysym was NoSymbol, which probably means that
-              we're in the midst of reading a Multi_key sequence,
-              or a "dead" key prefix, or XIM input.  Ignore it. */
+           /* If the emacs keysym is nil, then that means that the X
+              keysym was either a Modifier or NoSymbol, which
+              probably means that we're in the midst of reading a
+              Multi_key sequence, or a "dead" key prefix, or XIM
+              input. Ignore it. */
            if (NILP (keysym))
              return 0;
 
@@ -1337,14 +1342,17 @@ void emacs_Xt_handle_focus_event (XEvent *event);
 void
 emacs_Xt_handle_focus_event (XEvent *event)
 {
+  struct device *d = get_device_from_display (event->xany.display);
+  struct frame *f;
+
+  if (DEVICE_X_BEING_DELETED (d))
+    return;
+
   /*
    * It's curious that we're using x_any_window_to_frame() instead
    * of x_window_to_frame().  I don't know what the impact of this is.
    */
-
-  struct frame *f =
-    x_any_window_to_frame (get_device_from_display (event->xany.display),
-                          event->xfocus.window);
+  f = x_any_window_to_frame (d, event->xfocus.window);
   if (!f)
     /* focus events are sometimes generated just before
        a frame is destroyed. */
@@ -1511,7 +1519,7 @@ emacs_Xt_handle_magic_event (struct Lisp_Event *emacs_event)
   XEvent *event = &emacs_event->event.magic.underlying_x_event;
   struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
 
-  if (!FRAME_LIVE_P (f))
+  if (!FRAME_LIVE_P (f) || DEVICE_X_BEING_DELETED (XDEVICE (FRAME_DEVICE (f))))
     return;
 
   switch (event->type)
index 09054fd..f31da31 100644 (file)
@@ -98,6 +98,7 @@ static struct event_stream *mswindows_event_stream;
 #ifdef HAVE_MSG_SELECT
 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
 extern SELECT_TYPE process_only_mask, tty_only_mask;
+SELECT_TYPE zero_mask;
 extern int signal_event_pipe_initialized;
 int windows_fd;
 #endif
@@ -727,8 +728,11 @@ winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size)
   
   {
     ResetEvent (str->ov.hEvent);
-    
-    if (WriteFile ((HANDLE)str->s, data, size, NULL, &str->ov)
+
+    /* Docs indicate that 4th parameter to WriteFile can be NULL since this is
+     * an overlapped operation. This fails on Win95 with winsock 1.x so we
+     * supply a spare address which is ignored by Win95 anyway. Sheesh. */
+    if (WriteFile ((HANDLE)str->s, data, size, (LPDWORD)&str->buffer, &str->ov)
        || GetLastError() == ERROR_IO_PENDING)
       str->pending_p = 1;
     else
@@ -1294,6 +1298,29 @@ mswindows_need_event (int badly_p)
          EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
          pointer_to_this = &select_time_to_block;
        }
+
+      /* select() is slow and buggy so if we don't have any processes
+         just wait as normal */
+      if (memcmp (&process_only_mask, &zero_mask, sizeof(SELECT_TYPE))==0)
+       {
+         /* Now try getting a message or process event */
+         active = MsgWaitForMultipleObjects (0, mswindows_waitable_handles,
+                                             FALSE, badly_p ? INFINITE : 0,
+                                             QS_ALLINPUT);
+         
+         if (active == WAIT_TIMEOUT)
+           {
+             /* No luck trying - just return what we've already got */
+             return;
+           }
+         else if (active == WAIT_OBJECT_0)
+           {
+             /* Got your message, thanks */
+             mswindows_drain_windows_queue ();
+             continue;
+           }
+       }
+
       active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
       
       if (active == 0)
@@ -1572,8 +1599,37 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
     break;
 
+  case WM_KEYUP:
+  case WM_SYSKEYUP:
+    /* See Win95 comment under WM_KEYDOWN */
+    {
+      BYTE keymap[256];
+
+      if (wParam == VK_CONTROL)
+        {
+         GetKeyboardState (keymap);
+         keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
+         SetKeyboardState (keymap);
+       }
+      else if (wParam == VK_MENU)
+       {
+         GetKeyboardState (keymap);
+         keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
+         SetKeyboardState (keymap);
+       }
+    };
+    goto defproc;
+
   case WM_KEYDOWN:
   case WM_SYSKEYDOWN:
+    /* In some locales the right-hand Alt key is labelled AltGr. This key
+     * should produce alternative charcaters when combined with another key.
+     * eg on a German keyboard pressing AltGr+q should produce '@'.
+     * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
+     * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
+     * it translates as if AltGr were down.
+     * We get round this by removing all modifiers from the keymap before
+     * calling TranslateMessage() unless AltGr is *really* down. */
     {
       BYTE keymap[256];
       int has_AltGr = mswindows_current_layout_has_AltGr ();
@@ -1583,7 +1639,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       GetKeyboardState (keymap);
       mods = mswindows_modifier_state (keymap, has_AltGr);
 
-      /* Handle those keys that TranslateMessage won't generate a WM_CHAR for */
+      /* Handle those keys for which TranslateMessage won't generate a WM_CHAR */
       if (!NILP (keysym = mswindows_key_to_emacs_keysym(wParam, mods)))
        mswindows_enqueue_keypress_event (hwnd, keysym, mods);
       else
@@ -1591,12 +1647,21 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
          int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
          BYTE keymap_orig[256];
          MSG msg = { hwnd, message, wParam, lParam, GetMessageTime(), (GetMessagePos()) };
+
+         /* GetKeyboardState() does not work as documented on Win95. We have
+          * to loosely track Left and Right modifiers on behalf of the OS,
+          * without screwing up Windows NT which tracks them properly. */
+         if (wParam == VK_CONTROL)
+           keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
+         else if (wParam == VK_MENU)
+           keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] |= 0x80;
+
          memcpy (keymap_orig, keymap, 256);
 
          /* Remove shift modifier from an ascii character */
          mods &= ~MOD_SHIFT;
 
-         /* Clear control and alt modifiers out of the keymap */
+         /* Clear control and alt modifiers unless AltGr is pressed */
          keymap [VK_RCONTROL] = 0;
          keymap [VK_LMENU] = 0;
          if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) || !(keymap [VK_RMENU] & 0x80))
@@ -1608,7 +1673,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
            }
          SetKeyboardState (keymap);
 
-         /* Have some WM_[SYS]CHARS in the queue */
+         /* Maybe generate some WM_[SYS]CHARs in the queue */
          TranslateMessage (&msg);
 
          while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
@@ -2778,9 +2843,7 @@ init_event_mswindows_late (void)
   windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
   assert (windows_fd>=0);
   FD_SET (windows_fd, &input_wait_mask);
-  /* for some reason I get blocks on the signal event pipe, which is
-     bad... 
-     signal_event_pipe_initialized = 0; */
+  FD_ZERO(&zero_mask);
 #endif
 
   event_stream = mswindows_event_stream;
index da6bde7..aa0f4fc 100644 (file)
@@ -921,6 +921,8 @@ mark_extent_auxiliary (Lisp_Object obj, void (*markobj) (Lisp_Object))
   ((markobj) (data->read_only));
   ((markobj) (data->mouse_face));
   ((markobj) (data->initial_redisplay_function));
+  ((markobj) (data->before_change_functions));
+  ((markobj) (data->after_change_functions));
   return data->parent;
 }
 
@@ -3156,6 +3158,8 @@ extent_remprop (Lisp_Object obj, Lisp_Object prop)
       || EQ (prop, Qpriority)
       || EQ (prop, Qface)
       || EQ (prop, Qinitial_redisplay_function)
+      || EQ (prop, Qafter_change_functions)
+      || EQ (prop, Qbefore_change_functions)
       || EQ (prop, Qmouse_face)
       || EQ (prop, Qhighlight)
       || EQ (prop, Qbegin_glyph_layout)
@@ -4602,6 +4606,105 @@ process_extents_for_deletion (Lisp_Object object, Bytind from,
                      ME_END_CLOSED | ME_MIGHT_MODIFY_EXTENTS);
 }
 
+/* ------------------------------- */
+/*   report_extent_modification()  */
+/* ------------------------------- */
+struct report_extent_modification_closure {
+  Lisp_Object buffer;
+  Bufpos start, end;
+  int afterp;
+  int speccount;
+};
+
+/* This juggling with the pointer to another file's global variable is
+   kind of yucky.  Perhaps I should just export the variable.  */
+static int *inside_change_hook_pointer;
+
+static Lisp_Object
+report_extent_modification_restore (Lisp_Object buffer)
+{
+  *inside_change_hook_pointer = 0;
+  if (current_buffer != XBUFFER (buffer))
+    Fset_buffer (buffer);
+  return Qnil;
+}
+
+static int
+report_extent_modification_mapper (EXTENT extent, void *arg)
+{
+  struct report_extent_modification_closure *closure =
+    (struct report_extent_modification_closure *)arg;
+  Lisp_Object exobj, startobj, endobj;
+  Lisp_Object hook = (closure->afterp
+                     ? extent_after_change_functions (extent)
+                     : extent_before_change_functions (extent));
+  if (NILP (hook))
+    return 0;
+
+  XSETEXTENT (exobj, extent);
+  XSETINT (startobj, closure->start);
+  XSETINT (endobj, closure->end);
+
+  /* Now that we are sure to call elisp, set up an unwind-protect so
+     inside_change_hook gets restored in case we throw.  Also record
+     the current buffer, in case we change it.  Do the recording only
+     once.  */
+  if (closure->speccount == -1)
+    {
+      closure->speccount = specpdl_depth ();
+      record_unwind_protect (report_extent_modification_restore,
+                            Fcurrent_buffer ());
+    }
+
+  /* The functions will expect closure->buffer to be the current
+     buffer, so change it if it isn't.  */
+  if (current_buffer != XBUFFER (closure->buffer))
+    Fset_buffer (closure->buffer);
+
+  /* #### It's a shame that we can't use any of the existing run_hook*
+     functions here.  This is so because all of them work with
+     symbols, to be able to retrieve default values of local hooks.
+     <sigh> */
+
+  if (!CONSP (hook) || EQ (XCAR (hook), Qlambda))
+    call3 (hook, exobj, startobj, endobj);
+  else
+    {
+      Lisp_Object tail;
+      EXTERNAL_LIST_LOOP (tail, hook)
+       call3 (XCAR (tail), exobj, startobj, endobj);
+    }
+  return 0;
+}
+
+void
+report_extent_modification (Lisp_Object buffer, Bufpos start, Bufpos end,
+                           int *inside, int afterp)
+{
+  struct report_extent_modification_closure closure;
+
+  closure.buffer = buffer;
+  closure.start = start;
+  closure.end = end;
+  closure.afterp = afterp;
+  closure.speccount = -1;
+
+  inside_change_hook_pointer = inside;
+  *inside = 1;
+
+  map_extents (start, end, report_extent_modification_mapper, (void *)&closure,
+              buffer, NULL, ME_MIGHT_CALL_ELISP);
+
+  if (closure.speccount == -1)
+    *inside = 0;
+  else
+    {
+      /* We mustn't unbind when closure.speccount != -1 because
+        map_extents_bytind has already done that.  */
+      assert (*inside == 0);
+    }
+}
+
 \f
 /************************************************************************/
 /*                     extent properties                               */
@@ -5201,6 +5304,10 @@ The following symbols have predefined meanings:
     Fset_extent_face (extent, value);
   else if (EQ (property, Qinitial_redisplay_function))
     Fset_extent_initial_redisplay_function (extent, value);
+  else if (EQ (property, Qbefore_change_functions))
+    set_extent_before_change_functions (e, value);
+  else if (EQ (property, Qafter_change_functions))
+    set_extent_after_change_functions (e, value);
   else if (EQ (property, Qmouse_face))
     Fset_extent_mouse_face (extent, value);
   /* Obsolete: */
@@ -5306,6 +5413,10 @@ See `set-extent-property' for the built-in property names.
     return Fextent_face (extent);
   else if (EQ (property, Qinitial_redisplay_function))
     return extent_initial_redisplay_function (e);
+  else if (EQ (property, Qbefore_change_functions))
+    return extent_before_change_functions (e);
+  else if (EQ (property, Qafter_change_functions))
+    return extent_after_change_functions (e);
   else if (EQ (property, Qmouse_face))
     return Fextent_mouse_face (extent);
   /* Obsolete: */
@@ -5382,6 +5493,14 @@ Do not modify this list; use `set-extent-property' instead.
     result = cons3 (Qinitial_redisplay_function,
                    extent_initial_redisplay_function (anc), result);
 
+  if (!NILP (extent_before_change_functions (anc)))
+    result = cons3 (Qbefore_change_functions,
+                   extent_before_change_functions (anc), result);
+
+  if (!NILP (extent_after_change_functions (anc)))
+    result = cons3 (Qafter_change_functions,
+                   extent_after_change_functions (anc), result);
+
   if (!NILP (extent_invisible (anc)))
     result = cons3 (Qinvisible, extent_invisible (anc), result);
 
@@ -6723,6 +6842,8 @@ functions `get-text-property' or `get-char-property' are called.
   extent_auxiliary_defaults.read_only = Qnil;
   extent_auxiliary_defaults.mouse_face = Qnil;
   extent_auxiliary_defaults.initial_redisplay_function = Qnil;
+  extent_auxiliary_defaults.before_change_functions = Qnil;
+  extent_auxiliary_defaults.after_change_functions = Qnil;
 }
 
 void
index e9f1dff..be0d6e4 100644 (file)
@@ -82,17 +82,14 @@ struct extent
     unsigned int has_aux           :1; /*  6 extent has an aux. structure */
     unsigned int start_open        :1; /*  7 insertion behavior at start  */
     unsigned int end_open          :1; /*  8 insertion behavior at end    */
-    unsigned int unused9           :1; /*  9 unused                       */
-    unsigned int unique                    :1; /* 10 there may be only one attached  */
-    unsigned int duplicable        :1; /* 11 copied to strings by kill/undo  */
-    unsigned int REPLICATING       :1; /* 12 invoke old extent-replica behav.*/
-                                       /*    Not used any more */
-    unsigned int detachable        :1; /* 13 extent detaches if text deleted */
-    unsigned int internal          :1; /* 14 used by map-extents etc.        */
-    unsigned int in_red_event       :1; /* 15 An event has been spawned for
+    unsigned int unique                    :1; /*  9 there may be only one attached  */
+    unsigned int duplicable        :1; /* 10 copied to strings by kill/undo  */
+    unsigned int detachable        :1; /* 11 extent detaches if text deleted */
+    unsigned int internal          :1; /* 12 used by map-extents etc.        */
+    unsigned int in_red_event       :1; /* 13 An event has been spawned for
                                              initial redisplay.
-                                             Not exported to the lisp level */
-    unsigned int unused16          :1;  /* 16 unused                        */
+                                             (not exported to lisp) */
+    unsigned int unused16          :1;  /* 16 unused bits                   */
     /* --- Adding more flags will cause the extent struct to grow by another
        word.  It's not clear that this would make a difference, however,
        because on 32-bit machines things tend to get allocated in chunks
@@ -139,6 +136,7 @@ struct extent_auxiliary
   Lisp_Object read_only;
   Lisp_Object mouse_face;
   Lisp_Object initial_redisplay_function;
+  Lisp_Object before_change_functions, after_change_functions;
   int priority;
 };
 
@@ -230,6 +228,8 @@ extent_aux_or_default (EXTENT e)
 #define extent_read_only(e)    extent_aux_field (e, read_only)
 #define extent_mouse_face(e)   extent_aux_field (e, mouse_face)
 #define extent_initial_redisplay_function(e)   extent_aux_field (e, initial_redisplay_function)
+#define extent_before_change_functions(e) extent_aux_field (e, before_change_functions)
+#define extent_after_change_functions(e)  extent_aux_field (e, after_change_functions)
 
 #define set_extent_begin_glyph(e, value)       \
   set_extent_aux_field (e, begin_glyph, value)
@@ -246,6 +246,10 @@ extent_aux_or_default (EXTENT e)
 /* Use Fset_extent_initial_redisplay_function unless you know what you're doing */
 #define set_extent_initial_redisplay_function(e, value) \
   set_extent_aux_field (e, initial_redisplay_function, value)
+#define set_extent_before_change_functions(e, value)   \
+  set_extent_aux_field (e, before_change_functions, value)
+#define set_extent_after_change_functions(e, value)    \
+  set_extent_aux_field (e, after_change_functions, value)
 
 #define extent_face(e)              extent_normal_field (e, face)
 #define extent_begin_glyph_layout(e) extent_normal_field (e, begin_glyph_layout)
@@ -366,6 +370,7 @@ void process_extents_for_insertion (Lisp_Object object,
                                    Bytind opoint, Bytecount length);
 void process_extents_for_deletion (Lisp_Object object, Bytind from,
                                   Bytind to, int destroy_them);
+void report_extent_modification (Lisp_Object, Bufpos, Bufpos, int *, int);
 
 void set_extent_glyph (EXTENT extent, Lisp_Object glyph, int endp,
                       glyph_layout layout);
index 0f21f16..4893391 100644 (file)
@@ -454,13 +454,16 @@ Given a Unix syntax file name, returns a string ending in slash.
       Bufbyte *res = alloca (MAXPATHLEN + 1);
       if (getdefdir (toupper (*beg) - 'A' + 1, res))
        {
-         if (!IS_DIRECTORY_SEP (res[strlen ((char *) res) - 1]))
-           strcat ((char *) res, "/");
+         char *c=((char *) res) + strlen ((char *) res);
+         if (!IS_DIRECTORY_SEP (*c))
+           {
+             *c++ = DIRECTORY_SEP;
+             *c = '\0';
+           }
          beg = res;
          p = beg + strlen ((char *) beg);
        }
     }
-  CORRECT_DIR_SEPS (beg);
 #endif /* WINDOWSNT */
   return make_string (beg, p - beg);
 }
@@ -544,9 +547,6 @@ file_name_as_directory (char *out, char *in)
          out[size + 1] = '\0';
        }
     }
-#ifdef WINDOWSNT
-  CORRECT_DIR_SEPS (out);
-#endif
   return out;
 }
 
@@ -608,9 +608,6 @@ directory_file_name (CONST char *src, char *dst)
       )
     dst[slen - 1] = 0;
 #endif /* APOLLO */
-#ifdef WINDOWSNT
-  CORRECT_DIR_SEPS (dst);
-#endif /* WINDOWSNT */
   return 1;
 }
 
@@ -2288,7 +2285,7 @@ See also `file-exists-p' and `file-attributes'.
   if (!NILP (handler))
     RETURN_UNGCPRO (call2 (handler, Qfile_readable_p, abspath));
 
-#ifdef WINDOWSNT
+#if defined(WINDOWSNT) || defined(__CYGWIN32__)
   /* Under MS-DOS and Windows, open does not work for directories.  */
   UNGCPRO;
   if (access (XSTRING_DATA (abspath), 0) == 0)
index d216ab8..96ee76d 100644 (file)
@@ -1,24 +1,23 @@
-/* Copyright (C) 1985, 1986, 1987, 1992, 1993, 1994
-   Free Software Foundation, Inc.
+/* Copyright (C) 1985, 86, 87, 93, 94, 96 Free Software Foundation, Inc.
 
-This file is part of XEmacs.
+This file is part of GNU Emacs.
 
-XEmacs 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 2, or (at your option) any
-later version.
+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 2, or (at your option)
+any later version.
 
-XEmacs 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.
+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 XEmacs; see the file COPYING.  If not, write to
+along with GNU Emacs; see the file COPYING.  If not, write to
 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-/* Synched up with: FSF 19.30. */
+/* Synced with FSF 20.2 */
 
 #include <config.h>
 #include "lisp.h"
@@ -31,169 +30,271 @@ Boston, MA 02111-1307, USA.  */
 #include "syspwd.h"
 #include "syssignal.h" /* for kill */
 
-#ifndef CLASH_DETECTION
-#error  CLASH_DETECTION is not defined??
-#endif
-
-/* FSFmacs uses char *lock_dir and char *superlock_file instead of
-   the Lisp variables we use. */
-
-/* The name of the directory in which we keep lock files, with a '/'
-   appended.  */
-Lisp_Object Vlock_directory;
-
-#if 0 /* FSFmacs */
-/* Look in startup.el */
-/* The name of the file in the lock directory which is used to
-   arbitrate access to the entire directory.  */
-#define SUPERLOCK_NAME "!!!SuperLock!!!"
-#endif
-
-/* The name of the superlock file.  This is SUPERLOCK_NAME appended to
-   Vlock_directory.  */
-Lisp_Object Vsuperlock_file, Vconfigure_superlock_file;
-
 Lisp_Object Qask_user_about_supersession_threat;
 Lisp_Object Qask_user_about_lock;
 
-static void lock_superlock (CONST char *lfname);
-static int lock_file_1 (CONST char *lfname, int mode);
-static int lock_if_free (CONST char *lfname);
-static int current_lock_owner (CONST char *);
-static int current_lock_owner_1 (CONST char *);
-
-/* Set LOCK to the name of the lock file for the filename FILE.
-   char *LOCK; Lisp_Object FILE;
+#ifdef CLASH_DETECTION
+  
+/* The strategy: to lock a file FN, create a symlink .#FN in FN's
+   directory, with link data `user@host.pid'.  This avoids a single
+   mount (== failure) point for lock files.
+
+   When the host in the lock data is the current host, we can check if
+   the pid is valid with kill.
+   
+   Otherwise, we could look at a separate file that maps hostnames to
+   reboot times to see if the remote pid can possibly be valid, since we
+   don't want Emacs to have to communicate via pipes or sockets or
+   whatever to other processes, either locally or remotely; rms says
+   that's too unreliable.  Hence the separate file, which could
+   theoretically be updated by daemons running separately -- but this
+   whole idea is unimplemented; in practice, at least in our
+   environment, it seems such stale locks arise fairly infrequently, and
+   Emacs' standard methods of dealing with clashes suffice.
+
+   We use symlinks instead of normal files because (1) they can be
+   stored more efficiently on the filesystem, since the kernel knows
+   they will be small, and (2) all the info about the lock can be read
+   in a single system call (readlink).  Although we could use regular
+   files to be useful on old systems lacking symlinks, nowadays
+   virtually all such systems are probably single-user anyway, so it
+   didn't seem worth the complication.
+
+   Similarly, we don't worry about a possible 14-character limit on
+   file names, because those are all the same systems that don't have
+   symlinks.
+   
+   This is compatible with the locking scheme used by Interleaf (which
+   has contributed this implementation for Emacs), and was designed by
+   Ethan Jacobson, Kimbo Mundy, and others.
+   
+   --karl@cs.umb.edu/karl@hq.ileaf.com.  */
 
-   MAKE_LOCK_NAME assumes you have already verified that Vlock_directory
-   is a string. */
-
-#ifndef HAVE_LONG_FILE_NAMES
+\f
+/* Here is the structure that stores information about a lock.  */
 
-#define MAKE_LOCK_NAME(lock, file)                                     \
-  (lock = (char *) alloca (14 + XSTRING_LENGTH (Vlock_directory) + 1), \
-   fill_in_lock_short_file_name (lock, (file)))
+typedef struct
+{
+  char *user;
+  char *host;
+  unsigned long pid;
+} lock_info_type;
+
+/* When we read the info back, we might need this much more,
+   enough for decimal representation plus null.  */
+#define LOCK_PID_MAX (4 * sizeof (unsigned long))
+
+/* Free the two dynamically-allocated pieces in PTR.  */
+#define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0)
+
+/* Write the name of the lock file for FN into LFNAME.  Length will be
+   that of FN plus two more for the leading `.#' plus one for the null.  */
+#define MAKE_LOCK_NAME(lock, file) \
+  (lock = (char *) alloca (XSTRING_LENGTH(file) + 2 + 1), \
+   fill_in_lock_file_name (lock, (file)))
 
 static void
-fill_in_lock_short_file_name (REGISTER char *lockfile, REGISTER Lisp_Object fn)
+fill_in_lock_file_name (lockfile, fn)
+     register char *lockfile;
+     register Lisp_Object fn;
 {
-  REGISTER union
-    {
-      unsigned int  word [2];
-      unsigned char byte [8];
-    } crc;
-  REGISTER unsigned char *p, new;
+  register char *p;
 
-  CHECK_STRING (Vlock_directory);
+  strcpy (lockfile, XSTRING_DATA(fn));
 
-  /* 7-bytes cyclic code for burst correction on byte-by-byte basis.
-     the used polynomial is D^7 + D^6 + D^3 +1. pot@cnuce.cnr.it */
+  /* Shift the nondirectory part of the file name (including the null)
+     right two characters.  Here is one of the places where we'd have to
+     do something to support 14-character-max file names.  */
+  for (p = lockfile + strlen (lockfile); p != lockfile && *p != '/'; p--)
+    p[2] = *p;
 
-  crc.word[0] = crc.word[1] = 0;
-
-  for (p = XSTRING_DATA (fn); new = *p++; )
-    {
-      new += crc.byte[6];
-      crc.byte[6] = crc.byte[5] + new;
-      crc.byte[5] = crc.byte[4];
-      crc.byte[4] = crc.byte[3];
-      crc.byte[3] = crc.byte[2] + new;
-      crc.byte[2] = crc.byte[1];
-      crc.byte[1] = crc.byte[0];
-      crc.byte[0] = new;
-    }
-
-  {
-    int need_slash = 0;
-
-    /* in case lock-directory doesn't end in / */
-    if (XSTRING_BYTE (Vlock_directory,
-                    XSTRING_LENGTH (Vlock_directory) - 1) != '/')
-      need_slash = 1;
-
-    sprintf (lockfile, "%s%s%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
-            (char *) XSTRING_DATA (Vlock_directory),
-            need_slash ? "/" : "",
-            crc.byte[0], crc.byte[1], crc.byte[2], crc.byte[3],
-            crc.byte[4], crc.byte[5], crc.byte[6]);
-  }
+  /* Insert the `.#'.  */
+  p[1] = '.';
+  p[2] = '#';
 }
 
-#else /* defined HAVE_LONG_FILE_NAMES */
-
-/* +2 for terminating null and possible extra slash */
-#define MAKE_LOCK_NAME(lock, file)                                     \
-  (lock = (char *) alloca (XSTRING_LENGTH (file) +                     \
-                          XSTRING_LENGTH (Vlock_directory) + 2),       \
-   fill_in_lock_file_name (lock, (file)))
+/* Lock the lock file named LFNAME.
+   If FORCE is nonzero, we do so even if it is already locked.
+   Return 1 if successful, 0 if not.  */
 
-static void
-fill_in_lock_file_name (REGISTER char *lockfile, REGISTER Lisp_Object fn)
-     /* fn must be a Lisp_String! */
+static int
+lock_file_1 (char *lfname,int force)
 {
-  REGISTER char *p;
-
-  CHECK_STRING (Vlock_directory);
+  register int err;
+  char *user_name;
+  char *host_name;
+  char *lock_info_str;
 
-  strcpy (lockfile, (char *) XSTRING_DATA (Vlock_directory));
+  if (STRINGP (Fuser_login_name (Qnil)))
+    user_name = (char *)XSTRING_DATA((Fuser_login_name (Qnil)));
+  else
+    user_name = "";
+  if (STRINGP (Fsystem_name ()))
+    host_name = (char *)XSTRING_DATA((Fsystem_name ()));
+  else
+    host_name = "";
+  lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name)
+                         + LOCK_PID_MAX + 5);
 
-  p = lockfile + strlen (lockfile);
+  sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name,
+           (unsigned long) getpid ());
 
-  if (p == lockfile /* lock-directory is empty?? */
-      || *(p - 1) != '/')  /* in case lock-directory doesn't end in / */
+  err = symlink (lock_info_str, lfname);
+  if (errno == EEXIST && force)
     {
-      *p = '/';
-      p++;
+      unlink (lfname);
+      err = symlink (lock_info_str, lfname);
     }
 
-  strcpy (p, (char *) XSTRING_DATA (fn));
+  return err == 0;
+}
+\f
+/* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete,
+   1 if another process owns it (and set OWNER (if non-null) to info),
+   2 if the current process owns it,
+   or -1 if something is wrong with the locking mechanism.  */
 
-  for (; *p; p++)
+static int
+current_lock_owner (lock_info_type *owner, char *lfname)
+{
+#ifndef index
+  extern char *rindex (), *index ();
+#endif
+  int o, p, len, ret;
+  int local_owner = 0;
+  char *at, *dot;
+  char *lfinfo = 0;
+  int bufsize = 50;
+  /* Read arbitrarily-long contents of symlink.  Similar code in
+     file-symlink-p in fileio.c.  */
+  do
+    {
+      bufsize *= 2;
+      lfinfo = (char *) xrealloc (lfinfo, bufsize);
+      len = readlink (lfname, lfinfo, bufsize);
+    }
+  while (len >= bufsize);
+  
+  /* If nonexistent lock file, all is well; otherwise, got strange error. */
+  if (len == -1)
     {
-      if (*p == '/')
-       *p = '!';
+      xfree (lfinfo);
+      return errno == ENOENT ? 0 : -1;
     }
+
+  /* Link info exists, so `len' is its length.  Null terminate.  */
+  lfinfo[len] = 0;
+  
+  /* Even if the caller doesn't want the owner info, we still have to
+     read it to determine return value, so allocate it.  */
+  if (!owner)
+    {
+      owner = (lock_info_type *) alloca (sizeof (lock_info_type));
+      local_owner = 1;
+    }
+  
+  /* Parse USER@HOST.PID.  If can't parse, return -1.  */
+  /* The USER is everything before the first @.  */
+  at = index (lfinfo, '@');
+  dot = rindex (lfinfo, '.');
+  if (!at || !dot) {
+    xfree (lfinfo);
+    return -1;
+  }
+  len = at - lfinfo;
+  owner->user = (char *) xmalloc (len + 1);
+  strncpy (owner->user, lfinfo, len);
+  owner->user[len] = 0;
+  
+  /* The PID is everything after the last `.'.  */
+  owner->pid = atoi (dot + 1);
+
+  /* The host is everything in between.  */
+  len = dot - at - 1;
+  owner->host = (char *) xmalloc (len + 1);
+  strncpy (owner->host, at + 1, len);
+  owner->host[len] = 0;
+
+  /* We're done looking at the link info.  */
+  xfree (lfinfo);
+  
+  /* On current host?  */
+  if (STRINGP (Fsystem_name ()) 
+      && strcmp (owner->host, XSTRING_DATA(Fsystem_name ())) == 0)
+    {
+      if (owner->pid == getpid ())
+        ret = 2; /* We own it.  */
+      else if (owner->pid > 0
+               && (kill (owner->pid, 0) >= 0 || errno == EPERM))
+        ret = 1; /* An existing process on this machine owns it.  */
+      /* The owner process is dead or has a strange pid (<=0), so try to
+         zap the lockfile.  */
+      else if (unlink (lfname) < 0)
+        ret = -1;
+      else
+       ret = 0;
+    }
+  else
+    { /* If we wanted to support the check for stale locks on remote machines,
+         here's where we'd do it.  */
+      ret = 1;
+    }
+  
+  /* Avoid garbage.  */
+  if (local_owner || ret <= 0)
+    {
+      FREE_LOCK_INFO (*owner);
+    }
+  return ret;
 }
-#endif /* !defined HAVE_LONG_FILE_NAMES */
+\f
+/* Lock the lock named LFNAME if possible.
+   Return 0 in that case.
+   Return positive if some other process owns the lock, and info about
+     that process in CLASHER.
+   Return -1 if cannot lock for any other reason.  */
 
-static Lisp_Object
-lock_file_owner_name (CONST char *lfname)
+static int
+lock_if_free (lock_info_type *clasher, char *lfname)
 {
-  struct stat s;
-  struct passwd *the_pw = 0;
+  if (lock_file_1 (lfname, 0) == 0)
+    {
+      int locker;
 
-  if (lstat (lfname, &s) == 0)
-    the_pw = getpwuid (s.st_uid);
-  return (the_pw == 0 ? Qnil : build_string (the_pw->pw_name));
+      if (errno != EEXIST)
+       return -1;
+      
+      locker = current_lock_owner (clasher, lfname);
+      if (locker == 2)
+        {
+          FREE_LOCK_INFO (*clasher);
+          return 0;   /* We ourselves locked it.  */
+        }
+      else if (locker == 1)
+        return 1;  /* Someone else has it.  */
+
+      return -1; /* Something's wrong.  */
+    }
+  return 0;
 }
 
-
-/* lock_file locks file fn,
+/* lock_file locks file FN,
    meaning it serves notice on the world that you intend to edit that file.
    This should be done only when about to modify a file-visiting
    buffer previously unmodified.
-   Do not (normally) call lock_buffer for a buffer already modified,
+   Do not (normally) call this for a buffer already modified,
    as either the file is already locked, or the user has already
    decided to go ahead without locking.
 
-   When lock_buffer returns, either the lock is locked for us,
+   When this returns, either the lock is locked for us,
    or the user has said to go ahead without locking.
 
-   If the file is locked by someone else, lock_buffer calls
+   If the file is locked by someone else, this calls
    ask-user-about-lock (a Lisp function) with two arguments,
-   the file name and the name of the user who did the locking.
+   the file name and info about the user who did the locking.
    This function can signal an error, or return t meaning
    take away the lock, or return nil meaning ignore the lock.  */
 
-/* The lock file name is the file name with "/" replaced by "!"
-   and put in the Emacs lock directory.  */
-/* (ie., /ka/king/junk.tex -> /!/!ka!king!junk.tex). */
-
-/* If HAVE_LONG_FILE_NAMES is not defined, the lock file name is the hex
-   representation of a 14-bytes CRC generated from the file name
-   and put in the Emacs lock directory (not very nice, but it works).
-   (ie., /ka/king/junk.tex -> /!/12a82c62f1c6da). */
-
 void
 lock_file (Lisp_Object fn)
 {
@@ -201,16 +302,14 @@ lock_file (Lisp_Object fn)
   /* dmoore - and can destroy current_buffer and all sorts of other
      mean nasty things with pointy teeth.  If you call this make sure
      you protect things right. */
+  /* Somebody updated the code in this function and removed the previous 
+     comment.  -slb */
 
-  REGISTER Lisp_Object attack, orig_fn;
-  REGISTER char *lfname;
-  struct gcpro gcpro1, gcpro2;
-  Lisp_Object subject_buf = Qnil;
-
-  if (NILP (Vlock_directory) || NILP (Vsuperlock_file))
-    return;
-  CHECK_STRING (fn);
-  CHECK_STRING (Vlock_directory);
+  register Lisp_Object attack, orig_fn;
+  register char *lfname, *locker;
+  lock_info_type lock_info;
+  struct gcpro gcpro1,gcpro2;
+  Lisp_Object subject_buf;
 
   GCPRO2 (fn, subject_buf);
   orig_fn = fn;
@@ -221,29 +320,34 @@ lock_file (Lisp_Object fn)
 
   /* See if this file is visited and has changed on disk since it was
      visited.  */
-  subject_buf = Fget_file_buffer (fn);
-  if (!NILP (subject_buf)
-      && NILP (Fverify_visited_file_modtime (subject_buf))
-      && !NILP (Ffile_exists_p (fn)))
-    call1_in_buffer (XBUFFER (subject_buf),
-                    Qask_user_about_supersession_threat, fn);
+  {
+    subject_buf = get_truename_buffer (orig_fn);
+    if (!NILP (subject_buf)
+       && NILP (Fverify_visited_file_modtime (subject_buf))
+       && !NILP (Ffile_exists_p (fn)))
+      call1_in_buffer (XBUFFER(subject_buf),
+                       Qask_user_about_supersession_threat, fn);
+  }
 
   /* Try to lock the lock. */
-  if (lock_if_free (lfname) <= 0)
-    /* Return now if we have locked it, or if lock dir does not exist */
+  if (lock_if_free (&lock_info, lfname) <= 0)
+    /* Return now if we have locked it, or if lock creation failed */
     goto done;
 
   /* Else consider breaking the lock */
+  locker = (char *) alloca (strlen (lock_info.user) + strlen (lock_info.host)
+                           + LOCK_PID_MAX + 9);
+  sprintf (locker, "%s@%s (pid %lu)", lock_info.user, lock_info.host,
+           lock_info.pid);
+  FREE_LOCK_INFO (lock_info);
+  
   attack = call2_in_buffer (BUFFERP (subject_buf) ? XBUFFER (subject_buf) :
-                           current_buffer, Qask_user_about_lock, fn,
-                           lock_file_owner_name (lfname));
+                           current_buffer, Qask_user_about_lock , fn,
+                           build_string (locker));
   if (!NILP (attack))
     /* User says take the lock */
     {
-      CHECK_STRING (Vsuperlock_file);
-      lock_superlock (lfname);
-      lock_file_1 (lfname, O_WRONLY);
-      unlink ((char *) XSTRING_DATA (Vsuperlock_file));
+      lock_file_1 (lfname, 1);
       goto done;
     }
   /* User says ignore the lock */
@@ -251,197 +355,46 @@ lock_file (Lisp_Object fn)
   UNGCPRO;
 }
 
-
-/* Lock the lock file named LFNAME.
-   If MODE is O_WRONLY, we do so even if it is already locked.
-   If MODE is O_WRONLY | O_EXCL | O_CREAT, we do so only if it is free.
-   Return 1 if successful, 0 if not.  */
-
-static int
-lock_file_1 (CONST char *lfname, int mode)
-{
-  REGISTER int fd;
-  char buf[20];
-
-  if ((fd = open (lfname, mode, 0666)) >= 0)
-    {
-#if defined(WINDOWSNT)
-      chmod(lfname, _S_IREAD|_S_IWRITE);
-#elif defined(USG)
-      chmod (lfname, 0666);
-#else
-      fchmod (fd, 0666);
-#endif
-      sprintf (buf, "%ld ", (long) getpid ());
-      write (fd, buf, strlen (buf));
-      close (fd);
-      return 1;
-    }
-  else
-    return 0;
-}
-
-/* Lock the lock named LFNAME if possible.
-   Return 0 in that case.
-   Return positive if lock is really locked by someone else.
-   Return -1 if cannot lock for any other reason.  */
-
-static int
-lock_if_free (CONST char *lfname)
-{
-  REGISTER int clasher;
-
-  while (lock_file_1 (lfname, O_WRONLY | O_EXCL | O_CREAT) == 0)
-    {
-      if (errno != EEXIST)
-       return -1;
-      clasher = current_lock_owner (lfname);
-      if (clasher != 0)
-       if (clasher != getpid ())
-         return (clasher);
-       else return (0);
-      /* Try again to lock it */
-    }
-  return 0;
-}
-
-/* Return the pid of the process that claims to own the lock file LFNAME,
-   or 0 if nobody does or the lock is obsolete,
-   or -1 if something is wrong with the locking mechanism.  */
-
-static int
-current_lock_owner (CONST char *lfname)
-{
-  int owner = current_lock_owner_1 (lfname);
-  if (owner == 0 && errno == ENOENT)
-    return (0);
-  /* Is it locked by a process that exists?  */
-  if (owner != 0 && (kill (owner, 0) >= 0 || errno == EPERM))
-    return (owner);
-  if (unlink (lfname) < 0)
-    return (-1);
-  return (0);
-}
-
-static int
-current_lock_owner_1 (CONST char *lfname)
-{
-  REGISTER int fd;
-  char buf[20];
-  int tem;
-
-  fd = open (lfname, O_RDONLY, 0666);
-  if (fd < 0)
-    return 0;
-  tem = read (fd, buf, sizeof buf);
-  close (fd);
-  return (tem <= 0 ? 0 : atoi (buf));
-}
-
-\f
 void
 unlock_file (Lisp_Object fn)
 {
-  /* This function can GC. */
-  /* dmoore - and can destroy current_buffer and all sorts of other
-     mean nasty things with pointy teeth.  If you call this make sure
-     you protect things right. */
-
-  REGISTER char *lfname;
-  if (NILP (Vlock_directory) || NILP (Vsuperlock_file)) return;
-  CHECK_STRING (fn);
-  CHECK_STRING (Vlock_directory);
-  CHECK_STRING (Vsuperlock_file);
+  register char *lfname;
 
   fn = Fexpand_file_name (fn, Qnil);
 
   MAKE_LOCK_NAME (lfname, fn);
 
-  lock_superlock (lfname);
-
-  if (current_lock_owner_1 (lfname) == getpid ())
+  if (current_lock_owner (0, lfname) == 2)
     unlink (lfname);
-
-  unlink ((char *) XSTRING_DATA (Vsuperlock_file));
-}
-
-static void
-lock_superlock (CONST char *lfname)
-{
-  REGISTER int i, fd;
-  DIR *lockdir;
-
-  for (i = -20; i < 0 &&
-       (fd = open ((char *) XSTRING_DATA (Vsuperlock_file),
-                  O_WRONLY | O_EXCL | O_CREAT, 0666)) < 0;
-       i++)
-    {
-      if (errno != EEXIST)
-       return;
-
-      /* This seems to be necessary to prevent Emacs from hanging when the
-        competing process has already deleted the superlock, but it's still
-        in the NFS cache.  So we force NFS to synchronize the cache.  */
-      lockdir = opendir ((char *) XSTRING_DATA (Vlock_directory));
-      if (lockdir)
-       closedir (lockdir);
-
-      emacs_sleep (1);
-    }
-  if (fd >= 0)
-    {
-#if defined(WINDOWSNT)
-      chmod(lfname, _S_IREAD|_S_IWRITE);
-#elif defined(USG)
-      chmod ((char *) XSTRING_DATA (Vsuperlock_file), 0666);
-#else
-      fchmod (fd, 0666);
-#endif
-      write (fd, lfname, strlen (lfname));
-      close (fd);
-    }
 }
 
 void
-unlock_all_files (void)
+unlock_all_files ()
 {
-  /* This function can GC. */
-
-  Lisp_Object tail;
-  REGISTER struct buffer *b;
-  struct gcpro gcpro1;
+  register Lisp_Object tail;
+  register struct buffer *b;
 
-  GCPRO1 (tail);
-  for (tail = Vbuffer_alist; GC_CONSP (tail);
-       tail = XCDR (tail))
+  for (tail = Vbuffer_alist; GC_CONSP (tail); tail = XCDR (tail))
     {
       b = XBUFFER (XCDR (XCAR (tail)));
-      if (STRINGP (b->file_truename) &&
-         BUF_SAVE_MODIFF (b) < BUF_MODIFF (b))
+      if (STRINGP (b->file_truename) && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b))
        unlock_file (b->file_truename);
     }
-  UNGCPRO;
 }
-
 \f
-DEFUN ("lock-buffer", Flock_buffer, 0, 1, 0, /*
-Lock FILE, if current buffer is modified.
-FILE defaults to current buffer's visited file,
+DEFUN ("lock-buffer", Flock_buffer,   0, 1, 0, /*
+  Lock FILE, if current buffer is modified.\n\
+FILE defaults to current buffer's visited file,\n\
 or else nothing is done if current buffer isn't visiting a file.
 */
-       (fn))
+  (file))
 {
-  /* This function can GC */
-  /* dmoore - and can destroy current_buffer and all sorts of other
-     mean nasty things with pointy teeth.  If you call this make sure
-     you protect things right. */
-
-  if (NILP (fn))
-    fn = current_buffer->file_truename;
-  CHECK_STRING (fn);
+  if (NILP (file))
+    file = current_buffer->file_truename;
+  CHECK_STRING (file);
   if (BUF_SAVE_MODIFF (current_buffer) < BUF_MODIFF (current_buffer)
-      && !NILP (fn))
-    lock_file (fn);
+      && !NILP (file))
+    lock_file (file);
   return Qnil;
 }
 
@@ -462,9 +415,9 @@ if it should normally be locked.
   return Qnil;
 }
 
-\f
 /* Unlock the file visited in buffer BUFFER.  */
 
+
 void
 unlock_buffer (struct buffer *buffer)
 {
@@ -478,32 +431,37 @@ unlock_buffer (struct buffer *buffer)
 }
 
 DEFUN ("file-locked-p", Ffile_locked_p, 0, 1, 0, /*
-Return nil if the FILENAME is not locked,
+  Return nil if the FILENAME is not locked,\n\
 t if it is locked by you, else a string of the name of the locker.
 */
-       (fn))
+  (filename)) 
 {
-  /* This function can GC */
-  REGISTER char *lfname;
+  Lisp_Object ret;
+  register char *lfname;
   int owner;
+  lock_info_type locker;
 
-  if (NILP (Vlock_directory) || NILP (Vsuperlock_file))
-    return Qnil;
-  CHECK_STRING (Vlock_directory);
+  filename = Fexpand_file_name (filename, Qnil);
 
-  fn = Fexpand_file_name (fn, Qnil);
+  MAKE_LOCK_NAME (lfname, filename);
 
-  MAKE_LOCK_NAME (lfname, fn);
-
-  owner = current_lock_owner (lfname);
+  owner = current_lock_owner (&locker, lfname);
   if (owner <= 0)
-    return Qnil;
-  else if (owner == getpid ())
-    return Qt;
+    ret = Qnil;
+  else if (owner == 2)
+    ret = Qt;
+  else
+    ret = build_string (locker.user);
+
+  if (owner > 0)
+    FREE_LOCK_INFO (locker);
 
-  return lock_file_owner_name (lfname);
+  return ret;
 }
 
+\f
+/* Initialization functions.  */
+
 void
 syms_of_filelock (void)
 {
@@ -517,30 +475,5 @@ syms_of_filelock (void)
   defsymbol (&Qask_user_about_lock, "ask-user-about-lock");
 }
 
-void
-vars_of_filelock (void)
-{
-  DEFVAR_LISP ("lock-directory", &Vlock_directory /*
-Don't change this
-*/ );
-  Vlock_directory = Qnil;
-  DEFVAR_LISP ("superlock-file", &Vsuperlock_file /*
-Don't change this
-*/ );
-  Vsuperlock_file = Qnil;
-}
 
-void
-complex_vars_of_filelock (void)
-{
-  DEFVAR_LISP ("configure-superlock-file", &Vconfigure_superlock_file /*
-For internal use by the build procedure only.
-configure's idea of what SUPERLOCK-FILE will be.
-*/ );
-#ifdef PATH_SUPERLOCK
-  Vconfigure_superlock_file = build_string (PATH_SUPERLOCK);
-#else
-  Vconfigure_superlock_file = Qnil;
-#endif
-  /* All the rest done dynamically by startup.el */
-}
+#endif /* CLASH_DETECTION */
index 2fddbae..3c538f0 100644 (file)
@@ -2651,6 +2651,7 @@ x_delete_frame (struct frame *f)
   }
 #else
   XtDestroyWidget (w);
+  XFlush (XtDisplay(w));   /* make sure the windows are really gone! */
 #endif /* EXTERNAL_WIDGET */
 
   if (FRAME_X_GEOM_FREE_ME_PLEASE (f))
diff --git a/src/gif_io.c b/src/gif_io.c
new file mode 100644 (file)
index 0000000..ddbfb16
--- /dev/null
@@ -0,0 +1,259 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "gifrlib.h"
+
+/******************************************************************************
+* Set up the GifFileType structure for use.  This must be called first in any *
+* client program.  Then, if custom IO or Error functions are desired, call    *
+* GifSetIOFunc/GifSetErrorFunc, then call EGifInitWrite.  Else call           *
+* EGifOpenFileName or EGifOpenFileHandle for standard IO functions.           *
+* If setup fails, a NULL pointer is returned.                                 *
+******************************************************************************/
+GifFileType *GifSetup(void)
+{
+    GifIODataType *GifIO;
+    GifFileType *GifFile;
+
+    if ((GifFile = (GifFileType *) malloc(sizeof(GifFileType))) == NULL)
+       return NULL;
+    memset(GifFile, '\0', sizeof(GifFileType));
+    if ((GifIO = (GifIODataType *) malloc(sizeof(GifIODataType))) == NULL) {
+       free((char *) GifFile);
+       return NULL;
+    }
+    memset(GifIO, '\0', sizeof(GifIODataType));
+    GifFile->GifIO = GifIO;    
+    return GifFile;
+}
+
+void GifFree(GifFileType *GifFile)
+{
+    GifFilePrivateType *Private;
+
+    if (GifFile == NULL) return;
+
+    Private = (GifFilePrivateType *) GifFile->Private;
+
+    if (GifFile->SavedImages)
+       FreeSavedImages(GifFile);
+    if (GifFile->Image.ColorMap)
+       FreeMapObject(GifFile->Image.ColorMap);
+    if (GifFile->SColorMap)
+       FreeMapObject(GifFile->SColorMap);
+    if (Private)
+    {
+       free(Private);
+    }
+    if (GifFile->GifIO)
+       free(GifFile->GifIO);
+    free(GifFile);
+}
+
+/****************************************************************************
+* Install the specified ReadFunction into the GifFile specified.            *
+****************************************************************************/
+void GifSetReadFunc(GifFileType *GifFile, Gif_rw_func ReadFunc, VoidPtr data)
+{
+    GifIODataType *GifIO = (GifIODataType *)GifFile->GifIO;
+    GifIO->ReadFunc = ReadFunc;
+    GifIO->ReadFunc_data = data;
+}
+
+/****************************************************************************
+* Install the specified WriteFunction into the GifFile specified.           *
+****************************************************************************/
+void GifSetWriteFunc(GifFileType *GifFile, Gif_rw_func WriteFunc, VoidPtr data)
+{
+    GifIODataType *GifIO = (GifIODataType *)GifFile->GifIO;
+    GifIO->WriteFunc = WriteFunc;
+    GifIO->WriteFunc_data = data;
+}
+
+/****************************************************************************
+* Install the specified CloseFunction into the GifFile specified.           *
+****************************************************************************/
+void GifSetCloseFunc(GifFileType *GifFile, Gif_close_func CloseFunc, VoidPtr data)
+{
+    GifIODataType *GifIO = (GifIODataType *)GifFile->GifIO;
+    GifIO->CloseFunc = CloseFunc;
+    GifIO->CloseFunc_data = data;
+}
+
+/****************************************************************************
+* Install the standard IO funcs into the GifFile, including the FILE info   *
+****************************************************************************/
+void GifStdIOInit(GifFileType *GifFile, FILE *file, int filehandle)
+{
+    GifStdIODataType *IOData;
+    
+    if ((IOData = (GifStdIODataType*)malloc(sizeof(GifStdIODataType))) == NULL)
+       GifInternError(GifFile, GIF_ERR_NOT_ENOUGH_MEM);
+    IOData->File = file;
+    IOData->FileHandle = filehandle;
+    GifSetReadFunc(GifFile, GifStdRead, IOData);
+    GifSetWriteFunc(GifFile, GifStdWrite, IOData);
+    GifSetCloseFunc(GifFile, GifStdFileClose, IOData);
+}
+
+size_t GifStdRead(GifByteType *buf, size_t size, VoidPtr method_data)
+{
+  GifStdIODataType *IOtype = (GifStdIODataType*)method_data;
+  return (fread(buf, 1, size, IOtype->File));
+}
+
+size_t GifStdWrite(GifByteType *buf, size_t size, VoidPtr method_data)
+{
+  GifStdIODataType *IOtype = (GifStdIODataType*)method_data;
+  return (fwrite(buf, 1, size, IOtype->File));  
+}
+
+int GifStdFileClose(VoidPtr method_data)
+{
+  int ret;
+  GifStdIODataType *IOtype = (GifStdIODataType*)method_data;
+  ret = fclose(IOtype->File);
+  if (ret == 0 && IOtype->FileHandle != -1)
+    ret = close(IOtype->FileHandle);
+  return ret;
+}
+
+void GifRead(GifByteType *buf, size_t size, GifFileType *GifFile)
+{
+  GifIODataType *GifIO = (GifIODataType*)GifFile->GifIO;
+  if ((*(GifIO->ReadFunc))(buf, size, GifIO->ReadFunc_data) != size)
+    GifError(GifFile, "Read error!");
+}
+
+void GifWrite(GifByteType *buf, size_t size, GifFileType *GifFile)
+{
+  GifIODataType *GifIO = (GifIODataType*)GifFile->GifIO;
+  if ((*(GifIO->WriteFunc))(buf, size, GifIO->WriteFunc_data) != size)
+    GifError(GifFile, "Write error!");
+}
+
+int GifClose(GifFileType *GifFile) 
+{
+  GifIODataType *GifIO = (GifIODataType*)GifFile->GifIO;
+  return ((*(GifIO->CloseFunc))(GifIO->CloseFunc_data));
+}
+
+static char *GifErrorString[14] = {
+  "Failed to open given file",                 /* D_GIF_ERR_OPEN_FAILED */
+  "Failed to read from given file",            /* D_GIF_ERR_READ_FAILED */
+  "Given file is NOT a GIF file",              /* D_GIF_ERR_NOT_GIF_FILE */
+  "No Screen Descriptor detected",             /* D_GIF_ERR_NO_SCRN_DSCR */
+  "No Image Descriptor detected",              /* D_GIF_ERR_NO_IMAG_DSCR */
+  "No global or local color map",              /* D_GIF_ERR_NO_COLOR_MAP */
+  "Wrong record type detected",                        /* D_GIF_ERR_WRONG_RECORD */
+  "#Pixels bigger than Width * Height",                /* D_GIF_ERR_DATA_TOO_BIG */
+  "Fail to allocate required memory",          /* D_GIF_ERR_NOT_ENOUGH_MEM */
+  "Failed to close given file",                        /* D_GIF_ERR_CLOSE_FAILED */
+  "Given file was not opened for read",                /* D_GIF_ERR_CLOSE_FAILED */
+  "Image is defective, decoding aborted",      /* D_GIF_ERR_IMAGE_DEFECT */
+  "Image EOF detected before image complete",  /* D_GIF_ERR_EOF_TOO_SOON */
+  "Undefined error!",
+};
+
+const char *GetGifError(int error);
+
+/*****************************************************************************
+* Get the last GIF error in human-readable form.                            *
+*****************************************************************************/
+const char *GetGifError(int error)
+{
+    char *Err;
+
+    switch(error) {
+       case D_GIF_ERR_OPEN_FAILED:
+           Err = GifErrorString[0];
+           break;
+       case D_GIF_ERR_READ_FAILED:
+           Err = GifErrorString[1];
+           break;
+       case D_GIF_ERR_NOT_GIF_FILE:
+           Err = GifErrorString[2];
+           break;
+       case D_GIF_ERR_NO_SCRN_DSCR:
+           Err = GifErrorString[3];
+           break;
+       case D_GIF_ERR_NO_IMAG_DSCR:
+           Err = GifErrorString[4];
+           break;
+       case D_GIF_ERR_NO_COLOR_MAP:
+           Err = GifErrorString[5];
+           break;
+       case D_GIF_ERR_WRONG_RECORD:
+           Err = GifErrorString[6];
+           break;
+       case D_GIF_ERR_DATA_TOO_BIG:
+           Err = GifErrorString[7];
+           break;
+       case D_GIF_ERR_NOT_ENOUGH_MEM:
+           Err = GifErrorString[8];
+           break;
+       case D_GIF_ERR_CLOSE_FAILED:
+           Err = GifErrorString[9];
+           break;
+       case D_GIF_ERR_NOT_READABLE:
+           Err = GifErrorString[10];
+           break;
+       case D_GIF_ERR_IMAGE_DEFECT:
+           Err = GifErrorString[11];
+           break;
+       case D_GIF_ERR_EOF_TOO_SOON:
+           Err = GifErrorString[12];
+           break;
+       default:
+           Err = GifErrorString[13];
+           break;
+    }
+    return Err;
+}
+
+/******************************
+* These are called internally *        
+******************************/
+void GifError(GifFileType *GifFile, const char *err_str)
+{
+  GifIODataType *GifIO = (GifIODataType*)GifFile->GifIO;
+  if (GifIO->ErrorFunc)
+    (*(GifIO->ErrorFunc))(err_str, GifIO->ErrorFunc_data);
+  else
+    fprintf(stderr, "GIF FATAL ERROR: %s", err_str);
+  exit(-10);
+}
+
+void GifWarning(GifFileType *GifFile, const char *err_str)
+{
+  GifIODataType *GifIO = (GifIODataType*)GifFile->GifIO;
+  if (GifIO->WarningFunc) 
+    (*(GifIO->WarningFunc))(err_str, GifIO->WarningFunc_data);
+}
+
+void GifInternError(GifFileType *GifFile, int error_num)
+{
+  const char *ErrStr = GetGifError(error_num);
+  GifError(GifFile, ErrStr);
+}
+
+void GifInternWarning(GifFileType *GifFile, int error_num)
+{
+  const char *ErrStr = GetGifError(error_num);
+  GifWarning(GifFile, ErrStr);
+}
+
+void GifSetErrorFunc(GifFileType *GifFile, Gif_error_func ErrorFunc, VoidPtr data)
+{
+    GifIODataType *GifIO = (GifIODataType *)GifFile->GifIO;
+    GifIO->ErrorFunc = ErrorFunc;
+    GifIO->ErrorFunc_data = data;  
+}
+
+void GifSetWarningFunc(GifFileType *GifFile, Gif_error_func WarningFunc, VoidPtr data)
+{
+    GifIODataType *GifIO = (GifIODataType *)GifFile->GifIO;
+    GifIO->WarningFunc = WarningFunc;
+    GifIO->WarningFunc_data = data;
+}
diff --git a/src/gifrlib.h b/src/gifrlib.h
new file mode 100644 (file)
index 0000000..5b185d7
--- /dev/null
@@ -0,0 +1,272 @@
+/******************************************************************************
+* In order to make life a little bit easier when using the GIF file format,   *
+* this library was written, and which does all the dirty work...             *
+*                                                                            *
+*                                      Written by Gershon Elber,  Jun. 1989  *
+*                                      Hacks by Eric S. Raymond,  Sep. 1992  *
+*                                             and Jareth Hein,     Jan. 1998  *
+*******************************************************************************
+* History:                                                                   *
+* 14 Jun 89 - Version 1.0 by Gershon Elber.                                  *
+*  3 Sep 90 - Version 1.1 by Gershon Elber (Support for Gif89, Unique names). *
+* 15 Sep 90 - Version 2.0 by Eric S. Raymond (Changes to suoport GIF slurp)   *
+* 26 Jun 96 - Version 3.0 by Eric S. Raymond (Full GIF89 support)             *
+* 19 Jan 98 - Version 3.1 by Jareth Hein (Support for user-defined I/O).      *
+******************************************************************************/
+
+#ifndef GIF_LIB_H
+#define GIF_LIB_H
+
+#define        GIF_ERROR       0
+#define GIF_OK         1
+
+#ifndef TRUE
+#define TRUE           1
+#define FALSE          0
+#endif
+
+#ifndef NULL
+#define NULL           0
+#endif /* NULL */
+
+#define GIF_FILE_BUFFER_SIZE 16384  /* Files uses bigger buffers than usual. */
+
+typedef        int             GifBooleanType;
+typedef        unsigned char   GifPixelType;
+typedef unsigned char *        GifRowType;
+typedef unsigned char  GifByteType;
+
+#ifdef SYSV
+#define VoidPtr char *
+#else
+#define VoidPtr void *
+#endif /* SYSV */
+
+typedef struct GifColorType {
+    GifByteType Red, Green, Blue;
+} GifColorType;
+
+typedef struct ColorMapObject
+{
+    int        ColorCount;
+    int BitsPerPixel;
+    GifColorType *Colors;              /* on malloc(3) heap */
+}
+ColorMapObject;
+
+typedef struct GifImageDesc {
+    int Left, Top, Width, Height,      /* Current image dimensions. */
+       Interlace;                      /* Sequential/Interlaced lines. */
+    ColorMapObject *ColorMap;          /* The local color map */
+} GifImageDesc;
+
+/* I/O operations.  If you roll your own, they need to be semantically equivilent to
+   fread/fwrite, with an additional paramater to hold data local to your method. */
+typedef size_t (*Gif_rw_func)(GifByteType *buffer, size_t size, VoidPtr method_data);
+/* Finish up stream. Non-zero return indicates failure */
+typedef int (*Gif_close_func)(VoidPtr close_data);
+/* Error handling function */
+typedef void (*Gif_error_func)(const char *string, VoidPtr error_data);
+
+typedef struct GifFileType {
+    int SWidth, SHeight,               /* Screen dimensions. */
+       SColorResolution,               /* How many colors can we generate? */
+       SBackGroundColor;               /* I hope you understand this one... */
+    ColorMapObject *SColorMap;         /* NULL if it doesn't exist. */
+    int ImageCount;                    /* Number of current image */
+    GifImageDesc Image;                        /* Block describing current image */
+    struct SavedImage *SavedImages;    /* Use this to accumulate file state */
+    VoidPtr Private;                   /* Don't mess with this! */
+    VoidPtr GifIO;                     /* Contains all information for I/O */
+} GifFileType;
+
+typedef enum {
+    UNDEFINED_RECORD_TYPE,
+    SCREEN_DESC_RECORD_TYPE,
+    IMAGE_DESC_RECORD_TYPE,            /* Begin with ',' */
+    EXTENSION_RECORD_TYPE,             /* Begin with '!' */
+    TERMINATE_RECORD_TYPE              /* Begin with ';' */
+} GifRecordType;
+
+/******************************************************************************
+*  GIF89 extension function codes                                             *
+******************************************************************************/
+
+#define COMMENT_EXT_FUNC_CODE          0xfe    /* comment */
+#define GRAPHICS_EXT_FUNC_CODE         0xf9    /* graphics control */
+#define PLAINTEXT_EXT_FUNC_CODE                0x01    /* plaintext */
+#define APPLICATION_EXT_FUNC_CODE      0xff    /* application block */
+
+/******************************************************************************
+* IO related routines.  Defined in gif_io.c                                   *
+******************************************************************************/
+GifFileType *GifSetup(void);
+void GifFree(GifFileType *GifFile);
+void GifSetReadFunc (GifFileType *GifFile, Gif_rw_func func, VoidPtr data);
+void GifSetWriteFunc(GifFileType *GifFile, Gif_rw_func func, VoidPtr data);
+void GifSetCloseFunc(GifFileType *GifFile, Gif_close_func func, VoidPtr data);
+
+/******************************************************************************
+* O.K., here are the routines one can access in order to decode GIF file:     *
+******************************************************************************/
+
+void DGifOpenFileName(GifFileType *GifFile, const char *GifFileName);
+void DGifOpenFileHandle(GifFileType *GifFile, int GifFileHandle);
+void DGifInitRead(GifFileType *GifFile);
+void DGifSlurp(GifFileType *GifFile);
+void DGifGetScreenDesc(GifFileType *GifFile);
+void DGifGetRecordType(GifFileType *GifFile, GifRecordType *GifType);
+void DGifGetImageDesc(GifFileType *GifFile);
+void DGifGetLine(GifFileType *GifFile, GifPixelType *GifLine, int GifLineLen);
+void DGifGetPixel(GifFileType *GifFile, GifPixelType GifPixel);
+void DGifGetComment(GifFileType *GifFile, char *GifComment);
+void DGifGetExtension(GifFileType *GifFile, int *GifExtCode,
+                                               GifByteType **GifExtension);
+void DGifGetExtensionNext(GifFileType *GifFile, GifByteType **GifExtension);
+void DGifGetCode(GifFileType *GifFile, int *GifCodeSize,
+                                               GifByteType **GifCodeBlock);
+void DGifGetCodeNext(GifFileType *GifFile, GifByteType **GifCodeBlock);
+void DGifGetLZCodes(GifFileType *GifFile, int *GifCode);
+int DGifCloseFile(GifFileType *GifFile);
+
+#define        D_GIF_ERR_OPEN_FAILED   101             /* And DGif possible errors. */
+#define        D_GIF_ERR_READ_FAILED   102
+#define        D_GIF_ERR_NOT_GIF_FILE  103
+#define D_GIF_ERR_NO_SCRN_DSCR 104
+#define D_GIF_ERR_NO_IMAG_DSCR 105
+#define D_GIF_ERR_NO_COLOR_MAP 106
+#define D_GIF_ERR_WRONG_RECORD 107
+#define D_GIF_ERR_DATA_TOO_BIG 108
+#define GIF_ERR_NOT_ENOUGH_MEM 109
+#define D_GIF_ERR_NOT_ENOUGH_MEM 109
+#define D_GIF_ERR_CLOSE_FAILED 110
+#define D_GIF_ERR_NOT_READABLE 111
+#define D_GIF_ERR_IMAGE_DEFECT 112
+#define D_GIF_ERR_EOF_TOO_SOON 113
+
+/******************************************************************************
+* O.K., here are the error routines                                          *
+******************************************************************************/
+extern void GifSetErrorFunc(GifFileType *GifFile, Gif_error_func func, VoidPtr data);
+extern void GifSetWarningFunc(GifFileType *GifFile, Gif_error_func func, VoidPtr data);
+extern void GifInternError(GifFileType *GifFile, int errnum);
+extern void GifInternWarning(GifFileType *GifFile, int errnum);
+extern void GifError(GifFileType *GifFile, const char *err_str);
+extern void GifWarning(GifFileType *GifFile, const char *err_str);
+
+/*****************************************************************************
+ *
+ * Everything below this point is new after version 1.2, supporting `slurp
+ * mode' for doing I/O in two big belts with all the image-bashing in core.
+ *
+ *****************************************************************************/
+
+/******************************************************************************
+* Support for the in-core structures allocation (slurp mode).                *
+******************************************************************************/
+
+/* This is the in-core version of an extension record */
+typedef struct {
+    int                ByteCount;
+    char       *Bytes;         /* on malloc(3) heap */
+} ExtensionBlock;
+
+/* This holds an image header, its unpacked raster bits, and extensions */
+typedef struct SavedImage {
+    GifImageDesc       ImageDesc;
+
+    char               *RasterBits;            /* on malloc(3) heap */
+
+    int                        Function;
+    int                        ExtensionBlockCount;
+    ExtensionBlock     *ExtensionBlocks;       /* on malloc(3) heap */
+} SavedImage;
+
+extern void ApplyTranslation(SavedImage *Image, GifPixelType Translation[]);
+
+extern void MakeExtension(SavedImage *New, int Function);
+extern int AddExtensionBlock(SavedImage *New, int Length, GifByteType *data);
+extern void FreeExtension(SavedImage *Image);
+
+extern SavedImage *MakeSavedImage(GifFileType *GifFile, SavedImage *CopyFrom);
+extern void FreeSavedImages(GifFileType *GifFile);
+
+/*   Common defines used by encode/decode functions */
+
+#define COMMENT_EXT_FUNC_CODE  0xfe /* Extension function code for comment. */
+#define GIF_STAMP      "GIFVER"         /* First chars in file - GIF stamp. */
+#define GIF_STAMP_LEN  sizeof(GIF_STAMP) - 1
+#define GIF_VERSION_POS        3               /* Version first character in stamp. */
+#define GIF87_STAMP    "GIF87a"         /* First chars in file - GIF stamp. */
+#define GIF89_STAMP    "GIF89a"         /* First chars in file - GIF stamp. */
+
+#define LZ_MAX_CODE    4095            /* Biggest code possible in 12 bits. */
+#define LZ_BITS                12
+
+#define FILE_STATE_READ                0x01
+#define FILE_STATE_WRITE       0x01
+#define FILE_STATE_SCREEN      0x02
+#define FILE_STATE_IMAGE       0x04
+
+#define FLUSH_OUTPUT           4096    /* Impossible code, to signal flush. */
+#define FIRST_CODE             4097    /* Impossible code, to signal first. */
+#define NO_SUCH_CODE           4098    /* Impossible code, to signal empty. */
+
+#define IS_READABLE(Private)   (!(Private->FileState & FILE_STATE_READ))
+#define IS_WRITEABLE(Private)  (Private->FileState & FILE_STATE_WRITE)
+
+typedef struct GifFilePrivateType {
+    int FileState,
+       BitsPerPixel,       /* Bits per pixel (Codes uses at list this + 1). */
+       ClearCode,                                     /* The CLEAR LZ code. */
+       EOFCode,                                         /* The EOF LZ code. */
+       RunningCode,                /* The next code algorithm can generate. */
+       RunningBits,/* The number of bits required to represent RunningCode. */
+       MaxCode1,  /* 1 bigger than max. possible code, in RunningBits bits. */
+       LastCode,                       /* The code before the current code. */
+       CrntCode,                                 /* Current algorithm code. */
+       StackPtr,                        /* For character stack (see below). */
+       CrntShiftState;                 /* Number of bits in CrntShiftDWord. */
+    unsigned long CrntShiftDWord;     /* For bytes decomposition into codes. */
+    unsigned long PixelCount;                 /* Number of pixels in image. */
+    GifByteType Buf[256];             /* Compressed input is buffered here. */
+    GifByteType Stack[LZ_MAX_CODE];     /* Decoded pixels are stacked here. */
+    GifByteType Suffix[LZ_MAX_CODE+1];        /* So we can trace the codes. */
+    unsigned int Prefix[LZ_MAX_CODE+1];
+} GifFilePrivateType;
+
+typedef struct GifIODataType {
+    Gif_rw_func ReadFunc, WriteFunc;   /* Pointers to the functions that will do the I/O */
+    Gif_close_func CloseFunc;    
+    VoidPtr ReadFunc_data;             /* data to be passed to the read function */
+    VoidPtr WriteFunc_data;            /* data to be passed to the write function */
+    VoidPtr CloseFunc_data;            /* data to be passed to the close function */
+    Gif_error_func ErrorFunc;  /* MUST NOT RETURN (use lng_jmp or exit)!  */
+    Gif_error_func WarningFunc;        /* For warning messages (can be ignored) */
+    VoidPtr ErrorFunc_data;
+    VoidPtr WarningFunc_data;
+} GifIODataType;
+
+typedef struct GifStdIODataType {
+  FILE *File;
+  int FileHandle;
+} GifStdIODataType;
+
+/* Install StdIO funcs on FILE into GifFile */
+void GifStdIOInit(GifFileType *GifFile, FILE *file, int filehandle);
+
+/* Error checking reads, writes and closes */
+void GifRead(GifByteType *buf, size_t size, GifFileType *GifFile);
+void GifWrite(GifByteType *buf, size_t size, GifFileType *GifFile);
+int GifClose(GifFileType *GifFile);
+
+/* The default Read and Write functions for files */
+size_t GifStdRead(GifByteType *buf, size_t size, VoidPtr method_data);
+size_t GifStdWrite(GifByteType *buf, size_t size, VoidPtr method_data);
+int GifStdFileClose(VoidPtr method_data);
+
+ColorMapObject *MakeMapObject(int ColorCount, GifColorType *ColorMap);
+void FreeMapObject(ColorMapObject *Object);
+
+
+#endif /* GIF_LIB_H */
index 6ee899e..ddb16d4 100644 (file)
@@ -521,6 +521,8 @@ mswindows_create_resized_bitmap (struct Lisp_Image_Instance* ii,
                   IMAGE_INSTANCE_PIXMAP_HEIGHT (ii), 
                   SRCCOPY))
     {
+      DeleteObject (newbmp);
+      DeleteDC (hdcDst);
       return 0;
     }
 
@@ -553,6 +555,8 @@ mswindows_create_resized_mask (struct Lisp_Image_Instance* ii,
                      IMAGE_INSTANCE_PIXMAP_HEIGHT (ii), 
                      SRCCOPY))
        {
+         DeleteObject (newmask);
+         DeleteDC (hdcDst);
          return NULL;
        }
       
index 5b35f11..70b15e0 100644 (file)
@@ -39,6 +39,7 @@ Boston, MA 02111-1307, USA.  */
    Many changes for color work and optimizations by Jareth Hein for 21.0
    Switch of GIF/JPEG/PNG to new EImage intermediate code by Jareth Hein for 21.0
    TIFF code by Jareth Hein for 21.0
+   GIF/JPEG/PNG/TIFF code moved to new glyph-eimage.c for 21.0
 
    TODO:
    Convert images.el to C and stick it in here?
index 0b917a7..ac6f2dc 100644 (file)
@@ -324,8 +324,11 @@ menu_name_to_accelerator (char *name)
       ++name;
       if (!(*name))
        return Qnil;
-      if (*name=='_'&&*(name+1))
-       return make_char (tolower(*(name+1)));
+      if (*name=='_' && *(name+1))
+       {
+         int accelerator = (int) (unsigned char) (*(name+1));
+         return make_char (tolower (accelerator));
+       }
     }
     ++name;
   }
index 0de1d3f..944fed3 100644 (file)
@@ -156,7 +156,7 @@ void font_lock_buffer_was_killed (struct buffer *buf);
 void barf_if_buffer_read_only (struct buffer *buf, Bufpos from,
                               Bufpos to);
 
-void init_buffer_text (struct buffer *b, int indirect_p);
-void uninit_buffer_text (struct buffer *b, int indirect_p);
+void init_buffer_text (struct buffer *b);
+void uninit_buffer_text (struct buffer *b);
 
 #endif /* _XEMACS_INSDEL_H_ */
index efab47d..e2a5152 100644 (file)
@@ -4325,10 +4325,12 @@ Keymap of key translations that can override keymaps.
 This keymap works like `function-key-map', but comes after that,
 and applies even for keys that have ordinary bindings.
 */ );
+  Vkey_translation_map = Qnil;
 
   DEFVAR_LISP ("vertical-divider-map", &Vvertical_divider_map /*
 Keymap which handles mouse clicks over vertical dividers.
 */ );
+  Vvertical_divider_map = Qnil;
 
   DEFVAR_INT ("keymap-tick", &keymap_tick /*
 Incremented for each change to any keymap.
index a0ad5e1..05b42ff 100644 (file)
@@ -74,8 +74,8 @@ Boston, MA 02111-1307, USA.  */
 #define LINE_NUMBER_LARGE_STRING 256
 
 /* To be used only when you *know* the cache has been allocated!  */
-#define LINE_NUMBER_RING(b) (XCAR ((b)->line_number_cache))
-#define LINE_NUMBER_BEGV(b) (XCDR ((b)->line_number_cache))
+#define LINE_NUMBER_RING(b) (XCAR ((b)->text->line_number_cache))
+#define LINE_NUMBER_BEGV(b) (XCDR ((b)->text->line_number_cache))
 
 
 /* Initialize the cache.  Cache is (in pseudo-BNF):
@@ -89,12 +89,12 @@ Boston, MA 02111-1307, USA.  */
 
    Line number cache should never, ever, be visible to Lisp (because
    destructively modifying its elements can cause crashes.)  Debug it
-   using debug_print (current_buffer->last_number_cache).  */
+   using debug_print (current_buffer->text->last_number_cache).  */
 static void
 allocate_line_number_cache (struct buffer *b)
 {
-  b->line_number_cache = Fcons (make_vector (LINE_NUMBER_RING_SIZE, Qnil),
-                               Qzero);
+  b->text->line_number_cache = Fcons (make_vector (LINE_NUMBER_RING_SIZE, Qnil),
+                                     Qzero);
   narrow_line_number_cache (b);
 }
 
@@ -103,7 +103,7 @@ allocate_line_number_cache (struct buffer *b)
 void
 narrow_line_number_cache (struct buffer *b)
 {
-  if (NILP (b->line_number_cache))
+  if (NILP (b->text->line_number_cache))
     return;
 
   if (BUF_BEG (b) == BUF_BEGV (b))
@@ -161,7 +161,7 @@ void
 insert_invalidate_line_number_cache (struct buffer *b, Bufpos pos,
                                     CONST Bufbyte *nonreloc, Bytecount length)
 {
-  if (NILP (b->line_number_cache))
+  if (NILP (b->text->line_number_cache))
     return;
 
   if (length > LINE_NUMBER_LARGE_STRING
@@ -182,7 +182,7 @@ insert_invalidate_line_number_cache (struct buffer *b, Bufpos pos,
 void
 delete_invalidate_line_number_cache (struct buffer *b, Bufpos from, Bufpos to)
 {
-  if (NILP (b->line_number_cache))
+  if (NILP (b->text->line_number_cache))
     return;
 
   if ((to - from) > LINE_NUMBER_LARGE_STRING)
@@ -280,7 +280,7 @@ buffer_line_number (struct buffer *b, Bufpos pos, int cachep)
 
   if (cachep)
     {
-      if (NILP (b->line_number_cache))
+      if (NILP (b->text->line_number_cache))
        allocate_line_number_cache (b);
       /* If we don't know the line number of BUF_BEGV, calculate it now.  */
       if (XINT (LINE_NUMBER_BEGV (b)) == -1)
index d4c6260..a163241 100644 (file)
@@ -105,7 +105,7 @@ An argument of zero means repeat until error.
   int repeat;
 
   if (NILP (con->defining_kbd_macro))
-    error ("Not defining kbd macro.");
+    error ("Not defining kbd macro");
 
   if (NILP (arg))
     repeat = -1;
@@ -275,7 +275,7 @@ COUNT is a repeat count, or nil for once, or 0 for infinite loop.
 
   final = indirect_function (macro, 1);
   if (!STRINGP (final) && !VECTORP (final))
-    error ("Keyboard macros must be strings or vectors.");
+    error ("Keyboard macros must be strings or vectors");
 
   tem = Fcons (Vexecuting_macro, make_int (executing_macro_index));
   record_unwind_protect (pop_kbd_macro, tem);
index 507e314..88ef60b 100644 (file)
@@ -523,7 +523,10 @@ init_buffer_markers (struct buffer *b)
   b->mark = Fmake_marker ();
   BUF_MARKERS (b) = 0;
   b->point_marker = Fmake_marker ();
-  Fset_marker (b->point_marker, make_int (1), buf);
+  Fset_marker (b->point_marker,
+              /* For indirect buffers, point is already set.  */
+              b->base_buffer ? make_int (BUF_PT (b)) : make_int (1),
+              buf);
 }
 
 void
index bc47b7f..2075f92 100644 (file)
@@ -123,7 +123,7 @@ static HMENU top_level_menu;
  * "Left Flush\tRight Flush"
  */
 static char*
-displayable_menu_item (struct gui_item* pgui_item)
+displayable_menu_item (struct gui_item* pgui_item, int bar_p)
 {
   /* We construct the name in a static buffer. That's fine, beause
      menu items longer than 128 chars are probably programming errors,
@@ -135,12 +135,15 @@ displayable_menu_item (struct gui_item* pgui_item)
   /* Left flush part of the string */
   ll = gui_item_display_flush_left (pgui_item, buf, MAX_MENUITEM_LENGTH);
 
-  /* Right flush part */
-  assert (MAX_MENUITEM_LENGTH > ll + 1);
-  lr = gui_item_display_flush_right (pgui_item, buf + ll + 1,
-                                    MAX_MENUITEM_LENGTH - ll - 1);
-  if (lr)
-    buf [ll] = '\t';
+  /* Right flush part, unless we're at the top-level where it's not allowed */
+  if (!bar_p)
+    {
+      assert (MAX_MENUITEM_LENGTH > ll + 1);
+      lr = gui_item_display_flush_right (pgui_item, buf + ll + 1,
+                                        MAX_MENUITEM_LENGTH - ll - 1);
+      if (lr)
+       buf [ll] = '\t';
+     }
 
   return buf;
 }
@@ -223,7 +226,8 @@ checksum_menu_item (Lisp_Object item)
 
 static void
 populate_menu_add_item (HMENU menu, Lisp_Object path,
-                       Lisp_Object hash_tab, Lisp_Object item, int flush_right)
+                       Lisp_Object hash_tab, Lisp_Object item,
+                       int flush_right, int bar_p)
 {
   MENUITEMINFO item_info;
 
@@ -271,7 +275,7 @@ populate_menu_add_item (HMENU menu, Lisp_Object path,
       submenu = create_empty_popup_menu();
 
       item_info.fMask |= MIIM_SUBMENU;
-      item_info.dwTypeData = displayable_menu_item (&gui_item);
+      item_info.dwTypeData = displayable_menu_item (&gui_item, bar_p);
       item_info.hSubMenu = submenu;
 
       if (!(item_info.fState & MFS_GRAYED))
@@ -332,13 +336,13 @@ populate_menu_add_item (HMENU menu, Lisp_Object path,
 
       item_info.wID = (UINT) XINT(id);
       item_info.fType |= MFT_STRING;
-      item_info.dwTypeData = displayable_menu_item (&gui_item);
+      item_info.dwTypeData = displayable_menu_item (&gui_item, bar_p);
 
       UNGCPRO; /* gui_item */
     }
   else
     {
-      signal_simple_error ("Mailformed menu item descriptor", item);
+      signal_simple_error ("Malformed menu item descriptor", item);
     }
 
   if (flush_right)
@@ -408,7 +412,7 @@ populate_or_checksum_helper (HMENU menu, Lisp_Object path, Lisp_Object desc,
        }
       else if (populate_p)
        populate_menu_add_item (menu, path, hash_tab,
-                               XCAR (item_desc), flush_right);
+                               XCAR (item_desc), flush_right, bar_p);
       else
        checksum = HASH2 (checksum,
                          checksum_menu_item (XCAR (item_desc)));
index fac1c60..a225eb5 100644 (file)
@@ -333,6 +333,33 @@ restore_in_menu_callback (Lisp_Object val)
 }
 #endif /* LWLIB_MENUBARS_LUCID || LWLIB_MENUBARS_MOTIF */
 
+#if 0
+/* #### Sort of a hack needed to process Vactivate_menubar_hook
+   correctly wrt buffer-local values.  A correct solution would
+   involve adding a callback mechanism to run_hook().  This function
+   is currently unused.  */
+static int
+my_run_hook (Lisp_Object hooksym, int allow_global_p)
+{
+  /* This function can GC */
+  Lisp_Object tail;
+  Lisp_Object value = Fsymbol_value (hooksym);
+  int changes = 0;
+
+  if (!NILP (value) && (!CONSP (value) || EQ (XCAR (value), Qlambda)))
+    return !EQ (call0 (value), Qt);
+
+  EXTERNAL_LIST_LOOP (tail, value)
+    {
+      if (allow_global_p && EQ (XCAR (tail), Qt))
+       changes |= my_run_hook (Fdefault_value (hooksym), 0);
+      if (!EQ (call0 (XCAR (tail)), Qt))
+       changes = 1;
+    }
+  return changes;
+}
+#endif
+
 
 /* The order in which callbacks are run is funny to say the least.
    It's sometimes tricky to avoid running a callback twice, and to
@@ -358,12 +385,9 @@ static void
 pre_activate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
 {
   /* This function can GC */
-  struct gcpro gcpro1;
   struct device *d = get_device_from_display (XtDisplay (widget));
   struct frame *f = x_any_window_to_frame (d, XtWindow (widget));
-  Lisp_Object rest = Qnil;
   Lisp_Object frame;
-  int any_changes = 0;
   int count;
 
   /* set in lwlib to the time stamp associated with the most recent menu
@@ -418,24 +442,17 @@ pre_activate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
       replace_widget_value_tree (hack_wv, wv->contents);
       free_popup_widget_value_tree (wv);
     }
+  else if (!POPUP_DATAP (FRAME_MENUBAR_DATA (f)))
+    return;
   else
     {
-      if (!POPUP_DATAP (FRAME_MENUBAR_DATA (f)))
-       return;
+#if 0 /* Unused, see comment below. */
+      int any_changes;
+
       /* #### - this menubar update mechanism is expensively anti-social and
         the activate-menubar-hook is now mostly obsolete. */
-      /* make the activate-menubar-hook be a list of functions, not a single
-        function, just to simplify things. */
-      if (!NILP (Vactivate_menubar_hook) &&
-         (!CONSP (Vactivate_menubar_hook) ||
-          EQ (XCAR (Vactivate_menubar_hook), Qlambda)))
-       Vactivate_menubar_hook = Fcons (Vactivate_menubar_hook, Qnil);
-
-      GCPRO1 (rest);
-      for (rest = Vactivate_menubar_hook; !NILP (rest); rest = Fcdr (rest))
-       if (!EQ (call0 (XCAR (rest)), Qt))
-         any_changes = 1;
-#if 0
+      any_changes = my_run_hook (Qactivate_menubar_hook, 1);
+
       /* #### - It is necessary to *ALWAYS* call set_frame_menubar() now that
         incremental menus are implemented.  If a subtree of a menu has been
         updated incrementally (a destructive operation), then that subtree
@@ -446,12 +463,14 @@ pre_activate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
         that an INCREMENTAL_TYPE widget_value can be recreated...  Hmmmmm. */
       if (any_changes ||
          !XFRAME_MENUBAR_DATA (f)->menubar_contents_up_to_date)
-#endif
        set_frame_menubar (f, 1, 0);
+#else
+      run_hook (Qactivate_menubar_hook);
+      set_frame_menubar (f, 1, 0);
+#endif
       DEVICE_X_MOUSE_TIMESTAMP (XDEVICE (FRAME_DEVICE (f))) =
        DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (XDEVICE (FRAME_DEVICE (f))) =
        x_focus_timestamp_really_sucks_fix_me_better;
-      UNGCPRO;
     }
 }
 
index f144b04..bbfefee 100644 (file)
@@ -132,6 +132,8 @@ new_child (void)
   xzero (*cp);
   cp->fd = -1;
   cp->pid = -1;
+  if (cp->procinfo.hProcess)
+    CloseHandle(cp->procinfo.hProcess);
   cp->procinfo.hProcess = NULL;
   cp->status = STATUS_READ_ERROR;
 
@@ -234,10 +236,19 @@ reader_thread (void *arg)
   /* Our identity */
   cp = (child_process *)arg;
   
-  /* We have to wait for the go-ahead before we can start */
+  /* <matts@tibco.com> - I think the test below is wrong - we don't
+     want to wait for someone to signal char_consumed, as we haven't
+     read anything for them to consume yet! */
+
+  /*
   if (cp == NULL ||
       WaitForSingleObject (cp->char_consumed, INFINITE) != WAIT_OBJECT_0)
-    return 1;
+  */
+
+  if (cp == NULL)
+  {
+      return 1;
+  }
 
   for (;;)
     {
@@ -255,7 +266,28 @@ reader_thread (void *arg)
        }
 
       if (rc == STATUS_READ_ERROR)
-       return 1;
+      {
+        /* We are finished, so clean up handles and set to NULL so
+           that CHILD_ACTIVE will see what is going on */
+        if (cp->char_avail) {
+          CloseHandle (cp->char_avail);
+          cp->char_avail = NULL;
+        }
+        if (cp->thrd) {
+          CloseHandle (cp->thrd);
+          cp->thrd = NULL;
+        }
+        if (cp->char_consumed) {
+          CloseHandle(cp->char_consumed);
+          cp->char_consumed = NULL;
+        }
+        if (cp->procinfo.hProcess)
+        {
+          CloseHandle (cp->procinfo.hProcess);
+          cp->procinfo.hProcess=NULL;
+        }
+        return 1;
+      }
         
       /* If the read died, the child has died so let the thread die */
       if (rc == STATUS_READ_FAILED)
@@ -269,6 +301,26 @@ reader_thread (void *arg)
          break;
         }
     }
+  /* We are finished, so clean up handles and set to NULL so that
+     CHILD_ACTIVE will see what is going on */
+  if (cp->char_avail) {
+    CloseHandle (cp->char_avail);
+    cp->char_avail = NULL;
+  }
+  if (cp->thrd) {
+    CloseHandle (cp->thrd);
+    cp->thrd = NULL;
+  }
+  if (cp->char_consumed) {
+    CloseHandle(cp->char_consumed);
+    cp->char_consumed = NULL;
+  }
+  if (cp->procinfo.hProcess)
+  {
+    CloseHandle (cp->procinfo.hProcess);
+    cp->procinfo.hProcess=NULL;
+  }
+  
   return 0;
 }
 
@@ -325,6 +377,11 @@ create_child (char *exe, char *cmdline, char *env,
 
   cp->pid = (int) cp->procinfo.dwProcessId;
 
+  CloseHandle (cp->procinfo.hThread);
+  CloseHandle (cp->procinfo.hProcess);
+  cp->procinfo.hThread=NULL;
+  cp->procinfo.hProcess=NULL;
+
   /* Hack for Windows 95, which assigns large (ie negative) pids */
   if (cp->pid < 0)
     cp->pid = -cp->pid;
index 4435a25..dfe155d 100644 (file)
@@ -39,6 +39,9 @@ Boston, MA 02111-1307, USA.  */
 #include <winsock.h>
 #endif
 
+/* Arbitrary size limit for code fragments passed to run_in_other_process */
+#define FRAGMENT_CODE_SIZE 32
+
 /* Bound by winnt.el */
 Lisp_Object Qnt_quote_process_args;
 
@@ -143,8 +146,8 @@ free_process_memory (process_memory* pmc)
 
 /*
  * Run ROUTINE in the context of process determined by H_PROCESS. The
- * routine is passed the address of DATA as parameter. CODE_END is the 
- * address immediately after ROUTINE's code. DATA_SIZE is the size of
+ * routine is passed the address of DATA as parameter. The ROUTINE must
+ * not be longer than ROUTINE_CODE_SIZE bytes. DATA_SIZE is the size of
  * DATA structure.
  *
  * Note that the code must be positionally independent, and compiled
@@ -157,11 +160,11 @@ free_process_memory (process_memory* pmc)
  */
 static DWORD
 run_in_other_process (HANDLE h_process,
-                     LPTHREAD_START_ROUTINE routine, LPVOID code_end,
+                     LPTHREAD_START_ROUTINE routine,
                      LPVOID data, size_t data_size)
 {
   process_memory pm;
-  size_t code_size = (LPBYTE)code_end - (LPBYTE)routine;
+  CONST size_t code_size = FRAGMENT_CODE_SIZE;
   /* Need at most 3 extra bytes of memory, for data alignment */
   size_t total_size = code_size + data_size + 3;
   LPVOID remote_data;
@@ -223,6 +226,11 @@ run_in_other_process (HANDLE h_process,
  * SIGKILL, SIGTERM, SIGQUIT, SIGHUP - These four translate to ExitProcess
  *    executed by the remote process
  * SIGINT - The remote process is sent CTRL_BREAK_EVENT
+ *
+ * The MSVC5.0 compiler feels free to re-order functions within a
+ * compilation unit, so we have no way of finding out the size of the
+ * following functions. Therefore these functions must not be larger than
+ * FRAGMENT_CODE_SIZE.
  */
 
 /*
@@ -240,12 +248,6 @@ sigkill_proc (sigkill_data* data)
   return 1;
 }
 
-/* Watermark in code space */
-static void
-sigkill_code_end (void)
-{
-}
-
 /*
  * Sending break or control c
  */
@@ -261,12 +263,6 @@ sigint_proc (sigint_data* data)
   return (*data->adr_GenerateConsoleCtrlEvent) (data->event, 0);
 }
 
-/* Watermark in code space */
-static void
-sigint_code_end (void)
-{
-}
-
 /*
  * Enabling signals
  */
@@ -282,12 +278,6 @@ sig_enable_proc (sig_enable_data* data)
   return 1;
 }
 
-/* Watermark in code space */
-static void
-sig_enable_code_end (void)
-{
-}
-
 /*
  * Send signal SIGNO to process H_PROCESS.
  * Return nonzero if successful.
@@ -316,8 +306,7 @@ send_signal (HANDLE h_process, int signo)
        sigkill_data d;
        d.adr_ExitProcess = GetProcAddress (h_kernel, "ExitProcess");
        assert (d.adr_ExitProcess);
-       retval = run_in_other_process (h_process,
-                                      sigkill_proc, sigkill_code_end,
+       retval = run_in_other_process (h_process, sigkill_proc,
                                       &d, sizeof (d));
        break;
       }
@@ -328,8 +317,7 @@ send_signal (HANDLE h_process, int signo)
          GetProcAddress (h_kernel, "GenerateConsoleCtrlEvent");
        assert (d.adr_GenerateConsoleCtrlEvent);
        d.event = CTRL_C_EVENT;
-       retval = run_in_other_process (h_process,
-                                      sigint_proc, sigint_code_end,
+       retval = run_in_other_process (h_process, sigint_proc,
                                       &d, sizeof (d));
        break;
       }
@@ -353,8 +341,7 @@ enable_child_signals (HANDLE h_process)
   d.adr_SetConsoleCtrlHandler =
     GetProcAddress (h_kernel, "SetConsoleCtrlHandler");
   assert (d.adr_SetConsoleCtrlHandler);
-  run_in_other_process (h_process,
-                       sig_enable_proc, sig_enable_code_end,
+  run_in_other_process (h_process, sig_enable_proc,
                        &d, sizeof (d));
 }
   
index a0b6b74..85ad49b 100644 (file)
@@ -920,12 +920,14 @@ unix_create_process (struct Lisp_Process *p,
              EMACS_SET_TTY_PROCESS_GROUP (xforkin, &piddly);
            }
 
-# ifdef AIX
            /* On AIX, we've disabled SIGHUP above once we start a
               child on a pty.  Now reenable it in the child, so it
-              will die when we want it to.  */
+              will die when we want it to.
+              JV: This needs to be done ALWAYS as we might have inherited
+              a SIG_IGN handling from our parent (nohup) and we are in new
+              process group.          
+           */
            signal (SIGHUP, SIG_DFL);
-# endif /* AIX */
          }
 #endif /* HAVE_PTYS */
 
index f895d88..4c97bfc 100644 (file)
@@ -1108,7 +1108,9 @@ r_alloc_thaw ()
 \f
 /* The hook `malloc' uses for the function which gets more space
    from the system.  */
-/* extern POINTER (*__morecore) (long size); */
+#ifndef DOUG_LEA_MALLOC
+extern POINTER (*__morecore) (long size);
+#endif
 
 /* Initialize various things for memory allocation. */
 
index e45a70f..b277934 100644 (file)
@@ -71,15 +71,21 @@ Boston, MA 02111-1307, USA.  */
 /* cheesy way to determine cygwin version */
 #ifndef NOT_C_CODE
 #include <signal.h>
+#ifdef HAVE_CYGWIN32_VERSION_H
+#include <cygwin32/version.h>
+#else
 #ifdef SIGIO
 #define CYGWIN_B19
 #else
 #define BROKEN_CYGWIN
 #endif
+#endif
+
 extern void cygwin32_win32_to_posix_path_list(const char*, char*);
 extern int cygwin32_win32_to_posix_path_list_buf_size(const char*);
 extern void cygwin32_posix_to_win32_path_list(const char*, char*);
 extern int cygwin32_posix_to_win32_path_list_buf_size(const char*);
+#ifndef CYGWIN_DLL_VERSION_MAJOR
 struct timeval;
 struct timezone;
 struct itimerval;
@@ -102,6 +108,14 @@ extern int utimes(char *file, struct timeval *tvp);
 
 extern int srandom( unsigned seed);
 extern long random();
+
+#define SND_ASYNC              1
+#define SND_NODEFAULT          2
+#define SND_MEMORY             4
+#define SND_FILENAME           0x2000L
+#define VK_APPS                        0x5D
+#define SIF_TRACKPOS   0x0010
+#endif
 #endif
 
 #ifdef HAVE_MS_WINDOWS
@@ -117,12 +131,10 @@ extern long random();
 #define LIBS_SYSTEM -lwinmm
 
 #define ICC_BAR_CLASSES 4
-#define SIF_TRACKPOS   0x0010
 #define FW_BLACK       FW_HEAVY
 #define FW_ULTRABOLD   FW_EXTRABOLD
 #define FW_DEMIBOLD    FW_SEMIBOLD
 #define FW_ULTRALIGHT  FW_EXTRALIGHT
-#define VK_APPS                        0x5D
 #define APPCMD_FILTERINITS     0x20L
 #define CBF_FAIL_SELFCONNECTIONS 0x1000
 #define CBF_SKIP_ALLNOTIFICATIONS      0x3C0000
@@ -130,10 +142,6 @@ extern long random();
 #define CBF_FAIL_POKES         0x10000
 #define CBF_FAIL_REQUESTS      0x20000
 #define SZDDESYS_TOPIC         "System"
-#define SND_ASYNC              1
-#define SND_NODEFAULT          2
-#define SND_MEMORY             4
-#define SND_FILENAME           0x2000L
 #define JOHAB_CHARSET          130
 #define MAC_CHARSET            77
 
index eae989c..5f9f4ff 100644 (file)
 #define regoff_t sys_regoff_t
 #define regmatch_t sys_regmatch_t
 
+/* A perfectly ordinary link wins again - martin */
 #undef C_SWITCH_SYSTEM
-#define C_SWITCH_SYSTEM "-D_BSD"
+#undef LIBS_SYSTEM
+#undef LIBS_DEBUG
+#define ORDINARY_LINK
 
 #define SYSTEM_MALLOC
 
+#if 0 /* martin */
 /* Some V4.0* versions before V4.0B don't detect rename properly. */
 #ifndef HAVE_RENAME
 #define HAVE_RENAME
 #endif
 
 #define LIBS_DEBUG
+#endif /* 0 */
index 8d0229f..32eec34 100644 (file)
 
 #define LIBS_TERMCAP "-ltermcap"
 
+#ifdef __ELF__ /* since from 3.0-CURRENT(maybe 19980831 or later) */
+#ifndef NOT_C_CODE
+#include <stddef.h>
+#endif
+#define LD_SWITCH_SYSTEM
+#define START_FILES pre-crt0.o /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtbegin.o
+#define UNEXEC unexelf.o
+#define LIB_STANDARD -lgcc -lc -lgcc /usr/lib/crtend.o /usr/lib/crtn.o
+#define LINKER "$(CC) -nostdlib"
+#undef LIB_GCC
+#define LIB_GCC
+
+#else /* not __ELF__ */
+
 #ifndef NO_SHARED_LIBS
 #if 0 /* mrb */
 #define LIB_GCC "-lgcc"
@@ -79,6 +93,8 @@
 #endif /* __FreeBSD__ */
 #endif /* NO_SHARED_LIBS */
 
+#endif /* not __ELF__ */
+
 #define HAVE_GETLOADAVG
 /* #define NO_TERMIO */ /* detected in configure */
 #define DECLARE_GETPWUID_WITH_UID_T
index 6c12abf..dd9a443 100644 (file)
@@ -75,7 +75,9 @@ undo_prelude (struct buffer *b, int hack_pending_boundary)
   if (EQ (b->undo_list, Qt))
     return (0);
 
-  if (NILP (last_undo_buffer) || b != XBUFFER (last_undo_buffer))
+  if (NILP (last_undo_buffer)
+      || (BUFFER_BASE_BUFFER (b)
+         != BUFFER_BASE_BUFFER (XBUFFER (last_undo_buffer))))
     {
       undo_boundary (b);
       XSETBUFFER (last_undo_buffer, b);
index 9200f16..3a1a12f 100644 (file)
@@ -92,9 +92,11 @@ struct headers {
 #define DEFAULT_ENTRY_ADDRESS __start
 #endif
 \f
-unexec (new_name, a_name, data_start, bss_start, entry_address)
-     char *new_name, *a_name;
-     unsigned long data_start, bss_start, entry_address;
+int
+unexec (char *new_name, char *a_name,
+       unsigned long data_start,
+       unsigned long bss_start,
+       unsigned long entry_address)
 {
   int new, old;
   char * oldptr;
@@ -102,7 +104,6 @@ unexec (new_name, a_name, data_start, bss_start, entry_address)
   struct stat stat;
   long pagesize, brk;
   long newsyms, symrel;
-  int nread;
   int i;
   long vaddr, scnptr;
 #define BUFSIZE 8192
@@ -365,15 +366,15 @@ unexec (new_name, a_name, data_start, bss_start, entry_address)
 
 */
 
-
-update_dynamic_symbols (old, new_name, new, newsyms, nsyms, symoff, stroff)
-     char *old;                        /* Pointer to old executable */
-     char *new_name;            /* Name of new executable */
-     int new;                  /* File descriptor for new executable */
-     long newsyms;             /* Offset of Symbol table in new executable */
-     int nsyms;                        /* Number of symbol table entries */
-     long symoff;              /* Offset of External Symbols in old file */
-     long stroff;              /* Offset of string table in old file */
+int
+update_dynamic_symbols (
+     char *old,                        /* Pointer to old executable */
+     char *new_name,            /* Name of new executable */
+     int new,                  /* File descriptor for new executable */
+     long newsyms,             /* Offset of Symbol table in new executable */
+     int nsyms,                        /* Number of symbol table entries */
+     long symoff,              /* Offset of External Symbols in old file */
+     long stroff)              /* Offset of string table in old file */
 {
   long i;
   int found = 0;
index 4252ef1..785915e 100644 (file)
@@ -866,7 +866,9 @@ unexec (char *new_name, char *old_name, unsigned int data_start,
 
       for (; symp < symendp; symp ++)
        if (strcmp ((char *) (symnames + symp->st_name), "_end") == 0
-           || strcmp ((char *) (symnames + symp->st_name), "_edata") == 0)
+           || strcmp ((char *) (symnames + symp->st_name), "end") == 0
+           || strcmp ((char *) (symnames + symp->st_name), "_edata") == 0
+           || strcmp ((char *) (symnames + symp->st_name), "edata") == 0)
          memcpy (&symp->st_value, &new_bss_addr, sizeof (new_bss_addr));
     }
 
index 7d4f863..63a9aca 100644 (file)
@@ -1633,7 +1633,9 @@ from overriding motion of point in order to display at this exact start.
   CHECK_INT_COERCE_MARKER (pos);
   set_marker_restricted (w->start[CURRENT_DISP], pos, w->buffer);
   /* this is not right, but much easier than doing what is right. */
-  w->start_at_line_beg = 0;
+  /* w->start_at_line_beg = 0; */
+  /* WTF is the above supposed to mean?  GE */
+  w->start_at_line_beg = beginning_of_line_p (XBUFFER (w->buffer), XINT (pos));
   if (NILP (noforce))
     w->force_start = 1;
   w->redo_modeline = 1;
@@ -3163,7 +3165,9 @@ BUFFER can be a buffer or buffer name.
                         make_int (XBUFFER (buffer)->last_window_start),
                         buffer);
   Fset_marker (w->sb_point, w->start[CURRENT_DISP], buffer);
-  w->start_at_line_beg = 0;
+  /* set start_at_line_beg correctly. GE */
+  w->start_at_line_beg = beginning_of_line_p (XBUFFER (buffer),
+                                             XBUFFER (buffer)->last_window_start);  
   w->force_start = 0;           /* Lucid fix */
   SET_LAST_MODIFIED (w, 1);
   SET_LAST_FACECHANGE (w);