(Qforeground_color, Qbackground_color): Declare.
[bpt/emacs.git] / src / msdos.c
index 1ded2ce..fcbb412 100644 (file)
@@ -1,5 +1,5 @@
-/* MS-DOS specific C utilities.
-   Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
+/* MS-DOS specific C utilities.          -*- coding: raw-text -*-
+   Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -32,6 +32,19 @@ Boston, MA 02111-1307, USA.  */
 #include <sys/param.h>
 #include <sys/time.h>
 #include <dos.h>
+#include <errno.h>
+#include <string.h>     /* for bzero and string functions */
+#include <sys/stat.h>    /* for _fixpath */
+#include <unistd.h>     /* for chdir, dup, dup2, etc. */
+#if __DJGPP__ >= 2
+#include <fcntl.h>
+#include <io.h>                 /* for setmode */
+#include <dpmi.h>       /* for __dpmi_xxx stuff */
+#include <sys/farptr.h>         /* for _farsetsel, _farnspokeb */
+#include <libc/dosio.h>  /* for _USE_LFN */
+#include <conio.h>      /* for cputs */
+#endif
+
 #include "dosfns.h"
 #include "msdos.h"
 #include "systime.h"
@@ -40,6 +53,8 @@ Boston, MA 02111-1307, USA.  */
 #include "termopts.h"
 #include "frame.h"
 #include "window.h"
+#include "buffer.h"
+#include "commands.h"
 #include <go32.h>
 #include <pc.h>
 #include <ctype.h>
@@ -47,6 +62,38 @@ Boston, MA 02111-1307, USA.  */
 /* Damn that local process.h!  Instead we can define P_WAIT ourselves.  */
 #define P_WAIT 1
 
+#ifndef _USE_LFN
+#define _USE_LFN 0
+#endif
+
+#ifndef _dos_ds
+#define _dos_ds _go32_info_block.selector_for_linear_memory
+#endif
+
+#if __DJGPP__ > 1
+
+#include <signal.h>
+#include "syssignal.h"
+
+#ifndef SYSTEM_MALLOC
+
+#ifdef GNU_MALLOC
+
+/* If other `malloc' than ours is used, force our `sbrk' behave like
+   Unix programs expect (resize memory blocks to keep them contiguous).
+   If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
+   because that's what `gmalloc' expects to get.  */
+#include <crt0.h>
+
+#ifdef REL_ALLOC
+int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
+#else  /* not REL_ALLOC */
+int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
+#endif /* not REL_ALLOC */
+#endif /* GNU_MALLOC */
+
+#endif /* not SYSTEM_MALLOC */
+#endif /* __DJGPP__ > 1 */
 
 static unsigned long
 event_timestamp ()
@@ -110,6 +157,17 @@ mouse_off ()
     }
 }
 
+static void
+mouse_get_xy (int *x, int *y)
+{
+  union REGS regs;
+
+  regs.x.ax = 0x0003;
+  int86 (0x33, &regs, &regs);
+  *x = regs.x.cx / 8;
+  *y = regs.x.dx / 8;
+}
+
 void
 mouse_moveto (x, y)
      int x, y;
@@ -156,17 +214,6 @@ mouse_released (b, xp, yp)
   return (regs.x.bx != 0);
 }
 
-static void
-mouse_get_xy (int *x, int *y)
-{
-  union REGS regs;
-
-  regs.x.ax = 0x0003;
-  int86 (0x33, &regs, &regs);
-  *x = regs.x.cx / 8;
-  *y = regs.x.dx / 8;
-}
-
 void
 mouse_get_pos (f, insist, bar_window, part, x, y, time)
      FRAME_PTR *f;
@@ -176,17 +223,18 @@ mouse_get_pos (f, insist, bar_window, part, x, y, time)
      unsigned long *time;
 {
   int ix, iy;
-  union REGS regs;
+  Lisp_Object frame, tail;
+
+  /* Clear the mouse-moved flag for every frame on this display.  */
+  FOR_EACH_FRAME (tail, frame)
+    XFRAME (frame)->mouse_moved = 0;
 
-  regs.x.ax = 0x0003;
-  int86 (0x33, &regs, &regs);
   *f = selected_frame;
   *bar_window = Qnil;
   mouse_get_xy (&ix, &iy);
-  selected_frame->mouse_moved = 0;
-  *x = make_number (ix);
-  *y = make_number (iy);
   *time = event_timestamp ();
+  *x = make_number (mouse_last_x = ix);
+  *y = make_number (mouse_last_y = iy);
 }
 
 static void
@@ -260,10 +308,33 @@ struct x_output the_only_x_display;
 /* This is never dereferenced.  */
 Display *x_current_display;
 
+/* Support for DOS/V (allows Japanese characters to be displayed on
+   standard, non-Japanese, ATs).  Only supported for DJGPP v2 and later.  */
 
-#define SCREEN_SET_CURSOR()                                            \
-  if (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y)        \
-    ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X)
+/* Holds the address of the text-mode screen buffer.  */
+static unsigned long screen_old_address = 0;
+/* Segment and offset of the virtual screen.  If 0, DOS/V is NOT loaded.  */
+static unsigned short screen_virtual_segment = 0;
+static unsigned short screen_virtual_offset = 0;
+
+#if __DJGPP__ > 1
+/* Update the screen from a part of relocated DOS/V screen buffer which
+   begins at OFFSET and includes COUNT characters.  */
+static void
+dosv_refresh_virtual_screen (int offset, int count)
+{
+  __dpmi_regs regs;
+
+  if (offset < 0 || count < 0) /* paranoia; illegal values crash DOS/V */
+    return;
+
+  regs.h.ah = 0xff;    /* update relocated screen */
+  regs.x.es = screen_virtual_segment;
+  regs.x.di = screen_virtual_offset + offset;
+  regs.x.cx = count;
+  __dpmi_int (0x10, &regs);
+}
+#endif
 
 static
 dos_direct_output (y, x, buf, len)
@@ -272,12 +343,23 @@ dos_direct_output (y, x, buf, len)
      char *buf;
      int len;
 {
-  int t = (int) ScreenPrimary + 2 * (x + y * screen_size_X);
-  
+  int t0 = 2 * (x + y * screen_size_X);
+  int t = t0 + (int) ScreenPrimary;
+  int l0 = len;
+
+#if (__DJGPP__ < 2)
   while (--len >= 0) {
     dosmemput (buf++, 1, t);
     t += 2;
   }
+#else
+  /* This is faster.  */
+  for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
+    _farnspokeb (t, *buf);
+
+  if (screen_virtual_segment)
+    dosv_refresh_virtual_screen (t0, l0);
+#endif
 }
 #endif
 
@@ -331,10 +413,177 @@ ScreenVisualBell (void)
 
 #ifndef HAVE_X_WINDOWS
 
-/*
- * If we write a character in the position where the mouse is,
- * the mouse cursor may need to be refreshed.
- */
+static int blink_bit = -1;     /* the state of the blink bit at startup */
+
+/* Enable bright background colors.  */
+static void
+bright_bg (void)
+{
+  union REGS regs;
+
+  /* Remember the original state of the blink/bright-background bit.
+     It is stored at 0040:0065h in the BIOS data area.  */
+  if (blink_bit == -1)
+    blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
+
+  regs.h.bl = 0;
+  regs.x.ax = 0x1003;
+  int86 (0x10, &regs, &regs);
+}
+
+/* Disable bright background colors (and enable blinking) if we found
+   the video system in that state at startup.  */
+static void
+maybe_enable_blinking (void)
+{
+  if (blink_bit == 1)
+    {
+      union REGS regs;
+
+      regs.h.bl = 1;
+      regs.x.ax = 0x1003;
+      int86 (0x10, &regs, &regs);
+    }
+}
+
+/* Set the screen dimensions so that it can show no less than
+   ROWS x COLS frame.  */
+
+void
+dos_set_window_size (rows, cols)
+     int *rows, *cols;
+{
+  char video_name[30];
+  Lisp_Object video_mode;
+  int video_mode_value;
+  int have_vga = 0;
+  union REGS regs;
+  int current_rows = ScreenRows (), current_cols = ScreenCols ();
+
+  if (*rows == current_rows && *cols == current_cols)
+    return;
+
+  /* Do we have a VGA?  */
+  regs.x.ax = 0x1a00;
+  int86 (0x10, &regs, &regs);
+  if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
+    have_vga = 1;
+
+  mouse_off ();
+
+  /* If the user specified a special video mode for these dimensions,
+     use that mode.  */
+  sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
+  video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
+                                     Qnil))-> value;
+
+  if (INTEGERP (video_mode)
+      && (video_mode_value = XINT (video_mode)) > 0)
+    {
+      regs.x.ax = video_mode_value;
+      int86 (0x10, &regs, &regs);
+
+      if (have_mouse)
+       {
+         /* Must hardware-reset the mouse, or else it won't update
+            its notion of screen dimensions for some non-standard
+            video modes.  This is *painfully* slow...  */
+         regs.x.ax = 0;
+         int86 (0x33, &regs, &regs);
+       }
+    }
+
+  /* Find one of the dimensions supported by standard EGA/VGA
+     which gives us at least the required dimensions.  */
+
+#if __DJGPP__ > 1
+
+  else
+    {
+      static struct {
+       int rows;
+       int need_vga;
+      }        std_dimension[] = {
+         {25, 0},
+         {28, 1},
+         {35, 0},
+         {40, 1},
+         {43, 0},
+         {50, 1}
+      };
+      int i = 0;
+
+      while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
+       {
+        if (std_dimension[i].need_vga <= have_vga
+            && std_dimension[i].rows >= *rows)
+          {
+            if (std_dimension[i].rows != current_rows
+                || *cols != current_cols)
+              _set_screen_lines (std_dimension[i].rows);
+            break;
+          }
+        i++;
+       }
+    }
+
+#else /* not __DJGPP__ > 1 */
+
+  else if (*rows <= 25)
+    {
+      if (current_rows != 25 || current_cols != 80)
+       {
+         regs.x.ax = 3;
+         int86 (0x10, &regs, &regs);
+         regs.x.ax = 0x1101;
+         regs.h.bl = 0;
+         int86 (0x10, &regs, &regs);
+         regs.x.ax = 0x1200;
+         regs.h.bl = 32;
+         int86 (0x10, &regs, &regs);
+         regs.x.ax = 3;
+         int86 (0x10, &regs, &regs);
+       }
+    }
+  else if (*rows <= 50)
+    if (have_vga && (current_rows != 50 || current_cols != 80)
+       || *rows <= 43 && (current_rows != 43 || current_cols != 80))
+      {
+       regs.x.ax = 3;
+       int86 (0x10, &regs, &regs);
+       regs.x.ax = 0x1112;
+       regs.h.bl = 0;
+       int86 (0x10, &regs, &regs);
+       regs.x.ax = 0x1200;
+       regs.h.bl = 32;
+       int86 (0x10, &regs, &regs);
+       regs.x.ax = 0x0100;
+       regs.x.cx = 7;
+       int86 (0x10, &regs, &regs);
+      }
+#endif /* not __DJGPP__ > 1 */
+
+  if (have_mouse)
+    {
+      mouse_init ();
+      mouse_on ();
+    }
+
+  /* Tell the caller what dimensions have been REALLY set.  */
+  *rows = ScreenRows ();
+  *cols = ScreenCols ();
+
+  /* Enable bright background colors.  */
+  bright_bg ();
+
+  /* FIXME: I'm not sure the above will run at all on DOS/V.  But let's
+     be defensive anyway.  */
+  if (screen_virtual_segment)
+    dosv_refresh_virtual_screen (0, *cols * *rows);
+}
+
+/* If we write a character in the position where the mouse is,
+   the mouse cursor may need to be refreshed.  */
 
 static void
 mouse_off_maybe ()
@@ -381,7 +630,8 @@ IT_set_face (int face)
   else
     fp = intern_face (selected_frame, FRAME_COMPUTED_FACES (foo)[face]);
   if (termscript)
-    fprintf (termscript, "<FACE:%d:%d>", FACE_FOREGROUND (fp), FACE_BACKGROUND (fp));
+    fprintf (termscript, "<FACE %d: %d/%d>",
+            face, FACE_FOREGROUND (fp), FACE_BACKGROUND (fp));
   screen_face = face;
   ScreenAttrib = (FACE_BACKGROUND (fp) << 4) | FACE_FOREGROUND (fp);
 }
@@ -392,6 +642,7 @@ IT_write_glyphs (GLYPH *str, int len)
   int newface;
   int ch, l = len;
   unsigned char *buf, *bp;
+  int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
 
   if (len == 0) return;
   
@@ -412,8 +663,9 @@ IT_write_glyphs (GLYPH *str, int len)
     }
 
   mouse_off_maybe ();
-  dosmemput (buf, 2 * len, 
-            (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
+  dosmemput (buf, 2 * len, (int)ScreenPrimary + offset);
+  if (screen_virtual_segment)
+    dosv_refresh_virtual_screen (offset, len);
   new_pos_X += len;
 }
 
@@ -422,6 +674,7 @@ IT_clear_end_of_line (first_unused)
 {
   char *spaces, *sp;
   int i, j;
+  int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
 
   IT_set_face (0);
   if (termscript)
@@ -436,8 +689,9 @@ IT_clear_end_of_line (first_unused)
     }
 
   mouse_off_maybe ();
-  dosmemput (spaces, i, 
-            (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
+  dosmemput (spaces, i, (int)ScreenPrimary + offset);
+  if (screen_virtual_segment)
+    dosv_refresh_virtual_screen (offset, i / 2);
 }
 
 static
@@ -448,6 +702,8 @@ IT_clear_screen (void)
   IT_set_face (0);
   mouse_off ();
   ScreenClear ();
+  if (screen_virtual_segment)
+    dosv_refresh_virtual_screen (0, screen_size);
   new_pos_X = new_pos_Y = 0;
 }
 
@@ -473,6 +729,75 @@ IT_cursor_to (int y, int x)
   new_pos_Y = y;
 }
 
+static int cursor_cleared;
+
+static
+IT_display_cursor (int on)
+{
+  if (on && cursor_cleared)
+    {
+      ScreenSetCursor (current_pos_Y, current_pos_X);
+      cursor_cleared = 0;
+    }
+  else if (!on && !cursor_cleared)
+    {
+      ScreenSetCursor (-1, -1);
+      cursor_cleared = 1;
+    }
+}
+
+/* Emacs calls cursor-movement functions a lot when it updates the
+   display (probably a legacy of old terminals where you cannot
+   update a screen line without first moving the cursor there).
+   However, cursor movement is expensive on MSDOS (it calls a slow
+   BIOS function and requires 2 mode switches), while actual screen
+   updates access the video memory directly and don't depend on
+   cursor position.  To avoid slowing down the redisplay, we cheat:
+   all functions that move the cursor only set internal variables
+   which record the cursor position, whereas the cursor is only
+   moved to its final position whenever screen update is complete.
+
+   `IT_cmgoto' is called from the keyboard reading loop and when the
+   frame update is complete.  This means that we are ready for user
+   input, so we update the cursor position to show where the point is,
+   and also make the mouse pointer visible.
+
+   Special treatment is required when the cursor is in the echo area,
+   to put the cursor at the end of the text displayed there.  */
+
+static
+IT_cmgoto (f)
+     FRAME_PTR f;
+{
+  /* Only set the cursor to where it should be if the display is
+     already in sync with the window contents.  */
+  int update_cursor_pos = MODIFF == unchanged_modified;
+
+  /* If we are in the echo area, put the cursor at the end of text.  */
+  if (!update_cursor_pos
+      && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y)
+    {
+      new_pos_X = FRAME_DESIRED_GLYPHS (f)->used[new_pos_Y];
+      update_cursor_pos = 1;
+    }
+
+  if (update_cursor_pos
+      && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
+    {
+      ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
+      if (termscript)
+       fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
+    }
+
+  /* Maybe cursor is invisible, so make it visible.  */
+  IT_display_cursor (1);
+
+  /* Mouse pointer should be always visible if we are waiting for
+     keyboard input.  */
+  if (!mouse_visible)
+    mouse_on ();
+}
+
 static
 IT_reassert_line_highlight (new, vpos)
      int new, vpos;
@@ -503,42 +828,27 @@ IT_update_end ()
 {
 }
 
-/* This was more or less copied from xterm.c */
-static void
-IT_set_menu_bar_lines (window, n)
-  Lisp_Object window;
-  int n;
+/* set-window-configuration on window.c needs this.  */
+void
+x_set_menu_bar_lines (f, value, oldval)
+     struct frame *f;
+     Lisp_Object value, oldval;
 {
-  struct window *w = XWINDOW (window);
-
-  XSETFASTINT (w->last_modified, 0);
-  XSETFASTINT (w->top, XFASTINT (w->top) + n);
-  XSETFASTINT (w->height, XFASTINT (w->height) - n);
+  set_menu_bar_lines (f, value, oldval);
+}
 
-  /* Handle just the top child in a vertical split.  */
-  if (!NILP (w->vchild))
-    IT_set_menu_bar_lines (w->vchild, n);
+/* This was copied from xfns.c  */
 
-  /* Adjust all children in a horizontal split.  */
-  for (window = w->hchild; !NILP (window); window = w->next)
-    {
-      w = XWINDOW (window);
-      IT_set_menu_bar_lines (window, n);
-    }
-}
+Lisp_Object Qbackground_color;
+Lisp_Object Qforeground_color;
+extern Lisp_Object Qtitle;
 
-/*
- * IT_set_terminal_modes is called when emacs is started,
- * resumed, and whenever the screen is redrawn!
- */
+/* IT_set_terminal_modes is called when emacs is started,
+   resumed, and whenever the screen is redrawn!  */
 
 static
 IT_set_terminal_modes (void)
 {
-  char *colors;
-  FRAME_PTR f;
-  struct face *fp;
-
   if (termscript)
     fprintf (termscript, "\n<SET_TERM>");
   highlight = 0;
@@ -558,18 +868,46 @@ IT_set_terminal_modes (void)
   startup_screen_size_Y = screen_size_Y;
   startup_screen_attrib = ScreenAttrib;
 
+#if __DJGPP__ > 1
+  /* Is DOS/V (or any other RSIS software which relocates
+     the screen) installed?  */
+  {
+    unsigned short es_value;
+    __dpmi_regs regs;
+
+    regs.h.ah = 0xfe;  /* get relocated screen address */
+    if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
+      regs.x.es = (ScreenPrimary >> 4) & 0xffff;
+    else if (screen_old_address) /* already switched to Japanese mode once */
+      regs.x.es = (screen_old_address >> 4) & 0xffff;
+    else
+      regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
+    regs.x.di = 0;
+    es_value = regs.x.es;
+    __dpmi_int (0x10, &regs);
+
+    if (regs.x.es != es_value && regs.x.es != (ScreenPrimary >> 4) & 0xffff)
+      {
+       screen_old_address = ScreenPrimary;
+       screen_virtual_segment = regs.x.es;
+       screen_virtual_offset  = regs.x.di;
+       ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
+      }
+  }
+#endif /* __DJGPP__ > 1 */
+
   ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
   ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
 
   if (termscript)
     fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
-             screen_size_X, screen_size_Y);
+            screen_size_X, screen_size_Y);
+
+  bright_bg ();
 }
 
-/*
- * IT_reset_terminal_modes is called when emacs is
- * suspended or killed.
- */
+/* IT_reset_terminal_modes is called when emacs is
+   suspended or killed.  */
 
 static
 IT_reset_terminal_modes (void)
@@ -592,6 +930,10 @@ IT_reset_terminal_modes (void)
     return;
   
   mouse_off ();
+
+  /* Leave the video system in the same state as we found it,
+     as far as the blink/bright-background bit is concerned.  */
+  maybe_enable_blinking ();
  
   /* We have a situation here.
      We cannot just do ScreenUpdate(startup_screen_buffer) because
@@ -607,6 +949,8 @@ IT_reset_terminal_modes (void)
 
   ScreenAttrib = startup_screen_attrib;
   ScreenClear ();
+  if (screen_virtual_segment)
+    dosv_refresh_virtual_screen (0, screen_size);
 
   if (update_row_len > saved_row_len)
     update_row_len = saved_row_len;
@@ -620,6 +964,9 @@ IT_reset_terminal_modes (void)
   while (current_rows--)
     {
       dosmemput (saved_row, update_row_len, display_row_start);
+      if (screen_virtual_segment)
+       dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
+                                    update_row_len / 2);
       saved_row         += saved_row_len;
       display_row_start += to_next_row;
     }
@@ -640,68 +987,101 @@ IT_set_terminal_window (void)
 }
 
 void
-IT_set_frame_parameters (frame, alist)
-     FRAME_PTR frame;
+IT_set_frame_parameters (f, alist)
+     FRAME_PTR f;
      Lisp_Object alist;
 {
   Lisp_Object tail;
+  int length = XINT (Flength (alist));
+  int i;
+  Lisp_Object *parms
+    = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
+  Lisp_Object *values
+    = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
   int redraw;
   extern unsigned long load_color ();
-  FRAME_PTR f = (FRAME_PTR) &the_only_frame;
 
   redraw = 0;
+
+  /* Extract parm names and values into those vectors.  */
+  i = 0;
   for (tail = alist; CONSP (tail); tail = Fcdr (tail))
     {
-      Lisp_Object elt, prop, val;
+      Lisp_Object elt;
 
       elt = Fcar (tail);
-      prop = Fcar (elt);
-      val = Fcdr (elt);
-      CHECK_SYMBOL (prop, 1);
+      parms[i] = Fcar (elt);
+      CHECK_SYMBOL (parms[i], 1);
+      values[i] = Fcdr (elt);
+      i++;
+    }
+
+
+  /* Now process them in reverse of specified order.  */
+  for (i--; i >= 0; i--)
+    {
+      Lisp_Object prop = parms[i];
+      Lisp_Object val  = values[i];
 
-      if (EQ (prop, intern ("foreground-color")))
+      if (EQ (prop, Qforeground_color))
        {
          unsigned long new_color = load_color (f, val);
          if (new_color != ~0)
            {
              FRAME_FOREGROUND_PIXEL (f) = new_color;
              redraw = 1;
+             if (termscript)
+               fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
            }
        }
-      else if (EQ (prop, intern ("background-color")))
+      else if (EQ (prop, Qbackground_color))
        {
          unsigned long new_color = load_color (f, val);
          if (new_color != ~0)
            {
-             FRAME_BACKGROUND_PIXEL (f) = new_color & ~8;
+             FRAME_BACKGROUND_PIXEL (f) = new_color;
              redraw = 1;
+             if (termscript)
+               fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
            }
        }
-      else if (EQ (prop, intern ("menu-bar-lines")))
+      else if (EQ (prop, Qtitle))
        {
-         int new;
-         int old = FRAME_MENU_BAR_LINES (the_only_frame);
+         x_set_title (f, val);
+         if (termscript)
+           fprintf (termscript, "<TITLE: %s>\n", XSTRING (val)->data);
+       }
+      else if (EQ (prop, intern ("reverse")) && EQ (val, Qt))
+       {
+         unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
 
-         if (INTEGERP (val))
-           new = XINT (val);
-         else
-           new = 0;
-         FRAME_MENU_BAR_LINES (f) = new;
-         IT_set_menu_bar_lines (the_only_frame.root_window, new - old);
+         FRAME_FOREGROUND_PIXEL (f) = FRAME_BACKGROUND_PIXEL (f);
+         FRAME_BACKGROUND_PIXEL (f) = fg;
+         if (termscript)
+           fprintf (termscript, "<INVERSE-VIDEO>\n");
        }
+      store_frame_param (f, prop, val);
+
     }
 
   if (redraw)
     {
+      extern void recompute_basic_faces (FRAME_PTR);
+      extern void redraw_frame (FRAME_PTR);
+
       recompute_basic_faces (f);
-      Fredraw_frame (Fselected_frame ());
+      if (f == selected_frame)
+       redraw_frame (f);
     }
 }
 
+extern void init_frame_faces (FRAME_PTR);
+
 #endif /* !HAVE_X_WINDOWS */
 
 
-/* Do we need the internal terminal? */
+/* Do we need the internal terminal?  */
+
 void
 internal_terminal_init ()
 {
@@ -722,28 +1102,41 @@ internal_terminal_init ()
 #ifndef HAVE_X_WINDOWS
   if (!internal_terminal || inhibit_window_system)
     {
-      the_only_frame.output_method = output_termcap;
+      selected_frame->output_method = output_termcap;
       return;
     }
 
   Vwindow_system = intern ("pc");
   Vwindow_system_version = make_number (1);
+
+  /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address.  */
+  screen_old_address = 0;
+
   bzero (&the_only_x_display, sizeof the_only_x_display);
   the_only_x_display.background_pixel = 7; /* White */
   the_only_x_display.foreground_pixel = 0; /* Black */
+  bright_bg ();
   colors = getenv ("EMACSCOLORS");
   if (colors && strlen (colors) >= 2)
     {
-      the_only_x_display.foreground_pixel = colors[0] & 0x07;
-      the_only_x_display.background_pixel = colors[1] & 0x07;
+      /* The colors use 4 bits each (we enable bright background).  */
+      if (isdigit (colors[0]))
+        colors[0] -= '0';
+      else if (isxdigit (colors[0]))
+        colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
+      if (colors[0] >= 0 && colors[0] < 16)
+        the_only_x_display.foreground_pixel = colors[0];
+      if (isdigit (colors[1]))
+        colors[1] -= '0';
+      else if (isxdigit (colors[1]))
+        colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
+      if (colors[1] >= 0 && colors[1] < 16)
+        the_only_x_display.background_pixel = colors[1];
     }
   the_only_x_display.line_height = 1;
-  the_only_frame.output_data.x = &the_only_x_display;
-  the_only_frame.output_method = output_msdos_raw;
   the_only_x_display.font = (XFontStruct *)1;   /* must *not* be zero */
 
-  init_frame_faces ((FRAME_PTR) &the_only_frame);
+  init_frame_faces (selected_frame);
 
   ring_bell_hook = IT_ring_bell;
   write_glyphs_hook = IT_write_glyphs;
@@ -755,6 +1148,7 @@ internal_terminal_init ()
   update_begin_hook = IT_update_begin;
   update_end_hook = IT_update_end;
   reassert_line_highlight_hook = IT_reassert_line_highlight;
+  frame_up_to_date_hook = IT_cmgoto; /* position cursor when update is done */
 
   /* These hooks are called by term.c without being checked.  */
   set_terminal_modes_hook = IT_set_terminal_modes;
@@ -772,11 +1166,24 @@ dos_get_saved_screen (screen, rows, cols)
   *screen = startup_screen_buffer;
   *cols = startup_screen_size_X;
   *rows = startup_screen_size_Y;
-  return 1;
+  return *screen != (char *)0;
 #else
   return 0;
 #endif  
 }
+
+#ifndef HAVE_X_WINDOWS
+
+/* We are not X, but we can emulate it well enough for our needs... */
+void
+check_x (void)
+{
+  if (! FRAME_MSDOS_P (selected_frame))
+    error ("Not running under a windows system");
+}
+
+#endif
+
 \f
 /* ----------------------- Keyboard control ----------------------
  *
@@ -818,6 +1225,23 @@ static struct dos_keyboard_map fr_keyboard = {
   "  ~#{[|`\\^@]}             Ï                              "
 };
 
+/*
+ * Italian keyboard support, country code 39.
+ * '<' 56:3c*0000
+ * '>' 56:3e*0000
+ * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
+ * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
+ */
+static struct dos_keyboard_map it_keyboard = {
+/* 0          1         2         3         4         5     */
+/* 0 123456789012345678901234567890123456789012345678901234 */
+  "\\1234567890'\8d  qwertyuiop\8a+   asdfghjkl\95\85\97   zxcvbnm,.-  ",
+/* 01 23456789012345678901234567890123456789012345678901234 */
+  "|!\"\9c$%&/()=?^  QWERTYUIOP\82*   ASDFGHJKL\87øõ   ZXCVBNM;:_  ",
+/* 0123456789012345678901234567890123456789012345678901234 */
+  "        {}~`             []             @#               "
+};
+
 static struct dos_keyboard_map dk_keyboard = {
 /* 0         1         2         3         4         5      */
 /* 0123456789012345678901234567890123456789012345678901234 */
@@ -836,11 +1260,13 @@ static struct keyboard_layout_list
 {
   1, &us_keyboard,
   33, &fr_keyboard,
+  39, &it_keyboard,
   45, &dk_keyboard
 };
 
 static struct dos_keyboard_map *keyboard;
 static int keyboard_map_all;
+static int international_keyboard;
 
 int
 dos_set_keyboard (code, always)
@@ -848,6 +1274,13 @@ dos_set_keyboard (code, always)
      int always;
 {
   int i;
+  union REGS regs;
+
+  /* See if Keyb.Com is installed (for international keyboard support).  */
+  regs.x.ax = 0xad80;
+  int86 (0x2f, &regs, &regs);
+  if (regs.h.al == 0xff)
+    international_keyboard = 1;
 
   /* Initialize to US settings, for countries that don't have their own.  */
   keyboard = keyboard_layout_list[0].keyboard_map;
@@ -1155,9 +1588,16 @@ dos_get_modifiers (keymask)
              mask |= SUPER_P;
              modifiers |= super_modifier;
            }
+         else if (!international_keyboard)
+           {
+             /* If Keyb.Com is NOT installed, let Right Alt behave
+                like the Left Alt.  */
+             mask &= ~ALT_GR_P;
+             mask |= ALT_P;
+           }
        }
       
-      if (regs.h.ah & 1)               /* Left CTRL pressed
+      if (regs.h.ah & 1)               /* Left CTRL pressed ? */
        mask |= CTRL_P;
 
       if (regs.h.ah & 4)               /* Right CTRL pressed ? */
@@ -1219,6 +1659,9 @@ and then the scan code.")
 }
 
 /* Get a char from keyboard.  Function keys are put into the event queue.  */
+
+extern void kbd_buffer_store_event (struct input_event *);
+
 static int
 dos_rawgetc ()
 {
@@ -1226,10 +1669,10 @@ dos_rawgetc ()
   union REGS regs;
   
 #ifndef HAVE_X_WINDOWS
-  SCREEN_SET_CURSOR ();
-  if (!mouse_visible) mouse_on ();
+  /* Maybe put the cursor where it should be.  */
+  IT_cmgoto (selected_frame);
 #endif
-    
+
   /* The following condition is equivalent to `kbhit ()', except that
      it uses the bios to do its job.  This pleases DESQview/X.  */
   while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
@@ -1296,7 +1739,19 @@ dos_rawgetc ()
       
       if (c == 0)
        {
-         if (code & Alt)
+        /* We only look at the keyboard Ctrl/Shift/Alt keys when
+           Emacs is ready to read a key.  Therefore, if they press
+           `Alt-x' when Emacs is busy, by the time we get to
+           `dos_get_modifiers', they might have already released the
+           Alt key, and Emacs gets just `x', which is BAD.
+           However, for keys with the `Map' property set, the ASCII
+           code returns zero iff Alt is pressed.  So, when we DON'T
+           have to support international_keyboard, we don't have to
+           distinguish between the left and  right Alt keys, and we
+           can set the META modifier for any keys with the `Map'
+           property if they return zero ASCII code (c = 0).  */
+        if ( (code & Alt)
+             || ( (code & 0xf000) == Map && !international_keyboard))
            modifiers |= meta_modifier;
          if (code & Ctrl)
            modifiers |= ctrl_modifier;
@@ -1423,14 +1878,37 @@ dos_rawgetc ()
       for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
        for (press = 0; press < 2; press++)
          {
+           int button_num = but;
+
            if (press)
              ok = mouse_pressed (but, &x, &y);
            else
              ok = mouse_released (but, &x, &y);
            if (ok)
              {
+               /* Allow a simultaneous press/release of Mouse-1 and
+                  Mouse-2 to simulate Mouse-3 on two-button mice.  */
+               if (mouse_button_count == 2 && but < 2)
+                 {
+                   int x2, y2; /* don't clobber original coordinates */
+
+                   /* If only one button is pressed, wait 100 msec and
+                      check again.  This way, Speedy Gonzales isn't
+                      punished, while the slow get their chance.  */
+                   if (press && mouse_pressed (1-but, &x2, &y2)
+                       || !press && mouse_released (1-but, &x2, &y2))
+                     button_num = 2;
+                   else
+                     {
+                       delay (100);
+                       if (press && mouse_pressed (1-but, &x2, &y2)
+                           || !press && mouse_released (1-but, &x2, &y2))
+                         button_num = 2;
+                     }
+                 }
+
                event.kind = mouse_click;
-               event.code = but;
+               event.code = button_num;
                event.modifiers = dos_get_modifiers (0)
                  | (press ? down_modifier : up_modifier);
                event.x = x;
@@ -1448,6 +1926,7 @@ dos_rawgetc ()
 static int prev_get_char = -1;
 
 /* Return 1 if a key is ready to be read without suspending execution.  */
+
 dos_keysns ()
 {
   if (prev_get_char != -1)
@@ -1457,6 +1936,7 @@ dos_keysns ()
 }
 
 /* Read a key.  Return -1 if no key is ready.  */
+
 dos_keyread ()
 {
   if (prev_get_char != -1)
@@ -1581,7 +2061,7 @@ IT_menu_calc_size (XMenu *menu, int *width, int *height)
   *height = maxheight;
 }
 
-/* Display MENU at (X,Y) using FACES. */
+/* Display MENU at (X,Y) using FACES.  */
 
 static void
 IT_menu_display (XMenu *menu, int y, int x, int *faces)
@@ -1608,7 +2088,17 @@ IT_menu_display (XMenu *menu, int y, int x, int *faces)
       p = text;
       *p++ = FAST_MAKE_GLYPH (' ', face);
       for (j = 0, q = menu->text[i]; *q; j++)
-       *p++ = FAST_MAKE_GLYPH (*q++, face);
+       {
+         if (*q > 26)
+           *p++ = FAST_MAKE_GLYPH (*q++, face);
+         else  /* make '^x' */
+           {
+             *p++ = FAST_MAKE_GLYPH ('^', face);
+             j++;
+             *p++ = FAST_MAKE_GLYPH (*q++ + 64, face);
+           }
+       }
+           
       for (; j < width; j++)
        *p++ = FAST_MAKE_GLYPH (' ', face);
       *p++ = FAST_MAKE_GLYPH (menu->submenu[i] ? 16 : ' ', face);
@@ -1645,6 +2135,7 @@ int
 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
 {
   int len;
+  char *p;
 
   if (!enable)
     abort ();
@@ -1654,8 +2145,16 @@ XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
   menu->text[menu->count] = txt;
   menu->panenumber[menu->count] = ++menu->panecount;
   menu->count++;
-  if ((len = strlen (txt)) > menu->width)
+
+  /* Adjust length for possible control characters (which will
+     be written as ^x).  */
+  for (len = strlen (txt), p = txt; *p; p++)
+    if (*p < 27)
+      len++;
+
+  if (len > menu->width)
     menu->width = len;
+
   return menu->panecount;
 }
 
@@ -1666,6 +2165,7 @@ XMenuAddSelection (Display *bar, XMenu *menu, int pane,
                   int foo, char *txt, int enable)
 {
   int len;
+  char *p;
 
   if (pane)
     if (!(menu = IT_menu_search_pane (menu, pane)))
@@ -1675,8 +2175,16 @@ XMenuAddSelection (Display *bar, XMenu *menu, int pane,
   menu->text[menu->count] = txt;
   menu->panenumber[menu->count] = enable;
   menu->count++;
-  if ((len = strlen (txt)) > menu->width)
+
+  /* Adjust length for possible control characters (which will
+     be written as ^x).  */
+  for (len = strlen (txt), p = txt; *p; p++)
+    if (*p < 27)
+      len++;
+
+  if (len > menu->width)
     menu->width = len;
+
   return XM_SUCCESS;
 }
 
@@ -1714,29 +2222,36 @@ XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
   int faces[4], selectface;
   int leave, result, onepane;
   int title_faces[4];          /* face to display the menu title */
+  int buffers_num_deleted = 0;
 
   /* Just in case we got here without a mouse present...  */
   if (have_mouse <= 0)
     return XM_IA_SELECT;
+  /* Don't allow non-positive x0 and y0, lest the menu will wrap
+     around the display.  */
+  if (x0 <= 0)
+    x0 = 1;
+  if (y0 <= 0)
+    y0 = 1;
 
   state = alloca (menu->panecount * sizeof (struct IT_menu_state));
   screensize = screen_size * 2;
   faces[0]
-    = compute_glyph_face (&the_only_frame,
+    = compute_glyph_face (selected_frame,
                          face_name_id_number
-                         (&the_only_frame,
+                         (selected_frame,
                           intern ("msdos-menu-passive-face")),
                          0);
   faces[1]
-    = compute_glyph_face (&the_only_frame,
+    = compute_glyph_face (selected_frame,
                          face_name_id_number
-                         (&the_only_frame,
+                         (selected_frame,
                           intern ("msdos-menu-active-face")),
                          0);
   selectface
-    = face_name_id_number (&the_only_frame, intern ("msdos-menu-select-face"));
-  faces[2] = compute_glyph_face (&the_only_frame, selectface, faces[0]);
-  faces[3] = compute_glyph_face (&the_only_frame, selectface, faces[1]);
+    = face_name_id_number (selected_frame, intern ("msdos-menu-select-face"));
+  faces[2] = compute_glyph_face (selected_frame, selectface, faces[0]);
+  faces[3] = compute_glyph_face (selected_frame, selectface, faces[1]);
 
   /* Make sure the menu title is always displayed with
      `msdos-menu-active-face', no matter where the mouse pointer is.  */
@@ -1744,11 +2259,29 @@ XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
     title_faces[i] = faces[3];
 
   statecount = 1;
+
+  /* Don't let the title for the "Buffers" popup menu include a
+     digit (which is ugly).
+     
+     This is a terrible kludge, but I think the "Buffers" case is
+     the only one where the title includes a number, so it doesn't
+     seem to be necessary to make this more general.  */
+  if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
+    {
+      menu->text[0][7] = '\0';
+      buffers_num_deleted = 1;
+    }
   state[0].menu = menu;
   mouse_off ();
   ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
 
+  /* Turn off the cursor.  Otherwise it shows through the menu
+     panes, which is ugly.  */
+  IT_display_cursor (0);
+
   IT_menu_display (menu, y0 - 1, x0 - 1, title_faces); /* display menu title */
+  if (buffers_num_deleted)
+    menu->text[0][7] = ' ';
   if ((onepane = menu->count == 1 && menu->submenu[0]))
     {
       menu->width = menu->submenu[0]->width;
@@ -1796,6 +2329,8 @@ XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
                          statecount--;
                          mouse_off ();
                          ScreenUpdate (state[statecount].screen_behind);
+                         if (screen_virtual_segment)
+                           dosv_refresh_virtual_screen (0, screen_size);
                          xfree (state[statecount].screen_behind);
                        }
                    if (i == statecount - 1 && state[i].menu->submenu[dy])
@@ -1831,8 +2366,11 @@ XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
 
   mouse_off ();
   ScreenUpdate (state[0].screen_behind);
+  if (screen_virtual_segment)
+    dosv_refresh_virtual_screen (0, screen_size);
   while (statecount--)
     xfree (state[statecount].screen_behind);
+  IT_display_cursor (1);       /* turn cursor back on */
   return result;
 }
 
@@ -1869,12 +2407,16 @@ x_pixel_height (struct frame *f)
 \f
 /* ----------------------- DOS / UNIX conversion --------------------- */
 
+void msdos_downcase_filename (unsigned char *);
+
 /* Destructively turn backslashes into slashes.  */
 
 void
 dostounix_filename (p)
      register char *p;
 {
+  msdos_downcase_filename (p);
+
   while (*p)
     {
       if (*p == '\\')
@@ -1889,6 +2431,12 @@ void
 unixtodos_filename (p)
      register char *p;
 {
+  if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
+    {
+      *p += 'a' - 'A';
+      p += 2;
+    }
+
   while (*p)
     {
       if (*p == '/')
@@ -1904,14 +2452,27 @@ getdefdir (drive, dst)
      int drive;
      char *dst;
 {
-  union REGS regs;
+  char in_path[4], *p = in_path;
+  int e = errno;
 
-  *dst++ = '/';
-  regs.h.dl = drive;
-  regs.x.si = (int) dst;
-  regs.h.ah = 0x47;
-  intdos (&regs, &regs);
-  return !regs.x.cflag;
+  /* Generate "X:." (when drive is X) or "." (when drive is 0).  */
+  if (drive != 0)
+    {
+      *p++ = drive + 'A' - 1;
+      *p++ = ':';
+    }
+
+  *p++ = '.';
+  *p = '\0';
+  errno = 0;
+  _fixpath (in_path, dst);
+  if (errno)
+    return 0;
+
+  msdos_downcase_filename (dst);
+
+  errno = e;
+  return 1;
 }
 
 /* Remove all CR's that are followed by a LF.  */
@@ -1924,7 +2485,6 @@ crlf_to_lf (n, buf)
   unsigned char *np = buf;
   unsigned char *startp = buf;
   unsigned char *endp = buf + n;
-  unsigned char c;
 
   if (n == 0)
     return n;
@@ -1942,6 +2502,246 @@ crlf_to_lf (n, buf)
     *np++ = *buf++;
   return np - startp;
 }
+
+#if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
+
+/* In DJGPP v2.0, library `write' can call `malloc', which might
+   cause relocation of the buffer whose address we get in ADDR.
+   Here is a version of `write' that avoids calling `malloc',
+   to serve us until such time as the library is fixed.
+   Actually, what we define here is called `__write', because
+   `write' is a stub that just jmp's to `__write' (to be
+   POSIXLY-correct with respect to the global name-space).  */
+
+#include <io.h>                      /* for _write */
+#include <libc/dosio.h>       /* for __file_handle_modes[] */
+
+static char xbuf[64 * 1024];  /* DOS cannot write more in one chunk */
+
+#define XBUF_END (xbuf + sizeof (xbuf) - 1)
+
+int
+__write (int handle, const void *buffer, size_t count)
+{
+  if (count == 0)
+    return 0;
+
+  if(__file_handle_modes[handle] & O_BINARY)
+    return _write (handle, buffer, count);
+  else
+    {
+      char *xbp = xbuf;
+      const char *bp = buffer;
+      int total_written = 0;
+      int nmoved = 0, ncr = 0;
+
+      while (count)
+       {
+         /* The next test makes sure there's space for at least 2 more
+            characters in xbuf[], so both CR and LF can be put there.  */
+         if (xbp < XBUF_END)
+           {
+             if (*bp == '\n')
+               {
+                 ncr++;
+                 *xbp++ = '\r';
+               }
+             *xbp++ = *bp++;
+             nmoved++;
+             count--;
+           }
+         if (xbp >= XBUF_END || !count)
+           {
+             size_t to_write = nmoved + ncr;
+             int written = _write (handle, xbuf, to_write);
+
+             if (written == -1)
+               return -1;
+             else
+               total_written += nmoved;  /* CRs aren't counted in ret value */
+
+             /* If some, but not all were written (disk full?), return
+                an estimate of the total written bytes not counting CRs.  */
+             if (written < to_write)
+               return total_written - (to_write - written) * nmoved/to_write;
+
+             nmoved = 0;
+             ncr = 0;
+             xbp = xbuf;
+           }
+       }
+      return total_written;
+    }
+}
+
+/* A low-level file-renaming function which works around Windows 95 bug.
+   This is pulled directly out of DJGPP v2.01 library sources, and only
+   used when you compile with DJGPP v2.0.  */
+
+#include <io.h>
+int _rename(const char *old, const char *new)
+{
+  __dpmi_regs r;
+  int olen    = strlen(old) + 1;
+  int i;
+  int use_lfn = _USE_LFN;
+  char tempfile[FILENAME_MAX];
+  const char *orig = old;
+  int lfn_fd = -1;
+
+  r.x.dx = __tb_offset;
+  r.x.di = __tb_offset + olen;
+  r.x.ds = r.x.es = __tb_segment;
+
+  if (use_lfn)
+    {
+      /* Windows 95 bug: for some filenames, when you rename
+        file -> file~ (as in Emacs, to leave a backup), the
+        short 8+3 alias doesn't change, which effectively
+        makes OLD and NEW the same file.  We must rename
+        through a temporary file to work around this.  */
+
+      char *pbase = 0, *p;
+      static char try_char[] = "abcdefghijklmnopqrstuvwxyz012345789";
+      int idx = sizeof(try_char) - 1;
+
+      /* Generate a temporary name.  Can't use `tmpnam', since $TMPDIR
+        might point to another drive, which will fail the DOS call.  */
+      strcpy(tempfile, old);
+      for (p = tempfile; *p; p++) /* ensure temporary is on the same drive */
+       if (*p == '/' || *p == '\\' || *p == ':')
+         pbase = p;
+      if (pbase)
+       pbase++;
+      else
+       pbase = tempfile;
+      strcpy(pbase, "X$$djren$$.$$temp$$");
+
+      do
+       {
+         if (idx <= 0)
+           return -1;
+         *pbase = try_char[--idx];
+       } while (_chmod(tempfile, 0) != -1);
+
+      r.x.ax = 0x7156;
+      _put_path2(tempfile, olen);
+      _put_path(old);
+      __dpmi_int(0x21, &r);
+      if (r.x.flags & 1)
+       {
+         errno = __doserr_to_errno(r.x.ax);
+         return -1;
+       }
+
+      /* Now create a file with the original name.  This will
+        ensure that NEW will always have a 8+3 alias
+        different from that of OLD.  (Seems to be required
+        when NameNumericTail in the Registry is set to 0.)  */
+      lfn_fd = _creat(old, 0);
+
+      olen = strlen(tempfile) + 1;
+      old  = tempfile;
+      r.x.di = __tb_offset + olen;
+    }
+
+  for (i=0; i<2; i++)
+    {
+      if(use_lfn)
+       r.x.ax = 0x7156;
+      else
+       r.h.ah = 0x56;
+      _put_path2(new, olen);
+      _put_path(old);
+      __dpmi_int(0x21, &r);
+      if(r.x.flags & 1)
+       {
+         if (r.x.ax == 5 && i == 0) /* access denied */
+           remove(new);                 /* and try again */
+         else
+           {
+             errno = __doserr_to_errno(r.x.ax);
+
+             /* Restore to original name if we renamed it to temporary.  */
+             if (use_lfn)
+               {
+                 if (lfn_fd != -1)
+                   {
+                     _close (lfn_fd);
+                     remove (orig);
+                   }
+                 _put_path2(orig, olen);
+                 _put_path(tempfile);
+                 r.x.ax = 0x7156;
+                 __dpmi_int(0x21, &r);
+               }
+             return -1;
+           }
+       }
+      else
+       break;
+    }
+
+  /* Success.  Delete the file possibly created to work
+     around the Windows 95 bug.  */
+  if (lfn_fd != -1)
+    return (_close (lfn_fd) == 0) ? remove (orig) : -1;
+  return 0;
+}
+
+#endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
+
+DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
+  0, 0, 0,
+  "Return non-nil if long file names are supported on MSDOS.")
+  ()
+{
+  return (_USE_LFN ? Qt : Qnil);
+}
+
+/* Convert alphabetic characters in a filename to lower-case.  */
+
+void
+msdos_downcase_filename (p)
+     register unsigned char *p;
+{
+  /* Always lower-case drive letters a-z, even if the filesystem
+     preserves case in filenames.
+     This is so MSDOS filenames could be compared by string comparison
+     functions that are case-sensitive.  Even case-preserving filesystems
+     do not distinguish case in drive letters.  */
+  if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
+    {
+      *p += 'a' - 'A';
+      p += 2;
+    }
+
+  /* Under LFN we expect to get pathnames in their true case.  */
+  if (NILP (Fmsdos_long_file_names ()))
+    for ( ; *p; p++)
+      if (*p >= 'A' && *p <= 'Z')
+       *p += 'a' - 'A';
+}
+
+DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
+       1, 1, 0,
+  "Convert alphabetic characters in FILENAME to lower case and return that.\n\
+When long filenames are supported, doesn't change FILENAME.\n\
+If FILENAME is not a string, returns nil.\n\
+The argument object is never altered--the value is a copy.")
+  (filename)
+     Lisp_Object filename;
+{
+  Lisp_Object tem;
+
+  if (! STRINGP (filename))
+    return Qnil;
+
+  tem = Fcopy_sequence (filename);
+  msdos_downcase_filename (XSTRING (tem)->data);
+  return tem;
+}
 \f
 /* The Emacs root directory as determined by init_environment.  */
 
@@ -1976,15 +2776,17 @@ init_environment (argc, argv, skip_args)
      "c:/emacs/bin/emacs.exe" our root will be "c:/emacs".  */
   root = alloca (MAXPATHLEN + 20);
   _fixpath (argv[0], root);
-  strlwr (root);
+  msdos_downcase_filename (root);
   len = strlen (root);
   while (len > 0 && root[len] != '/' && root[len] != ':')
     len--;
   root[len] = '\0';
-  if (len > 4 && strcmp (root + len - 4, "/bin") == 0)
+  if (len > 4
+      && (strcmp (root + len - 4, "/bin") == 0
+         || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
     root[len - 4] = '\0';
   else
-    strcpy (root, "c:/emacs");  /* Only under debuggers, I think.  */
+    strcpy (root, "c:/emacs");  /* let's be defensive */
   len = strlen (root);
   strcpy (emacsroot, root);
 
@@ -2010,7 +2812,6 @@ init_environment (argc, argv, skip_args)
   if (!s) s = "c:/command.com";
   t = alloca (strlen (s) + 1);
   strcpy (t, s);
-  strlwr (t);
   dostounix_filename (t);
   setenv ("SHELL", t, 0);
 
@@ -2021,7 +2822,6 @@ init_environment (argc, argv, skip_args)
   /* Current directory is always considered part of MsDos's path but it is
      not normally mentioned.  Now it is.  */
   strcat (strcpy (t, ".;"), s);
-  strlwr (t);
   dostounix_filename (t); /* Not a single file name, but this should work.  */
   setenv ("PATH", t, 1);
 
@@ -2073,7 +2873,7 @@ init_environment (argc, argv, skip_args)
        setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
        break;
       }
-  init_gettimeofday ();
+  tzset ();
 }
 
 \f
@@ -2081,6 +2881,8 @@ init_environment (argc, argv, skip_args)
 static int break_stat;  /* BREAK check mode status.    */
 static int stdin_stat;  /* stdin IOCTL status.         */
 
+#if __DJGPP__ < 2
+
 /* These must be global.  */
 static _go32_dpmi_seginfo ctrl_break_vector;
 static _go32_dpmi_registers ctrl_break_regs;
@@ -2110,11 +2912,10 @@ install_ctrl_break_check ()
     }
 }
 
-/*
- * Turn off Dos' Ctrl-C checking and inhibit interpretation of
- * control chars by Dos.
- * Determine the keyboard type.
- */
+#endif /* __DJGPP__ < 2 */
+
+/* Turn off Dos' Ctrl-C checking and inhibit interpretation of
+   control chars by DOS.   Determine the keyboard type.  */
 
 int
 dos_ttraw ()
@@ -2124,7 +2925,9 @@ dos_ttraw ()
   
   break_stat = getcbrk ();
   setcbrk (0);
+#if __DJGPP__ < 2
   install_ctrl_break_check ();
+#endif
 
   if (first_time)
     {
@@ -2175,9 +2978,24 @@ dos_ttraw ()
              mouse_init ();
            }
        }
-      
+
       first_time = 0;
+
+#if __DJGPP__ >= 2
+
+      stdin_stat = setmode (fileno (stdin), O_BINARY);
+      return (stdin_stat != -1);
     }
+  else
+    return (setmode (fileno (stdin), O_BINARY) != -1);
+
+#else /* __DJGPP__ < 2 */
+
+    }
+
+  /* I think it is wrong to overwrite `stdin_stat' every time
+     but the first one this function is called, but I don't
+     want to change the way it used to work in v1.x.--EZ  */
 
   inregs.x.ax = 0x4400;                /* Get IOCTL status. */
   inregs.x.bx = 0x00;          /* 0 = stdin. */
@@ -2188,9 +3006,12 @@ dos_ttraw ()
   inregs.x.ax = 0x4401;                /* Set IOCTL status */
   intdos (&inregs, &outregs);
   return !outregs.x.cflag;
+
+#endif /* __DJGPP__ < 2 */
 }
 
 /*  Restore status of standard input and Ctrl-C checking.  */
+
 int
 dos_ttcooked ()
 {
@@ -2199,34 +3020,55 @@ dos_ttcooked ()
   setcbrk (break_stat);
   mouse_off ();
 
+#if __DJGPP__ >= 2
+
+  return (setmode (fileno (stdin), stdin_stat) != -1);
+
+#else  /* not __DJGPP__ >= 2 */
+
   inregs.x.ax = 0x4401;        /* Set IOCTL status.    */
   inregs.x.bx = 0x00;  /* 0 = stdin.           */
   inregs.x.dx = stdin_stat;
   intdos (&inregs, &outregs);
   return !outregs.x.cflag;
+
+#endif /* not __DJGPP__ >= 2 */
 }
 
 \f
 /* Run command as specified by ARGV in directory DIR.
    The command is run with input from TEMPIN, output to
    file TEMPOUT and stderr to TEMPERR.  */
+
 int
 run_msdos_command (argv, dir, tempin, tempout, temperr)
      unsigned char **argv;
      Lisp_Object dir;
      int tempin, tempout, temperr;
 {
-  char *saveargv1, *saveargv2, **envv;
+  char *saveargv1, *saveargv2, **envv, *lowcase_argv0, *pa, *pl;
   char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS.  */
   int msshell, result = -1;
-  int in, out, inbak, outbak, errbak;
+  int inbak, outbak, errbak;
   int x, y;
   Lisp_Object cmd;
 
   /* Get current directory as MSDOS cwd is not per-process.  */
   getwd (oldwd);
 
-  cmd = Ffile_name_nondirectory (build_string (argv[0]));
+  /* If argv[0] is the shell, it might come in any lettercase.
+     Since `Fmember' is case-sensitive, we need to downcase
+     argv[0], even if we are on case-preserving filesystems.  */
+  lowcase_argv0 = alloca (strlen (argv[0]) + 1);
+  for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
+    {
+      *pl = *pa++;
+      if (*pl >= 'A' && *pl <= 'Z')
+       *pl += 'a' - 'A';
+    }
+  *pl = '\0';
+
+  cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
   msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
     && !strcmp ("-c", argv[1]);
   if (msshell)
@@ -2287,6 +3129,25 @@ run_msdos_command (argv, dir, tempin, tempout, temperr)
   dup2 (tempout, 1);
   dup2 (temperr, 2);
 
+#if __DJGPP__ > 1
+
+  if (msshell && !argv[3])
+    {
+      /* MS-DOS native shells are too restrictive.  For starters, they
+        cannot grok commands longer than 126 characters.  In DJGPP v2
+        and later, `system' is much smarter, so we'll call it instead.  */
+
+      extern char **environ;
+      environ = envv;
+
+      /* A shell gets a single argument--its full command
+        line--whose original was saved in `saveargv2'.  */
+      result = system (saveargv2);
+    }
+  else
+
+#endif /* __DJGPP__ > 1 */
+
   result = spawnve (P_WAIT, argv[0], argv, envv);
   
   dup2 (inbak, 0);
@@ -2302,6 +3163,11 @@ run_msdos_command (argv, dir, tempin, tempout, temperr)
       mouse_init ();
       mouse_moveto (x, y);
     }
+
+  /* Some programs might change the meaning of the highest bit of the
+     text attribute byte, so we get blinking characters instead of the
+     bright background colors.  Restore that.  */
+  bright_bg ();
   
  done:
   chdir (oldwd);
@@ -2321,15 +3187,15 @@ croak (badfunc)
   exit (1);
 }
 \f
+#if __DJGPP__ < 2
+
 /* ------------------------- Compatibility functions -------------------
  *     gethostname
  *     gettimeofday
  */
 
-/*
- * Hostnames for a pc are not really funny,
- * but they are used in change log so we emulate the best we can.
- */
+/* Hostnames for a pc are not really funny,
+   but they are used in change log so we emulate the best we can.  */
 
 gethostname (p, size)
      char *p;
@@ -2382,85 +3248,150 @@ gettimeofday (struct timeval *tp, struct timezone *tzp)
   return 0;
 }
 
+#endif /* __DJGPP__ < 2 */
 
 /*
  * A list of unimplemented functions that we silently ignore.
  */
 
+#if __DJGPP__ < 2
 unsigned alarm (s) unsigned s; {}
 fork () { return 0; }
 int kill (x, y) int x, y; { return -1; }
 nice (p) int p; {}
 void volatile pause () {}
-request_sigio () {}
+sigsetmask (x) int x; { return 0; }
+sigblock (mask) int mask; { return 0; } 
+#endif
+
+void request_sigio (void) {}
 setpgrp () {return 0; }
 setpriority (x,y,z) int x,y,z; { return 0; }
-sigsetmask (x) int x; { return 0; }
-unrequest_sigio () {}
+void unrequest_sigio (void) {}
 
-#ifndef HAVE_SELECT
-#include "sysselect.h"
+#if __DJGPP__ > 1
+
+#ifdef POSIX_SIGNALS
 
-static struct time last_time  = {120, 120, 120, 120};
-static int modeline_time_displayed = 0;
+/* Augment DJGPP library POSIX signal functions.  This is needed
+   as of DJGPP v2.01, but might be in the library in later releases. */
 
-Lisp_Object Vdos_display_time;
+#include <libc/bss.h>
 
+/* A counter to know when to re-initialize the static sets.  */
+static int sigprocmask_count = -1;
+
+/* Which signals are currently blocked (initially none).  */
+static sigset_t current_mask;
+
+/* Which signals are pending (initially none).  */
+static sigset_t pending_signals;
+
+/* Previous handlers to restore when the blocked signals are unblocked.  */
+typedef void (*sighandler_t)(int);
+static sighandler_t prev_handlers[320];
+
+/* A signal handler which just records that a signal occured
+   (it will be raised later, if and when the signal is unblocked).  */
 static void
-check_timer (t)
-  struct time *t;
+sig_suspender (signo)
+     int signo;
 {
-  int sec, min, hour, hund;
+  sigaddset (&pending_signals, signo);
+}
 
-  gettime (t);
-  sec  = t->ti_sec;
-  hund = t->ti_hund;
-  hour = t->ti_hour;
-  min  = t->ti_min;
+int
+sigprocmask (how, new_set, old_set)
+     int how;
+     const sigset_t *new_set;
+     sigset_t *old_set;
+{
+  int signo;
+  sigset_t new_mask;
 
-  /* Any chance of not getting here 24 hours or more since last time? */
-  if (hour == last_time.ti_hour
-      && min == last_time.ti_min
-      && sec == last_time.ti_sec)
-    return;
+  /* If called for the first time, initialize.  */
+  if (sigprocmask_count != __bss_count)
+    {
+      sigprocmask_count = __bss_count;
+      sigemptyset (&pending_signals);
+      sigemptyset (&current_mask);
+      for (signo = 0; signo < 320; signo++)
+       prev_handlers[signo] = SIG_ERR;
+    }
+
+  if (old_set)
+    *old_set = current_mask;
+
+  if (new_set == 0)
+    return 0;
 
-  if (!NILP (Vdos_display_time))
+  if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
     {
-      int interval;
-      Lisp_Object dti = XSYMBOL (Fintern_soft (build_string ("display-time-interval"), Qnil))->value;
-      int delta_time  = ((hour - last_time.ti_hour) * 3600
-                        + (min  - last_time.ti_min) * 60
-                        + (sec  - last_time.ti_sec));
-
-      /* Who knows what the user may put into `display-time-interval'?  */
-      if (!INTEGERP (dti) || (interval = XINT (dti)) <= 0)
-       interval = 60;
-
-      /* When it's time to renew the display, fake a `wakeup' call.  */
-      if (!modeline_time_displayed     /* first time */
-         || delta_time >= interval     /* or if we were busy for a long time */
-         || interval == 1              /* and every `interval' seconds hence */
-         || interval == 60 && sec == 0 /* (usual cases first) */
-         || (hour * 3600 + min * 60 + sec) % interval == 0)
-       call2 (intern ("display-time-filter"), Qnil,
-              build_string ("Wake up!\n"));
-
-      modeline_time_displayed = 1;
+      errno = EINVAL;
+      return -1;
     }
-  else if (modeline_time_displayed)
+
+  sigemptyset (&new_mask);
+
+  /* DJGPP supports upto 320 signals.  */
+  for (signo = 0; signo < 320; signo++)
     {
-      modeline_time_displayed = 0;
-      Fset (intern ("display-time-string"), build_string (""));
+      if (sigismember (&current_mask, signo))
+       sigaddset (&new_mask, signo);
+      else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
+       {
+         sigaddset (&new_mask, signo);
 
-      /* Force immediate redisplay of modelines.  */
-      update_mode_lines++;
-      redisplay_preserve_echo_area ();
+         /* SIGKILL is silently ignored, as on other platforms.  */
+         if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
+           prev_handlers[signo] = signal (signo, sig_suspender);
+       }
+      if ((   how == SIG_UNBLOCK
+             && sigismember (&new_mask, signo)
+             && sigismember (new_set, signo))
+         || (how == SIG_SETMASK
+             && sigismember (&new_mask, signo)
+             && !sigismember (new_set, signo)))
+       {
+         sigdelset (&new_mask, signo);
+         if (prev_handlers[signo] != SIG_ERR)
+           {
+             signal (signo, prev_handlers[signo]);
+             prev_handlers[signo] = SIG_ERR;
+           }
+         if (sigismember (&pending_signals, signo))
+           {
+             sigdelset (&pending_signals, signo);
+             raise (signo);
+           }
+       }
     }
-  
-  last_time  = *t;
+  current_mask = new_mask;
+  return 0;
 }
 
+#else /* not POSIX_SIGNALS */
+
+sigsetmask (x) int x; { return 0; }
+sigblock (mask) int mask; { return 0; } 
+
+#endif /* not POSIX_SIGNALS */
+#endif /* __DJGPP__ > 1 */
+
+#ifndef HAVE_SELECT
+#include "sysselect.h"
+
+#ifndef EMACS_TIME_ZERO_OR_NEG_P
+#define EMACS_TIME_ZERO_OR_NEG_P(time) \
+  ((long)(time).tv_sec < 0             \
+   || ((time).tv_sec == 0              \
+       && (long)(time).tv_usec <= 0))
+#endif
+
+
 /* Only event queue is checked.  */
+/* We don't have to call timer_check here
+   because wait_reading_process_input takes care of that.  */
 int
 sys_select (nfds, rfds, wfds, efds, timeout)
      int nfds;
@@ -2468,7 +3399,6 @@ sys_select (nfds, rfds, wfds, efds, timeout)
      EMACS_TIME *timeout;
 {
   int check_input;
-  long timeoutval, clnow, cllast;
   struct time t;
 
   check_input = 0;
@@ -2489,27 +3419,39 @@ sys_select (nfds, rfds, wfds, efds, timeout)
      just read it and wait -- that's more efficient.  */
   if (!timeout)
     {
-      do
-       check_timer (&t);  /* check timer even if some input is pending */
-      while (!detect_input_pending ());
+      while (!detect_input_pending ())
+       {
+#if __DJGPP__ >= 2
+         __dpmi_yield ();
+#endif   
+       }
     }
   else
     {
-      timeoutval = EMACS_SECS (*timeout) * 100 + EMACS_USECS (*timeout) / 10000;
-      check_timer (&t);
-      cllast = t.ti_sec * 100 + t.ti_hund;
+      EMACS_TIME clnow, cllast, cldiff;
+
+      gettime (&t);
+      EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
 
       while (!check_input || !detect_input_pending ())
        {
-         check_timer (&t);
-         clnow = t.ti_sec * 100 + t.ti_hund;
-         if (clnow < cllast) /* time wrap */
-           timeoutval -= clnow + 6000 - cllast;
-         else
-           timeoutval -= clnow - cllast;
-         if (timeoutval <= 0)  /* Stop on timer being cleared */
+         gettime (&t);
+         EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
+         EMACS_SUB_TIME (cldiff, clnow, cllast);
+
+         /* When seconds wrap around, we assume that no more than
+            1 minute passed since last `gettime'.  */
+         if (EMACS_TIME_NEG_P (cldiff))
+           EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
+         EMACS_SUB_TIME (*timeout, *timeout, cldiff);
+
+         /* Stop when timeout value crosses zero.  */
+         if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
            return 0;
          cllast = clnow;
+#if __DJGPP__ >= 2
+         __dpmi_yield ();
+#endif   
        }
     }
   
@@ -2602,20 +3544,55 @@ abort ()
   dos_ttcooked ();
   ScreenSetCursor (10, 0);
   cputs ("\r\n\nEmacs aborted!\r\n");
+#if __DJGPP__ > 1
+#if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
+  if (screen_virtual_segment)
+    dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
+#endif /* __DJGPP_MINOR__ < 2 */
+  /* Generate traceback, so we could tell whodunit.  */
+  signal (SIGINT, SIG_DFL);
+  __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
+#endif
   exit (2);
 }
 #endif
 
+/* The following two are required so that customization feature
+   won't complain about unbound variables.  */
+#ifndef HAVE_X_WINDOWS
+/* Search path for bitmap files (xfns.c).  */
+Lisp_Object Vx_bitmap_file_path;
+#endif
+#ifndef subprocesses
+/* Nonzero means delete a process right away if it exits (process.c).  */
+static int delete_exited_processes;
+#endif
+
 syms_of_msdos ()
 {
   recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
   staticpro (&recent_doskeys);
+#ifndef HAVE_X_WINDOWS
+  DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
+    "List of directories to search for bitmap files for X.");
+  Vx_bitmap_file_path = decode_env_path ((char *) 0, ".");
+
+  /* The following two are from xfns.c:  */
+  Qbackground_color = intern ("background-color");
+  staticpro (&Qbackground_color);
+  Qforeground_color = intern ("foreground-color");
+  staticpro (&Qforeground_color);
+#endif
+#ifndef subprocesses
+  DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
+    "*Non-nil means delete processes immediately when they exit.\n\
+nil means don't delete them until `list-processes' is run.");
+  delete_exited_processes = 0;
+#endif
 
   defsubr (&Srecent_doskeys);
-
-  DEFVAR_LISP ("dos-display-time", &Vdos_display_time,
-    "*When non-nil, `display-time' is in effect on DOS systems.");
-  Vdos_display_time = Qnil;
+  defsubr (&Smsdos_long_file_names);
+  defsubr (&Smsdos_downcase_filename);
 }
 
 #endif /* MSDOS */