root/src/msdos.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. event_timestamp
  2. mouse_on
  3. mouse_off
  4. mouse_setup_buttons
  5. DEFUN
  6. mouse_get_xy
  7. mouse_moveto
  8. mouse_pressed
  9. mouse_released
  10. mouse_button_depressed
  11. mouse_get_pos
  12. mouse_check_moved
  13. mouse_clear_clicks
  14. mouse_init
  15. dosv_refresh_virtual_screen
  16. dos_direct_output
  17. bright_bg
  18. maybe_enable_blinking
  19. vga_installed
  20. dos_set_window_size
  21. mouse_off_maybe
  22. msdos_set_cursor_shape
  23. IT_set_cursor_type
  24. IT_ring_bell
  25. IT_set_face
  26. IT_write_glyphs
  27. popup_activated
  28. tty_draw_row_with_mouse_face
  29. IT_clear_end_of_line
  30. IT_clear_screen
  31. IT_clear_to_end
  32. IT_cursor_to
  33. IT_display_cursor
  34. IT_cmgoto
  35. IT_update_begin
  36. IT_update_end
  37. IT_frame_up_to_date
  38. IT_copy_glyphs
  39. IT_insert_glyphs
  40. IT_delete_glyphs
  41. IT_set_terminal_modes
  42. IT_reset_terminal_modes
  43. DEFUN
  44. IT_set_frame_parameters
  45. internal_terminal_init
  46. initialize_msdos_display
  47. dos_get_saved_screen
  48. dos_set_keyboard
  49. dos_get_modifiers
  50. DEFUN
  51. dos_rawgetc
  52. dos_keysns
  53. dos_keyread
  54. IT_menu_create
  55. IT_menu_make_room
  56. IT_menu_search_pane
  57. IT_menu_calc_size
  58. IT_menu_display
  59. XMenuCreate
  60. XMenuAddPane
  61. XMenuAddSelection
  62. XMenuLocate
  63. XMenuActivate
  64. XMenuDestroy
  65. dostounix_filename
  66. unixtodos_filename
  67. getdefdir
  68. emacs_root_dir
  69. crlf_to_lf
  70. DEFUN
  71. msdos_downcase_filename
  72. DEFUN
  73. rootrelativepath
  74. init_environment
  75. dos_ttraw
  76. dos_ttcooked
  77. run_msdos_command
  78. croak
  79. tcgetpgrp
  80. setpgid
  81. setpriority
  82. setsid
  83. readlink
  84. sys_opendir
  85. readlinkat
  86. openat
  87. fchmodat
  88. careadlinkat
  89. futimens
  90. utimensat
  91. faccessat
  92. fstatat
  93. unsetenv
  94. dos_yield_time_slice
  95. sys_select
  96. sys_chdir
  97. init_gettimeofday
  98. msdos_abort
  99. msdos_fatal_signal
  100. syms_of_msdos

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

/* [<][>][^][v][top][bottom][index][help] */