]> code.delx.au - gnu-emacs/blobdiff - src/msdos.c
Initial revision
[gnu-emacs] / src / msdos.c
index cafd6df1fe08ab22d503945d5581dad8748669e5..55d2fc27490610631f1a56042e746f796e73d622 100644 (file)
@@ -1,5 +1,5 @@
-/* MS-DOS specific C utilities.  Coded by Morten Welinder 1993
-   Copyright (C) 1993 Free Software Foundation, Inc.
+/* MS-DOS specific C utilities.
+   Copyright (C) 1993, 1994 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -17,6 +17,8 @@ You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
+/* Contributed by Morten Welinder */
+
 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
 
 #include <config.h>
@@ -62,7 +64,7 @@ dos_ttraw ()
   break_stat = getcbrk ();
   setcbrk (0);
   install_ctrl_break_check ();
-  have_mouse = Mouse_init1 ();
+  have_mouse = mouse_init1 ();
 
   inregs.x.ax = 0x4400;        /* Get IOCTL status. */
   inregs.x.bx = 0x00;  /* 0 = stdin. */
@@ -82,7 +84,7 @@ dos_ttcooked ()
   union REGS inregs, outregs;
 
   setcbrk (break_stat);
-  if (have_mouse) Mouse_off ();
+  if (have_mouse) mouse_off ();
 
   inregs.x.ax = 0x4401;        /* Set IOCTL status.    */
   inregs.x.bx = 0x00;  /* 0 = stdin.           */
@@ -258,9 +260,16 @@ dos_rawgetc ()
   int86 (0x16, &regs, &regs);
   ctrl_p = ((regs.h.al & 4) != 0);
   shift_p = ((regs.h.al & 3) != 0);
+  /* Please be very careful here not to break international keyboard support.
+     When Keyb.Com is loaded, the key marked `Alt Gr' is used for accessing
+     characters like { and } if their positions are overlaid.  */
   alt_p = ((extended_kbd ? (regs.h.ah & 2) : (regs.h.al & 8)) != 0);
 
-  while (kbhit ())
+  /* 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),
+        int86 (0x16, &regs, &regs),
+        (regs.x.flags & 0x40) == 0)
     {
       union REGS regs;
       register unsigned char c;
@@ -274,6 +283,11 @@ dos_rawgetc ()
       /* Determine from the scan code if a keypad key was pressed.  */
       if (c >= '0' && c <= '9' && sc > 0xb)
        sc = (c == '0') ? 0xb : (c - '0' + 1), c = 0;
+      else if (sc == 0x53 && c != 0xe0)
+       {
+         code = 0xffae; /* Keypad decimal point/comma.  */
+         goto nonascii;
+       }
       else if (sc == 0xe0)
        {
          switch (c)
@@ -282,10 +296,6 @@ dos_rawgetc ()
            case 13:
              sc = 0x1c;
              break;
-           case '.': /* Decimal point or decimal comma */
-           case ',':
-             sc = 0x53;
-             break;
            case '/':
              sc = 0x35;
              break;
@@ -313,15 +323,26 @@ dos_rawgetc ()
          {
            if (code >= 0x100)
              {
+             nonascii:
                event.kind = non_ascii_keystroke;
-               event.code = code & 0xff;
+               event.code = (code & 0xff) + 0xff00;
              }
            else
              {
-               /* Don't return S- if we don't have to.  */
-               if (code >= 'a' && code <= 'z')
+               /* Don't return S- if we don't have to.  `shifted' is
+                  supposed to be the shifted versions of the characters
+                  in `unshifted'.  Unfortunately, this is only true for
+                  US keyboard layout.  If anyone knows how to do this
+                  right, please tell us.  */
+               static char *unshifted
+                 = "abcdefghijklmnopqrstuvwxyz,./=;[\\]'-`0123456789";
+               static char *shifted
+                 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ<>?+:{|}\"_~)!@#$%^&*(";
+               char *pos;
+
+               if (shift_p && (pos = strchr (unshifted, code)))
                  {
-                   c = shift_p ? toupper (code) : code;
+                   c = shifted[pos - unshifted];
                    shift_p = 0;
                  }
                else
@@ -348,15 +369,15 @@ dos_rawgetc ()
       int but, press, x, y, ok;
 
       /* Check for mouse movement *before* buttons.  */
-      Mouse_check_moved ();
+      mouse_check_moved ();
 
       for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
        for (press = 0; press < 2; press++)
          {
            if (press)
-             ok = Mouse_pressed (but, &x, &y);
+             ok = mouse_pressed (but, &x, &y);
            else
-             ok = Mouse_released (but, &x, &y);
+             ok = mouse_released (but, &x, &y);
            if (ok)
              {
                event.kind = mouse_click;
@@ -471,7 +492,7 @@ crlf_to_lf (n, buf)
 
   if (n == 0)
     return n;
-  while (buf < endp)
+  while (buf < endp - 1)
     {
       if (*buf == 0x0d)
        {
@@ -481,6 +502,8 @@ crlf_to_lf (n, buf)
       else
        *np++ = *buf++;
     }
+  if (buf < endp)
+    *np++ = *buf++;
   return np - startp;
 }
 
@@ -508,19 +531,31 @@ run_msdos_command (argv, dir, tempin, tempout)
   if (msshell)
     {
       saveargv1 = argv[1];
+      saveargv2 = argv[2];
       argv[1] = "/c";
       if (argv[2])
        {
-         saveargv2 = argv[2];
-         unixtodos_filename (argv[2] = strdup (argv[2]));
+         char *p = alloca (strlen (argv[2]) + 1);
+
+         strcpy (argv[2] = p, saveargv2);
+         while (*p && isspace (*p))
+           p++;
+         while (*p && !isspace (*p))
+           if (*p == '/')
+             *p++ = '\\';
+           else
+             p++;
        }
     }
 
   /* Build the environment array.  */
   {
     extern Lisp_Object Vprocess_environment;
-    Lisp_Object tmp, lst = Vprocess_environment;
-    int i, len = XFASTINT (Flength (lst));
+    Lisp_Object tmp, lst;
+    int i, len;
+
+    lst = Vprocess_environment;
+    len = XFASTINT (Flength (lst));
 
     envv = alloca ((len + 1) * sizeof (char *));
     for (i = 0; i < len; i++)
@@ -556,11 +591,7 @@ run_msdos_command (argv, dir, tempin, tempout)
   if (msshell)
     {
       argv[1] = saveargv1;
-      if (argv[2])
-       {
-         free (argv[2]);
-         argv[2] = saveargv2;
-       }
+      argv[2] = saveargv2;
     }
   return result;
 }
@@ -630,6 +661,21 @@ sleep_or_kbd_hit (secs, kbdok)
   while (clnow < clthen);
 }
 
+/* The Emacs root directory as determined by init_environment.  */
+static char emacsroot[MAXPATHLEN];
+
+char *
+rootrelativepath (rel)
+     char *rel;
+{
+  static char result[MAXPATHLEN + 10];
+
+  strcpy (result, emacsroot);
+  strcat (result, "/");
+  strcat (result, rel);
+  return result;
+}
+
 /* Define a lot of environment variables if not already defined.  Don't
    remove anything unless you know what you're doing -- lots of code will
    break if one or more of these are missing.  */
@@ -639,32 +685,30 @@ init_environment (argc, argv, skip_args)
      char **argv;
      int skip_args;
 {
-  char *s, *t;
-
-  /* We default HOME to the directory from which Emacs was started, but with
-     a "/bin" suffix removed.  */
-  s = argv[0];
-  t = alloca (strlen (s) + 1);
-  strcpy (t, s);
-  s = t + strlen (t);
-  while (s != t && *s != '/' && *s != ':') s--;
-  if (s == t)
-    t = "c:/emacs"; /* When run under debug32.  */
+  char *s, *t, *root;
+  int len;
+
+  /* Find our root from argv[0].  Assuming argv[0] is, say,
+     "c:/emacs/bin/emacs.exe" our root will be "c:/emacs".  */
+  len = strlen (argv[0]);
+  root = alloca (len + 10);  /* A little extra space for the stuff below.  */
+  strcpy (root, argv[0]);
+  while (len > 0 && root[len] != '/' && root[len] != ':')
+    len--;
+  root[len] = '\0';
+  if (len > 4 && strcmp (root + len - 4, "/bin") == 0)
+    root[len - 4] = '\0';
   else
-    {
-      if (*s == ':') s++;
-      *s = 0;
-      if (s - 4 >= t && strcmp (s - 4, "/bin") == 0)
-       s[strlen (s) - 4] = 0;
-    }
-  setenv ("HOME", t, 0);
+    strcpy (root, "c:/emacs");  /* Only under debuggers, I think.  */
+  len = strlen (root);
+  strcpy (emacsroot, root);
+
+  /* We default HOME to our root.  */
+  setenv ("HOME", root, 0);
 
-  /* We set EMACSPATH to ~/bin (expanded) */
-  s = getenv ("HOME");
-  t = strcpy (alloca (strlen (s) + 6), s);
-  if (s[strlen (s) - 1] != '/') strcat (t, "/");
-  strcat (t, "bin");
-  setenv ("EMACSPATH", t, 0);
+  /* We default EMACSPATH to root + "/bin".  */
+  strcpy (root + len, "/bin");
+  setenv ("EMACSPATH", root, 0);
 
   /* I don't expect anybody to ever use other terminals so the internal
      terminal is the default.  */
@@ -734,52 +778,72 @@ init_environment (argc, argv, skip_args)
       break;
     }
   tzset ();
+  init_gettimeofday ();
 }
 
 /* Flash the screen as a substitute for BEEPs.  */
 
-static unsigned char _xorattr;
-
-void
-visible_bell (xorattr)
+static void
+do_visible_bell (xorattr)
      unsigned char xorattr;
 {
-  _xorattr = xorattr;
-  asm ("  pushl  %eax
-         pushl  %ebx
-         pushl  %ecx
-         pushl  %edx
-         movl   $1,%edx
+  asm volatile
+    ("  movb   $1,%%dl
 visible_bell_0:
-         movl   _ScreenPrimary,%eax
-         call   dosmemsetup
-         movl   %eax,%ebx
-         call   _ScreenRows
-         movl   %eax,%ecx
-         call   _ScreenCols
-         imull  %eax,%ecx
-         movb   (__xorattr),%al
-         incl   %ebx
+       movl   _ScreenPrimary,%%eax
+       call   dosmemsetup
+       movl   %%eax,%%ebx
+       movl   %1,%%ecx
+       movb   %0,%%al
+       incl   %%ebx
 visible_bell_1:
-         xorb   %al,%gs:(%ebx)
-         addl   $2,%ebx
-         decl   %ecx
-         jne    visible_bell_1
-         decl   %edx
-         jne    visible_bell_3
+       xorb   %%al,%%gs:(%%ebx)
+       addl   $2,%%ebx
+       decl   %%ecx
+       jne    visible_bell_1
+       decb   %%dl
+       jne    visible_bell_3
 visible_bell_2:
-         movzwl %ax,%eax
-          movzwl %ax,%eax
-         movzwl %ax,%eax
-         movzwl %ax,%eax
-         decw   %cx
-         jne    visible_bell_2
-         jmp    visible_bell_0
-visible_bell_3:
-         popl  %edx
-         popl  %ecx
-         popl  %ebx
-         popl  %eax");
+       movzwl %%ax,%%eax
+        movzwl %%ax,%%eax
+       movzwl %%ax,%%eax
+       movzwl %%ax,%%eax
+       decw   %%cx
+       jne    visible_bell_2
+       jmp    visible_bell_0
+visible_bell_3:"
+     : /* no output */
+     : "m" (xorattr), "g" (ScreenCols () * ScreenRows ())
+     : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
+}
+
+/* At screen position (X,Y), output C characters from string S with
+   attribute A.  Do it fast!  */
+
+static void
+output_string (x, y, s, c, a)
+     int x, y, c;
+     unsigned char *s;
+     unsigned char a;
+{
+  char *t = (char *)ScreenPrimary + 2 * (x + ScreenCols () * y);
+  asm volatile
+    ("  movl   %1,%%eax
+        call   dosmemsetup
+        movl   %%eax,%%edi
+        movb   %0,%%ah
+        movl   %2,%%ecx
+        movl   %3,%%esi
+output_string1:
+        movb   (%%esi),%%al
+        movw   %%ax,%%gs:(%%edi)
+        addl   $2,%%edi
+        incl   %%esi
+        decl   %%ecx
+        jne    output_string1"
+     : /* no output */
+     : "m" (a), "g" (t), "g" (c), "g" (s)
+     : "%eax", "%ecx", /* "%gs",*/ "%esi", "%edi");
 }
 
 static int internal_terminal = 0;
@@ -789,19 +853,20 @@ int
 internal_flush (f)
      FILE *f;
 {
+  static char spaces[] = "                                                                                ";
   static int x;
   static int y;
-  char c, *cp;
-  int count, i;
+  unsigned char *cp, *cp0;
+  int count, i, j;
 
   if (internal_terminal && f == stdout)
     {
-      if (have_mouse) Mouse_off ();
+      if (have_mouse) mouse_off ();
       cp = stdout->_base;
       count = stdout->_ptr - stdout->_base;
       while (count > 0)
        {
-         switch (c = *cp++)
+         switch (*cp++)
            {
            case 27:
              switch (*cp++)
@@ -816,7 +881,7 @@ internal_flush (f)
                  count -= 3;
                  break;
                case 'B':
-                 visible_bell (*cp++);
+                 do_visible_bell (*cp++);
                  count -= 3;
                  break;
                case 'C':
@@ -825,8 +890,17 @@ internal_flush (f)
                  count -= 2;
                  break;
                case 'E':
-                 for (i = ScreenCols () - 1; i >= x; i--)
-                   ScreenPutChar (' ', ScreenAttrib, i, y);
+                 i = ScreenCols () - x;
+                 j = x;
+                 while (i >= sizeof spaces)
+                   {
+                     output_string (j, y, spaces, sizeof spaces,
+                                    ScreenAttrib);
+                     j += sizeof spaces;
+                     i -= sizeof spaces;
+                   }
+                 if (i > 0)
+                   output_string (j, y, spaces, i, ScreenAttrib);
                  count -= 2;
                  break;
                case 'R':
@@ -845,6 +919,10 @@ internal_flush (f)
                  count -= 2;
                }
              break;
+           case 7:
+             write (1, "\007", 1);
+             count--;
+             break;
            case 8:
              x--;
              count--;
@@ -858,13 +936,17 @@ internal_flush (f)
              count--;
              break;
            default:
-             ScreenPutChar (c, ScreenAttrib, x++, y);
+             cp0 = cp - 1;
              count--;
+             while (count > 0 && *cp >= ' ')
+               cp++, count--;
+             output_string (x, y, cp0, cp - cp0, ScreenAttrib);
+             x += (cp - cp0);
            }
        }
       fpurge (stdout);
       ScreenSetCursor (y, x);
-      if (have_mouse) Mouse_on ();
+      if (have_mouse) mouse_on ();
     }
   else
     /* This is a call to the original fflush.  */
@@ -880,7 +962,59 @@ internal_terminal_init ()
   internal_terminal
     = (!noninteractive) && term && !strcmp (term, "internal");
 }
+\f
+/* When time zones are set from Ms-Dos too may C-libraries are playing
+   tricks with time values.  We solve this by defining our own version
+   of `gettimeofday' bypassing GO32.  Our version needs to be initialized
+   once and after each call to `tzset' with TZ changed.  */
+
+static int daylight, gmtoffset;
+
+int
+gettimeofday (struct timeval *tp, struct timezone *tzp)
+{
+  if (tp)
+    {
+      struct time t;
+      struct date d;
+      struct tm tmrec;
+
+      gettime (&t);
+      getdate (&d);
+      tmrec.tm_year = d.da_year - 1900;
+      tmrec.tm_mon = d.da_mon - 1;
+      tmrec.tm_mday = d.da_day;
+      tmrec.tm_hour = t.ti_hour;
+      tmrec.tm_min = t.ti_min;
+      tmrec.tm_sec = t.ti_sec;
+      tmrec.tm_gmtoff = gmtoffset;
+      tmrec.tm_isdst = daylight;
+      tp->tv_sec = mktime (&tmrec);
+      tp->tv_usec = t.ti_hund * (1000000 / 100);
+    }
+  if (tzp)
+    {
+      tzp->tz_minuteswest = gmtoffset;
+      tzp->tz_dsttime = daylight;
+    }
+  return 0;
+}
 
+void
+init_gettimeofday ()
+{
+  time_t ltm, gtm;
+  struct tm *lstm;
+
+  daylight = 0;
+  gmtoffset = 0;
+  ltm = gtm = time (NULL);
+  ltm = mktime (lstm = localtime (&ltm));
+  gtm = mktime (gmtime (&gtm));
+  daylight = lstm->tm_isdst;
+  gmtoffset = (int)(gtm - ltm) / 60;
+}
+\f
 /* These must be global.  */
 static _go32_dpmi_seginfo ctrl_break_vector;
 static _go32_dpmi_registers ctrl_break_regs;
@@ -900,7 +1034,7 @@ install_ctrl_break_check ()
   if (!ctrlbreakinstalled)
     {
       /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
-        was compiler with Djgpp 1.11 maintenance level 2 or later!  */
+        was compiler with Djgpp 1.11 maintenance level 5 or later!  */
       ctrlbreakinstalled = 1;
       ctrl_break_vector.pm_offset = (int) ctrl_break_func;
       _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
@@ -978,7 +1112,7 @@ mouse_pressed (b, xp, yp)
   regs.x.bx = mouse_button_translate[b];
   int86 (0x33, &regs, &regs);
   if (regs.x.bx)
-    *xp = regs.x.cx / 8, *yp = regs.x.dx /8;
+    *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
   return (regs.x.bx != 0);
 }
 
@@ -1040,9 +1174,22 @@ mouse_init1 ()
   union REGS regs;
   int present;
 
+  if (!internal_terminal)
+    return 0;
+
   regs.x.ax = 0x0021;
   int86 (0x33, &regs, &regs);
-  present = internal_terminal && (regs.x.ax & 0xffff) == 0xffff;
+  present = (regs.x.ax & 0xffff) == 0xffff;
+  if (!present)
+    {
+      /* Reportedly, the above doesn't work for some mouse drivers.  There
+        is an additional detection method that should work, but might be
+        a little slower.  Use that as an alternative.  */
+      regs.x.ax = 0x0000;
+      int86 (0x33, &regs, &regs);
+      present = (regs.x.ax & 0xffff) == 0xffff;
+    }
+
   if (present)
     {
       if (regs.x.bx == 3)
@@ -1064,4 +1211,31 @@ mouse_init1 ()
   return present;
 }
 
+/* See xterm.c for more info.  */
+void
+pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
+     FRAME_PTR f;
+     register int pix_x, pix_y;
+     register int *x, *y;
+     void /* XRectangle */ *bounds;
+     int noclip;
+{
+  if (bounds) abort ();
+
+  /* Ignore clipping.  */
+
+  *x = pix_x;
+  *y = pix_y;
+}
+
+void
+glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
+     FRAME_PTR f;
+     register int x, y;
+     register int *pix_x, *pix_y;
+{
+  *pix_x = x;
+  *pix_y = y;
+}
+
 #endif /* MSDOS */