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

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