1 /* MS-DOS specific C utilities.          -*- coding: raw-text -*-
   2    Copyright (C) 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002,
   3                  2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
   4                  Free Software Foundation, Inc.
   5 
   6 This file is part of GNU Emacs.
   7 
   8 GNU Emacs is free software: you can redistribute it and/or modify
   9 it under the terms of the GNU General Public License as published by
  10 the Free Software Foundation, either version 3 of the License, or
  11 (at your option) any later version.
  12 
  13 GNU Emacs is distributed in the hope that it will be useful,
  14 but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 GNU General Public License for more details.
  17 
  18 You should have received a copy of the GNU General Public License
  19 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
  20 
  21 /* Contributed by Morten Welinder */
  22 /* New display, keyboard, and mouse control by Kim F. Storm */
  23 
  24 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
  25 
  26 #include <config.h>
  27 
  28 #ifdef MSDOS
  29 #include <setjmp.h>
  30 #include "lisp.h"
  31 #include <stdio.h>
  32 #include <stdlib.h>
  33 #include <time.h>
  34 #include <sys/param.h>
  35 #include <sys/time.h>
  36 #include <dos.h>
  37 #include <errno.h>
  38 #include <string.h>      /* for bzero and string functions */
  39 #include <sys/stat.h>    /* for _fixpath */
  40 #include <unistd.h>      /* for chdir, dup, dup2, etc. */
  41 #include <dir.h>         /* for getdisk */
  42 #pragma pack(0)          /* dir.h does a pack(4), which isn't GCC's default */
  43 #include <fcntl.h>
  44 #include <io.h>          /* for setmode */
  45 #include <dpmi.h>        /* for __dpmi_xxx stuff */
  46 #include <sys/farptr.h>  /* for _farsetsel, _farnspokeb */
  47 #include <libc/dosio.h>  /* for _USE_LFN */
  48 #include <conio.h>       /* for cputs */
  49 
  50 #include "msdos.h"
  51 #include "systime.h"
  52 #include "frame.h"
  53 #include "termhooks.h"
  54 #include "termchar.h"
  55 #include "dispextern.h"
  56 #include "dosfns.h"
  57 #include "termopts.h"
  58 #include "character.h"
  59 #include "coding.h"
  60 #include "disptab.h"
  61 #include "window.h"
  62 #include "buffer.h"
  63 #include "commands.h"
  64 #include "blockinput.h"
  65 #include "keyboard.h"
  66 #include "intervals.h"
  67 #include <go32.h>
  68 #include <pc.h>
  69 #include <ctype.h>
  70 /* #include <process.h> */
  71 /* Damn that local process.h!  Instead we can define P_WAIT ourselves.  */
  72 #define P_WAIT 1
  73 
  74 #ifndef _USE_LFN
  75 #define _USE_LFN 0
  76 #endif
  77 
  78 #ifndef _dos_ds
  79 #define _dos_ds _go32_info_block.selector_for_linear_memory
  80 #endif
  81 
  82 #include <signal.h>
  83 #include "syssignal.h"
  84 
  85 #ifndef SYSTEM_MALLOC
  86 
  87 #ifdef GNU_MALLOC
  88 
  89 /* If other `malloc' than ours is used, force our `sbrk' behave like
  90    Unix programs expect (resize memory blocks to keep them contiguous).
  91    If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
  92    because that's what `gmalloc' expects to get.  */
  93 #include <crt0.h>
  94 
  95 #ifdef REL_ALLOC
  96 int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
  97 #else  /* not REL_ALLOC */
  98 int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
  99 #endif /* not REL_ALLOC */
 100 #endif /* GNU_MALLOC */
 101 
 102 #endif /* not SYSTEM_MALLOC */
 103 
 104 static unsigned long
 105 event_timestamp ()
 106 {
 107   struct time t;
 108   unsigned long s;
 109 
 110   gettime (&t);
 111   s = t.ti_min;
 112   s *= 60;
 113   s += t.ti_sec;
 114   s *= 1000;
 115   s += t.ti_hund * 10;
 116 
 117   return s;
 118 }
 119 
 120 
 121 /* ------------------------ Mouse control ---------------------------
 122  *
 123  * Coordinates are in screen positions and zero based.
 124  * Mouse buttons are numbered from left to right and also zero based.
 125  */
 126 
 127 /* This used to be in termhooks.h, but mainstream Emacs code no longer
 128    uses it, and it was removed...  */
 129 #define NUM_MOUSE_BUTTONS (5)
 130 
 131 int have_mouse;          /* 0: no, 1: enabled, -1: disabled */
 132 static int mouse_visible;
 133 
 134 static int mouse_last_x;
 135 static int mouse_last_y;
 136 
 137 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
 138 static int mouse_button_count;
 139 
 140 void
 141 mouse_on ()
 142 {
 143   union REGS regs;
 144 
 145   if (have_mouse > 0 && !mouse_visible)
 146     {
 147       struct tty_display_info *tty = CURTTY ();
 148 
 149       if (tty->termscript)
 150         fprintf (tty->termscript, "<M_ON>");
 151       regs.x.ax = 0x0001;
 152       int86 (0x33, &regs, &regs);
 153       mouse_visible = 1;
 154     }
 155 }
 156 
 157 void
 158 mouse_off ()
 159 {
 160   union REGS regs;
 161 
 162   if (have_mouse > 0 && mouse_visible)
 163     {
 164       struct tty_display_info *tty = CURTTY ();
 165 
 166       if (tty->termscript)
 167         fprintf (tty->termscript, "<M_OFF>");
 168       regs.x.ax = 0x0002;
 169       int86 (0x33, &regs, &regs);
 170       mouse_visible = 0;
 171     }
 172 }
 173 
 174 static void
 175 mouse_setup_buttons (int n_buttons)
 176 {
 177   if (n_buttons == 3)
 178     {
 179       mouse_button_count = 3;
 180       mouse_button_translate[0] = 0; /* Left */
 181       mouse_button_translate[1] = 2; /* Middle */
 182       mouse_button_translate[2] = 1; /* Right */
 183     }
 184   else  /* two, what else? */
 185     {
 186       mouse_button_count = 2;
 187       mouse_button_translate[0] = 0;
 188       mouse_button_translate[1] = 1;
 189     }
 190 }
 191 
 192 DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons, Smsdos_set_mouse_buttons,
 193        1, 1, "NSet number of mouse buttons to: ",
 194        doc: /* Set the number of mouse buttons to use by Emacs.
 195 This is useful with mice that report the number of buttons inconsistently,
 196 e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
 197 them.  This happens with wheeled mice on Windows 9X, for example.  */)
 198      (nbuttons)
 199      Lisp_Object nbuttons;
 200 {
 201   int n;
 202 
 203   CHECK_NUMBER (nbuttons);
 204   n = XINT (nbuttons);
 205   if (n < 2 || n > 3)
 206     xsignal2 (Qargs_out_of_range,
 207               build_string ("only 2 or 3 mouse buttons are supported"),
 208               nbuttons);
 209   mouse_setup_buttons (n);
 210   return Qnil;
 211 }
 212 
 213 static void
 214 mouse_get_xy (int *x, int *y)
 215 {
 216   union REGS regs;
 217 
 218   regs.x.ax = 0x0003;
 219   int86 (0x33, &regs, &regs);
 220   *x = regs.x.cx / 8;
 221   *y = regs.x.dx / 8;
 222 }
 223 
 224 void
 225 mouse_moveto (x, y)
 226      int x, y;
 227 {
 228   union REGS regs;
 229   struct tty_display_info *tty = CURTTY ();
 230 
 231   if (tty->termscript)
 232     fprintf (tty->termscript, "<M_XY=%dx%d>", x, y);
 233   regs.x.ax = 0x0004;
 234   mouse_last_x = regs.x.cx = x * 8;
 235   mouse_last_y = regs.x.dx = y * 8;
 236   int86 (0x33, &regs, &regs);
 237 }
 238 
 239 static int
 240 mouse_pressed (b, xp, yp)
 241      int b, *xp, *yp;
 242 {
 243   union REGS regs;
 244 
 245   if (b >= mouse_button_count)
 246     return 0;
 247   regs.x.ax = 0x0005;
 248   regs.x.bx = mouse_button_translate[b];
 249   int86 (0x33, &regs, &regs);
 250   if (regs.x.bx)
 251     *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
 252   return (regs.x.bx != 0);
 253 }
 254 
 255 static int
 256 mouse_released (b, xp, yp)
 257      int b, *xp, *yp;
 258 {
 259   union REGS regs;
 260 
 261   if (b >= mouse_button_count)
 262     return 0;
 263   regs.x.ax = 0x0006;
 264   regs.x.bx = mouse_button_translate[b];
 265   int86 (0x33, &regs, &regs);
 266   if (regs.x.bx)
 267     *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
 268   return (regs.x.bx != 0);
 269 }
 270 
 271 static int
 272 mouse_button_depressed (b, xp, yp)
 273      int b, *xp, *yp;
 274 {
 275   union REGS regs;
 276 
 277   if (b >= mouse_button_count)
 278     return 0;
 279   regs.x.ax = 0x0003;
 280   int86 (0x33, &regs, &regs);
 281   if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
 282     {
 283       *xp = regs.x.cx / 8;
 284       *yp = regs.x.dx / 8;
 285       return 1;
 286     }
 287   return 0;
 288 }
 289 
 290 void
 291 mouse_get_pos (f, insist, bar_window, part, x, y, time)
 292      FRAME_PTR *f;
 293      int insist;
 294      Lisp_Object *bar_window, *x, *y;
 295      enum scroll_bar_part *part;
 296      unsigned long *time;
 297 {
 298   int ix, iy;
 299   Lisp_Object frame, tail;
 300 
 301   /* Clear the mouse-moved flag for every frame on this display.  */
 302   FOR_EACH_FRAME (tail, frame)
 303     XFRAME (frame)->mouse_moved = 0;
 304 
 305   *f = SELECTED_FRAME();
 306   *bar_window = Qnil;
 307   mouse_get_xy (&ix, &iy);
 308   *time = event_timestamp ();
 309   *x = make_number (mouse_last_x = ix);
 310   *y = make_number (mouse_last_y = iy);
 311 }
 312 
 313 static void
 314 mouse_check_moved ()
 315 {
 316   int x, y;
 317 
 318   mouse_get_xy (&x, &y);
 319   SELECTED_FRAME()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
 320   mouse_last_x = x;
 321   mouse_last_y = y;
 322 }
 323 
 324 /* Force the mouse driver to ``forget'' about any button clicks until
 325    now.  */
 326 static void
 327 mouse_clear_clicks (void)
 328 {
 329   int b;
 330 
 331   for (b = 0; b < mouse_button_count; b++)
 332     {
 333       int dummy_x, dummy_y;
 334 
 335       (void) mouse_pressed (b, &dummy_x, &dummy_y);
 336       (void) mouse_released (b, &dummy_x, &dummy_y);
 337     }
 338 }
 339 
 340 void
 341 mouse_init ()
 342 {
 343   union REGS regs;
 344   struct tty_display_info *tty = CURTTY ();
 345 
 346   if (tty->termscript)
 347     fprintf (tty->termscript, "<M_INIT>");
 348 
 349   regs.x.ax = 0x0021;
 350   int86 (0x33, &regs, &regs);
 351 
 352   /* Reset the mouse last press/release info.  It seems that Windows
 353      doesn't do that automatically when function 21h is called, which
 354      causes Emacs to ``remember'' the click that switched focus to the
 355      window just before Emacs was started from that window.  */
 356   mouse_clear_clicks ();
 357 
 358   regs.x.ax = 0x0007;
 359   regs.x.cx = 0;
 360   regs.x.dx = 8 * (ScreenCols () - 1);
 361   int86 (0x33, &regs, &regs);
 362 
 363   regs.x.ax = 0x0008;
 364   regs.x.cx = 0;
 365   regs.x.dx = 8 * (ScreenRows () - 1);
 366   int86 (0x33, &regs, &regs);
 367 
 368   mouse_moveto (0, 0);
 369   mouse_visible = 0;
 370 }
 371 
 372 /* ------------------------- Screen control ----------------------
 373  *
 374  */
 375 
 376 static int internal_terminal = 0;
 377 
 378 #ifndef HAVE_X_WINDOWS
 379 extern unsigned char ScreenAttrib;
 380 static int screen_face;
 381 
 382 static int screen_size_X;
 383 static int screen_size_Y;
 384 static int screen_size;
 385 
 386 static int current_pos_X;
 387 static int current_pos_Y;
 388 static int new_pos_X;
 389 static int new_pos_Y;
 390 
 391 static void *startup_screen_buffer;
 392 static int startup_screen_size_X;
 393 static int startup_screen_size_Y;
 394 static int startup_pos_X;
 395 static int startup_pos_Y;
 396 static unsigned char startup_screen_attrib;
 397 
 398 static clock_t startup_time;
 399 
 400 static int term_setup_done;
 401 
 402 static unsigned short outside_cursor;
 403 
 404 /* Similar to the_only_frame.  */
 405 struct tty_display_info the_only_display_info;
 406 
 407 /* Support for DOS/V (allows Japanese characters to be displayed on
 408    standard, non-Japanese, ATs).  Only supported for DJGPP v2 and later.  */
 409 
 410 /* Holds the address of the text-mode screen buffer.  */
 411 static unsigned long screen_old_address = 0;
 412 /* Segment and offset of the virtual screen.  If 0, DOS/V is NOT loaded.  */
 413 static unsigned short screen_virtual_segment = 0;
 414 static unsigned short screen_virtual_offset = 0;
 415 /* A flag to control how to display unibyte 8-bit characters.  */
 416 extern int unibyte_display_via_language_environment;
 417 
 418 extern Lisp_Object Qcursor_type;
 419 extern Lisp_Object Qbar, Qhbar;
 420 
 421 /* The screen colors of the current frame, which serve as the default
 422    colors for newly-created frames.  */
 423 static int initial_screen_colors[2];
 424 
 425 /* Update the screen from a part of relocated DOS/V screen buffer which
 426    begins at OFFSET and includes COUNT characters.  */
 427 static void
 428 dosv_refresh_virtual_screen (int offset, int count)
 429 {
 430   __dpmi_regs regs;
 431 
 432   if (offset < 0 || count < 0)  /* paranoia; invalid values crash DOS/V */
 433     return;
 434 
 435   regs.h.ah = 0xff;     /* update relocated screen */
 436   regs.x.es = screen_virtual_segment;
 437   regs.x.di = screen_virtual_offset + offset;
 438   regs.x.cx = count;
 439   __dpmi_int (0x10, &regs);
 440 }
 441 
 442 static void
 443 dos_direct_output (y, x, buf, len)
 444      int x, y;
 445      char *buf;
 446      int len;
 447 {
 448   int t0 = 2 * (x + y * screen_size_X);
 449   int t = t0 + (int) ScreenPrimary;
 450   int l0 = len;
 451 
 452   /* This is faster.  */
 453   for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
 454     _farnspokeb (t, *buf);
 455 
 456   if (screen_virtual_segment)
 457     dosv_refresh_virtual_screen (t0, l0);
 458 }
 459 #endif
 460 
 461 #ifndef HAVE_X_WINDOWS
 462 
 463 static int blink_bit = -1;      /* the state of the blink bit at startup */
 464 
 465 /* Enable bright background colors.  */
 466 static void
 467 bright_bg (void)
 468 {
 469   union REGS regs;
 470 
 471   /* Remember the original state of the blink/bright-background bit.
 472      It is stored at 0040:0065h in the BIOS data area.  */
 473   if (blink_bit == -1)
 474     blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
 475 
 476   regs.h.bl = 0;
 477   regs.x.ax = 0x1003;
 478   int86 (0x10, &regs, &regs);
 479 }
 480 
 481 /* Disable bright background colors (and enable blinking) if we found
 482    the video system in that state at startup.  */
 483 static void
 484 maybe_enable_blinking (void)
 485 {
 486   if (blink_bit == 1)
 487     {
 488       union REGS regs;
 489 
 490       regs.h.bl = 1;
 491       regs.x.ax = 0x1003;
 492       int86 (0x10, &regs, &regs);
 493     }
 494 }
 495 
 496 /* Return non-zero if the system has a VGA adapter.  */
 497 static int
 498 vga_installed (void)
 499 {
 500   union REGS regs;
 501 
 502   regs.x.ax = 0x1a00;
 503   int86 (0x10, &regs, &regs);
 504   if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
 505     return 1;
 506   return 0;
 507 }
 508 
 509 /* Set the screen dimensions so that it can show no less than
 510    ROWS x COLS frame.  */
 511 
 512 void
 513 dos_set_window_size (rows, cols)
 514      int *rows, *cols;
 515 {
 516   char video_name[30];
 517   union REGS regs;
 518   Lisp_Object video_mode;
 519   int video_mode_value, have_vga = 0;
 520   int current_rows = ScreenRows (), current_cols = ScreenCols ();
 521 
 522   if (*rows == current_rows && *cols == current_cols)
 523     return;
 524 
 525   mouse_off ();
 526   have_vga = vga_installed ();
 527 
 528   /* If the user specified a special video mode for these dimensions,
 529      use that mode.  */
 530   sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
 531   video_mode = Fsymbol_value (Fintern_soft (build_string (video_name), Qnil));
 532 
 533   if (INTEGERP (video_mode)
 534       && (video_mode_value = XINT (video_mode)) > 0)
 535     {
 536       regs.x.ax = video_mode_value;
 537       int86 (0x10, &regs, &regs);
 538 
 539       if (have_mouse)
 540         {
 541           /* Must hardware-reset the mouse, or else it won't update
 542              its notion of screen dimensions for some non-standard
 543              video modes.  This is *painfully* slow...  */
 544           regs.x.ax = 0;
 545           int86 (0x33, &regs, &regs);
 546         }
 547     }
 548 
 549   /* Find one of the dimensions supported by standard EGA/VGA
 550      which gives us at least the required dimensions.  */
 551   else
 552     {
 553       static struct {
 554         int rows, need_vga;
 555       } std_dimension[] = {
 556           {25, 0},
 557           {28, 1},
 558           {35, 0},
 559           {40, 1},
 560           {43, 0},
 561           {50, 1}
 562       };
 563       int i = 0;
 564 
 565       while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
 566         {
 567          if (std_dimension[i].need_vga <= have_vga
 568              && std_dimension[i].rows >= *rows)
 569            {
 570              if (std_dimension[i].rows != current_rows
 571                  || *cols != current_cols)
 572                _set_screen_lines (std_dimension[i].rows);
 573              break;
 574            }
 575          i++;
 576         }
 577     }
 578 
 579 
 580   if (have_mouse)
 581     {
 582       mouse_init ();
 583       mouse_on ();
 584     }
 585 
 586   /* Tell the caller what dimensions have been REALLY set.  */
 587   *rows = ScreenRows ();
 588   *cols = ScreenCols ();
 589 
 590   /* Update Emacs' notion of screen dimensions.  */
 591   screen_size_X = *cols;
 592   screen_size_Y = *rows;
 593   screen_size = *cols * *rows;
 594 
 595   /* If the dimensions changed, the mouse highlight info is invalid.  */
 596   if (current_rows != *rows || current_cols != *cols)
 597     {
 598       struct frame *f = SELECTED_FRAME();
 599       struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
 600       Lisp_Object window = dpyinfo->mouse_face_window;
 601 
 602       if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
 603         {
 604           dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
 605           dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
 606           dpyinfo->mouse_face_window = Qnil;
 607         }
 608     }
 609 
 610   /* Enable bright background colors.  */
 611   bright_bg ();
 612 
 613   /* FIXME: I'm not sure the above will run at all on DOS/V.  But let's
 614      be defensive anyway.  */
 615   if (screen_virtual_segment)
 616     dosv_refresh_virtual_screen (0, *cols * *rows);
 617 }
 618 
 619 /* If we write a character in the position where the mouse is,
 620    the mouse cursor may need to be refreshed.  */
 621 
 622 static void
 623 mouse_off_maybe ()
 624 {
 625   int x, y;
 626 
 627   if (!mouse_visible)
 628     return;
 629 
 630   mouse_get_xy (&x, &y);
 631   if (y != new_pos_Y || x < new_pos_X)
 632     return;
 633 
 634   mouse_off ();
 635 }
 636 
 637 #define DEFAULT_CURSOR_START (-1)
 638 #define DEFAULT_CURSOR_WIDTH (-1)
 639 #define BOX_CURSOR_WIDTH     (-32)
 640 
 641 /* Set cursor to begin at scan line START_LINE in the character cell
 642    and extend for WIDTH scan lines.  Scan lines are counted from top
 643    of the character cell, starting from zero.  */
 644 static void
 645 msdos_set_cursor_shape (struct frame *f, int start_line, int width)
 646 {
 647   unsigned desired_cursor;
 648   __dpmi_regs regs;
 649   int max_line, top_line, bot_line;
 650   struct tty_display_info *tty = FRAME_TTY (f);
 651 
 652   /* Avoid the costly BIOS call if F isn't the currently selected
 653      frame.  Allow for NULL as unconditionally meaning the selected
 654      frame.  */
 655   if (f && f != SELECTED_FRAME())
 656     return;
 657 
 658   if (tty->termscript)
 659     fprintf (tty->termscript, "\nCURSOR SHAPE=(%d,%d)", start_line, width);
 660 
 661   /* The character cell size in scan lines is stored at 40:85 in the
 662      BIOS data area.  */
 663   max_line = _farpeekw (_dos_ds, 0x485) - 1;
 664   switch (max_line)
 665     {
 666       default:  /* this relies on CGA cursor emulation being ON! */
 667       case 7:
 668         bot_line = 7;
 669         break;
 670       case 9:
 671         bot_line = 9;
 672         break;
 673       case 13:
 674         bot_line = 12;
 675         break;
 676       case 15:
 677         bot_line = 14;
 678         break;
 679     }
 680 
 681   if (width < 0)
 682     {
 683       if (width == BOX_CURSOR_WIDTH)
 684         {
 685           top_line = 0;
 686           bot_line = max_line;
 687         }
 688       else if (start_line != DEFAULT_CURSOR_START)
 689         {
 690           top_line = start_line;
 691           bot_line = top_line - width - 1;
 692         }
 693       else if (width != DEFAULT_CURSOR_WIDTH)
 694         {
 695           top_line = 0;
 696           bot_line = -1 - width;
 697         }
 698       else
 699         top_line = bot_line + 1;
 700     }
 701   else if (width == 0)
 702     {
 703       /* [31, 0] seems to DTRT for all screen sizes.  */
 704       top_line = 31;
 705       bot_line = 0;
 706     }
 707   else  /* WIDTH is positive */
 708     {
 709       if (start_line != DEFAULT_CURSOR_START)
 710         bot_line = start_line;
 711       top_line = bot_line - (width - 1);
 712     }
 713 
 714   /* If the current cursor shape is already what they want, we are
 715      history here.  */
 716   desired_cursor = ((top_line & 0x1f) << 8) | (bot_line & 0x1f);
 717   if (desired_cursor == _farpeekw (_dos_ds, 0x460))
 718     return;
 719 
 720   regs.h.ah = 1;
 721   regs.x.cx = desired_cursor;
 722   __dpmi_int (0x10, &regs);
 723 }
 724 
 725 static void
 726 IT_set_cursor_type (struct frame *f, Lisp_Object cursor_type)
 727 {
 728   if (EQ (cursor_type, Qbar) || EQ (cursor_type, Qhbar))
 729     {
 730       /* Just BAR means the normal EGA/VGA cursor.  */
 731       msdos_set_cursor_shape (f, DEFAULT_CURSOR_START, DEFAULT_CURSOR_WIDTH);
 732     }
 733   else if (CONSP (cursor_type)
 734            && (EQ (XCAR (cursor_type), Qbar)
 735                || EQ (XCAR (cursor_type), Qhbar)))
 736     {
 737       Lisp_Object bar_parms = XCDR (cursor_type);
 738       int width;
 739 
 740       if (INTEGERP (bar_parms))
 741         {
 742           /* Feature: negative WIDTH means cursor at the top
 743              of the character cell, zero means invisible cursor.  */
 744           width = XINT (bar_parms);
 745           msdos_set_cursor_shape (f, width >= 0 ? DEFAULT_CURSOR_START : 0,
 746                                   width);
 747         }
 748       else if (CONSP (bar_parms)
 749                && INTEGERP (XCAR (bar_parms))
 750                && INTEGERP (XCDR (bar_parms)))
 751         {
 752           int start_line = XINT (XCDR (bar_parms));
 753 
 754           width = XINT (XCAR (bar_parms));
 755           msdos_set_cursor_shape (f, start_line, width);
 756         }
 757     }
 758   else
 759     {
 760       /* Treat anything unknown as "box cursor".  This includes nil, so
 761          that a frame which doesn't specify a cursor type gets a box,
 762          which is the default in Emacs.  */
 763       msdos_set_cursor_shape (f, 0, BOX_CURSOR_WIDTH);
 764     }
 765 }
 766 
 767 static void
 768 IT_ring_bell (struct frame *f)
 769 {
 770   if (visible_bell)
 771     {
 772       mouse_off ();
 773       ScreenVisualBell ();
 774     }
 775   else
 776     {
 777       union REGS inregs, outregs;
 778       inregs.h.ah = 2;
 779       inregs.h.dl = 7;
 780       intdos (&inregs, &outregs);
 781     }
 782 }
 783 
 784 /* Given a face id FACE, extract the face parameters to be used for
 785    display until the face changes.  The face parameters (actually, its
 786    color) are used to construct the video attribute byte for each
 787    glyph during the construction of the buffer that is then blitted to
 788    the video RAM.  */
 789 static void
 790 IT_set_face (int face)
 791 {
 792   struct frame *sf = SELECTED_FRAME();
 793   struct face *fp  = FACE_FROM_ID (sf, face);
 794   struct face *dfp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
 795   unsigned long fg, bg, dflt_fg, dflt_bg;
 796   struct tty_display_info *tty = FRAME_TTY (sf);
 797 
 798   if (!fp)
 799     {
 800       fp = dfp;
 801       /* The default face for the frame should always be realized and
 802          cached.  */
 803       if (!fp)
 804         abort ();
 805     }
 806   screen_face = face;
 807   fg = fp->foreground;
 808   bg = fp->background;
 809   dflt_fg = dfp->foreground;
 810   dflt_bg = dfp->background;
 811 
 812   /* Don't use invalid colors.  In particular, FACE_TTY_DEFAULT_* colors
 813      mean use the colors of the default face.  Note that we assume all
 814      16 colors to be available for the background, since Emacs switches
 815      on this mode (and loses the blinking attribute) at startup.  */
 816   if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
 817     fg = FRAME_FOREGROUND_PIXEL (sf);
 818   else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
 819     fg = FRAME_BACKGROUND_PIXEL (sf);
 820   if (bg == FACE_TTY_DEFAULT_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR)
 821     bg = FRAME_BACKGROUND_PIXEL (sf);
 822   else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
 823     bg = FRAME_FOREGROUND_PIXEL (sf);
 824 
 825   /* Make sure highlighted lines really stand out, come what may.  */
 826   if (fp->tty_reverse_p && (fg == dflt_fg && bg == dflt_bg))
 827     {
 828       unsigned long tem = fg;
 829 
 830       fg = bg;
 831       bg = tem;
 832     }
 833   /* If the user requested inverse video, obey.  */
 834   if (inverse_video)
 835     {
 836       unsigned long tem2 = fg;
 837 
 838       fg = bg;
 839       bg = tem2;
 840     }
 841   if (tty->termscript)
 842     fprintf (tty->termscript, "<FACE %d: %d/%d[FG:%d/BG:%d]>", face,
 843              fp->foreground, fp->background, fg, bg);
 844   if (fg >= 0 && fg < 16)
 845     {
 846       ScreenAttrib &= 0xf0;
 847       ScreenAttrib |= fg;
 848     }
 849   if (bg >= 0 && bg < 16)
 850     {
 851       ScreenAttrib &= 0x0f;
 852       ScreenAttrib |= ((bg & 0x0f) << 4);
 853     }
 854 }
 855 
 856 /* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
 857    width of a DOS display in any known text mode.  We multiply by 2 to
 858    accomodate the screen attribute byte.  */
 859 #define MAX_SCREEN_BUF 160*2
 860 
 861 Lisp_Object Vdos_unsupported_char_glyph;
 862 extern unsigned char *encode_terminal_code (struct glyph *, int,
 863                                             struct coding_system *);
 864 static void
 865 IT_write_glyphs (struct frame *f, struct glyph *str, int str_len)
 866 {
 867   unsigned char screen_buf[MAX_SCREEN_BUF], *screen_bp, *bp;
 868   int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
 869   register int sl = str_len;
 870   struct tty_display_info *tty = FRAME_TTY (f);
 871   struct frame *sf;
 872   unsigned char *conversion_buffer;
 873 
 874   /* Do we need to consider conversion of unibyte characters to
 875      multibyte?  */
 876   int convert_unibyte_characters
 877     = (NILP (current_buffer->enable_multibyte_characters)
 878        && unibyte_display_via_language_environment);
 879 
 880   /* If terminal_coding does any conversion, use it, otherwise use
 881      safe_terminal_coding.  We can't use CODING_REQUIRE_ENCODING here
 882      because it always returns 1 if terminal_coding.src_multibyte is 1.  */
 883   struct coding_system *coding = FRAME_TERMINAL_CODING (f);
 884 
 885   if (!(coding->common_flags & CODING_REQUIRE_ENCODING_MASK))
 886     coding = &safe_terminal_coding;
 887 
 888   if (str_len <= 0) return;
 889 
 890   sf = SELECTED_FRAME();
 891 
 892   /* Since faces get cached and uncached behind our back, we can't
 893      rely on their indices in the cache being consistent across
 894      invocations.  So always reset the screen face to the default
 895      face of the frame, before writing glyphs, and let the glyphs
 896      set the right face if it's different from the default.  */
 897   IT_set_face (DEFAULT_FACE_ID);
 898 
 899   /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
 900      the tail.  */
 901   coding->mode &= ~CODING_MODE_LAST_BLOCK;
 902   screen_bp = &screen_buf[0];
 903   while (sl > 0)
 904     {
 905       int cf;
 906       int n;
 907 
 908       /* If the face of this glyph is different from the current
 909          screen face, update the screen attribute byte.  */
 910       cf = str->face_id;
 911       if (cf != screen_face)
 912         IT_set_face (cf);       /* handles invalid faces gracefully */
 913 
 914       /* Identify a run of glyphs with the same face.  */
 915       for (n = 1; n < sl; ++n)
 916         if (str[n].face_id != cf)
 917           break;
 918 
 919       if (n >= sl)
 920         /* This is the last glyph.  */
 921         coding->mode |= CODING_MODE_LAST_BLOCK;
 922 
 923       conversion_buffer = encode_terminal_code (str, n, coding);
 924       if (coding->produced > 0)
 925         {
 926           /* Copy the encoded bytes to the screen buffer.  */
 927           for (bp = conversion_buffer; coding->produced--; bp++)
 928             {
 929               /* Paranoia: discard bytes that would overrun the end of
 930                  the screen buffer.  */
 931               if (screen_bp - screen_buf <= MAX_SCREEN_BUF - 2)
 932                 {
 933                   *screen_bp++ = (unsigned char)*bp;
 934                   *screen_bp++ = ScreenAttrib;
 935                 }
 936               if (tty->termscript)
 937                 fputc (*bp, tty->termscript);
 938             }
 939         }
 940       /* Update STR and its remaining length.  */
 941       str += n;
 942       sl -= n;
 943     }
 944 
 945   /* Dump whatever we have in the screen buffer.  */
 946   mouse_off_maybe ();
 947   dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
 948   if (screen_virtual_segment)
 949     dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
 950   new_pos_X += (screen_bp - screen_buf) / 2;
 951 }
 952 
 953 /************************************************************************
 954                           Mouse Highlight (and friends..)
 955  ************************************************************************/
 956 
 957 /* Last window where we saw the mouse.  Used by mouse-autoselect-window.  */
 958 static Lisp_Object last_mouse_window;
 959 
 960 static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
 961 
 962 /* Set the mouse pointer shape according to whether it is in the
 963    area where the mouse highlight is in effect.  */
 964 static void
 965 IT_set_mouse_pointer (int mode)
 966 {
 967   /* A no-op for now.  DOS text-mode mouse pointer doesn't offer too
 968      many possibilities to change its shape, and the available
 969      functionality pretty much sucks (e.g., almost every reasonable
 970      shape will conceal the character it is on).  Since the color of
 971      the pointer changes in the highlighted area, it is not clear to
 972      me whether anything else is required, anyway.  */
 973 }
 974 
 975 /* Display the active region described by mouse_face_*
 976    in its mouse-face if HL > 0, in its normal face if HL = 0.  */
 977 static void
 978 show_mouse_face (struct tty_display_info *dpyinfo, int hl)
 979 {
 980   struct window *w = XWINDOW (dpyinfo->mouse_face_window);
 981   struct frame *f = XFRAME (WINDOW_FRAME (w));
 982   int i;
 983   struct face *fp;
 984   struct tty_display_info *tty = FRAME_TTY (f);
 985 
 986 
 987   /* If window is in the process of being destroyed, don't bother
 988      doing anything.  */
 989   if (w->current_matrix == NULL)
 990     goto set_cursor_shape;
 991 
 992   /* Recognize when we are called to operate on rows that don't exist
 993      anymore.  This can happen when a window is split.  */
 994   if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
 995     goto set_cursor_shape;
 996 
 997   /* There's no sense to do anything if the mouse face isn't realized.  */
 998   if (hl > 0)
 999     {
1000       if (dpyinfo->mouse_face_hidden)
1001         goto set_cursor_shape;
1002 
1003       fp = FACE_FROM_ID (SELECTED_FRAME(), dpyinfo->mouse_face_face_id);
1004       if (!fp)
1005         goto set_cursor_shape;
1006     }
1007 
1008   /* Note that mouse_face_beg_row etc. are window relative.  */
1009   for (i = dpyinfo->mouse_face_beg_row;
1010        i <= dpyinfo->mouse_face_end_row;
1011        i++)
1012     {
1013       int start_hpos, end_hpos;
1014       struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
1015 
1016       /* Don't do anything if row doesn't have valid contents.  */
1017       if (!row->enabled_p)
1018         continue;
1019 
1020       /* For all but the first row, the highlight starts at column 0.  */
1021       if (i == dpyinfo->mouse_face_beg_row)
1022         start_hpos = dpyinfo->mouse_face_beg_col;
1023       else
1024         start_hpos = 0;
1025 
1026       if (i == dpyinfo->mouse_face_end_row)
1027         end_hpos = dpyinfo->mouse_face_end_col;
1028       else
1029         end_hpos = row->used[TEXT_AREA];
1030 
1031       if (end_hpos <= start_hpos)
1032         continue;
1033       /* Record that some glyphs of this row are displayed in
1034          mouse-face.  */
1035       row->mouse_face_p = hl > 0;
1036       if (hl > 0)
1037         {
1038           int vpos = row->y + WINDOW_TOP_EDGE_Y (w);
1039           int kstart = start_hpos + WINDOW_LEFT_EDGE_X (w);
1040           int nglyphs = end_hpos - start_hpos;
1041           int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
1042           int start_offset = offset;
1043 
1044           if (tty->termscript)
1045             fprintf (tty->termscript, "\n<MH+ %d-%d:%d>",
1046                      kstart, kstart + nglyphs - 1, vpos);
1047 
1048           mouse_off ();
1049           IT_set_face (dpyinfo->mouse_face_face_id);
1050           /* Since we are going to change only the _colors_ of the
1051              displayed text, there's no need to go through all the
1052              pain of generating and encoding the text from the glyphs.
1053              Instead, we simply poke the attribute byte of each
1054              affected position in video memory with the colors
1055              computed by IT_set_face!  */
1056           _farsetsel (_dos_ds);
1057           while (nglyphs--)
1058             {
1059               _farnspokeb (offset, ScreenAttrib);
1060               offset += 2;
1061             }
1062           if (screen_virtual_segment)
1063             dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
1064           mouse_on ();
1065         }
1066       else
1067         {
1068           /* We are removing a previously-drawn mouse highlight.  The
1069              safest way to do so is to redraw the glyphs anew, since
1070              all kinds of faces and display tables could have changed
1071              behind our back.  */
1072           int nglyphs = end_hpos - start_hpos;
1073           int save_x = new_pos_X, save_y = new_pos_Y;
1074 
1075           if (end_hpos >= row->used[TEXT_AREA])
1076             nglyphs = row->used[TEXT_AREA] - start_hpos;
1077 
1078           /* IT_write_glyphs writes at cursor position, so we need to
1079              temporarily move cursor coordinates to the beginning of
1080              the highlight region.  */
1081           new_pos_X = start_hpos + WINDOW_LEFT_EDGE_X (w);
1082           new_pos_Y = row->y + WINDOW_TOP_EDGE_Y (w);
1083 
1084           if (tty->termscript)
1085             fprintf (tty->termscript, "<MH- %d-%d:%d>",
1086                      new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1087           IT_write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1088           if (tty->termscript)
1089             fputs ("\n", tty->termscript);
1090           new_pos_X = save_x;
1091           new_pos_Y = save_y;
1092         }
1093     }
1094 
1095  set_cursor_shape:
1096   /* Change the mouse pointer shape.  */
1097   IT_set_mouse_pointer (hl);
1098 }
1099 
1100 /* Clear out the mouse-highlighted active region.
1101    Redraw it un-highlighted first.  */
1102 static void
1103 clear_mouse_face (struct tty_display_info *dpyinfo)
1104 {
1105   if (!dpyinfo->mouse_face_hidden && ! NILP (dpyinfo->mouse_face_window))
1106     show_mouse_face (dpyinfo, 0);
1107 
1108   dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1109   dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1110   dpyinfo->mouse_face_window = Qnil;
1111 }
1112 
1113 /* Find the glyph matrix position of buffer position POS in window W.
1114    *HPOS and *VPOS are set to the positions found.  W's current glyphs
1115    must be up to date.  If POS is above window start return (0, 0).
1116    If POS is after end of W, return end of last line in W.  */
1117 static int
1118 fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
1119 {
1120   int i, lastcol, line_start_position, maybe_next_line_p = 0;
1121   int yb = window_text_bottom_y (w);
1122   struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0), *best_row = row;
1123 
1124   while (row->y < yb)
1125     {
1126       if (row->used[TEXT_AREA])
1127         line_start_position = row->glyphs[TEXT_AREA]->charpos;
1128       else
1129         line_start_position = 0;
1130 
1131       if (line_start_position > pos)
1132         break;
1133       /* If the position sought is the end of the buffer,
1134          don't include the blank lines at the bottom of the window.  */
1135       else if (line_start_position == pos
1136                && pos == BUF_ZV (XBUFFER (w->buffer)))
1137         {
1138           maybe_next_line_p = 1;
1139           break;
1140         }
1141       else if (line_start_position > 0)
1142         best_row = row;
1143 
1144       /* Don't overstep the last matrix row, lest we get into the
1145          never-never land... */
1146       if (row->y + 1 >= yb)
1147         break;
1148 
1149       ++row;
1150     }
1151 
1152   /* Find the right column within BEST_ROW.  */
1153   lastcol = 0;
1154   row = best_row;
1155   for (i = 0; i < row->used[TEXT_AREA]; i++)
1156     {
1157       struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
1158       int charpos;
1159 
1160       charpos = glyph->charpos;
1161       if (charpos == pos)
1162         {
1163           *hpos = i;
1164           *vpos = row->y;
1165           return 1;
1166         }
1167       else if (charpos > pos)
1168         break;
1169       else if (charpos > 0)
1170         lastcol = i;
1171     }
1172 
1173   /* If we're looking for the end of the buffer,
1174      and we didn't find it in the line we scanned,
1175      use the start of the following line.  */
1176   if (maybe_next_line_p)
1177     {
1178       ++row;
1179       lastcol = 0;
1180     }
1181 
1182   *vpos = row->y;
1183   *hpos = lastcol + 1;
1184   return 0;
1185 }
1186 
1187 /* Take proper action when mouse has moved to the mode or top line of
1188    window W, x-position X.  MODE_LINE_P non-zero means mouse is on the
1189    mode line.  X is relative to the start of the text display area of
1190    W, so the width of fringes and scroll bars must be subtracted
1191    to get a position relative to the start of the mode line.  */
1192 static void
1193 IT_note_mode_line_highlight (struct window *w, int x, int mode_line_p)
1194 {
1195   struct frame *f = XFRAME (w->frame);
1196   struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1197   struct glyph_row *row;
1198 
1199   if (mode_line_p)
1200     row = MATRIX_MODE_LINE_ROW (w->current_matrix);
1201   else
1202     row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
1203 
1204   if (row->enabled_p)
1205     {
1206       extern Lisp_Object Qhelp_echo;
1207       struct glyph *glyph, *end;
1208       Lisp_Object help, map;
1209 
1210       /* Find the glyph under X.  */
1211       glyph = (row->glyphs[TEXT_AREA]
1212                + x
1213                /* in case someone implements scroll bars some day... */
1214                - WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w));
1215       end = glyph + row->used[TEXT_AREA];
1216       if (glyph < end
1217           && STRINGP (glyph->object)
1218           && STRING_INTERVALS (glyph->object)
1219           && glyph->charpos >= 0
1220           && glyph->charpos < SCHARS (glyph->object))
1221         {
1222           /* If we're on a string with `help-echo' text property,
1223              arrange for the help to be displayed.  This is done by
1224              setting the global variable help_echo to the help string.  */
1225           help = Fget_text_property (make_number (glyph->charpos),
1226                                      Qhelp_echo, glyph->object);
1227           if (!NILP (help))
1228             {
1229               help_echo_string = help;
1230               XSETWINDOW (help_echo_window, w);
1231               help_echo_object = glyph->object;
1232               help_echo_pos = glyph->charpos;
1233             }
1234         }
1235     }
1236 }
1237 
1238 /* Take proper action when the mouse has moved to position X, Y on
1239    frame F as regards highlighting characters that have mouse-face
1240    properties.  Also de-highlighting chars where the mouse was before.
1241    X and Y can be negative or out of range.  */
1242 static void
1243 IT_note_mouse_highlight (struct frame *f, int x, int y)
1244 {
1245   struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1246   enum window_part part = ON_NOTHING;
1247   Lisp_Object window;
1248   struct window *w;
1249 
1250   /* When a menu is active, don't highlight because this looks odd.  */
1251   if (mouse_preempted)
1252     return;
1253 
1254   if (NILP (Vmouse_highlight)
1255       || !f->glyphs_initialized_p)
1256     return;
1257 
1258   dpyinfo->mouse_face_mouse_x = x;
1259   dpyinfo->mouse_face_mouse_y = y;
1260   dpyinfo->mouse_face_mouse_frame = f;
1261 
1262   if (dpyinfo->mouse_face_defer)
1263     return;
1264 
1265   if (gc_in_progress)
1266     {
1267       dpyinfo->mouse_face_deferred_gc = 1;
1268       return;
1269     }
1270 
1271   /* Which window is that in?  */
1272   window = window_from_coordinates (f, x, y, &part, &x, &y, 0);
1273 
1274   /* If we were displaying active text in another window, clear that.  */
1275   if (! EQ (window, dpyinfo->mouse_face_window))
1276     clear_mouse_face (dpyinfo);
1277 
1278   /* Not on a window -> return.  */
1279   if (!WINDOWP (window))
1280     return;
1281 
1282   /* Convert to window-relative coordinates.  */
1283   w = XWINDOW (window);
1284 
1285   if (part == ON_MODE_LINE || part == ON_HEADER_LINE)
1286     {
1287       /* Mouse is on the mode or top line.  */
1288       IT_note_mode_line_highlight (w, x, part == ON_MODE_LINE);
1289       return;
1290     }
1291 
1292   IT_set_mouse_pointer (0);
1293 
1294   /* Are we in a window whose display is up to date?
1295      And verify the buffer's text has not changed.  */
1296   if (part == ON_TEXT
1297       && EQ (w->window_end_valid, w->buffer)
1298       && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
1299       && (XFASTINT (w->last_overlay_modified)
1300           == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
1301     {
1302       int pos, i, nrows = w->current_matrix->nrows;
1303       struct glyph_row *row;
1304       struct glyph *glyph;
1305 
1306       /* Find the glyph under X/Y.  */
1307       glyph = NULL;
1308       if (y >= 0 && y < nrows)
1309         {
1310           row = MATRIX_ROW (w->current_matrix, y);
1311           /* Give up if some row before the one we are looking for is
1312              not enabled.  */
1313           for (i = 0; i <= y; i++)
1314             if (!MATRIX_ROW (w->current_matrix, i)->enabled_p)
1315               break;
1316           if (i > y  /* all rows upto and including the one at Y are enabled */
1317               && row->displays_text_p
1318               && x <  window_box_width (w, TEXT_AREA))
1319             {
1320               glyph = row->glyphs[TEXT_AREA];
1321               if (x >= row->used[TEXT_AREA])
1322                 glyph = NULL;
1323               else
1324                 {
1325                   glyph += x;
1326                   if (!BUFFERP (glyph->object))
1327                     glyph = NULL;
1328                 }
1329             }
1330         }
1331 
1332       /* Clear mouse face if X/Y not over text.  */
1333       if (glyph == NULL)
1334         {
1335           clear_mouse_face (dpyinfo);
1336           return;
1337         }
1338 
1339       if (!BUFFERP (glyph->object))
1340         abort ();
1341       pos = glyph->charpos;
1342 
1343       /* Check for mouse-face and help-echo.  */
1344       {
1345         extern Lisp_Object Qmouse_face;
1346         Lisp_Object mouse_face, overlay, position, *overlay_vec;
1347         int noverlays, obegv, ozv;
1348         struct buffer *obuf;
1349 
1350         /* If we get an out-of-range value, return now; avoid an error.  */
1351         if (pos > BUF_Z (XBUFFER (w->buffer)))
1352           return;
1353 
1354         /* Make the window's buffer temporarily current for
1355            overlays_at and compute_char_face.  */
1356         obuf = current_buffer;
1357         current_buffer = XBUFFER (w->buffer);
1358         obegv = BEGV;
1359         ozv = ZV;
1360         BEGV = BEG;
1361         ZV = Z;
1362 
1363         /* Is this char mouse-active or does it have help-echo?  */
1364         XSETINT (position, pos);
1365 
1366         /* Put all the overlays we want in a vector in overlay_vec. */
1367         GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0);
1368         /* Sort overlays into increasing priority order.  */
1369         noverlays = sort_overlays (overlay_vec, noverlays, w);
1370 
1371         /* Check mouse-face highlighting.  */
1372         if (! (EQ (window, dpyinfo->mouse_face_window)
1373                && y >= dpyinfo->mouse_face_beg_row
1374                && y <= dpyinfo->mouse_face_end_row
1375                && (y > dpyinfo->mouse_face_beg_row
1376                    || x >= dpyinfo->mouse_face_beg_col)
1377                && (y < dpyinfo->mouse_face_end_row
1378                    || x < dpyinfo->mouse_face_end_col
1379                    || dpyinfo->mouse_face_past_end)))
1380           {
1381             /* Clear the display of the old active region, if any.  */
1382             clear_mouse_face (dpyinfo);
1383 
1384             /* Find highest priority overlay that has a mouse-face prop.  */
1385             overlay = Qnil;
1386             for (i = noverlays - 1; i >= 0; --i)
1387               {
1388                 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
1389                 if (!NILP (mouse_face))
1390                   {
1391                     overlay = overlay_vec[i];
1392                     break;
1393                   }
1394               }
1395 
1396             /* If no overlay applies, get a text property.  */
1397             if (NILP (overlay))
1398               mouse_face = Fget_text_property (position, Qmouse_face,
1399                                                w->buffer);
1400 
1401             /* Handle the overlay case.  */
1402             if (! NILP (overlay))
1403               {
1404                 /* Find the range of text around this char that
1405                    should be active.  */
1406                 Lisp_Object before, after;
1407                 EMACS_INT ignore;
1408 
1409                 before = Foverlay_start (overlay);
1410                 after = Foverlay_end (overlay);
1411                 /* Record this as the current active region.  */
1412                 fast_find_position (w, XFASTINT (before),
1413                                     &dpyinfo->mouse_face_beg_col,
1414                                     &dpyinfo->mouse_face_beg_row);
1415                 dpyinfo->mouse_face_past_end
1416                   = !fast_find_position (w, XFASTINT (after),
1417                                          &dpyinfo->mouse_face_end_col,
1418                                          &dpyinfo->mouse_face_end_row);
1419                 dpyinfo->mouse_face_window = window;
1420                 dpyinfo->mouse_face_face_id
1421                   = face_at_buffer_position (w, pos, 0, 0,
1422                                              &ignore, pos + 1,
1423                                              !dpyinfo->mouse_face_hidden,
1424                                              -1);
1425 
1426                 /* Display it as active.  */
1427                 show_mouse_face (dpyinfo, 1);
1428               }
1429             /* Handle the text property case.  */
1430             else if (! NILP (mouse_face))
1431               {
1432                 /* Find the range of text around this char that
1433                    should be active.  */
1434                 Lisp_Object before, after, beginning, end;
1435                 EMACS_INT ignore;
1436 
1437                 beginning = Fmarker_position (w->start);
1438                 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
1439                                - XFASTINT (w->window_end_pos)));
1440                 before
1441                   = Fprevious_single_property_change (make_number (pos + 1),
1442                                                       Qmouse_face,
1443                                                       w->buffer, beginning);
1444                 after
1445                   = Fnext_single_property_change (position, Qmouse_face,
1446                                                   w->buffer, end);
1447                 /* Record this as the current active region.  */
1448                 fast_find_position (w, XFASTINT (before),
1449                                     &dpyinfo->mouse_face_beg_col,
1450                                     &dpyinfo->mouse_face_beg_row);
1451                 dpyinfo->mouse_face_past_end
1452                   = !fast_find_position (w, XFASTINT (after),
1453                                          &dpyinfo->mouse_face_end_col,
1454                                          &dpyinfo->mouse_face_end_row);
1455                 dpyinfo->mouse_face_window = window;
1456                 dpyinfo->mouse_face_face_id
1457                   = face_at_buffer_position (w, pos, 0, 0,
1458                                              &ignore, pos + 1,
1459                                              !dpyinfo->mouse_face_hidden,
1460                                              -1);
1461 
1462                 /* Display it as active.  */
1463                 show_mouse_face (dpyinfo, 1);
1464               }
1465           }
1466 
1467         /* Look for a `help-echo' property.  */
1468         {
1469           Lisp_Object help;
1470           extern Lisp_Object Qhelp_echo;
1471 
1472           /* Check overlays first.  */
1473           help = Qnil;
1474           for (i = noverlays - 1; i >= 0 && NILP (help); --i)
1475             {
1476               overlay = overlay_vec[i];
1477               help = Foverlay_get (overlay, Qhelp_echo);
1478             }
1479 
1480           if (!NILP (help))
1481             {
1482               help_echo_string = help;
1483               help_echo_window = window;
1484               help_echo_object = overlay;
1485               help_echo_pos = pos;
1486             }
1487           /* Try text properties.  */
1488           else if (NILP (help)
1489                    && ((STRINGP (glyph->object)
1490                         && glyph->charpos >= 0
1491                         && glyph->charpos < SCHARS (glyph->object))
1492                        || (BUFFERP (glyph->object)
1493                            && glyph->charpos >= BEGV
1494                            && glyph->charpos < ZV)))
1495             {
1496               help = Fget_text_property (make_number (glyph->charpos),
1497                                          Qhelp_echo, glyph->object);
1498               if (!NILP (help))
1499                 {
1500                   help_echo_string = help;
1501                   help_echo_window = window;
1502                   help_echo_object = glyph->object;
1503                   help_echo_pos = glyph->charpos;
1504                 }
1505             }
1506         }
1507 
1508         BEGV = obegv;
1509         ZV = ozv;
1510         current_buffer = obuf;
1511       }
1512     }
1513 }
1514 
1515 static void
1516 IT_clear_end_of_line (struct frame *f, int first_unused)
1517 {
1518   char *spaces, *sp;
1519   int i, j, offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
1520   extern int fatal_error_in_progress;
1521   struct tty_display_info *tty = FRAME_TTY (f);
1522 
1523   if (new_pos_X >= first_unused || fatal_error_in_progress)
1524     return;
1525 
1526   IT_set_face (0);
1527   i = (j = first_unused - new_pos_X) * 2;
1528   if (tty->termscript)
1529     fprintf (tty->termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
1530   spaces = sp = alloca (i);
1531 
1532   while (--j >= 0)
1533     {
1534       *sp++ = ' ';
1535       *sp++ = ScreenAttrib;
1536     }
1537 
1538   mouse_off_maybe ();
1539   dosmemput (spaces, i, (int)ScreenPrimary + offset);
1540   if (screen_virtual_segment)
1541     dosv_refresh_virtual_screen (offset, i / 2);
1542 
1543   /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1544      Let's follow their lead, in case someone relies on this.  */
1545   new_pos_X = first_unused;
1546 }
1547 
1548 static void
1549 IT_clear_screen (struct frame *f)
1550 {
1551   struct tty_display_info *tty = FRAME_TTY (f);
1552 
1553   if (tty->termscript)
1554     fprintf (tty->termscript, "<CLR:SCR>");
1555   /* We are sometimes called (from clear_garbaged_frames) when a new
1556      frame is being created, but its faces are not yet realized.  In
1557      such a case we cannot call IT_set_face, since it will fail to find
1558      any valid faces and will abort.  Instead, use the initial screen
1559      colors; that should mimic what a Unix tty does, which simply clears
1560      the screen with whatever default colors are in use.  */
1561   if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID) == NULL)
1562     ScreenAttrib = (initial_screen_colors[0] << 4) | initial_screen_colors[1];
1563   else
1564     IT_set_face (0);
1565   mouse_off ();
1566   ScreenClear ();
1567   if (screen_virtual_segment)
1568     dosv_refresh_virtual_screen (0, screen_size);
1569   new_pos_X = new_pos_Y = 0;
1570 }
1571 
1572 static void
1573 IT_clear_to_end (struct frame *f)
1574 {
1575   struct tty_display_info *tty = FRAME_TTY (f);
1576 
1577   if (tty->termscript)
1578     fprintf (tty->termscript, "<CLR:EOS>");
1579 
1580   while (new_pos_Y < screen_size_Y) {
1581     new_pos_X = 0;
1582     IT_clear_end_of_line (f, screen_size_X);
1583     new_pos_Y++;
1584   }
1585 }
1586 
1587 static void
1588 IT_cursor_to (struct frame *f, int y, int x)
1589 {
1590   struct tty_display_info *tty = FRAME_TTY (f);
1591 
1592   if (tty->termscript)
1593     fprintf (tty->termscript, "\n<XY=%dx%d>", x, y);
1594   new_pos_X = x;
1595   new_pos_Y = y;
1596 }
1597 
1598 static int cursor_cleared;
1599 
1600 static void
1601 IT_display_cursor (int on)
1602 {
1603   struct tty_display_info *tty = CURTTY ();
1604 
1605   if (on && cursor_cleared)
1606     {
1607       ScreenSetCursor (current_pos_Y, current_pos_X);
1608       cursor_cleared = 0;
1609       if (tty->termscript)
1610         fprintf (tty->termscript, "\nCURSOR ON");
1611     }
1612   else if (!on && !cursor_cleared)
1613     {
1614       ScreenSetCursor (-1, -1);
1615       cursor_cleared = 1;
1616       if (tty->termscript)
1617         fprintf (tty->termscript, "\nCURSOR OFF");
1618     }
1619 }
1620 
1621 /* Emacs calls cursor-movement functions a lot when it updates the
1622    display (probably a legacy of old terminals where you cannot
1623    update a screen line without first moving the cursor there).
1624    However, cursor movement is expensive on MSDOS (it calls a slow
1625    BIOS function and requires 2 mode switches), while actual screen
1626    updates access the video memory directly and don't depend on
1627    cursor position.  To avoid slowing down the redisplay, we cheat:
1628    all functions that move the cursor only set internal variables
1629    which record the cursor position, whereas the cursor is only
1630    moved to its final position whenever screen update is complete.
1631 
1632    `IT_cmgoto' is called from the keyboard reading loop and when the
1633    frame update is complete.  This means that we are ready for user
1634    input, so we update the cursor position to show where the point is,
1635    and also make the mouse pointer visible.
1636 
1637    Special treatment is required when the cursor is in the echo area,
1638    to put the cursor at the end of the text displayed there.  */
1639 
1640 static void
1641 IT_cmgoto (FRAME_PTR f)
1642 {
1643   /* Only set the cursor to where it should be if the display is
1644      already in sync with the window contents.  */
1645   int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1646   struct tty_display_info *tty = FRAME_TTY (f);
1647 
1648   /* FIXME: This needs to be rewritten for the new redisplay, or
1649      removed.  */
1650 #if 0
1651   static int previous_pos_X = -1;
1652 
1653   update_cursor_pos = 1;        /* temporary!!! */
1654 
1655   /* If the display is in sync, forget any previous knowledge about
1656      cursor position.  This is primarily for unexpected events like
1657      C-g in the minibuffer.  */
1658   if (update_cursor_pos && previous_pos_X >= 0)
1659     previous_pos_X = -1;
1660   /* If we are in the echo area, put the cursor at the
1661      end of the echo area message.  */
1662   if (!update_cursor_pos
1663       && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f))) <= new_pos_Y)
1664     {
1665       int tem_X = current_pos_X, dummy;
1666 
1667       if (echo_area_glyphs)
1668         {
1669           tem_X = echo_area_glyphs_length;
1670           /* Save current cursor position, to be restored after the
1671              echo area message is erased.  Only remember one level
1672              of previous cursor position.  */
1673           if (previous_pos_X == -1)
1674             ScreenGetCursor (&dummy, &previous_pos_X);
1675         }
1676       else if (previous_pos_X >= 0)
1677         {
1678           /* We wind up here after the echo area message is erased.
1679              Restore the cursor position we remembered above.  */
1680           tem_X = previous_pos_X;
1681           previous_pos_X = -1;
1682         }
1683 
1684       if (current_pos_X != tem_X)
1685         {
1686           new_pos_X = tem_X;
1687           update_cursor_pos = 1;
1688         }
1689     }
1690 #endif
1691 
1692   if (update_cursor_pos
1693       && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1694     {
1695       ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1696       if (tty->termscript)
1697         fprintf (tty->termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1698     }
1699 
1700   /* Maybe cursor is invisible, so make it visible.  */
1701   IT_display_cursor (1);
1702 
1703   /* Mouse pointer should be always visible if we are waiting for
1704      keyboard input.  */
1705   if (!mouse_visible)
1706     mouse_on ();
1707 }
1708 
1709 static void
1710 IT_update_begin (struct frame *f)
1711 {
1712   struct tty_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
1713   struct frame *mouse_face_frame = display_info->mouse_face_mouse_frame;
1714 
1715   if (display_info->termscript)
1716     fprintf (display_info->termscript, "\n\n<UPDATE_BEGIN");
1717 
1718   BLOCK_INPUT;
1719 
1720   if (f && f == mouse_face_frame)
1721     {
1722       /* Don't do highlighting for mouse motion during the update.  */
1723       display_info->mouse_face_defer = 1;
1724 
1725       /* If F needs to be redrawn, simply forget about any prior mouse
1726          highlighting.  */
1727       if (FRAME_GARBAGED_P (f))
1728         display_info->mouse_face_window = Qnil;
1729 
1730       /* Can we tell that this update does not affect the window
1731          where the mouse highlight is?  If so, no need to turn off.
1732          Likewise, don't do anything if none of the enabled rows
1733          contains glyphs highlighted in mouse face.  */
1734       if (!NILP (display_info->mouse_face_window)
1735           && WINDOWP (display_info->mouse_face_window))
1736         {
1737           struct window *w = XWINDOW (display_info->mouse_face_window);
1738           int i;
1739 
1740           /* If the mouse highlight is in the window that was deleted
1741              (e.g., if it was popped by completion), clear highlight
1742              unconditionally.  */
1743           if (NILP (w->buffer))
1744             display_info->mouse_face_window = Qnil;
1745           else
1746             {
1747               for (i = 0; i < w->desired_matrix->nrows; ++i)
1748                 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)
1749                     && MATRIX_ROW (w->current_matrix, i)->mouse_face_p)
1750                   break;
1751             }
1752 
1753           if (NILP (w->buffer) || i < w->desired_matrix->nrows)
1754             clear_mouse_face (display_info);
1755         }
1756     }
1757   else if (mouse_face_frame && !FRAME_LIVE_P (mouse_face_frame))
1758     {
1759       /* If the frame with mouse highlight was deleted, invalidate the
1760          highlight info.  */
1761       display_info->mouse_face_beg_row = display_info->mouse_face_beg_col = -1;
1762       display_info->mouse_face_end_row = display_info->mouse_face_end_col = -1;
1763       display_info->mouse_face_window = Qnil;
1764       display_info->mouse_face_deferred_gc = 0;
1765       display_info->mouse_face_mouse_frame = NULL;
1766     }
1767 
1768   UNBLOCK_INPUT;
1769 }
1770 
1771 static void
1772 IT_update_end (struct frame *f)
1773 {
1774   struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1775 
1776   if (dpyinfo->termscript)
1777     fprintf (dpyinfo->termscript, "\n<UPDATE_END\n");
1778   dpyinfo->mouse_face_defer = 0;
1779 }
1780 
1781 static void
1782 IT_frame_up_to_date (struct frame *f)
1783 {
1784   struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1785   Lisp_Object new_cursor, frame_desired_cursor;
1786   struct window *sw;
1787 
1788   if (dpyinfo->mouse_face_deferred_gc
1789       || (f && f == dpyinfo->mouse_face_mouse_frame))
1790     {
1791       BLOCK_INPUT;
1792       if (dpyinfo->mouse_face_mouse_frame)
1793         IT_note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1794                                  dpyinfo->mouse_face_mouse_x,
1795                                  dpyinfo->mouse_face_mouse_y);
1796       dpyinfo->mouse_face_deferred_gc = 0;
1797       UNBLOCK_INPUT;
1798     }
1799 
1800   /* Set the cursor type to whatever they wanted.  In a minibuffer
1801      window, we want the cursor to appear only if we are reading input
1802      from this window, and we want the cursor to be taken from the
1803      frame parameters.  For the selected window, we use either its
1804      buffer-local value or the value from the frame parameters if the
1805      buffer doesn't define its local value for the cursor type.  */
1806   sw = XWINDOW (f->selected_window);
1807   frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
1808   if (cursor_in_echo_area
1809       && FRAME_HAS_MINIBUF_P (f)
1810       && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
1811       && sw == XWINDOW (echo_area_window))
1812     new_cursor = frame_desired_cursor;
1813   else
1814     {
1815       struct buffer *b = XBUFFER (sw->buffer);
1816 
1817       if (EQ (b->cursor_type, Qt))
1818         new_cursor = frame_desired_cursor;
1819       else if (NILP (b->cursor_type)) /* nil means no cursor */
1820         new_cursor = Fcons (Qbar, make_number (0));
1821       else
1822         new_cursor = b->cursor_type;
1823     }
1824 
1825   IT_set_cursor_type (f, new_cursor);
1826 
1827   IT_cmgoto (f);  /* position cursor when update is done */
1828 }
1829 
1830 /* Copy LEN glyphs displayed on a single line whose vertical position
1831    is YPOS, beginning at horizontal position XFROM to horizontal
1832    position XTO, by moving blocks in the video memory.  Used by
1833    functions that insert and delete glyphs.  */
1834 static void
1835 IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1836 {
1837   /* The offsets of source and destination relative to the
1838      conventional memorty selector.  */
1839   int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1840   int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1841 
1842   if (from == to || len <= 0)
1843     return;
1844 
1845   _farsetsel (_dos_ds);
1846 
1847   /* The source and destination might overlap, so we need to move
1848      glyphs non-destructively.  */
1849   if (from > to)
1850     {
1851       for ( ; len; from += 2, to += 2, len--)
1852         _farnspokew (to, _farnspeekw (from));
1853     }
1854   else
1855     {
1856       from += (len - 1) * 2;
1857       to += (len - 1) * 2;
1858       for ( ; len; from -= 2, to -= 2, len--)
1859         _farnspokew (to, _farnspeekw (from));
1860     }
1861   if (screen_virtual_segment)
1862     dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1863 }
1864 
1865 /* Insert and delete glyphs.  */
1866 static void
1867 IT_insert_glyphs (f, start, len)
1868      struct frame *f;
1869      register struct glyph *start;
1870      register int len;
1871 {
1872   int shift_by_width = screen_size_X - (new_pos_X + len);
1873 
1874   /* Shift right the glyphs from the nominal cursor position to the
1875      end of this line.  */
1876   IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
1877 
1878   /* Now write the glyphs to be inserted.  */
1879   IT_write_glyphs (f, start, len);
1880 }
1881 
1882 static void
1883 IT_delete_glyphs (f, n)
1884      struct frame *f;
1885      register int n;
1886 {
1887   abort ();
1888 }
1889 
1890 /* set-window-configuration on window.c needs this.  */
1891 void
1892 x_set_menu_bar_lines (f, value, oldval)
1893      struct frame *f;
1894      Lisp_Object value, oldval;
1895 {
1896   set_menu_bar_lines (f, value, oldval);
1897 }
1898 
1899 /* This was copied from xfaces.c  */
1900 
1901 extern Lisp_Object Qbackground_color;
1902 extern Lisp_Object Qforeground_color;
1903 Lisp_Object Qreverse;
1904 extern Lisp_Object Qtitle;
1905 
1906 /* IT_set_terminal_modes is called when emacs is started,
1907    resumed, and whenever the screen is redrawn!  */
1908 
1909 static void
1910 IT_set_terminal_modes (struct terminal *term)
1911 {
1912   struct tty_display_info *tty;
1913 
1914   /* If called with initial terminal, it's too early to do anything
1915      useful.  */
1916   if (term->type == output_initial)
1917     return;
1918 
1919   tty = term->display_info.tty;
1920 
1921   if (tty->termscript)
1922     fprintf (tty->termscript, "\n<SET_TERM>");
1923 
1924   screen_size_X = ScreenCols ();
1925   screen_size_Y = ScreenRows ();
1926   screen_size = screen_size_X * screen_size_Y;
1927 
1928   new_pos_X = new_pos_Y = 0;
1929   current_pos_X = current_pos_Y = -1;
1930 
1931   if (term_setup_done)
1932     return;
1933   term_setup_done = 1;
1934 
1935   startup_screen_size_X = screen_size_X;
1936   startup_screen_size_Y = screen_size_Y;
1937   startup_screen_attrib = ScreenAttrib;
1938 
1939   /* Is DOS/V (or any other RSIS software which relocates
1940      the screen) installed?  */
1941   {
1942     unsigned short es_value;
1943     __dpmi_regs regs;
1944 
1945     regs.h.ah = 0xfe;   /* get relocated screen address */
1946     if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
1947       regs.x.es = (ScreenPrimary >> 4) & 0xffff;
1948     else if (screen_old_address) /* already switched to Japanese mode once */
1949       regs.x.es = (screen_old_address >> 4) & 0xffff;
1950     else
1951       regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
1952     regs.x.di = 0;
1953     es_value = regs.x.es;
1954     __dpmi_int (0x10, &regs);
1955 
1956     if (regs.x.es != es_value)
1957       {
1958         /* screen_old_address is only set if ScreenPrimary does NOT
1959            already point to the relocated buffer address returned by
1960            the Int 10h/AX=FEh call above.  DJGPP v2.02 and later sets
1961            ScreenPrimary to that address at startup under DOS/V.  */
1962         if (regs.x.es != (ScreenPrimary >> 4) & 0xffff)
1963           screen_old_address = ScreenPrimary;
1964         screen_virtual_segment = regs.x.es;
1965         screen_virtual_offset  = regs.x.di;
1966         ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
1967       }
1968   }
1969 
1970   ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
1971   ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
1972 
1973   bright_bg ();
1974 }
1975 
1976 /* IT_reset_terminal_modes is called when emacs is
1977    suspended or killed.  */
1978 
1979 static void
1980 IT_reset_terminal_modes (struct terminal *term)
1981 {
1982   int display_row_start = (int) ScreenPrimary;
1983   int saved_row_len     = startup_screen_size_X * 2;
1984   int update_row_len    = ScreenCols () * 2, current_rows = ScreenRows ();
1985   int to_next_row       = update_row_len;
1986   unsigned char *saved_row = startup_screen_buffer;
1987   int cursor_pos_X = ScreenCols () - 1, cursor_pos_Y = ScreenRows () - 1;
1988   struct tty_display_info *tty = term->display_info.tty;
1989 
1990   if (tty->termscript)
1991     fprintf (tty->termscript, "\n<RESET_TERM>");
1992 
1993   if (!term_setup_done)
1994     return;
1995 
1996   mouse_off ();
1997 
1998   /* Leave the video system in the same state as we found it,
1999      as far as the blink/bright-background bit is concerned.  */
2000   maybe_enable_blinking ();
2001 
2002   /* We have a situation here.
2003      We cannot just do ScreenUpdate(startup_screen_buffer) because
2004      the luser could have changed screen dimensions inside Emacs
2005      and failed (or didn't want) to restore them before killing
2006      Emacs.  ScreenUpdate() uses the *current* screen dimensions and
2007      thus will happily use memory outside what was allocated for
2008      `startup_screen_buffer'.
2009      Thus we only restore as much as the current screen dimensions
2010      can hold, and clear the rest (if the saved screen is smaller than
2011      the current) with the color attribute saved at startup.  The cursor
2012      is also restored within the visible dimensions.  */
2013 
2014   ScreenAttrib = startup_screen_attrib;
2015 
2016   /* Don't restore the screen if we are exiting less than 2 seconds
2017      after startup: we might be crashing, and the screen might show
2018      some vital clues to what's wrong.  */
2019   if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
2020     {
2021       ScreenClear ();
2022       if (screen_virtual_segment)
2023         dosv_refresh_virtual_screen (0, screen_size);
2024 
2025       if (update_row_len > saved_row_len)
2026         update_row_len = saved_row_len;
2027       if (current_rows > startup_screen_size_Y)
2028         current_rows = startup_screen_size_Y;
2029 
2030       if (tty->termscript)
2031         fprintf (tty->termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2032                  update_row_len / 2, current_rows);
2033 
2034       while (current_rows--)
2035         {
2036           dosmemput (saved_row, update_row_len, display_row_start);
2037           if (screen_virtual_segment)
2038             dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
2039                                          update_row_len / 2);
2040           saved_row         += saved_row_len;
2041           display_row_start += to_next_row;
2042         }
2043     }
2044   if (startup_pos_X < cursor_pos_X)
2045     cursor_pos_X = startup_pos_X;
2046   if (startup_pos_Y < cursor_pos_Y)
2047     cursor_pos_Y = startup_pos_Y;
2048 
2049   ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
2050   xfree (startup_screen_buffer);
2051   startup_screen_buffer = NULL;
2052 
2053   term_setup_done = 0;
2054 }
2055 
2056 static void
2057 IT_set_terminal_window (struct frame *f, int foo)
2058 {
2059 }
2060 
2061 /* Remember the screen colors of the curent frame, to serve as the
2062    default colors for newly-created frames.  */
2063 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
2064        Smsdos_remember_default_colors, 1, 1, 0,
2065        doc: /* Remember the screen colors of the current frame.  */)
2066      (frame)
2067      Lisp_Object frame;
2068 {
2069   struct frame *f;
2070 
2071   CHECK_FRAME (frame);
2072   f = XFRAME (frame);
2073 
2074   /* This function is called after applying default-frame-alist to the
2075      initial frame.  At that time, if reverse-colors option was
2076      specified in default-frame-alist, it was already applied, and
2077      frame colors are reversed.  */
2078   initial_screen_colors[0] = FRAME_FOREGROUND_PIXEL (f);
2079   initial_screen_colors[1] = FRAME_BACKGROUND_PIXEL (f);
2080 }
2081 
2082 void
2083 IT_set_frame_parameters (f, alist)
2084      struct frame *f;
2085      Lisp_Object alist;
2086 {
2087   Lisp_Object tail;
2088   int i, j, length = XINT (Flength (alist));
2089   Lisp_Object *parms
2090     = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2091   Lisp_Object *values
2092     = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2093   /* Do we have to reverse the foreground and background colors?  */
2094   int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
2095   int need_to_reverse, was_reverse = reverse;
2096   int redraw = 0, fg_set = 0, bg_set = 0;
2097   unsigned long orig_fg, orig_bg;
2098   Lisp_Object frame_bg, frame_fg;
2099   extern Lisp_Object Qdefault, QCforeground, QCbackground;
2100   struct tty_display_info *tty = FRAME_TTY (f);
2101 
2102   /* If we are creating a new frame, begin with the original screen colors
2103      used for the initial frame.  */
2104   if (EQ (alist, Vdefault_frame_alist)
2105       && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
2106     {
2107       FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
2108       FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
2109       init_frame_faces (f);
2110     }
2111   orig_fg = FRAME_FOREGROUND_PIXEL (f);
2112   orig_bg = FRAME_BACKGROUND_PIXEL (f);
2113   frame_fg = Fcdr (Fassq (Qforeground_color, f->param_alist));
2114   frame_bg = Fcdr (Fassq (Qbackground_color, f->param_alist));
2115   /* frame_fg and frame_bg could be nil if, for example,
2116      f->param_alist is nil, e.g. if we are called from
2117      Fmake_terminal_frame.  */
2118   if (NILP (frame_fg))
2119     frame_fg = build_string (unspecified_fg);
2120   if (NILP (frame_bg))
2121     frame_bg = build_string (unspecified_bg);
2122 
2123   /* Extract parm names and values into those vectors.  */
2124   i = 0;
2125   for (tail = alist; CONSP (tail); tail = Fcdr (tail))
2126     {
2127       Lisp_Object elt;
2128 
2129       elt = Fcar (tail);
2130       parms[i] = Fcar (elt);
2131       CHECK_SYMBOL (parms[i]);
2132       values[i] = Fcdr (elt);
2133       i++;
2134     }
2135 
2136   j = i;
2137 
2138   for (i = 0; i < j; i++)
2139     {
2140       Lisp_Object prop, val;
2141 
2142       prop = parms[i];
2143       val  = values[i];
2144 
2145       if (EQ (prop, Qreverse))
2146         reverse = EQ (val, Qt);
2147     }
2148 
2149   need_to_reverse = reverse && !was_reverse;
2150   if (tty->termscript && need_to_reverse)
2151     fprintf (tty->termscript, "<INVERSE-VIDEO>\n");
2152 
2153   /* Now process the alist elements in reverse of specified order.  */
2154   for (i--; i >= 0; i--)
2155     {
2156       Lisp_Object prop, val, frame;
2157 
2158       prop = parms[i];
2159       val  = values[i];
2160 
2161       if (EQ (prop, Qforeground_color))
2162         {
2163           unsigned long new_color = load_color (f, NULL, val, need_to_reverse
2164                                                 ? LFACE_BACKGROUND_INDEX
2165                                                 : LFACE_FOREGROUND_INDEX);
2166           if (new_color !=  FACE_TTY_DEFAULT_COLOR
2167               && new_color != FACE_TTY_DEFAULT_FG_COLOR
2168               && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2169             {
2170               FRAME_FOREGROUND_PIXEL (f) = new_color;
2171               /* Make sure the foreground of the default face for this
2172                  frame is changed as well.  */
2173               XSETFRAME (frame, f);
2174               Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2175                                                  val, frame);
2176               fg_set = 1;
2177               redraw = 1;
2178               if (tty->termscript)
2179                 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
2180             }
2181         }
2182       else if (EQ (prop, Qbackground_color))
2183         {
2184           unsigned long new_color = load_color (f, NULL, val, need_to_reverse
2185                                                 ? LFACE_FOREGROUND_INDEX
2186                                                 : LFACE_BACKGROUND_INDEX);
2187           if (new_color != FACE_TTY_DEFAULT_COLOR
2188               && new_color != FACE_TTY_DEFAULT_FG_COLOR
2189               && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2190             {
2191               FRAME_BACKGROUND_PIXEL (f) = new_color;
2192               /* Make sure the background of the default face for this
2193                  frame is changed as well.  */
2194               XSETFRAME (frame, f);
2195               Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2196                                                  val, frame);
2197               bg_set = 1;
2198               redraw = 1;
2199               if (tty->termscript)
2200                 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
2201             }
2202         }
2203       else if (EQ (prop, Qtitle))
2204         {
2205           x_set_title (f, val);
2206           if (tty->termscript)
2207             fprintf (tty->termscript, "<TITLE: %s>\n", SDATA (val));
2208         }
2209       else if (EQ (prop, Qcursor_type))
2210         {
2211           IT_set_cursor_type (f, val);
2212           if (tty->termscript)
2213             fprintf (tty->termscript, "<CTYPE: %s>\n",
2214                      EQ (val, Qbar) || EQ (val, Qhbar)
2215                      || CONSP (val) && (EQ (XCAR (val), Qbar)
2216                                         || EQ (XCAR (val), Qhbar))
2217                      ? "bar" : "box");
2218         }
2219       else if (EQ (prop, Qtty_type))
2220         {
2221           internal_terminal_init ();
2222           if (tty->termscript)
2223             fprintf (tty->termscript, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
2224                      SBYTES (val), SDATA (val));
2225         }
2226       store_frame_param (f, prop, val);
2227     }
2228 
2229   /* If they specified "reverse", but not the colors, we need to swap
2230      the current frame colors.  */
2231   if (need_to_reverse)
2232     {
2233       Lisp_Object frame;
2234 
2235       if (!fg_set)
2236         {
2237           XSETFRAME (frame, f);
2238           Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2239                                              tty_color_name (f, orig_bg),
2240                                              frame);
2241           redraw = 1;
2242         }
2243       if (!bg_set)
2244         {
2245           XSETFRAME (frame, f);
2246           Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2247                                              tty_color_name (f, orig_fg),
2248                                              frame);
2249           redraw = 1;
2250         }
2251     }
2252 
2253   if (redraw)
2254     {
2255       face_change_count++;      /* forces xdisp.c to recompute basic faces */
2256       if (f == SELECTED_FRAME())
2257         redraw_frame (f);
2258     }
2259 }
2260 
2261 extern void init_frame_faces (FRAME_PTR);
2262 
2263 #endif /* !HAVE_X_WINDOWS */
2264 
2265 
2266 /* Do we need the internal terminal?  */
2267 
2268 void
2269 internal_terminal_init ()
2270 {
2271   static int init_needed = 1;
2272   char *term = getenv ("TERM"), *colors;
2273   struct frame *sf = SELECTED_FRAME();
2274   struct tty_display_info *tty;
2275 
2276 #ifdef HAVE_X_WINDOWS
2277   if (!inhibit_window_system)
2278     return;
2279 #endif
2280 
2281   /* If this is the initial terminal, we are done here.  */
2282   if (sf->output_method == output_initial)
2283     return;
2284 
2285   internal_terminal
2286     = (!noninteractive) && term && !strcmp (term, "internal");
2287 
2288 #ifndef HAVE_X_WINDOWS
2289   if (!internal_terminal || inhibit_window_system)
2290     {
2291       sf->output_method = output_termcap;
2292       return;
2293     }
2294 
2295   tty = FRAME_TTY (sf);
2296   current_kboard->Vwindow_system = Qpc;
2297   sf->output_method = output_msdos_raw;
2298   if (init_needed)
2299     {
2300       if (!tty->termscript && getenv ("EMACSTEST"))
2301         tty->termscript = fopen (getenv ("EMACSTEST"), "wt");
2302       if (tty->termscript)
2303         {
2304           time_t now = time (NULL);
2305           struct tm *tnow = localtime (&now);
2306           char tbuf[100];
2307 
2308           strftime (tbuf, sizeof (tbuf) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow);
2309           fprintf (tty->termscript, "\nEmacs session started at %s\n", tbuf);
2310           fprintf (tty->termscript,   "=====================\n\n");
2311         }
2312 
2313       Vinitial_window_system = Qpc;
2314       Vwindow_system_version = make_number (23); /* RE Emacs version */
2315       tty->terminal->type = output_msdos_raw;
2316 
2317       /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
2318          address.  */
2319       screen_old_address = 0;
2320 
2321       /* Forget the stale screen colors as well.  */
2322       initial_screen_colors[0] = initial_screen_colors[1] = -1;
2323 
2324       FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
2325       FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
2326       bright_bg ();
2327       colors = getenv ("EMACSCOLORS");
2328       if (colors && strlen (colors) >= 2)
2329         {
2330           /* The colors use 4 bits each (we enable bright background).  */
2331           if (isdigit (colors[0]))
2332             colors[0] -= '0';
2333           else if (isxdigit (colors[0]))
2334             colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
2335           if (colors[0] >= 0 && colors[0] < 16)
2336             FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors[0];
2337           if (isdigit (colors[1]))
2338             colors[1] -= '0';
2339           else if (isxdigit (colors[1]))
2340             colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
2341           if (colors[1] >= 0 && colors[1] < 16)
2342             FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors[1];
2343         }
2344       the_only_display_info.mouse_face_mouse_frame = NULL;
2345       the_only_display_info.mouse_face_deferred_gc = 0;
2346       the_only_display_info.mouse_face_beg_row =
2347         the_only_display_info.mouse_face_beg_col = -1;
2348       the_only_display_info.mouse_face_end_row =
2349         the_only_display_info.mouse_face_end_col = -1;
2350       the_only_display_info.mouse_face_face_id = DEFAULT_FACE_ID;
2351       the_only_display_info.mouse_face_window = Qnil;
2352       the_only_display_info.mouse_face_mouse_x =
2353         the_only_display_info.mouse_face_mouse_y = 0;
2354       the_only_display_info.mouse_face_defer = 0;
2355       the_only_display_info.mouse_face_hidden = 0;
2356 
2357       if (have_mouse)   /* detected in dos_ttraw, which see */
2358         {
2359           have_mouse = 1;       /* enable mouse */
2360           mouse_visible = 0;
2361           mouse_setup_buttons (mouse_button_count);
2362           tty->terminal->mouse_position_hook = &mouse_get_pos;
2363           mouse_init ();
2364         }
2365 
2366       if (tty->termscript && screen_size)
2367         fprintf (tty->termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2368                  screen_size_X, screen_size_Y);
2369 
2370       init_frame_faces (sf);
2371       init_needed = 0;
2372     }
2373 #endif
2374 }
2375 
2376 void
2377 initialize_msdos_display (struct terminal *term)
2378 {
2379   term->rif = 0;                /* we don't support window-based display */
2380   term->cursor_to_hook = term->raw_cursor_to_hook = IT_cursor_to;
2381   term->clear_to_end_hook = IT_clear_to_end;
2382   term->clear_frame_hook = IT_clear_screen;
2383   term->clear_end_of_line_hook = IT_clear_end_of_line;
2384   term->ins_del_lines_hook = 0;
2385   term->insert_glyphs_hook = IT_insert_glyphs;
2386   term->write_glyphs_hook = IT_write_glyphs;
2387   term->delete_glyphs_hook = IT_delete_glyphs;
2388   term->ring_bell_hook = IT_ring_bell;
2389   term->reset_terminal_modes_hook = IT_reset_terminal_modes;
2390   term->set_terminal_modes_hook = IT_set_terminal_modes;
2391   term->set_terminal_window_hook = IT_set_terminal_window;
2392   term->update_begin_hook = IT_update_begin;
2393   term->update_end_hook = IT_update_end;
2394   term->frame_up_to_date_hook = IT_frame_up_to_date;
2395   term->mouse_position_hook = 0; /* set later by dos_ttraw */
2396   term->frame_rehighlight_hook = 0;
2397   term->frame_raise_lower_hook = 0;
2398   term->set_vertical_scroll_bar_hook = 0;
2399   term->condemn_scroll_bars_hook = 0;
2400   term->redeem_scroll_bar_hook = 0;
2401   term->judge_scroll_bars_hook = 0;
2402   term->read_socket_hook = &tty_read_avail_input; /* from keyboard.c */
2403 }
2404 
2405 dos_get_saved_screen (screen, rows, cols)
2406      char **screen;
2407      int *rows;
2408      int *cols;
2409 {
2410 #ifndef HAVE_X_WINDOWS
2411   *screen = startup_screen_buffer;
2412   *cols = startup_screen_size_X;
2413   *rows = startup_screen_size_Y;
2414   return *screen != (char *)0;
2415 #else
2416   return 0;
2417 #endif
2418 }
2419 
2420 #ifndef HAVE_X_WINDOWS
2421 
2422 /* We are not X, but we can emulate it well enough for our needs... */
2423 void
2424 check_x (void)
2425 {
2426   if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2427     error ("Not running under a window system");
2428 }
2429 
2430 #endif
2431 
2432 
2433 /* ----------------------- Keyboard control ----------------------
2434  *
2435  * Keymaps reflect the following keyboard layout:
2436  *
2437  *    0  1  2  3  4  5  6  7  8  9  10 11 12  BS
2438  *    TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2439  *    CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2440  *    SH () 45 46 47 48 49 50 51 52 53 54  SHIFT
2441  *                    SPACE
2442  */
2443 
2444 #define Ignore  0x0000
2445 #define Normal  0x0000  /* normal key - alt changes scan-code */
2446 #define FctKey  0x1000  /* func key if c == 0, else c */
2447 #define Special 0x2000  /* func key even if c != 0 */
2448 #define ModFct  0x3000  /* special if mod-keys, else 'c' */
2449 #define Map     0x4000  /* alt scan-code, map to unshift/shift key */
2450 #define KeyPad  0x5000  /* map to insert/kp-0 depending on c == 0xe0 */
2451 #define Grey    0x6000  /* Grey keypad key */
2452 
2453 #define Alt     0x0100  /* alt scan-code */
2454 #define Ctrl    0x0200  /* ctrl scan-code */
2455 #define Shift   0x0400  /* shift scan-code */
2456 
2457 static int extended_kbd; /* 101 (102) keyboard present. */
2458 
2459 struct kbd_translate {
2460   unsigned char  sc;
2461   unsigned char  ch;
2462   unsigned short code;
2463 };
2464 
2465 struct dos_keyboard_map
2466 {
2467   char *unshifted;
2468   char *shifted;
2469   char *alt_gr;
2470   struct kbd_translate *translate_table;
2471 };
2472 
2473 
2474 static struct dos_keyboard_map us_keyboard = {
2475 /* 0         1         2         3         4         5      */
2476 /* 01234567890123456789012345678901234567890 12345678901234 */
2477   "`1234567890-=  qwertyuiop[]   asdfghjkl;'\\   zxcvbnm,./  ",
2478 /* 0123456789012345678901234567890123456789 012345678901234 */
2479   "~!@#$%^&*()_+  QWERTYUIOP{}   ASDFGHJKL:\"|   ZXCVBNM<>?  ",
2480   0,                            /* no Alt-Gr key */
2481   0                             /* no translate table */
2482 };
2483 
2484 static struct dos_keyboard_map fr_keyboard = {
2485 /* 0         1         2         3         4         5      */
2486 /* 012 3456789012345678901234567890123456789012345678901234 */
2487   "\375&\202\",(-\212_\200\205)=  azertyuiop^$   qsdfghjklm\227*   wxcvbnm;:!  ",
2488 /* 0123456789012345678901234567890123456789012345678901234 */
2489   " 1234567890\370+  AZERTYUIOP\371\234   QSDFGHJKLM%\346   WXCVBN?./\365  ",
2490 /* 01234567 89012345678901234567890123456789012345678901234 */
2491   "  ~#{[|`\\^@]}             \317                              ",
2492   0                             /* no translate table */
2493 };
2494 
2495 /*
2496  * Italian keyboard support, country code 39.
2497  * '<' 56:3c*0000
2498  * '>' 56:3e*0000
2499  * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2500  * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2501  */
2502 
2503 static struct kbd_translate it_kbd_translate_table[] = {
2504   { 0x56, 0x3c, Normal | 13 },
2505   { 0x56, 0x3e, Normal | 27 },
2506   { 0, 0, 0 }
2507 };
2508 static struct dos_keyboard_map it_keyboard = {
2509 /* 0          1         2         3         4         5     */
2510 /* 0 123456789012345678901234567890123456789012345678901234 */
2511   "\\1234567890'\215< qwertyuiop\212+>  asdfghjkl\225\205\227   zxcvbnm,.-  ",
2512 /* 01 23456789012345678901234567890123456789012345678901234 */
2513   "|!\"\234$%&/()=?^> QWERTYUIOP\202*   ASDFGHJKL\207\370\365   ZXCVBNM;:_  ",
2514 /* 0123456789012345678901234567890123456789012345678901234 */
2515   "        {}~`             []             @#               ",
2516   it_kbd_translate_table
2517 };
2518 
2519 static struct dos_keyboard_map dk_keyboard = {
2520 /* 0         1         2         3         4         5      */
2521 /* 0123456789012345678901234567890123456789012345678901234 */
2522   "\2531234567890+|  qwertyuiop\206~   asdfghjkl\221\233'   zxcvbnm,.-  ",
2523 /* 01 23456789012345678901234567890123456789012345678901234 */
2524   "\365!\"#$%&/()=?`  QWERTYUIOP\217^   ASDFGHJKL\222\235*   ZXCVBNM;:_  ",
2525 /* 0123456789012345678901234567890123456789012345678901234 */
2526   "  @\234$  {[]} |                                             ",
2527   0                             /* no translate table */
2528 };
2529 
2530 static struct kbd_translate jp_kbd_translate_table[] = {
2531   { 0x73, 0x5c, Normal | 0 },
2532   { 0x73, 0x5f, Normal | 0 },
2533   { 0x73, 0x1c, Map | 0 },
2534   { 0x7d, 0x5c, Normal | 13 },
2535   { 0x7d, 0x7c, Normal | 13 },
2536   { 0x7d, 0x1c, Map | 13 },
2537   { 0, 0, 0 }
2538 };
2539 static struct dos_keyboard_map jp_keyboard = {
2540 /*  0         1          2         3         4         5     */
2541 /*  0123456789012 345678901234567890123456789012345678901234 */
2542   "\\1234567890-^\\ qwertyuiop@[   asdfghjkl;:]   zxcvbnm,./  ",
2543 /*  01 23456789012345678901234567890123456789012345678901234 */
2544    "_!\"#$%&'()~=~| QWERTYUIOP`{   ASDFGHJKL+*}   ZXCVBNM<>?  ",
2545   0,                            /* no Alt-Gr key */
2546   jp_kbd_translate_table
2547 };
2548 
2549 static struct keyboard_layout_list
2550 {
2551   int country_code;
2552   struct dos_keyboard_map *keyboard_map;
2553 } keyboard_layout_list[] =
2554 {
2555   1, &us_keyboard,
2556   33, &fr_keyboard,
2557   39, &it_keyboard,
2558   45, &dk_keyboard,
2559   81, &jp_keyboard
2560 };
2561 
2562 static struct dos_keyboard_map *keyboard;
2563 static int keyboard_map_all;
2564 static int international_keyboard;
2565 
2566 int
2567 dos_set_keyboard (code, always)
2568      int code;
2569      int always;
2570 {
2571   int i;
2572   _go32_dpmi_registers regs;
2573 
2574   /* See if Keyb.Com is installed (for international keyboard support).
2575      Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2576      of Windows 9X!  So don't do that!  */
2577   regs.x.ax = 0xad80;
2578   regs.x.ss = regs.x.sp = regs.x.flags = 0;
2579   _go32_dpmi_simulate_int (0x2f, &regs);
2580   if (regs.h.al == 0xff)
2581     international_keyboard = 1;
2582 
2583   /* Initialize to US settings, for countries that don't have their own.  */
2584   keyboard = keyboard_layout_list[0].keyboard_map;
2585   keyboard_map_all = always;
2586   dos_keyboard_layout = 1;
2587 
2588   for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
2589     if (code == keyboard_layout_list[i].country_code)
2590       {
2591         keyboard = keyboard_layout_list[i].keyboard_map;
2592         keyboard_map_all = always;
2593         dos_keyboard_layout = code;
2594         return 1;
2595       }
2596   return 0;
2597 }
2598 
2599 static struct
2600 {
2601   unsigned char char_code;      /* normal code  */
2602   unsigned char meta_code;      /* M- code      */
2603   unsigned char keypad_code;    /* keypad code  */
2604   unsigned char editkey_code;   /* edit key     */
2605 } keypad_translate_map[] = {
2606   '0',  '0',  0xb0, /* kp-0 */          0x63, /* insert */
2607   '1',  '1',  0xb1, /* kp-1 */          0x57, /* end */
2608   '2',  '2',  0xb2, /* kp-2 */          0x54, /* down */
2609   '3',  '3',  0xb3, /* kp-3 */          0x56, /* next */
2610   '4',  '4',  0xb4, /* kp-4 */          0x51, /* left */
2611   '5',  '5',  0xb5, /* kp-5 */          0xb5, /* kp-5 */
2612   '6',  '6',  0xb6, /* kp-6 */          0x53, /* right */
2613   '7',  '7',  0xb7, /* kp-7 */          0x50, /* home */
2614   '8',  '8',  0xb8, /* kp-8 */          0x52, /* up */
2615   '9',  '9',  0xb9, /* kp-9 */          0x55, /* prior */
2616   '.',  '-',  0xae, /* kp-decimal */    0xff  /* delete */
2617 };
2618 
2619 static struct
2620 {
2621   unsigned char char_code;      /* normal code  */
2622   unsigned char keypad_code;    /* keypad code  */
2623 } grey_key_translate_map[] = {
2624   '/',  0xaf, /* kp-decimal */
2625   '*',  0xaa, /* kp-multiply */
2626   '-',  0xad, /* kp-subtract */
2627   '+',  0xab, /* kp-add */
2628   '\r', 0x8d  /* kp-enter */
2629 };
2630 
2631 static unsigned short
2632 ibmpc_translate_map[] =
2633 {
2634   /* --------------- 00 to 0f --------------- */
2635   Normal | 0xff,        /* Ctrl Break + Alt-NNN */
2636   Alt | ModFct | 0x1b,          /* Escape */
2637   Normal | 1,                   /* '1' */
2638   Normal | 2,                   /* '2' */
2639   Normal | 3,                   /* '3' */
2640   Normal | 4,                   /* '4' */
2641   Normal | 5,                   /* '5' */
2642   Normal | 6,                   /* '6' */
2643   Normal | 7,                   /* '7' */
2644   Normal | 8,                   /* '8' */
2645   Normal | 9,                   /* '9' */
2646   Normal | 10,                  /* '0' */
2647   Normal | 11,                  /* '-' */
2648   Normal | 12,                  /* '=' */
2649   Special | 0x08,               /* Backspace */
2650   ModFct | 0x74,                /* Tab/Backtab */
2651 
2652   /* --------------- 10 to 1f --------------- */
2653   Map | 15,                     /* 'q' */
2654   Map | 16,                     /* 'w' */
2655   Map | 17,                     /* 'e' */
2656   Map | 18,                     /* 'r' */
2657   Map | 19,                     /* 't' */
2658   Map | 20,                     /* 'y' */
2659   Map | 21,                     /* 'u' */
2660   Map | 22,                     /* 'i' */
2661   Map | 23,                     /* 'o' */
2662   Map | 24,                     /* 'p' */
2663   Map | 25,                     /* '[' */
2664   Map | 26,                     /* ']' */
2665   ModFct | 0x0d,                /* Return */
2666   Ignore,                       /* Ctrl */
2667   Map | 30,                     /* 'a' */
2668   Map | 31,                     /* 's' */
2669 
2670   /* --------------- 20 to 2f --------------- */
2671   Map | 32,                     /* 'd' */
2672   Map | 33,                     /* 'f' */
2673   Map | 34,                     /* 'g' */
2674   Map | 35,                     /* 'h' */
2675   Map | 36,                     /* 'j' */
2676   Map | 37,                     /* 'k' */
2677   Map | 38,                     /* 'l' */
2678   Map | 39,                     /* ';' */
2679   Map | 40,                     /* '\'' */
2680   Map |  0,                     /* '`' */
2681   Ignore,                       /* Left shift */
2682   Map | 41,                     /* '\\' */
2683   Map | 45,                     /* 'z' */
2684   Map | 46,                     /* 'x' */
2685   Map | 47,                     /* 'c' */
2686   Map | 48,                     /* 'v' */
2687 
2688   /* --------------- 30 to 3f --------------- */
2689   Map | 49,                     /* 'b' */
2690   Map | 50,                     /* 'n' */
2691   Map | 51,                     /* 'm' */
2692   Map | 52,                     /* ',' */
2693   Map | 53,                     /* '.' */
2694   Map | 54,                     /* '/' */
2695   Ignore,                       /* Right shift */
2696   Grey | 1,                     /* Grey * */
2697   Ignore,                       /* Alt */
2698   Normal | 55,                  /* ' ' */
2699   Ignore,                       /* Caps Lock */
2700   FctKey | 0xbe,                /* F1 */
2701   FctKey | 0xbf,                /* F2 */
2702   FctKey | 0xc0,                /* F3 */
2703   FctKey | 0xc1,                /* F4 */
2704   FctKey | 0xc2,                /* F5 */
2705 
2706   /* --------------- 40 to 4f --------------- */
2707   FctKey | 0xc3,                /* F6 */
2708   FctKey | 0xc4,                /* F7 */
2709   FctKey | 0xc5,                /* F8 */
2710   FctKey | 0xc6,                /* F9 */
2711   FctKey | 0xc7,                /* F10 */
2712   Ignore,                       /* Num Lock */
2713   Ignore,                       /* Scroll Lock */
2714   KeyPad | 7,                   /* Home */
2715   KeyPad | 8,                   /* Up */
2716   KeyPad | 9,                   /* Page Up */
2717   Grey | 2,                     /* Grey - */
2718   KeyPad | 4,                   /* Left */
2719   KeyPad | 5,                   /* Keypad 5 */
2720   KeyPad | 6,                   /* Right */
2721   Grey | 3,                     /* Grey + */
2722   KeyPad | 1,                   /* End */
2723 
2724   /* --------------- 50 to 5f --------------- */
2725   KeyPad | 2,                   /* Down */
2726   KeyPad | 3,                   /* Page Down */
2727   KeyPad | 0,                   /* Insert */
2728   KeyPad | 10,                  /* Delete */
2729   Shift | FctKey | 0xbe,        /* (Shift) F1 */
2730   Shift | FctKey | 0xbf,        /* (Shift) F2 */
2731   Shift | FctKey | 0xc0,        /* (Shift) F3 */
2732   Shift | FctKey | 0xc1,        /* (Shift) F4 */
2733   Shift | FctKey | 0xc2,        /* (Shift) F5 */
2734   Shift | FctKey | 0xc3,        /* (Shift) F6 */
2735   Shift | FctKey | 0xc4,        /* (Shift) F7 */
2736   Shift | FctKey | 0xc5,        /* (Shift) F8 */
2737   Shift | FctKey | 0xc6,        /* (Shift) F9 */
2738   Shift | FctKey | 0xc7,        /* (Shift) F10 */
2739   Ctrl | FctKey | 0xbe,         /* (Ctrl) F1 */
2740   Ctrl | FctKey | 0xbf,         /* (Ctrl) F2 */
2741 
2742   /* --------------- 60 to 6f --------------- */
2743   Ctrl | FctKey | 0xc0,         /* (Ctrl) F3 */
2744   Ctrl | FctKey | 0xc1,         /* (Ctrl) F4 */
2745   Ctrl | FctKey | 0xc2,         /* (Ctrl) F5 */
2746   Ctrl | FctKey | 0xc3,         /* (Ctrl) F6 */
2747   Ctrl | FctKey | 0xc4,         /* (Ctrl) F7 */
2748   Ctrl | FctKey | 0xc5,         /* (Ctrl) F8 */
2749   Ctrl | FctKey | 0xc6,         /* (Ctrl) F9 */
2750   Ctrl | FctKey | 0xc7,         /* (Ctrl) F10 */
2751   Alt | FctKey | 0xbe,          /* (Alt) F1 */
2752   Alt | FctKey | 0xbf,          /* (Alt) F2 */
2753   Alt | FctKey | 0xc0,          /* (Alt) F3 */
2754   Alt | FctKey | 0xc1,          /* (Alt) F4 */
2755   Alt | FctKey | 0xc2,          /* (Alt) F5 */
2756   Alt | FctKey | 0xc3,          /* (Alt) F6 */
2757   Alt | FctKey | 0xc4,          /* (Alt) F7 */
2758   Alt | FctKey | 0xc5,          /* (Alt) F8 */
2759 
2760   /* --------------- 70 to 7f --------------- */
2761   Alt | FctKey | 0xc6,          /* (Alt) F9 */
2762   Alt | FctKey | 0xc7,          /* (Alt) F10 */
2763   Ctrl | FctKey | 0x6d,         /* (Ctrl) Sys Rq */
2764   Ctrl | KeyPad | 4,            /* (Ctrl) Left */
2765   Ctrl | KeyPad | 6,            /* (Ctrl) Right */
2766   Ctrl | KeyPad | 1,            /* (Ctrl) End */
2767   Ctrl | KeyPad | 3,            /* (Ctrl) Page Down */
2768   Ctrl | KeyPad | 7,            /* (Ctrl) Home */
2769   Alt | Map | 1,                /* '1' */
2770   Alt | Map | 2,                /* '2' */
2771   Alt | Map | 3,                /* '3' */
2772   Alt | Map | 4,                /* '4' */
2773   Alt | Map | 5,                /* '5' */
2774   Alt | Map | 6,                /* '6' */
2775   Alt | Map | 7,                /* '7' */
2776   Alt | Map | 8,                /* '8' */
2777 
2778   /* --------------- 80 to 8f --------------- */
2779   Alt | Map | 9,                /* '9' */
2780   Alt | Map | 10,               /* '0' */
2781   Alt | Map | 11,               /* '-' */
2782   Alt | Map | 12,               /* '=' */
2783   Ctrl | KeyPad | 9,            /* (Ctrl) Page Up */
2784   FctKey | 0xc8,                /* F11 */
2785   FctKey | 0xc9,                /* F12 */
2786   Shift | FctKey | 0xc8,        /* (Shift) F11 */
2787   Shift | FctKey | 0xc9,        /* (Shift) F12 */
2788   Ctrl | FctKey | 0xc8,         /* (Ctrl) F11 */
2789   Ctrl | FctKey | 0xc9,         /* (Ctrl) F12 */
2790   Alt | FctKey | 0xc8,          /* (Alt) F11 */
2791   Alt | FctKey | 0xc9,          /* (Alt) F12 */
2792   Ctrl | KeyPad | 8,            /* (Ctrl) Up */
2793   Ctrl | Grey | 2,              /* (Ctrl) Grey - */
2794   Ctrl | KeyPad | 5,            /* (Ctrl) Keypad 5 */
2795 
2796   /* --------------- 90 to 9f --------------- */
2797   Ctrl | Grey | 3,              /* (Ctrl) Grey + */
2798   Ctrl | KeyPad | 2,            /* (Ctrl) Down */
2799   Ctrl | KeyPad | 0,            /* (Ctrl) Insert */
2800   Ctrl | KeyPad | 10,           /* (Ctrl) Delete */
2801   Ctrl | FctKey | 0x09,         /* (Ctrl) Tab */
2802   Ctrl | Grey | 0,              /* (Ctrl) Grey / */
2803   Ctrl | Grey | 1,              /* (Ctrl) Grey * */
2804   Alt | FctKey | 0x50,          /* (Alt) Home */
2805   Alt | FctKey | 0x52,          /* (Alt) Up */
2806   Alt | FctKey | 0x55,          /* (Alt) Page Up */
2807   Ignore,                       /* NO KEY */
2808   Alt | FctKey | 0x51,          /* (Alt) Left */
2809   Ignore,                       /* NO KEY */
2810   Alt | FctKey | 0x53,          /* (Alt) Right */
2811   Ignore,                       /* NO KEY */
2812   Alt | FctKey | 0x57,          /* (Alt) End */
2813 
2814   /* --------------- a0 to af --------------- */
2815   Alt | KeyPad | 2,             /* (Alt) Down */
2816   Alt | KeyPad | 3,             /* (Alt) Page Down */
2817   Alt | KeyPad | 0,             /* (Alt) Insert */
2818   Alt | KeyPad | 10,            /* (Alt) Delete */
2819   Alt | Grey | 0,               /* (Alt) Grey / */
2820   Alt | FctKey | 0x09,          /* (Alt) Tab */
2821   Alt | Grey | 4                /* (Alt) Keypad Enter */
2822 };
2823 
2824 /* These bit-positions corresponds to values returned by BIOS */
2825 #define SHIFT_P         0x0003  /* two bits! */
2826 #define CTRL_P          0x0004
2827 #define ALT_P           0x0008
2828 #define SCRLOCK_P       0x0010
2829 #define NUMLOCK_P       0x0020
2830 #define CAPSLOCK_P      0x0040
2831 #define ALT_GR_P        0x0800
2832 #define SUPER_P         0x4000  /* pseudo */
2833 #define HYPER_P         0x8000  /* pseudo */
2834 
2835 static int
2836 dos_get_modifiers (keymask)
2837      int *keymask;
2838 {
2839   union REGS regs;
2840   int mask, modifiers = 0;
2841 
2842   /* Calculate modifier bits */
2843   regs.h.ah = extended_kbd ? 0x12 : 0x02;
2844   int86 (0x16, &regs, &regs);
2845 
2846   if (!extended_kbd)
2847     {
2848       mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
2849                           SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2850     }
2851   else
2852     {
2853       mask = regs.h.al & (SHIFT_P |
2854                           SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2855 
2856       /* Do not break international keyboard support.   */
2857       /* When Keyb.Com is loaded, the right Alt key is  */
2858       /* used for accessing characters like { and }       */
2859       if (regs.h.ah & 2)                /* Left ALT pressed ? */
2860         mask |= ALT_P;
2861 
2862       if ((regs.h.ah & 8) != 0)         /* Right ALT pressed ? */
2863         {
2864           mask |= ALT_GR_P;
2865           if (dos_hyper_key == 1)
2866             {
2867               mask |= HYPER_P;
2868               modifiers |= hyper_modifier;
2869             }
2870           else if (dos_super_key == 1)
2871             {
2872               mask |= SUPER_P;
2873               modifiers |= super_modifier;
2874             }
2875           else if (!international_keyboard)
2876             {
2877               /* If Keyb.Com is NOT installed, let Right Alt behave
2878                  like the Left Alt.  */
2879               mask &= ~ALT_GR_P;
2880               mask |= ALT_P;
2881             }
2882         }
2883 
2884       if (regs.h.ah & 1)                /* Left CTRL pressed ? */
2885         mask |= CTRL_P;
2886 
2887       if (regs.h.ah & 4)                /* Right CTRL pressed ? */
2888         {
2889           if (dos_hyper_key == 2)
2890             {
2891               mask |= HYPER_P;
2892               modifiers |= hyper_modifier;
2893             }
2894           else if (dos_super_key == 2)
2895             {
2896               mask |= SUPER_P;
2897               modifiers |= super_modifier;
2898             }
2899           else
2900             mask |= CTRL_P;
2901         }
2902     }
2903 
2904   if (mask & SHIFT_P)
2905     modifiers |= shift_modifier;
2906   if (mask & CTRL_P)
2907     modifiers |= ctrl_modifier;
2908   if (mask & ALT_P)
2909     modifiers |= meta_modifier;
2910 
2911   if (keymask)
2912     *keymask = mask;
2913   return modifiers;
2914 }
2915 
2916 #define NUM_RECENT_DOSKEYS (100)
2917 int recent_doskeys_index;       /* Index for storing next element into recent_doskeys */
2918 int total_doskeys;              /* Total number of elements stored into recent_doskeys */
2919 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
2920 
2921 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
2922        doc: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
2923 Each input key receives two values in this vector: first the ASCII code,
2924 and then the scan code.  */)
2925      ()
2926 {
2927   Lisp_Object val, *keys = XVECTOR (recent_doskeys)->contents;
2928 
2929   if (total_doskeys < NUM_RECENT_DOSKEYS)
2930     return Fvector (total_doskeys, keys);
2931   else
2932     {
2933       val = Fvector (NUM_RECENT_DOSKEYS, keys);
2934       bcopy (keys + recent_doskeys_index,
2935              XVECTOR (val)->contents,
2936              (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
2937       bcopy (keys,
2938              XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
2939              recent_doskeys_index * sizeof (Lisp_Object));
2940       return val;
2941     }
2942 }
2943 
2944 /* Get a char from keyboard.  Function keys are put into the event queue.  */
2945 static int
2946 dos_rawgetc ()
2947 {
2948   struct input_event event;
2949   union REGS regs;
2950   struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (SELECTED_FRAME());
2951   EVENT_INIT (event);
2952 
2953 #ifndef HAVE_X_WINDOWS
2954   /* Maybe put the cursor where it should be.  */
2955   IT_cmgoto (SELECTED_FRAME());
2956 #endif
2957 
2958   /* The following condition is equivalent to `kbhit ()', except that
2959      it uses the bios to do its job.  This pleases DESQview/X.  */
2960   while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
2961          int86 (0x16, &regs, &regs),
2962          (regs.x.flags & 0x40) == 0)
2963     {
2964       union REGS regs;
2965       register unsigned char c;
2966       int modifiers, sc, code = -1, mask, kp_mode;
2967 
2968       regs.h.ah = extended_kbd ? 0x10 : 0x00;
2969       int86 (0x16, &regs, &regs);
2970       c = regs.h.al;
2971       sc = regs.h.ah;
2972 
2973       total_doskeys += 2;
2974       XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2975         = make_number (c);
2976       if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2977         recent_doskeys_index = 0;
2978       XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2979         = make_number (sc);
2980       if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2981         recent_doskeys_index = 0;
2982 
2983       modifiers = dos_get_modifiers (&mask);
2984 
2985 #ifndef HAVE_X_WINDOWS
2986       if (!NILP (Vdos_display_scancodes))
2987         {
2988           char buf[11];
2989           sprintf (buf, "%02x:%02x*%04x",
2990                    (unsigned) (sc&0xff), (unsigned) c, mask);
2991           dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
2992         }
2993 #endif
2994 
2995       if (sc == 0xe0)
2996         {
2997           switch (c)
2998             {
2999             case 10:            /* Ctrl Grey Enter */
3000               code = Ctrl | Grey | 4;
3001               break;
3002             case 13:            /* Grey Enter */
3003               code = Grey | 4;
3004               break;
3005             case '/':           /* Grey / */
3006               code = Grey | 0;
3007               break;
3008             default:
3009               continue;
3010             };
3011           c = 0;
3012         }
3013       else
3014         {
3015           /* Try the keyboard-private translation table first.  */
3016           if (keyboard->translate_table)
3017             {
3018               struct kbd_translate *p = keyboard->translate_table;
3019 
3020               while (p->sc)
3021                 {
3022                   if (p->sc == sc && p->ch == c)
3023                     {
3024                       code = p->code;
3025                       break;
3026                     }
3027                   p++;
3028                 }
3029             }
3030           /* If the private table didn't translate it, use the general
3031              one.  */
3032           if (code == -1)
3033             {
3034               if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
3035                 continue;
3036               if ((code = ibmpc_translate_map[sc]) == Ignore)
3037                 continue;
3038             }
3039         }
3040 
3041       if (c == 0)
3042         {
3043         /* We only look at the keyboard Ctrl/Shift/Alt keys when
3044            Emacs is ready to read a key.  Therefore, if they press
3045            `Alt-x' when Emacs is busy, by the time we get to
3046            `dos_get_modifiers', they might have already released the
3047            Alt key, and Emacs gets just `x', which is BAD.
3048            However, for keys with the `Map' property set, the ASCII
3049            code returns zero only if Alt is pressed.  So, when we DON'T
3050            have to support international_keyboard, we don't have to
3051            distinguish between the left and  right Alt keys, and we
3052            can set the META modifier for any keys with the `Map'
3053            property if they return zero ASCII code (c = 0).  */
3054         if ( (code & Alt)
3055              || ( (code & 0xf000) == Map && !international_keyboard))
3056             modifiers |= meta_modifier;
3057           if (code & Ctrl)
3058             modifiers |= ctrl_modifier;
3059           if (code & Shift)
3060             modifiers |= shift_modifier;
3061         }
3062 
3063       switch (code & 0xf000)
3064         {
3065         case ModFct:
3066           if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
3067             return c;
3068           c = 0;                /* Special */
3069 
3070         case FctKey:
3071           if (c != 0)
3072             return c;
3073 
3074         case Special:
3075           code |= 0xff00;
3076           break;
3077 
3078         case Normal:
3079           if (sc == 0)
3080             {
3081               if (c == 0)       /* ctrl-break */
3082                 continue;
3083               return c;         /* ALT-nnn */
3084             }
3085           if (!keyboard_map_all)
3086             {
3087               if (c != ' ')
3088                 return c;
3089               code = c;
3090               break;
3091             }
3092 
3093         case Map:
3094           if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
3095             if (!keyboard_map_all)
3096               return c;
3097 
3098           code &= 0xff;
3099           if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
3100             mask |= SHIFT_P;    /* ALT-1 => M-! etc. */
3101 
3102           if (mask & SHIFT_P)
3103             {
3104               code = keyboard->shifted[code];
3105               mask -= SHIFT_P;
3106               modifiers &= ~shift_modifier;
3107             }
3108           else
3109             if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
3110               code = keyboard->alt_gr[code];
3111             else
3112               code = keyboard->unshifted[code];
3113           break;
3114 
3115         case KeyPad:
3116           code &= 0xff;
3117           if (c == 0xe0)        /* edit key */
3118             kp_mode = 3;
3119           else
3120             if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
3121               kp_mode = dos_keypad_mode & 0x03;
3122             else
3123               kp_mode = (dos_keypad_mode >> 4) & 0x03;
3124 
3125           switch (kp_mode)
3126             {
3127             case 0:
3128               if (code == 10 && dos_decimal_point)
3129                 return dos_decimal_point;
3130               return keypad_translate_map[code].char_code;
3131 
3132             case 1:
3133               code = 0xff00 | keypad_translate_map[code].keypad_code;
3134               break;
3135 
3136             case 2:
3137               code = keypad_translate_map[code].meta_code;
3138               modifiers = meta_modifier;
3139               break;
3140 
3141             case 3:
3142               code = 0xff00 | keypad_translate_map[code].editkey_code;
3143               break;
3144             }
3145           break;
3146 
3147         case Grey:
3148           code &= 0xff;
3149           kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
3150           if (dos_keypad_mode & kp_mode)
3151             code = 0xff00 | grey_key_translate_map[code].keypad_code;
3152           else
3153             code = grey_key_translate_map[code].char_code;
3154           break;
3155         }
3156 
3157     make_event:
3158       if (code == 0)
3159         continue;
3160 
3161       if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
3162         {
3163           clear_mouse_face (dpyinfo);
3164           dpyinfo->mouse_face_hidden = 1;
3165         }
3166 
3167       if (code >= 0x100)
3168         event.kind = NON_ASCII_KEYSTROKE_EVENT;
3169       else
3170         event.kind = ASCII_KEYSTROKE_EVENT;
3171       event.code = code;
3172       event.modifiers = modifiers;
3173       event.frame_or_window = selected_frame;
3174       event.arg = Qnil;
3175       event.timestamp = event_timestamp ();
3176       kbd_buffer_store_event (&event);
3177     }
3178 
3179   if (have_mouse > 0 && !mouse_preempted)
3180     {
3181       int but, press, x, y, ok;
3182       int mouse_prev_x = mouse_last_x, mouse_prev_y = mouse_last_y;
3183       Lisp_Object mouse_window = Qnil;
3184 
3185       /* Check for mouse movement *before* buttons.  */
3186       mouse_check_moved ();
3187 
3188       /* If the mouse moved from the spot of its last sighting, we
3189          might need to update mouse highlight.  */
3190       if (mouse_last_x != mouse_prev_x || mouse_last_y != mouse_prev_y)
3191         {
3192           if (dpyinfo->mouse_face_hidden)
3193             {
3194               dpyinfo->mouse_face_hidden = 0;
3195               clear_mouse_face (dpyinfo);
3196             }
3197 
3198           /* Generate SELECT_WINDOW_EVENTs when needed.  */
3199           if (!NILP (Vmouse_autoselect_window))
3200             {
3201               mouse_window = window_from_coordinates (SELECTED_FRAME(),
3202                                                       mouse_last_x,
3203                                                       mouse_last_y,
3204                                                       0, 0, 0, 0);
3205               /* A window will be selected only when it is not
3206                  selected now, and the last mouse movement event was
3207                  not in it.  A minibuffer window will be selected iff
3208                  it is active.  */
3209               if (WINDOWP (mouse_window)
3210                   && !EQ (mouse_window, last_mouse_window)
3211                   && !EQ (mouse_window, selected_window))
3212                 {
3213                   event.kind = SELECT_WINDOW_EVENT;
3214                   event.frame_or_window = mouse_window;
3215                   event.arg = Qnil;
3216                   event.timestamp = event_timestamp ();
3217                   kbd_buffer_store_event (&event);
3218                 }
3219               last_mouse_window = mouse_window;
3220             }
3221           else
3222             last_mouse_window = Qnil;
3223 
3224           previous_help_echo_string = help_echo_string;
3225           help_echo_string = help_echo_object = help_echo_window = Qnil;
3226           help_echo_pos = -1;
3227           IT_note_mouse_highlight (SELECTED_FRAME(),
3228                                    mouse_last_x, mouse_last_y);
3229           /* If the contents of the global variable help_echo has
3230              changed, generate a HELP_EVENT.  */
3231           if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
3232             {
3233               event.kind = HELP_EVENT;
3234               event.frame_or_window = selected_frame;
3235               event.arg = help_echo_object;
3236               event.x = WINDOWP (help_echo_window)
3237                 ? help_echo_window : selected_frame;
3238               event.y = help_echo_string;
3239               event.timestamp = event_timestamp ();
3240               event.code = help_echo_pos;
3241               kbd_buffer_store_event (&event);
3242             }
3243         }
3244 
3245       for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
3246         for (press = 0; press < 2; press++)
3247           {
3248             int button_num = but;
3249 
3250             if (press)
3251               ok = mouse_pressed (but, &x, &y);
3252             else
3253               ok = mouse_released (but, &x, &y);
3254             if (ok)
3255               {
3256                 /* Allow a simultaneous press/release of Mouse-1 and
3257                    Mouse-2 to simulate Mouse-3 on two-button mice.  */
3258                 if (mouse_button_count == 2 && but < 2)
3259                   {
3260                     int x2, y2; /* don't clobber original coordinates */
3261 
3262                     /* If only one button is pressed, wait 100 msec and
3263                        check again.  This way, Speedy Gonzales isn't
3264                        punished, while the slow get their chance.  */
3265                     if (press && mouse_pressed (1-but, &x2, &y2)
3266                         || !press && mouse_released (1-but, &x2, &y2))
3267                       button_num = 2;
3268                     else
3269                       {
3270                         delay (100);
3271                         if (press && mouse_pressed (1-but, &x2, &y2)
3272                             || !press && mouse_released (1-but, &x2, &y2))
3273                           button_num = 2;
3274                       }
3275                   }
3276 
3277                 event.kind = MOUSE_CLICK_EVENT;
3278                 event.code = button_num;
3279                 event.modifiers = dos_get_modifiers (0)
3280                   | (press ? down_modifier : up_modifier);
3281                 event.x = make_number (x);
3282                 event.y = make_number (y);
3283                 event.frame_or_window = selected_frame;
3284                 event.arg = Qnil;
3285                 event.timestamp = event_timestamp ();
3286                 kbd_buffer_store_event (&event);
3287               }
3288           }
3289     }
3290 
3291   return -1;
3292 }
3293 
3294 static int prev_get_char = -1;
3295 
3296 /* Return 1 if a key is ready to be read without suspending execution.  */
3297 
3298 dos_keysns ()
3299 {
3300   if (prev_get_char != -1)
3301     return 1;
3302   else
3303     return ((prev_get_char = dos_rawgetc ()) != -1);
3304 }
3305 
3306 /* Read a key.  Return -1 if no key is ready.  */
3307 
3308 dos_keyread ()
3309 {
3310   if (prev_get_char != -1)
3311     {
3312       int c = prev_get_char;
3313       prev_get_char = -1;
3314       return c;
3315     }
3316   else
3317     return dos_rawgetc ();
3318 }
3319 
3320 #ifndef HAVE_X_WINDOWS
3321 
3322 /* Simulation of X's menus.  Nothing too fancy here -- just make it work
3323    for now.
3324 
3325    Actually, I don't know the meaning of all the parameters of the functions
3326    here -- I only know how they are called by xmenu.c.  I could of course
3327    grab the nearest Xlib manual (down the hall, second-to-last door on the
3328    left), but I don't think it's worth the effort.  */
3329 
3330 /* These hold text of the current and the previous menu help messages.  */
3331 static char *menu_help_message, *prev_menu_help_message;
3332 /* Pane number and item number of the menu item which generated the
3333    last menu help message.  */
3334 static int menu_help_paneno, menu_help_itemno;
3335 
3336 static XMenu *
3337 IT_menu_create ()
3338 {
3339   XMenu *menu;
3340 
3341   menu = (XMenu *) xmalloc (sizeof (XMenu));
3342   menu->allocated = menu->count = menu->panecount = menu->width = 0;
3343   return menu;
3344 }
3345 
3346 /* Allocate some (more) memory for MENU ensuring that there is room for one
3347    for item.  */
3348 
3349 static void
3350 IT_menu_make_room (XMenu *menu)
3351 {
3352   if (menu->allocated == 0)
3353     {
3354       int count = menu->allocated = 10;
3355       menu->text = (char **) xmalloc (count * sizeof (char *));
3356       menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
3357       menu->panenumber = (int *) xmalloc (count * sizeof (int));
3358       menu->help_text = (char **) xmalloc (count * sizeof (char *));
3359     }
3360   else if (menu->allocated == menu->count)
3361     {
3362       int count = menu->allocated = menu->allocated + 10;
3363       menu->text
3364         = (char **) xrealloc (menu->text, count * sizeof (char *));
3365       menu->submenu
3366         = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
3367       menu->panenumber
3368         = (int *) xrealloc (menu->panenumber, count * sizeof (int));
3369       menu->help_text
3370         = (char **) xrealloc (menu->help_text, count * sizeof (char *));
3371     }
3372 }
3373 
3374 /* Search the given menu structure for a given pane number.  */
3375 
3376 static XMenu *
3377 IT_menu_search_pane (XMenu *menu, int pane)
3378 {
3379   int i;
3380   XMenu *try;
3381 
3382   for (i = 0; i < menu->count; i++)
3383     if (menu->submenu[i])
3384       {
3385         if (pane == menu->panenumber[i])
3386           return menu->submenu[i];
3387         if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
3388           return try;
3389       }
3390   return (XMenu *) 0;
3391 }
3392 
3393 /* Determine how much screen space a given menu needs.  */
3394 
3395 static void
3396 IT_menu_calc_size (XMenu *menu, int *width, int *height)
3397 {
3398   int i, h2, w2, maxsubwidth, maxheight;
3399 
3400   maxsubwidth = 0;
3401   maxheight = menu->count;
3402   for (i = 0; i < menu->count; i++)
3403     {
3404       if (menu->submenu[i])
3405         {
3406           IT_menu_calc_size (menu->submenu[i], &w2, &h2);
3407           if (w2 > maxsubwidth) maxsubwidth = w2;
3408           if (i + h2 > maxheight) maxheight = i + h2;
3409         }
3410     }
3411   *width = menu->width + maxsubwidth;
3412   *height = maxheight;
3413 }
3414 
3415 /* Display MENU at (X,Y) using FACES.  */
3416 
3417 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P)  \
3418   do                                                       \
3419     {                                                      \
3420       (GLYPH).type = CHAR_GLYPH;                           \
3421       SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P);  \
3422       (GLYPH).charpos = -1;                                \
3423     }                                                      \
3424   while (0)
3425 
3426 static void
3427 IT_menu_display (XMenu *menu, int y, int x, int pn, int *faces, int disp_help)
3428 {
3429   int i, j, face, width,  mx, my, enabled, mousehere, row, col;
3430   struct glyph *text, *p;
3431   const unsigned char *q;
3432   struct frame *sf = SELECTED_FRAME();
3433 
3434   menu_help_message = NULL;
3435 
3436   width = menu->width;
3437   /* We multiply width by 2 to account for possible control characters.
3438      FIXME: cater to non-ASCII characters in menus.  */
3439   text = (struct glyph *) xmalloc ((width * 2 + 2) * sizeof (struct glyph));
3440   ScreenGetCursor (&row, &col);
3441   mouse_get_xy (&mx, &my);
3442   IT_update_begin (sf);
3443   for (i = 0; i < menu->count; i++)
3444     {
3445       int max_width = width + 2;
3446 
3447       IT_cursor_to (sf, y + i, x);
3448       enabled
3449         = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
3450       mousehere = (y + i == my && x <= mx && mx < x + max_width);
3451       face = faces[enabled + mousehere * 2];
3452       /* The following if clause means that we display the menu help
3453          strings even if the menu item is currently disabled.  */
3454       if (disp_help && enabled + mousehere * 2 >= 2)
3455         {
3456           menu_help_message = menu->help_text[i];
3457           menu_help_paneno = pn - 1;
3458           menu_help_itemno = i;
3459         }
3460       p = text;
3461       BUILD_CHAR_GLYPH (*p, ' ', face, 0);
3462       p++;
3463       for (j = 0, q = menu->text[i]; *q; j++)
3464         {
3465           unsigned c = STRING_CHAR_ADVANCE (q);
3466 
3467           if (c > 26)
3468             {
3469               BUILD_CHAR_GLYPH (*p, c, face, 0);
3470               p++;
3471             }
3472           else  /* make '^x' */
3473             {
3474               BUILD_CHAR_GLYPH (*p, '^', face, 0);
3475               p++;
3476               j++;
3477               BUILD_CHAR_GLYPH (*p, c + 64, face, 0);
3478               p++;
3479             }
3480         }
3481       /* Don't let the menu text overflow into the next screen row.  */
3482       if (x + max_width > screen_size_X)
3483         {
3484           max_width = screen_size_X - x;
3485           text[max_width - 1].u.ch = '$'; /* indicate it's truncated */
3486         }
3487       for (; j < max_width - 2; j++, p++)
3488         BUILD_CHAR_GLYPH (*p, ' ', face, 0);
3489 
3490       /* 16 is the character code of a character that on DOS terminal
3491          produces a nice-looking right-pointing arrow glyph.  */
3492       BUILD_CHAR_GLYPH (*p, menu->submenu[i] ? 16 : ' ', face, 0);
3493       p++;
3494       IT_write_glyphs (sf, text, max_width);
3495     }
3496   IT_update_end (sf);
3497   IT_cursor_to (sf, row, col);
3498   xfree (text);
3499 }
3500 
3501 /* --------------------------- X Menu emulation ---------------------- */
3502 
3503 /* Report availability of menus.  */
3504 
3505 int
3506 have_menus_p () {  return 1; }
3507 
3508 /* Create a brand new menu structure.  */
3509 
3510 XMenu *
3511 XMenuCreate (Display *foo1, Window foo2, char *foo3)
3512 {
3513   return IT_menu_create ();
3514 }
3515 
3516 /* Create a new pane and place it on the outer-most level.  It is not
3517    clear that it should be placed out there, but I don't know what else
3518    to do.  */
3519 
3520 int
3521 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
3522 {
3523   int len;
3524   char *p;
3525 
3526   if (!enable)
3527     abort ();
3528 
3529   IT_menu_make_room (menu);
3530   menu->submenu[menu->count] = IT_menu_create ();
3531   menu->text[menu->count] = txt;
3532   menu->panenumber[menu->count] = ++menu->panecount;
3533   menu->help_text[menu->count] = NULL;
3534   menu->count++;
3535 
3536   /* Adjust length for possible control characters (which will
3537      be written as ^x).  */
3538   for (len = strlen (txt), p = txt; *p; p++)
3539     if (*p < 27)
3540       len++;
3541 
3542   if (len > menu->width)
3543     menu->width = len;
3544 
3545   return menu->panecount;
3546 }
3547 
3548 /* Create a new item in a menu pane.  */
3549 
3550 int
3551 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
3552                    int foo, char *txt, int enable, char *help_text)
3553 {
3554   int len;
3555   char *p;
3556 
3557   if (pane)
3558     if (!(menu = IT_menu_search_pane (menu, pane)))
3559       return XM_FAILURE;
3560   IT_menu_make_room (menu);
3561   menu->submenu[menu->count] = (XMenu *) 0;
3562   menu->text[menu->count] = txt;
3563   menu->panenumber[menu->count] = enable;
3564   menu->help_text[menu->count] = help_text;
3565   menu->count++;
3566 
3567   /* Adjust length for possible control characters (which will
3568      be written as ^x).  */
3569   for (len = strlen (txt), p = txt; *p; p++)
3570     if (*p < 27)
3571       len++;
3572 
3573   if (len > menu->width)
3574     menu->width = len;
3575 
3576   return XM_SUCCESS;
3577 }
3578 
3579 /* Decide where the menu would be placed if requested at (X,Y).  */
3580 
3581 void
3582 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
3583              int *ulx, int *uly, int *width, int *height)
3584 {
3585   IT_menu_calc_size (menu, width, height);
3586   *ulx = x + 1;
3587   *uly = y;
3588   *width += 2;
3589 }
3590 
3591 struct IT_menu_state
3592 {
3593   void *screen_behind;
3594   XMenu *menu;
3595   int pane;
3596   int x, y;
3597 };
3598 
3599 
3600 /* Display menu, wait for user's response, and return that response.  */
3601 
3602 int
3603 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
3604                int x0, int y0, unsigned ButtonMask, char **txt,
3605                void (*help_callback)(char *, int, int))
3606 {
3607   struct IT_menu_state *state;
3608   int statecount, x, y, i, b, screensize, leave, result, onepane;
3609   int title_faces[4];           /* face to display the menu title */
3610   int faces[4], buffers_num_deleted = 0;
3611   struct frame *sf = SELECTED_FRAME();
3612   Lisp_Object saved_echo_area_message, selectface;
3613 
3614   /* Just in case we got here without a mouse present...  */
3615   if (have_mouse <= 0)
3616     return XM_IA_SELECT;
3617   /* Don't allow non-positive x0 and y0, lest the menu will wrap
3618      around the display.  */
3619   if (x0 <= 0)
3620     x0 = 1;
3621   if (y0 <= 0)
3622     y0 = 1;
3623 
3624   /* We will process all the mouse events directly, so we had
3625      better prevent dos_rawgetc from stealing them from us.  */
3626   mouse_preempted++;
3627 
3628   state = alloca (menu->panecount * sizeof (struct IT_menu_state));
3629   screensize = screen_size * 2;
3630   faces[0]
3631     = lookup_derived_face (sf, intern ("msdos-menu-passive-face"),
3632                            DEFAULT_FACE_ID, 1);
3633   faces[1]
3634     = lookup_derived_face (sf, intern ("msdos-menu-active-face"),
3635                            DEFAULT_FACE_ID, 1);
3636   selectface = intern ("msdos-menu-select-face");
3637   faces[2] = lookup_derived_face (sf, selectface,
3638                                   faces[0], 1);
3639   faces[3] = lookup_derived_face (sf, selectface,
3640                                   faces[1], 1);
3641 
3642   /* Make sure the menu title is always displayed with
3643      `msdos-menu-active-face', no matter where the mouse pointer is.  */
3644   for (i = 0; i < 4; i++)
3645     title_faces[i] = faces[3];
3646 
3647   statecount = 1;
3648 
3649   /* Don't let the title for the "Buffers" popup menu include a
3650      digit (which is ugly).
3651 
3652      This is a terrible kludge, but I think the "Buffers" case is
3653      the only one where the title includes a number, so it doesn't
3654      seem to be necessary to make this more general.  */
3655   if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3656     {
3657       menu->text[0][7] = '\0';
3658       buffers_num_deleted = 1;
3659     }
3660 
3661   /* We need to save the current echo area message, so that we could
3662      restore it below, before we exit.  See the commentary below,
3663      before the call to message_with_string.  */
3664   saved_echo_area_message = Fcurrent_message ();
3665   state[0].menu = menu;
3666   mouse_off ();
3667   ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
3668 
3669   /* Turn off the cursor.  Otherwise it shows through the menu
3670      panes, which is ugly.  */
3671   IT_display_cursor (0);
3672 
3673   /* Display the menu title.  */
3674   IT_menu_display (menu, y0 - 1, x0 - 1, 1, title_faces, 0);
3675   if (buffers_num_deleted)
3676     menu->text[0][7] = ' ';
3677   if ((onepane = menu->count == 1 && menu->submenu[0]))
3678     {
3679       menu->width = menu->submenu[0]->width;
3680       state[0].menu = menu->submenu[0];
3681     }
3682   else
3683     {
3684       state[0].menu = menu;
3685     }
3686   state[0].x = x0 - 1;
3687   state[0].y = y0;
3688   state[0].pane = onepane;
3689 
3690   mouse_last_x = -1;  /* A hack that forces display.  */
3691   leave = 0;
3692   while (!leave)
3693     {
3694       if (!mouse_visible) mouse_on ();
3695       mouse_check_moved ();
3696       if (sf->mouse_moved)
3697         {
3698           sf->mouse_moved = 0;
3699           result = XM_IA_SELECT;
3700           mouse_get_xy (&x, &y);
3701           for (i = 0; i < statecount; i++)
3702             if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3703               {
3704                 int dy = y - state[i].y;
3705                 if (0 <= dy && dy < state[i].menu->count)
3706                   {
3707                     if (!state[i].menu->submenu[dy])
3708                       if (state[i].menu->panenumber[dy])
3709                         result = XM_SUCCESS;
3710                       else
3711                         result = XM_IA_SELECT;
3712                     *pane = state[i].pane - 1;
3713                     *selidx = dy;
3714                     /* We hit some part of a menu, so drop extra menus that
3715                        have been opened.  That does not include an open and
3716                        active submenu.  */
3717                     if (i != statecount - 2
3718                         || state[i].menu->submenu[dy] != state[i+1].menu)
3719                       while (i != statecount - 1)
3720                         {
3721                           statecount--;
3722                           mouse_off ();
3723                           ScreenUpdate (state[statecount].screen_behind);
3724                           if (screen_virtual_segment)
3725                             dosv_refresh_virtual_screen (0, screen_size);
3726                           xfree (state[statecount].screen_behind);
3727                         }
3728                     if (i == statecount - 1 && state[i].menu->submenu[dy])
3729                       {
3730                         IT_menu_display (state[i].menu,
3731                                          state[i].y,
3732                                          state[i].x,
3733                                          state[i].pane,
3734                                          faces, 1);
3735                         state[statecount].menu = state[i].menu->submenu[dy];
3736                         state[statecount].pane = state[i].menu->panenumber[dy];
3737                         mouse_off ();
3738                         ScreenRetrieve (state[statecount].screen_behind
3739                                         = xmalloc (screensize));
3740                         state[statecount].x
3741                           = state[i].x + state[i].menu->width + 2;
3742                         state[statecount].y = y;
3743                         statecount++;
3744                       }
3745                   }
3746               }
3747           IT_menu_display (state[statecount - 1].menu,
3748                            state[statecount - 1].y,
3749                            state[statecount - 1].x,
3750                            state[statecount - 1].pane,
3751                            faces, 1);
3752         }
3753       else
3754         {
3755           if ((menu_help_message || prev_menu_help_message)
3756               && menu_help_message != prev_menu_help_message)
3757             {
3758               help_callback (menu_help_message,
3759                              menu_help_paneno, menu_help_itemno);
3760               IT_display_cursor (0);
3761               prev_menu_help_message = menu_help_message;
3762             }
3763           /* We are busy-waiting for the mouse to move, so let's be nice
3764              to other Windows applications by releasing our time slice.  */
3765           __dpmi_yield ();
3766         }
3767       for (b = 0; b < mouse_button_count && !leave; b++)
3768         {
3769           /* Only leave if user both pressed and released the mouse, and in
3770              that order.  This avoids popping down the menu pane unless
3771              the user is really done with it.  */
3772           if (mouse_pressed (b, &x, &y))
3773             {
3774               while (mouse_button_depressed (b, &x, &y))
3775                 __dpmi_yield ();
3776               leave = 1;
3777             }
3778           (void) mouse_released (b, &x, &y);
3779         }
3780     }
3781 
3782   mouse_off ();
3783   ScreenUpdate (state[0].screen_behind);
3784   if (screen_virtual_segment)
3785     dosv_refresh_virtual_screen (0, screen_size);
3786 
3787   /* We have a situation here.  ScreenUpdate has just restored the
3788      screen contents as it was before we started drawing this menu.
3789      That includes any echo area message that could have been
3790      displayed back then.  (In reality, that echo area message will
3791      almost always be the ``keystroke echo'' that echoes the sequence
3792      of menu items chosen by the user.)  However, if the menu had some
3793      help messages, then displaying those messages caused Emacs to
3794      forget about the original echo area message.  So when
3795      ScreenUpdate restored it, it created a discrepancy between the
3796      actual screen contents and what Emacs internal data structures
3797      know about it.
3798 
3799      To avoid this conflict, we force Emacs to restore the original
3800      echo area message as we found it when we entered this function.
3801      The irony of this is that we then erase the restored message
3802      right away, so the only purpose of restoring it is so that
3803      erasing it works correctly...  */
3804   if (! NILP (saved_echo_area_message))
3805     message_with_string ("%s", saved_echo_area_message, 0);
3806   message (0);
3807   while (statecount--)
3808     xfree (state[statecount].screen_behind);
3809   IT_display_cursor (1);        /* turn cursor back on */
3810   /* Clean up any mouse events that are waiting inside Emacs event queue.
3811      These events are likely to be generated before the menu was even
3812      displayed, probably because the user pressed and released the button
3813      (which invoked the menu) too quickly.  If we don't remove these events,
3814      Emacs will process them after we return and surprise the user.  */
3815   discard_mouse_events ();
3816   mouse_clear_clicks ();
3817   if (!kbd_buffer_events_waiting (1))
3818     clear_input_pending ();
3819   /* Allow mouse events generation by dos_rawgetc.  */
3820   mouse_preempted--;
3821   return result;
3822 }
3823 
3824 /* Dispose of a menu.  */
3825 
3826 void
3827 XMenuDestroy (Display *foo, XMenu *menu)
3828 {
3829   int i;
3830   if (menu->allocated)
3831     {
3832       for (i = 0; i < menu->count; i++)
3833         if (menu->submenu[i])
3834           XMenuDestroy (foo, menu->submenu[i]);
3835       xfree (menu->text);
3836       xfree (menu->submenu);
3837       xfree (menu->panenumber);
3838       xfree (menu->help_text);
3839     }
3840   xfree (menu);
3841   menu_help_message = prev_menu_help_message = NULL;
3842 }
3843 
3844 int
3845 x_pixel_width (struct frame *f)
3846 {
3847   return FRAME_COLS (f);
3848 }
3849 
3850 int
3851 x_pixel_height (struct frame *f)
3852 {
3853   return FRAME_LINES (f);
3854 }
3855 #endif /* !HAVE_X_WINDOWS */
3856 
3857 /* ----------------------- DOS / UNIX conversion --------------------- */
3858 
3859 void msdos_downcase_filename (unsigned char *);
3860 
3861 /* Destructively turn backslashes into slashes.  */
3862 
3863 void
3864 dostounix_filename (p)
3865      register char *p;
3866 {
3867   msdos_downcase_filename (p);
3868 
3869   while (*p)
3870     {
3871       if (*p == '\\')
3872         *p = '/';
3873       p++;
3874     }
3875 }
3876 
3877 /* Destructively turn slashes into backslashes.  */
3878 
3879 void
3880 unixtodos_filename (p)
3881      register char *p;
3882 {
3883   if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3884     {
3885       *p += 'a' - 'A';
3886       p += 2;
3887     }
3888 
3889   while (*p)
3890     {
3891       if (*p == '/')
3892         *p = '\\';
3893       p++;
3894     }
3895 }
3896 
3897 /* Get the default directory for a given drive.  0=def, 1=A, 2=B, ...  */
3898 
3899 int
3900 getdefdir (drive, dst)
3901      int drive;
3902      char *dst;
3903 {
3904   char in_path[4], *p = in_path, e = errno;
3905 
3906   /* Generate "X:." (when drive is X) or "." (when drive is 0).  */
3907   if (drive != 0)
3908     {
3909       *p++ = drive + 'A' - 1;
3910       *p++ = ':';
3911     }
3912 
3913   *p++ = '.';
3914   *p = '\0';
3915   errno = 0;
3916   _fixpath (in_path, dst);
3917     /* _fixpath can set errno to ENOSYS on non-LFN systems because
3918        it queries the LFN support, so ignore that error.  */
3919   if ((errno && errno != ENOSYS) || *dst == '\0')
3920     return 0;
3921 
3922   msdos_downcase_filename (dst);
3923 
3924   errno = e;
3925   return 1;
3926 }
3927 
3928 char *
3929 emacs_root_dir (void)
3930 {
3931   static char root_dir[4];
3932 
3933   sprintf (root_dir, "%c:/", 'A' + getdisk ());
3934   root_dir[0] = tolower (root_dir[0]);
3935   return root_dir;
3936 }
3937 
3938 /* Remove all CR's that are followed by a LF.  */
3939 
3940 int
3941 crlf_to_lf (n, buf)
3942      register int n;
3943      register unsigned char *buf;
3944 {
3945   unsigned char *np = buf, *startp = buf, *endp = buf + n;
3946 
3947   if (n == 0)
3948     return n;
3949   while (buf < endp - 1)
3950     {
3951       if (*buf == 0x0d)
3952         {
3953           if (*(++buf) != 0x0a)
3954             *np++ = 0x0d;
3955         }
3956       else
3957         *np++ = *buf++;
3958     }
3959   if (buf < endp)
3960     *np++ = *buf++;
3961   return np - startp;
3962 }
3963 
3964 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
3965        0, 0, 0,
3966        doc: /* Return non-nil if long file names are supported on MS-DOS.  */)
3967      ()
3968 {
3969   return (_USE_LFN ? Qt : Qnil);
3970 }
3971 
3972 /* Convert alphabetic characters in a filename to lower-case.  */
3973 
3974 void
3975 msdos_downcase_filename (p)
3976      register unsigned char *p;
3977 {
3978   /* Always lower-case drive letters a-z, even if the filesystem
3979      preserves case in filenames.
3980      This is so MSDOS filenames could be compared by string comparison
3981      functions that are case-sensitive.  Even case-preserving filesystems
3982      do not distinguish case in drive letters.  */
3983   if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3984     {
3985       *p += 'a' - 'A';
3986       p += 2;
3987     }
3988 
3989   /* Under LFN we expect to get pathnames in their true case.  */
3990   if (NILP (Fmsdos_long_file_names ()))
3991     for ( ; *p; p++)
3992       if (*p >= 'A' && *p <= 'Z')
3993         *p += 'a' - 'A';
3994 }
3995 
3996 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
3997        1, 1, 0,
3998        doc: /* Convert alphabetic characters in FILENAME to lower case and return that.
3999 When long filenames are supported, doesn't change FILENAME.
4000 If FILENAME is not a string, returns nil.
4001 The argument object is never altered--the value is a copy.  */)
4002      (filename)
4003      Lisp_Object filename;
4004 {
4005   Lisp_Object tem;
4006 
4007   if (! STRINGP (filename))
4008     return Qnil;
4009 
4010   tem = Fcopy_sequence (filename);
4011   msdos_downcase_filename (SDATA (tem));
4012   return tem;
4013 }
4014 
4015 /* The Emacs root directory as determined by init_environment.  */
4016 
4017 static char emacsroot[MAXPATHLEN];
4018 
4019 char *
4020 rootrelativepath (rel)
4021      char *rel;
4022 {
4023   static char result[MAXPATHLEN + 10];
4024 
4025   strcpy (result, emacsroot);
4026   strcat (result, "/");
4027   strcat (result, rel);
4028   return result;
4029 }
4030 
4031 /* Define a lot of environment variables if not already defined.  Don't
4032    remove anything unless you know what you're doing -- lots of code will
4033    break if one or more of these are missing.  */
4034 
4035 void
4036 init_environment (argc, argv, skip_args)
4037      int argc;
4038      char **argv;
4039      int skip_args;
4040 {
4041   char *s, *t, *root;
4042   int len, i;
4043   static const char * const tempdirs[] = {
4044     "$TMPDIR", "$TEMP", "$TMP", "c:/"
4045   };
4046   const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
4047 
4048   /* Make sure they have a usable $TMPDIR.  Many Emacs functions use
4049      temporary files and assume "/tmp" if $TMPDIR is unset, which
4050      will break on DOS/Windows.  Refuse to work if we cannot find
4051      a directory, not even "c:/", usable for that purpose.  */
4052   for (i = 0; i < imax ; i++)
4053     {
4054       const char *tmp = tempdirs[i];
4055       char buf[FILENAME_MAX];
4056 
4057       if (*tmp == '$')
4058         {
4059           int tmp_len;
4060 
4061           tmp = getenv (tmp + 1);
4062           if (!tmp)
4063             continue;
4064 
4065           /* Some lusers set TMPDIR=e:, probably because some losing
4066              programs cannot handle multiple slashes if they use e:/.
4067              e: fails in `access' below, so we interpret e: as e:/.  */
4068           tmp_len = strlen(tmp);
4069           if (tmp[tmp_len - 1] != '/' && tmp[tmp_len - 1] != '\\')
4070             {
4071               strcpy(buf, tmp);
4072               buf[tmp_len++] = '/', buf[tmp_len] = 0;
4073               tmp = buf;
4074             }
4075         }
4076 
4077       /* Note that `access' can lie to us if the directory resides on a
4078          read-only filesystem, like CD-ROM or a write-protected floppy.
4079          The only way to be really sure is to actually create a file and
4080          see if it succeeds.  But I think that's too much to ask.  */
4081       if (tmp && access (tmp, D_OK) == 0)
4082         {
4083           setenv ("TMPDIR", tmp, 1);
4084           break;
4085         }
4086     }
4087   if (i >= imax)
4088     cmd_error_internal
4089       (Fcons (Qerror,
4090               Fcons (build_string ("no usable temporary directories found!!"),
4091                      Qnil)),
4092        "While setting TMPDIR: ");
4093 
4094   /* Note the startup time, so we know not to clear the screen if we
4095      exit immediately; see IT_reset_terminal_modes.
4096      (Yes, I know `clock' returns zero the first time it's called, but
4097      I do this anyway, in case some wiseguy changes that at some point.)  */
4098   startup_time = clock ();
4099 
4100   /* Find our root from argv[0].  Assuming argv[0] is, say,
4101      "c:/emacs/bin/emacs.exe" our root will be "c:/emacs".  */
4102   root = alloca (MAXPATHLEN + 20);
4103   _fixpath (argv[0], root);
4104   msdos_downcase_filename (root);
4105   len = strlen (root);
4106   while (len > 0 && root[len] != '/' && root[len] != ':')
4107     len--;
4108   root[len] = '\0';
4109   if (len > 4
4110       && (strcmp (root + len - 4, "/bin") == 0
4111           || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
4112     root[len - 4] = '\0';
4113   else
4114     strcpy (root, "c:/emacs");  /* let's be defensive */
4115   len = strlen (root);
4116   strcpy (emacsroot, root);
4117 
4118   /* We default HOME to our root.  */
4119   setenv ("HOME", root, 0);
4120 
4121   /* We default EMACSPATH to root + "/bin".  */
4122   strcpy (root + len, "/bin");
4123   setenv ("EMACSPATH", root, 0);
4124 
4125   /* I don't expect anybody to ever use other terminals so the internal
4126      terminal is the default.  */
4127   setenv ("TERM", "internal", 0);
4128 
4129 #ifdef HAVE_X_WINDOWS
4130   /* Emacs expects DISPLAY to be set.  */
4131   setenv ("DISPLAY", "unix:0.0", 0);
4132 #endif
4133 
4134   /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4135      downcase it and mirror the backslashes.  */
4136   s = getenv ("COMSPEC");
4137   if (!s) s = "c:/command.com";
4138   t = alloca (strlen (s) + 1);
4139   strcpy (t, s);
4140   dostounix_filename (t);
4141   setenv ("SHELL", t, 0);
4142 
4143   /* PATH is also downcased and backslashes mirrored.  */
4144   s = getenv ("PATH");
4145   if (!s) s = "";
4146   t = alloca (strlen (s) + 3);
4147   /* Current directory is always considered part of MsDos's path but it is
4148      not normally mentioned.  Now it is.  */
4149   strcat (strcpy (t, ".;"), s);
4150   dostounix_filename (t); /* Not a single file name, but this should work.  */
4151   setenv ("PATH", t, 1);
4152 
4153   /* In some sense all dos users have root privileges, so...  */
4154   setenv ("USER", "root", 0);
4155   setenv ("NAME", getenv ("USER"), 0);
4156 
4157   /* Time zone determined from country code.  To make this possible, the
4158      country code may not span more than one time zone.  In other words,
4159      in the USA, you lose.  */
4160   if (!getenv ("TZ"))
4161     switch (dos_country_code)
4162       {
4163       case 31:                  /* Belgium */
4164       case 32:                  /* The Netherlands */
4165       case 33:                  /* France */
4166       case 34:                  /* Spain */
4167       case 36:                  /* Hungary */
4168       case 38:                  /* Yugoslavia (or what's left of it?) */
4169       case 39:                  /* Italy */
4170       case 41:                  /* Switzerland */
4171       case 42:                  /* Tjekia */
4172       case 45:                  /* Denmark */
4173       case 46:                  /* Sweden */
4174       case 47:                  /* Norway */
4175       case 48:                  /* Poland */
4176       case 49:                  /* Germany */
4177         /* Daylight saving from last Sunday in March to last Sunday in
4178            September, both at 2AM.  */
4179         setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4180         break;
4181       case 44:                  /* United Kingdom */
4182       case 351:                 /* Portugal */
4183       case 354:                 /* Iceland */
4184         setenv ("TZ", "GMT+00", 0);
4185         break;
4186       case 81:                  /* Japan */
4187       case 82:                  /* Korea */
4188         setenv ("TZ", "JST-09", 0);
4189         break;
4190       case 90:                  /* Turkey */
4191       case 358:                 /* Finland */
4192         setenv ("TZ", "EET-02", 0);
4193         break;
4194       case 972:                 /* Israel */
4195         /* This is an approximation.  (For exact rules, use the
4196            `zoneinfo/israel' file which comes with DJGPP, but you need
4197            to install it in `/usr/share/zoneinfo/' directory first.)  */
4198         setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4199         break;
4200       }
4201   tzset ();
4202 }
4203 
4204 
4205 
4206 static int break_stat;   /* BREAK check mode status.    */
4207 static int stdin_stat;   /* stdin IOCTL status.         */
4208 
4209 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4210    control chars by DOS.   Determine the keyboard type.  */
4211 
4212 int
4213 dos_ttraw (struct tty_display_info *tty)
4214 {
4215   union REGS inregs, outregs;
4216   static int first_time = 1;
4217 
4218   /* If we are called for the initial terminal, it's too early to do
4219      anything, and termscript isn't set up.  */
4220   if (tty->terminal->type == output_initial)
4221     return;
4222 
4223   break_stat = getcbrk ();
4224   setcbrk (0);
4225 
4226   if (first_time)
4227     {
4228       inregs.h.ah = 0xc0;
4229       int86 (0x15, &inregs, &outregs);
4230       extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
4231 
4232       have_mouse = 0;
4233 
4234       if (1
4235 #ifdef HAVE_X_WINDOWS
4236           && inhibit_window_system
4237 #endif
4238           )
4239         {
4240           inregs.x.ax = 0x0021;
4241           int86 (0x33, &inregs, &outregs);
4242           have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4243           if (!have_mouse)
4244             {
4245               /* Reportedly, the above doesn't work for some mouse drivers.  There
4246                  is an additional detection method that should work, but might be
4247                  a little slower.  Use that as an alternative.  */
4248               inregs.x.ax = 0x0000;
4249               int86 (0x33, &inregs, &outregs);
4250               have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
4251             }
4252           if (have_mouse)
4253             mouse_button_count = outregs.x.bx;
4254 
4255 #ifndef HAVE_X_WINDOWS
4256           /* Save the cursor shape used outside Emacs.  */
4257           outside_cursor = _farpeekw (_dos_ds, 0x460);
4258 #endif
4259         }
4260 
4261       first_time = 0;
4262 
4263       stdin_stat = setmode (fileno (stdin), O_BINARY);
4264       return (stdin_stat != -1);
4265     }
4266   else
4267     return (setmode (fileno (stdin), O_BINARY) != -1);
4268 }
4269 
4270 /*  Restore status of standard input and Ctrl-C checking.  */
4271 
4272 int
4273 dos_ttcooked ()
4274 {
4275   union REGS inregs, outregs;
4276 
4277   setcbrk (break_stat);
4278   mouse_off ();
4279 
4280 #ifndef HAVE_X_WINDOWS
4281   /* Restore the cursor shape we found on startup.  */
4282   if (outside_cursor)
4283     {
4284       inregs.h.ah = 1;
4285       inregs.x.cx = outside_cursor;
4286       int86 (0x10, &inregs, &outregs);
4287     }
4288 #endif
4289 
4290   return (setmode (fileno (stdin), stdin_stat) != -1);
4291 }
4292 
4293 
4294 /* Run command as specified by ARGV in directory DIR.
4295    The command is run with input from TEMPIN, output to
4296    file TEMPOUT and stderr to TEMPERR.  */
4297 
4298 int
4299 run_msdos_command (argv, working_dir, tempin, tempout, temperr, envv)
4300      unsigned char **argv;
4301      const char *working_dir;
4302      int tempin, tempout, temperr;
4303      char **envv;
4304 {
4305   char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
4306   char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS.  */
4307   int msshell, result = -1, inbak, outbak, errbak, x, y;
4308   Lisp_Object cmd;
4309 
4310   /* Get current directory as MSDOS cwd is not per-process.  */
4311   getwd (oldwd);
4312 
4313   /* If argv[0] is the shell, it might come in any lettercase.
4314      Since `Fmember' is case-sensitive, we need to downcase
4315      argv[0], even if we are on case-preserving filesystems.  */
4316   lowcase_argv0 = alloca (strlen (argv[0]) + 1);
4317   for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
4318     {
4319       *pl = *pa++;
4320       if (*pl >= 'A' && *pl <= 'Z')
4321         *pl += 'a' - 'A';
4322     }
4323   *pl = '\0';
4324 
4325   cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
4326   msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
4327     && !strcmp ("-c", argv[1]);
4328   if (msshell)
4329     {
4330       saveargv1 = argv[1];
4331       saveargv2 = argv[2];
4332       argv[1] = "/c";
4333       /* We only need to mirror slashes if a DOS shell will be invoked
4334          not via `system' (which does the mirroring itself).  Yes, that
4335          means DJGPP v1.x will lose here.  */
4336       if (argv[2] && argv[3])
4337         {
4338           char *p = alloca (strlen (argv[2]) + 1);
4339 
4340           strcpy (argv[2] = p, saveargv2);
4341           while (*p && isspace (*p))
4342             p++;
4343           while (*p)
4344             {
4345               if (*p == '/')
4346                 *p++ = '\\';
4347               else
4348                 p++;
4349             }
4350         }
4351     }
4352 
4353   chdir (working_dir);
4354   inbak = dup (0);
4355   outbak = dup (1);
4356   errbak = dup (2);
4357   if (inbak < 0 || outbak < 0 || errbak < 0)
4358     goto done; /* Allocation might fail due to lack of descriptors.  */
4359 
4360   if (have_mouse > 0)
4361     mouse_get_xy (&x, &y);
4362 
4363   if (!noninteractive)
4364     dos_ttcooked ();    /* do it here while 0 = stdin */
4365 
4366   dup2 (tempin, 0);
4367   dup2 (tempout, 1);
4368   dup2 (temperr, 2);
4369 
4370   if (msshell && !argv[3])
4371     {
4372       /* MS-DOS native shells are too restrictive.  For starters, they
4373          cannot grok commands longer than 126 characters.  In DJGPP v2
4374          and later, `system' is much smarter, so we'll call it instead.  */
4375 
4376       const char *cmnd;
4377 
4378       /* A shell gets a single argument--its full command
4379          line--whose original was saved in `saveargv2'.  */
4380 
4381       /* Don't let them pass empty command lines to `system', since
4382          with some shells it will try to invoke an interactive shell,
4383          which will hang Emacs.  */
4384       for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
4385         ;
4386       if (*cmnd)
4387         {
4388           extern char **environ;
4389           char **save_env = environ;
4390           int save_system_flags = __system_flags;
4391 
4392           /* Request the most powerful version of `system'.  We need
4393              all the help we can get to avoid calling stock DOS shells.  */
4394           __system_flags =  (__system_redirect
4395                              | __system_use_shell
4396                              | __system_allow_multiple_cmds
4397                              | __system_allow_long_cmds
4398                              | __system_handle_null_commands
4399                              | __system_emulate_chdir);
4400 
4401           environ = envv;
4402           result = system (cmnd);
4403           __system_flags = save_system_flags;
4404           environ = save_env;
4405         }
4406       else
4407         result = 0;     /* emulate Unixy shell behavior with empty cmd line */
4408     }
4409   else
4410     result = spawnve (P_WAIT, argv[0], argv, envv);
4411 
4412   dup2 (inbak, 0);
4413   dup2 (outbak, 1);
4414   dup2 (errbak, 2);
4415   emacs_close (inbak);
4416   emacs_close (outbak);
4417   emacs_close (errbak);
4418 
4419   if (!noninteractive)
4420     dos_ttraw (CURTTY ());
4421   if (have_mouse > 0)
4422     {
4423       mouse_init ();
4424       mouse_moveto (x, y);
4425     }
4426 
4427   /* Some programs might change the meaning of the highest bit of the
4428      text attribute byte, so we get blinking characters instead of the
4429      bright background colors.  Restore that.  */
4430   if (!noninteractive)
4431     bright_bg ();
4432 
4433  done:
4434   chdir (oldwd);
4435   if (msshell)
4436     {
4437       argv[1] = saveargv1;
4438       argv[2] = saveargv2;
4439     }
4440   return result;
4441 }
4442 
4443 void
4444 croak (badfunc)
4445      char *badfunc;
4446 {
4447   fprintf (stderr, "%s not yet implemented\r\n", badfunc);
4448   reset_all_sys_modes ();
4449   exit (1);
4450 }
4451 
4452 /*
4453  * A few unimplemented functions that we silently ignore.
4454  */
4455 setpgrp () {return 0; }
4456 setpriority (x,y,z) int x,y,z; { return 0; }
4457 
4458 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4459 
4460 /* Augment DJGPP library POSIX signal functions.  This is needed
4461    as of DJGPP v2.01, but might be in the library in later releases. */
4462 
4463 #include <libc/bss.h>
4464 
4465 /* A counter to know when to re-initialize the static sets.  */
4466 static int sigprocmask_count = -1;
4467 
4468 /* Which signals are currently blocked (initially none).  */
4469 static sigset_t current_mask;
4470 
4471 /* Which signals are pending (initially none).  */
4472 static sigset_t msdos_pending_signals;
4473 
4474 /* Previous handlers to restore when the blocked signals are unblocked.  */
4475 typedef void (*sighandler_t)(int);
4476 static sighandler_t prev_handlers[320];
4477 
4478 /* A signal handler which just records that a signal occurred
4479    (it will be raised later, if and when the signal is unblocked).  */
4480 static void
4481 sig_suspender (signo)
4482      int signo;
4483 {
4484   sigaddset (&msdos_pending_signals, signo);
4485 }
4486 
4487 int
4488 sigprocmask (how, new_set, old_set)
4489      int how;
4490      const sigset_t *new_set;
4491      sigset_t *old_set;
4492 {
4493   int signo;
4494   sigset_t new_mask;
4495 
4496   /* If called for the first time, initialize.  */
4497   if (sigprocmask_count != __bss_count)
4498     {
4499       sigprocmask_count = __bss_count;
4500       sigemptyset (&msdos_pending_signals);
4501       sigemptyset (&current_mask);
4502       for (signo = 0; signo < 320; signo++)
4503         prev_handlers[signo] = SIG_ERR;
4504     }
4505 
4506   if (old_set)
4507     *old_set = current_mask;
4508 
4509   if (new_set == 0)
4510     return 0;
4511 
4512   if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
4513     {
4514       errno = EINVAL;
4515       return -1;
4516     }
4517 
4518   sigemptyset (&new_mask);
4519 
4520   /* DJGPP supports upto 320 signals.  */
4521   for (signo = 0; signo < 320; signo++)
4522     {
4523       if (sigismember (&current_mask, signo))
4524         sigaddset (&new_mask, signo);
4525       else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
4526         {
4527           sigaddset (&new_mask, signo);
4528 
4529           /* SIGKILL is silently ignored, as on other platforms.  */
4530           if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
4531             prev_handlers[signo] = signal (signo, sig_suspender);
4532         }
4533       if ((   how == SIG_UNBLOCK
4534               && sigismember (&new_mask, signo)
4535               && sigismember (new_set, signo))
4536           || (how == SIG_SETMASK
4537               && sigismember (&new_mask, signo)
4538               && !sigismember (new_set, signo)))
4539         {
4540           sigdelset (&new_mask, signo);
4541           if (prev_handlers[signo] != SIG_ERR)
4542             {
4543               signal (signo, prev_handlers[signo]);
4544               prev_handlers[signo] = SIG_ERR;
4545             }
4546           if (sigismember (&msdos_pending_signals, signo))
4547             {
4548               sigdelset (&msdos_pending_signals, signo);
4549               raise (signo);
4550             }
4551         }
4552     }
4553   current_mask = new_mask;
4554   return 0;
4555 }
4556 
4557 #endif /* not __DJGPP_MINOR__ < 2 */
4558 
4559 #ifndef HAVE_SELECT
4560 #include "sysselect.h"
4561 
4562 #ifndef EMACS_TIME_ZERO_OR_NEG_P
4563 #define EMACS_TIME_ZERO_OR_NEG_P(time)  \
4564   ((long)(time).tv_sec < 0              \
4565    || ((time).tv_sec == 0               \
4566        && (long)(time).tv_usec <= 0))
4567 #endif
4568 
4569 /* This yields the rest of the current time slice to the task manager.
4570    It should be called by any code which knows that it has nothing
4571    useful to do except idle.
4572 
4573    I don't use __dpmi_yield here, since versions of library before 2.02
4574    called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4575    on some versions of Windows 9X.  */
4576 
4577 void
4578 dos_yield_time_slice (void)
4579 {
4580   _go32_dpmi_registers r;
4581 
4582   r.x.ax = 0x1680;
4583   r.x.ss = r.x.sp = r.x.flags = 0;
4584   _go32_dpmi_simulate_int (0x2f, &r);
4585   if (r.h.al == 0x80)
4586     errno = ENOSYS;
4587 }
4588 
4589 /* Only event queue is checked.  */
4590 /* We don't have to call timer_check here
4591    because wait_reading_process_output takes care of that.  */
4592 int
4593 sys_select (nfds, rfds, wfds, efds, timeout)
4594      int nfds;
4595      SELECT_TYPE *rfds, *wfds, *efds;
4596      EMACS_TIME *timeout;
4597 {
4598   int check_input;
4599   struct time t;
4600 
4601   check_input = 0;
4602   if (rfds)
4603     {
4604       check_input = FD_ISSET (0, rfds);
4605       FD_ZERO (rfds);
4606     }
4607   if (wfds)
4608     FD_ZERO (wfds);
4609   if (efds)
4610     FD_ZERO (efds);
4611 
4612   if (nfds != 1)
4613     abort ();
4614 
4615   /* If we are looking only for the terminal, with no timeout,
4616      just read it and wait -- that's more efficient.  */
4617   if (!timeout)
4618     {
4619       while (!detect_input_pending ())
4620         {
4621           dos_yield_time_slice ();
4622         }
4623     }
4624   else
4625     {
4626       EMACS_TIME clnow, cllast, cldiff;
4627 
4628       gettime (&t);
4629       EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
4630 
4631       while (!check_input || !detect_input_pending ())
4632         {
4633           gettime (&t);
4634           EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
4635           EMACS_SUB_TIME (cldiff, clnow, cllast);
4636 
4637           /* When seconds wrap around, we assume that no more than
4638              1 minute passed since last `gettime'.  */
4639           if (EMACS_TIME_NEG_P (cldiff))
4640             EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
4641           EMACS_SUB_TIME (*timeout, *timeout, cldiff);
4642 
4643           /* Stop when timeout value crosses zero.  */
4644           if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
4645             return 0;
4646           cllast = clnow;
4647           dos_yield_time_slice ();
4648         }
4649     }
4650 
4651   FD_SET (0, rfds);
4652   return 1;
4653 }
4654 #endif
4655 
4656 /*
4657  * Define overlaid functions:
4658  *
4659  *      chdir -> sys_chdir
4660  *      tzset -> init_gettimeofday
4661  *      abort -> dos_abort
4662  */
4663 
4664 #ifdef chdir
4665 #undef chdir
4666 extern int chdir ();
4667 
4668 int
4669 sys_chdir (path)
4670      const char* path;
4671 {
4672   int len = strlen (path);
4673   char *tmp = (char *)path;
4674 
4675   if (*tmp && tmp[1] == ':')
4676     {
4677       if (getdisk () != tolower (tmp[0]) - 'a')
4678         setdisk (tolower (tmp[0]) - 'a');
4679       tmp += 2; /* strip drive: KFS 1995-07-06 */
4680       len -= 2;
4681     }
4682 
4683   if (len > 1 && (tmp[len - 1] == '/'))
4684     {
4685       char *tmp1 = (char *) alloca (len + 1);
4686       strcpy (tmp1, tmp);
4687       tmp1[len - 1] = 0;
4688       tmp = tmp1;
4689     }
4690   return chdir (tmp);
4691 }
4692 #endif
4693 
4694 #ifdef tzset
4695 #undef tzset
4696 extern void tzset (void);
4697 
4698 void
4699 init_gettimeofday ()
4700 {
4701   time_t ltm, gtm;
4702   struct tm *lstm;
4703 
4704   tzset ();
4705   ltm = gtm = time (NULL);
4706   ltm = mktime (lstm = localtime (&ltm));
4707   gtm = mktime (gmtime (&gtm));
4708   time_rec.tm_hour = 99;        /* force gettimeofday to get date */
4709   time_rec.tm_isdst = lstm->tm_isdst;
4710   dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
4711 }
4712 #endif
4713 
4714 #ifdef abort
4715 #undef abort
4716 void
4717 dos_abort (file, line)
4718      char *file;
4719      int  line;
4720 {
4721   char buffer1[200], buffer2[400];
4722   int i, j;
4723 
4724   sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
4725   for (i = j = 0; buffer1[i]; i++) {
4726     buffer2[j++] = buffer1[i];
4727     buffer2[j++] = 0x70;
4728   }
4729   dosmemput (buffer2, j, (int)ScreenPrimary);
4730   ScreenSetCursor (2, 0);
4731   abort ();
4732 }
4733 #else
4734 void
4735 abort ()
4736 {
4737   dos_ttcooked ();
4738   ScreenSetCursor (10, 0);
4739   cputs ("\r\n\nEmacs aborted!\r\n");
4740 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4741   if (screen_virtual_segment)
4742     dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
4743   /* Generate traceback, so we could tell whodunit.  */
4744   signal (SIGINT, SIG_DFL);
4745   __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
4746 #else  /* __DJGPP_MINOR__ >= 2 */
4747   raise (SIGABRT);
4748 #endif /* __DJGPP_MINOR__ >= 2 */
4749   exit (2);
4750 }
4751 #endif
4752 
4753 /* The following variables are required so that cus-start.el won't
4754    complain about unbound variables.  */
4755 #ifndef subprocesses
4756 /* Nonzero means delete a process right away if it exits (process.c).  */
4757 static int delete_exited_processes;
4758 #endif
4759 
4760 syms_of_msdos ()
4761 {
4762   recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
4763   staticpro (&recent_doskeys);
4764 
4765 #ifndef HAVE_X_WINDOWS
4766 
4767   /* The following two are from xfns.c:  */
4768   Qreverse = intern ("reverse");
4769   staticpro (&Qreverse);
4770 
4771   DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph,
4772                doc: /* *Glyph to display instead of chars not supported by current codepage.
4773 This variable is used only by MS-DOS terminals.  */);
4774   Vdos_unsupported_char_glyph = make_number ('\177');
4775 
4776 #endif
4777 #ifndef subprocesses
4778   DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
4779                doc: /* *Non-nil means delete processes immediately when they exit.
4780 A value of nil means don't delete them until `list-processes' is run.  */);
4781   delete_exited_processes = 0;
4782 #endif
4783 
4784   defsubr (&Srecent_doskeys);
4785   defsubr (&Smsdos_long_file_names);
4786   defsubr (&Smsdos_downcase_filename);
4787   defsubr (&Smsdos_remember_default_colors);
4788   defsubr (&Smsdos_set_mouse_buttons);
4789 }
4790 
4791 #endif /* MSDOS */
4792 
4793 /* arch-tag: db404e92-52a5-475f-9eb2-1cb78dd05f30
4794    (do not change this comment) */