included commits to RCS files with non-trunk default branches.
}
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
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
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_ */
#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;
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)
{
{
WNDCLASSEX wc;
HDC hdc;
- LOGFONT logfont;
- struct font_enum_t font_enum;
DEVICE_CLASS (d) = Qcolor;
DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
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 */
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;
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)))
{
{
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, /*
*/ );
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
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);
}
#include "opaque.h"
#include "sysfile.h"
#include "sysdir.h"
+#include "systime.h"
+#include "syspwd.h"
Lisp_Object Vcompletion_ignored_extensions;
Lisp_Object Qdirectory_files;
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;
}
}
\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)
{
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);
}
`file-name-all-completions'.
*/ );
Vcompletion_ignored_extensions = Qnil;
+
+ user_cache = NULL;
+ user_cache_len = 0;
+ user_cache_max = 0;
}
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);
/* simple_p means don't try too hard (ASCII only) */
{
KeySym keysym = 0;
-
+
#ifdef HAVE_XIM
int len;
char buffer[64];
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 */
{
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:
{
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)
{
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;
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. */
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)
#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
{
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
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)
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 ();
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
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))
}
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)
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;
((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;
}
|| 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)
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 */
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: */
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: */
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);
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
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
Lisp_Object read_only;
Lisp_Object mouse_face;
Lisp_Object initial_redisplay_function;
+ Lisp_Object before_change_functions, after_change_functions;
int priority;
};
#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)
/* 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)
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);
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);
}
out[size + 1] = '\0';
}
}
-#ifdef WINDOWSNT
- CORRECT_DIR_SEPS (out);
-#endif
return out;
}
)
dst[slen - 1] = 0;
#endif /* APOLLO */
-#ifdef WINDOWSNT
- CORRECT_DIR_SEPS (dst);
-#endif /* WINDOWSNT */
return 1;
}
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)
-/* 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"
#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)
{
/* 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;
/* 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 */
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;
}
return Qnil;
}
-\f
/* Unlock the file visited in buffer BUFFER. */
+
void
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)
{
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 */
}
#else
XtDestroyWidget (w);
+ XFlush (XtDisplay(w)); /* make sure the windows are really gone! */
#endif /* EXTERNAL_WIDGET */
if (FRAME_X_GEOM_FREE_ME_PLEASE (f))
--- /dev/null
+#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;
+}
--- /dev/null
+/******************************************************************************
+* 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 */
IMAGE_INSTANCE_PIXMAP_HEIGHT (ii),
SRCCOPY))
{
+ DeleteObject (newbmp);
+ DeleteDC (hdcDst);
return 0;
}
IMAGE_INSTANCE_PIXMAP_HEIGHT (ii),
SRCCOPY))
{
+ DeleteObject (newmask);
+ DeleteDC (hdcDst);
return NULL;
}
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?
++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;
}
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_ */
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.
#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):
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);
}
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))
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
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)
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)
int repeat;
if (NILP (con->defining_kbd_macro))
- error ("Not defining kbd macro.");
+ error ("Not defining kbd macro");
if (NILP (arg))
repeat = -1;
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);
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
* "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,
/* 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;
}
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;
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))
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)
}
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)));
}
#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
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
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
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;
}
}
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;
/* 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 (;;)
{
}
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)
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;
}
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;
#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;
/*
* 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
*/
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;
* 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.
*/
/*
return 1;
}
-/* Watermark in code space */
-static void
-sigkill_code_end (void)
-{
-}
-
/*
* Sending break or control c
*/
return (*data->adr_GenerateConsoleCtrlEvent) (data->event, 0);
}
-/* Watermark in code space */
-static void
-sigint_code_end (void)
-{
-}
-
/*
* Enabling signals
*/
return 1;
}
-/* Watermark in code space */
-static void
-sig_enable_code_end (void)
-{
-}
-
/*
* Send signal SIGNO to process H_PROCESS.
* Return nonzero if successful.
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;
}
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;
}
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));
}
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 */
\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. */
/* 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;
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
#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
#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
#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 */
#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"
#endif /* __FreeBSD__ */
#endif /* NO_SHARED_LIBS */
+#endif /* not __ELF__ */
+
#define HAVE_GETLOADAVG
/* #define NO_TERMIO */ /* detected in configure */
#define DECLARE_GETPWUID_WITH_UID_T
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);
#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;
struct stat stat;
long pagesize, brk;
long newsyms, symrel;
- int nread;
int i;
long vaddr, scnptr;
#define BUFSIZE 8192
*/
-
-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;
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));
}
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;
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);