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