1 /* MS-DOS specific C utilities.
2 Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Contributed by Morten Welinder */
22 /* New display, keyboard, and mouse control by Kim F. Storm */
24 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
32 #include <sys/param.h>
36 #include <sys/stat.h> /* for _fixpath */
39 #include <libc/dosio.h> /* for _USE_LFN */
45 #include "termhooks.h"
46 #include "dispextern.h"
53 /* #include <process.h> */
54 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
69 /* If other `malloc' than ours is used, force our `sbrk' behave like
70 Unix programs expect (resize memory blocks to keep them contiguous).
71 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
72 because that's what `gmalloc' expects to get. */
76 int _crt0_startup_flags
= _CRT0_FLAG_UNIX_SBRK
;
77 #else /* not REL_ALLOC */
78 int _crt0_startup_flags
= (_CRT0_FLAG_UNIX_SBRK
| _CRT0_FLAG_FILL_SBRK_MEMORY
);
79 #endif /* not REL_ALLOC */
80 #endif /* GNU_MALLOC */
82 #endif /* not SYSTEM_MALLOC */
83 #endif /* __DJGPP__ > 1 */
102 /* ------------------------ Mouse control ---------------------------
104 * Coordinates are in screen positions and zero based.
105 * Mouse buttons are numbered from left to right and also zero based.
108 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
109 static int mouse_visible
;
111 static int mouse_last_x
;
112 static int mouse_last_y
;
114 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
115 static int mouse_button_count
;
122 if (have_mouse
> 0 && !mouse_visible
)
125 fprintf (termscript
, "<M_ON>");
127 int86 (0x33, ®s
, ®s
);
137 if (have_mouse
> 0 && mouse_visible
)
140 fprintf (termscript
, "<M_OFF>");
142 int86 (0x33, ®s
, ®s
);
154 fprintf (termscript
, "<M_XY=%dx%d>", x
, y
);
156 mouse_last_x
= regs
.x
.cx
= x
* 8;
157 mouse_last_y
= regs
.x
.dx
= y
* 8;
158 int86 (0x33, ®s
, ®s
);
162 mouse_pressed (b
, xp
, yp
)
167 if (b
>= mouse_button_count
)
170 regs
.x
.bx
= mouse_button_translate
[b
];
171 int86 (0x33, ®s
, ®s
);
173 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
174 return (regs
.x
.bx
!= 0);
178 mouse_released (b
, xp
, yp
)
183 if (b
>= mouse_button_count
)
186 regs
.x
.bx
= mouse_button_translate
[b
];
187 int86 (0x33, ®s
, ®s
);
189 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
190 return (regs
.x
.bx
!= 0);
194 mouse_get_xy (int *x
, int *y
)
199 int86 (0x33, ®s
, ®s
);
205 mouse_get_pos (f
, insist
, bar_window
, part
, x
, y
, time
)
208 Lisp_Object
*bar_window
, *x
, *y
;
209 enum scroll_bar_part
*part
;
216 int86 (0x33, ®s
, ®s
);
219 mouse_get_xy (&ix
, &iy
);
220 selected_frame
->mouse_moved
= 0;
221 *x
= make_number (ix
);
222 *y
= make_number (iy
);
223 *time
= event_timestamp ();
231 mouse_get_xy (&x
, &y
);
232 selected_frame
->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
243 fprintf (termscript
, "<M_INIT>");
246 int86 (0x33, ®s
, ®s
);
250 regs
.x
.dx
= 8 * (ScreenCols () - 1);
251 int86 (0x33, ®s
, ®s
);
255 regs
.x
.dx
= 8 * (ScreenRows () - 1);
256 int86 (0x33, ®s
, ®s
);
262 /* ------------------------- Screen control ----------------------
266 static int internal_terminal
= 0;
268 #ifndef HAVE_X_WINDOWS
269 extern unsigned char ScreenAttrib
;
270 static int screen_face
;
271 static int highlight
;
273 static int screen_size_X
;
274 static int screen_size_Y
;
275 static int screen_size
;
277 static int current_pos_X
;
278 static int current_pos_Y
;
279 static int new_pos_X
;
280 static int new_pos_Y
;
282 static void *startup_screen_buffer
;
283 static int startup_screen_size_X
;
284 static int startup_screen_size_Y
;
285 static int startup_pos_X
;
286 static int startup_pos_Y
;
287 static unsigned char startup_screen_attrib
;
289 static int term_setup_done
;
291 /* Similar to the_only_frame. */
292 struct x_output the_only_x_display
;
294 /* This is never dereferenced. */
295 Display
*x_current_display
;
298 #define SCREEN_SET_CURSOR() \
299 if (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y) \
300 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X)
303 dos_direct_output (y
, x
, buf
, len
)
309 int t
= (int) ScreenPrimary
+ 2 * (x
+ y
* screen_size_X
);
312 dosmemput (buf
++, 1, t
);
318 /* Flash the screen as a substitute for BEEPs. */
322 do_visible_bell (xorattr
)
323 unsigned char xorattr
;
328 movl _ScreenPrimary,%%eax
335 xorb %%al,%%gs:(%%ebx)
351 : "m" (xorattr
), "g" (screen_size
)
352 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
356 ScreenVisualBell (void)
358 /* This creates an xor-mask that will swap the default fore- and
359 background colors. */
360 do_visible_bell (((the_only_x_display
.foreground_pixel
361 ^ the_only_x_display
.background_pixel
)
366 #ifndef HAVE_X_WINDOWS
368 /* Enable bright background colors. */
376 int86 (0x10, ®s
, ®s
);
379 /* Set the screen dimensions so that it can show no less than
380 ROWS x COLS frame. */
383 dos_set_window_size (rows
, cols
)
387 Lisp_Object video_mode
;
388 int video_mode_value
;
391 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
393 if (*rows
== current_rows
&& *cols
== current_cols
)
396 /* Do we have a VGA? */
398 int86 (0x10, ®s
, ®s
);
399 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
404 /* If the user specified a special video mode for these dimensions,
406 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
407 video_mode
= XSYMBOL (Fintern_soft (build_string (video_name
),
410 if (INTEGERP (video_mode
)
411 && (video_mode_value
= XINT (video_mode
)) > 0)
413 regs
.x
.ax
= video_mode_value
;
414 int86 (0x10, ®s
, ®s
);
418 /* Must hardware-reset the mouse, or else it won't update
419 its notion of screen dimensions for some non-standard
420 video modes. This is *painfully* slow... */
422 int86 (0x33, ®s
, ®s
);
426 /* Find one of the dimensions supported by standard EGA/VGA
427 which gives us at least the required dimensions. */
436 } std_dimension
[] = {
446 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
448 if (std_dimension
[i
].need_vga
<= have_vga
449 && std_dimension
[i
].rows
>= *rows
)
451 if (std_dimension
[i
].rows
!= current_rows
452 || *cols
!= current_cols
)
453 _set_screen_lines (std_dimension
[i
].rows
);
460 #else /* not __DJGPP__ > 1 */
462 else if (*rows
<= 25)
464 if (current_rows
!= 25 || current_cols
!= 80)
467 int86 (0x10, ®s
, ®s
);
470 int86 (0x10, ®s
, ®s
);
473 int86 (0x10, ®s
, ®s
);
475 int86 (0x10, ®s
, ®s
);
478 else if (*rows
<= 50)
479 if (have_vga
&& (current_rows
!= 50 || current_cols
!= 80)
480 || *rows
<= 43 && (current_rows
!= 43 || current_cols
!= 80))
483 int86 (0x10, ®s
, ®s
);
486 int86 (0x10, ®s
, ®s
);
489 int86 (0x10, ®s
, ®s
);
492 int86 (0x10, ®s
, ®s
);
494 #endif /* not __DJGPP__ > 1 */
502 /* Tell the caller what dimensions have been REALLY set. */
503 *rows
= ScreenRows ();
504 *cols
= ScreenCols ();
506 /* Enable bright background colors. */
510 /* If we write a character in the position where the mouse is,
511 the mouse cursor may need to be refreshed. */
521 mouse_get_xy (&x
, &y
);
522 if (y
!= new_pos_Y
|| x
< new_pos_X
)
538 union REGS inregs
, outregs
;
541 intdos (&inregs
, &outregs
);
546 IT_set_face (int face
)
549 extern struct face
*intern_face (/* FRAME_PTR, struct face * */);
551 if (face
== 1 || (face
== 0 && highlight
))
552 fp
= FRAME_MODE_LINE_FACE (foo
);
553 else if (face
<= 0 || face
>= FRAME_N_COMPUTED_FACES (foo
))
554 fp
= FRAME_DEFAULT_FACE (foo
);
556 fp
= intern_face (selected_frame
, FRAME_COMPUTED_FACES (foo
)[face
]);
558 fprintf (termscript
, "<FACE:%d:%d>", FACE_FOREGROUND (fp
), FACE_BACKGROUND (fp
));
560 ScreenAttrib
= (FACE_BACKGROUND (fp
) << 4) | FACE_FOREGROUND (fp
);
564 IT_write_glyphs (GLYPH
*str
, int len
)
568 unsigned char *buf
, *bp
;
570 if (len
== 0) return;
572 buf
= bp
= alloca (len
* 2);
576 newface
= FAST_GLYPH_FACE (*str
);
577 if (newface
!= screen_face
)
578 IT_set_face (newface
);
579 ch
= FAST_GLYPH_CHAR (*str
);
580 *bp
++ = (unsigned char)ch
;
581 *bp
++ = ScreenAttrib
;
584 fputc (ch
, termscript
);
589 dosmemput (buf
, 2 * len
,
590 (int)ScreenPrimary
+ 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
));
595 IT_clear_end_of_line (first_unused
)
602 fprintf (termscript
, "<CLR:EOL>");
603 i
= (j
= screen_size_X
- new_pos_X
) * 2;
604 spaces
= sp
= alloca (i
);
609 *sp
++ = ScreenAttrib
;
613 dosmemput (spaces
, i
,
614 (int)ScreenPrimary
+ 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
));
618 IT_clear_screen (void)
621 fprintf (termscript
, "<CLR:SCR>");
625 new_pos_X
= new_pos_Y
= 0;
629 IT_clear_to_end (void)
632 fprintf (termscript
, "<CLR:EOS>");
634 while (new_pos_Y
< screen_size_Y
) {
636 IT_clear_end_of_line (0);
642 IT_cursor_to (int y
, int x
)
645 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
651 IT_reassert_line_highlight (new, vpos
)
655 IT_set_face (0); /* To possibly clear the highlighting. */
659 IT_change_line_highlight (new_highlight
, vpos
, first_unused_hpos
)
661 highlight
= new_highlight
;
662 IT_set_face (0); /* To possibly clear the highlighting. */
663 IT_cursor_to (vpos
, 0);
664 IT_clear_end_of_line (first_unused_hpos
);
671 IT_set_face (0); /* To possibly clear the highlighting. */
680 /* This was more or less copied from xterm.c
682 Nowadays, the corresponding function under X is `x_set_menu_bar_lines_1'
686 IT_set_menu_bar_lines (window
, n
)
690 struct window
*w
= XWINDOW (window
);
692 XSETFASTINT (w
->last_modified
, 0);
693 XSETFASTINT (w
->top
, XFASTINT (w
->top
) + n
);
694 XSETFASTINT (w
->height
, XFASTINT (w
->height
) - n
);
696 /* Handle just the top child in a vertical split. */
697 if (!NILP (w
->vchild
))
698 IT_set_menu_bar_lines (w
->vchild
, n
);
700 /* Adjust all children in a horizontal split. */
701 for (window
= w
->hchild
; !NILP (window
); window
= w
->next
)
703 w
= XWINDOW (window
);
704 IT_set_menu_bar_lines (window
, n
);
708 /* This was copied from xfns.c */
711 x_set_menu_bar_lines (f
, value
, oldval
)
713 Lisp_Object value
, oldval
;
716 int olines
= FRAME_MENU_BAR_LINES (f
);
718 /* Right now, menu bars don't work properly in minibuf-only frames;
719 most of the commands try to apply themselves to the minibuffer
720 frame itslef, and get an error because you can't switch buffers
721 in or split the minibuffer window. */
722 if (FRAME_MINIBUF_ONLY_P (f
))
725 if (INTEGERP (value
))
726 nlines
= XINT (value
);
730 FRAME_MENU_BAR_LINES (f
) = nlines
;
731 IT_set_menu_bar_lines (f
->root_window
, nlines
- olines
);
734 /* IT_set_terminal_modes is called when emacs is started,
735 resumed, and whenever the screen is redrawn! */
738 IT_set_terminal_modes (void)
745 fprintf (termscript
, "\n<SET_TERM>");
748 screen_size_X
= ScreenCols ();
749 screen_size_Y
= ScreenRows ();
750 screen_size
= screen_size_X
* screen_size_Y
;
752 new_pos_X
= new_pos_Y
= 0;
753 current_pos_X
= current_pos_Y
= -1;
759 startup_screen_size_X
= screen_size_X
;
760 startup_screen_size_Y
= screen_size_Y
;
761 startup_screen_attrib
= ScreenAttrib
;
763 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
764 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
767 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
768 screen_size_X
, screen_size_Y
);
773 /* IT_reset_terminal_modes is called when emacs is
774 suspended or killed. */
777 IT_reset_terminal_modes (void)
779 int display_row_start
= (int) ScreenPrimary
;
780 int saved_row_len
= startup_screen_size_X
* 2;
781 int update_row_len
= ScreenCols () * 2;
782 int current_rows
= ScreenRows ();
783 int to_next_row
= update_row_len
;
784 unsigned char *saved_row
= startup_screen_buffer
;
785 int cursor_pos_X
= ScreenCols () - 1;
786 int cursor_pos_Y
= ScreenRows () - 1;
789 fprintf (termscript
, "\n<RESET_TERM>");
793 if (!term_setup_done
)
798 /* We have a situation here.
799 We cannot just do ScreenUpdate(startup_screen_buffer) because
800 the luser could have changed screen dimensions inside Emacs
801 and failed (or didn't want) to restore them before killing
802 Emacs. ScreenUpdate() uses the *current* screen dimensions and
803 thus will happily use memory outside what was allocated for
804 `startup_screen_buffer'.
805 Thus we only restore as much as the current screen dimensions
806 can hold, and clear the rest (if the saved screen is smaller than
807 the current) with the color attribute saved at startup. The cursor
808 is also restored within the visible dimensions. */
810 ScreenAttrib
= startup_screen_attrib
;
813 if (update_row_len
> saved_row_len
)
814 update_row_len
= saved_row_len
;
815 if (current_rows
> startup_screen_size_Y
)
816 current_rows
= startup_screen_size_Y
;
819 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
820 update_row_len
/ 2, current_rows
);
822 while (current_rows
--)
824 dosmemput (saved_row
, update_row_len
, display_row_start
);
825 saved_row
+= saved_row_len
;
826 display_row_start
+= to_next_row
;
828 if (startup_pos_X
< cursor_pos_X
)
829 cursor_pos_X
= startup_pos_X
;
830 if (startup_pos_Y
< cursor_pos_Y
)
831 cursor_pos_Y
= startup_pos_Y
;
833 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
834 xfree (startup_screen_buffer
);
840 IT_set_terminal_window (void)
845 IT_set_frame_parameters (f
, alist
)
851 extern unsigned long load_color ();
854 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
856 Lisp_Object elt
, prop
, val
;
861 CHECK_SYMBOL (prop
, 1);
863 if (EQ (prop
, intern ("foreground-color")))
865 unsigned long new_color
= load_color (f
, val
);
868 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
871 fprintf (termscript
, "<FGCOLOR %d>\n", new_color
);
874 else if (EQ (prop
, intern ("background-color")))
876 unsigned long new_color
= load_color (f
, val
);
879 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
882 fprintf (termscript
, "<BGCOLOR %d>\n", new_color
);
885 else if (EQ (prop
, intern ("menu-bar-lines")))
886 x_set_menu_bar_lines (f
, val
, 0);
891 recompute_basic_faces (f
);
892 if (f
== selected_frame
)
897 #endif /* !HAVE_X_WINDOWS */
900 /* Do we need the internal terminal? */
903 internal_terminal_init ()
905 char *term
= getenv ("TERM");
908 #ifdef HAVE_X_WINDOWS
909 if (!inhibit_window_system
)
914 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
916 if (getenv ("EMACSTEST"))
917 termscript
= fopen (getenv ("EMACSTEST"), "wt");
919 #ifndef HAVE_X_WINDOWS
920 if (!internal_terminal
|| inhibit_window_system
)
922 selected_frame
->output_method
= output_termcap
;
926 Vwindow_system
= intern ("pc");
927 Vwindow_system_version
= make_number (1);
929 bzero (&the_only_x_display
, sizeof the_only_x_display
);
930 the_only_x_display
.background_pixel
= 7; /* White */
931 the_only_x_display
.foreground_pixel
= 0; /* Black */
933 colors
= getenv ("EMACSCOLORS");
934 if (colors
&& strlen (colors
) >= 2)
936 /* The colors use 4 bits each (we enable bright background). */
937 if (isdigit (colors
[0]))
939 else if (isxdigit (colors
[0]))
940 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
941 if (colors
[0] >= 0 && colors
[0] < 16)
942 the_only_x_display
.foreground_pixel
= colors
[0];
943 if (isdigit (colors
[1]))
945 else if (isxdigit (colors
[1]))
946 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
947 if (colors
[1] >= 0 && colors
[1] < 16)
948 the_only_x_display
.background_pixel
= colors
[1];
950 the_only_x_display
.line_height
= 1;
951 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
953 init_frame_faces (selected_frame
);
955 ring_bell_hook
= IT_ring_bell
;
956 write_glyphs_hook
= IT_write_glyphs
;
957 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
958 clear_to_end_hook
= IT_clear_to_end
;
959 clear_end_of_line_hook
= IT_clear_end_of_line
;
960 clear_frame_hook
= IT_clear_screen
;
961 change_line_highlight_hook
= IT_change_line_highlight
;
962 update_begin_hook
= IT_update_begin
;
963 update_end_hook
= IT_update_end
;
964 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
966 /* These hooks are called by term.c without being checked. */
967 set_terminal_modes_hook
= IT_set_terminal_modes
;
968 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
969 set_terminal_window_hook
= IT_set_terminal_window
;
973 dos_get_saved_screen (screen
, rows
, cols
)
978 #ifndef HAVE_X_WINDOWS
979 *screen
= startup_screen_buffer
;
980 *cols
= startup_screen_size_X
;
981 *rows
= startup_screen_size_Y
;
988 #ifndef HAVE_X_WINDOWS
990 /* We are not X, but we can emulate it well enough for our needs... */
994 if (! FRAME_MSDOS_P (selected_frame
))
995 error ("Not running under a windows system");
1001 /* ----------------------- Keyboard control ----------------------
1003 * Keymaps reflect the following keyboard layout:
1005 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1006 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1007 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1008 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1012 static int extended_kbd
; /* 101 (102) keyboard present. */
1014 struct dos_keyboard_map
1022 static struct dos_keyboard_map us_keyboard
= {
1024 /* 01234567890123456789012345678901234567890 12345678901234 */
1025 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1026 /* 0123456789012345678901234567890123456789 012345678901234 */
1027 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1028 0 /* no Alt-Gr key */
1031 static struct dos_keyboard_map fr_keyboard
= {
1033 /* 012 3456789012345678901234567890123456789012345678901234 */
1034 "ý&\82\",(-\8a_\80\85)= azertyuiop^$ qsdfghjklm\97* wxcvbnm;:! ",
1035 /* 0123456789012345678901234567890123456789012345678901234 */
1036 " 1234567890ø+ AZERTYUIOPù\9c QSDFGHJKLM%æ WXCVBN?./õ ",
1037 /* 01234567 89012345678901234567890123456789012345678901234 */
1041 static struct dos_keyboard_map dk_keyboard
= {
1043 /* 0123456789012345678901234567890123456789012345678901234 */
1044 "«1234567890+| qwertyuiop\86~ asdfghjkl\91\9b' zxcvbnm,.- ",
1045 /* 01 23456789012345678901234567890123456789012345678901234 */
1046 "õ!\"#$%&/()=?` QWERTYUIOP\8f^ ASDFGHJKL\92\9d* ZXCVBNM;:_ ",
1047 /* 0123456789012345678901234567890123456789012345678901234 */
1051 static struct keyboard_layout_list
1054 struct dos_keyboard_map
*keyboard_map
;
1055 } keyboard_layout_list
[] =
1062 static struct dos_keyboard_map
*keyboard
;
1063 static int keyboard_map_all
;
1066 dos_set_keyboard (code
, always
)
1072 /* Initialize to US settings, for countries that don't have their own. */
1073 keyboard
= keyboard_layout_list
[0].keyboard_map
;
1074 keyboard_map_all
= always
;
1075 dos_keyboard_layout
= 1;
1077 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
1078 if (code
== keyboard_layout_list
[i
].country_code
)
1080 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
1081 keyboard_map_all
= always
;
1082 dos_keyboard_layout
= code
;
1088 #define Ignore 0x0000
1089 #define Normal 0x0000 /* normal key - alt changes scan-code */
1090 #define FctKey 0x1000 /* func key if c == 0, else c */
1091 #define Special 0x2000 /* func key even if c != 0 */
1092 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1093 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1094 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1095 #define Grey 0x6000 /* Grey keypad key */
1097 #define Alt 0x0100 /* alt scan-code */
1098 #define Ctrl 0x0200 /* ctrl scan-code */
1099 #define Shift 0x0400 /* shift scan-code */
1103 unsigned char char_code
; /* normal code */
1104 unsigned char meta_code
; /* M- code */
1105 unsigned char keypad_code
; /* keypad code */
1106 unsigned char editkey_code
; /* edit key */
1107 } keypad_translate_map
[] = {
1108 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1109 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1110 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1111 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1112 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1113 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1114 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1115 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1116 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1117 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1118 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1123 unsigned char char_code
; /* normal code */
1124 unsigned char keypad_code
; /* keypad code */
1125 } grey_key_translate_map
[] = {
1126 '/', 0xaf, /* kp-decimal */
1127 '*', 0xaa, /* kp-multiply */
1128 '-', 0xad, /* kp-subtract */
1129 '+', 0xab, /* kp-add */
1130 '\r', 0x8d /* kp-enter */
1133 static unsigned short
1134 ibmpc_translate_map
[] =
1136 /* --------------- 00 to 0f --------------- */
1137 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
1138 Alt
| ModFct
| 0x1b, /* Escape */
1139 Normal
| 1, /* '1' */
1140 Normal
| 2, /* '2' */
1141 Normal
| 3, /* '3' */
1142 Normal
| 4, /* '4' */
1143 Normal
| 5, /* '5' */
1144 Normal
| 6, /* '6' */
1145 Normal
| 7, /* '7' */
1146 Normal
| 8, /* '8' */
1147 Normal
| 9, /* '9' */
1148 Normal
| 10, /* '0' */
1149 Normal
| 11, /* '-' */
1150 Normal
| 12, /* '=' */
1151 Special
| 0x08, /* Backspace */
1152 ModFct
| 0x74, /* Tab/Backtab */
1154 /* --------------- 10 to 1f --------------- */
1167 ModFct
| 0x0d, /* Return */
1172 /* --------------- 20 to 2f --------------- */
1181 Map
| 40, /* '\'' */
1183 Ignore
, /* Left shift */
1184 Map
| 41, /* '\\' */
1190 /* --------------- 30 to 3f --------------- */
1197 Ignore
, /* Right shift */
1198 Grey
| 1, /* Grey * */
1200 Normal
| ' ', /* ' ' */
1201 Ignore
, /* Caps Lock */
1202 FctKey
| 0xbe, /* F1 */
1203 FctKey
| 0xbf, /* F2 */
1204 FctKey
| 0xc0, /* F3 */
1205 FctKey
| 0xc1, /* F4 */
1206 FctKey
| 0xc2, /* F5 */
1208 /* --------------- 40 to 4f --------------- */
1209 FctKey
| 0xc3, /* F6 */
1210 FctKey
| 0xc4, /* F7 */
1211 FctKey
| 0xc5, /* F8 */
1212 FctKey
| 0xc6, /* F9 */
1213 FctKey
| 0xc7, /* F10 */
1214 Ignore
, /* Num Lock */
1215 Ignore
, /* Scroll Lock */
1216 KeyPad
| 7, /* Home */
1217 KeyPad
| 8, /* Up */
1218 KeyPad
| 9, /* Page Up */
1219 Grey
| 2, /* Grey - */
1220 KeyPad
| 4, /* Left */
1221 KeyPad
| 5, /* Keypad 5 */
1222 KeyPad
| 6, /* Right */
1223 Grey
| 3, /* Grey + */
1224 KeyPad
| 1, /* End */
1226 /* --------------- 50 to 5f --------------- */
1227 KeyPad
| 2, /* Down */
1228 KeyPad
| 3, /* Page Down */
1229 KeyPad
| 0, /* Insert */
1230 KeyPad
| 10, /* Delete */
1231 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
1232 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
1233 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
1234 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
1235 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
1236 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
1237 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
1238 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
1239 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
1240 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
1241 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
1242 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
1244 /* --------------- 60 to 6f --------------- */
1245 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
1246 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
1247 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
1248 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
1249 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
1250 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
1251 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
1252 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
1253 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
1254 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
1255 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
1256 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
1257 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
1258 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
1259 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
1260 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
1262 /* --------------- 70 to 7f --------------- */
1263 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
1264 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
1265 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
1266 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
1267 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
1268 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
1269 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
1270 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
1271 Alt
| Map
| 1, /* '1' */
1272 Alt
| Map
| 2, /* '2' */
1273 Alt
| Map
| 3, /* '3' */
1274 Alt
| Map
| 4, /* '4' */
1275 Alt
| Map
| 5, /* '5' */
1276 Alt
| Map
| 6, /* '6' */
1277 Alt
| Map
| 7, /* '7' */
1278 Alt
| Map
| 8, /* '8' */
1280 /* --------------- 80 to 8f --------------- */
1281 Alt
| Map
| 9, /* '9' */
1282 Alt
| Map
| 10, /* '0' */
1283 Alt
| Map
| 11, /* '-' */
1284 Alt
| Map
| 12, /* '=' */
1285 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
1286 FctKey
| 0xc8, /* F11 */
1287 FctKey
| 0xc9, /* F12 */
1288 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
1289 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
1290 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
1291 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
1292 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
1293 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
1294 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
1295 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
1296 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
1298 /* --------------- 90 to 9f --------------- */
1299 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
1300 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
1301 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
1302 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
1303 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
1304 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
1305 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
1306 Alt
| FctKey
| 0x50, /* (Alt) Home */
1307 Alt
| FctKey
| 0x52, /* (Alt) Up */
1308 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
1309 Ignore
, /* NO KEY */
1310 Alt
| FctKey
| 0x51, /* (Alt) Left */
1311 Ignore
, /* NO KEY */
1312 Alt
| FctKey
| 0x53, /* (Alt) Right */
1313 Ignore
, /* NO KEY */
1314 Alt
| FctKey
| 0x57, /* (Alt) End */
1316 /* --------------- a0 to af --------------- */
1317 Alt
| KeyPad
| 2, /* (Alt) Down */
1318 Alt
| KeyPad
| 3, /* (Alt) Page Down */
1319 Alt
| KeyPad
| 0, /* (Alt) Insert */
1320 Alt
| KeyPad
| 10, /* (Alt) Delete */
1321 Alt
| Grey
| 0, /* (Alt) Grey / */
1322 Alt
| FctKey
| 0x09, /* (Alt) Tab */
1323 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
1326 /* These bit-positions corresponds to values returned by BIOS */
1327 #define SHIFT_P 0x0003 /* two bits! */
1328 #define CTRL_P 0x0004
1329 #define ALT_P 0x0008
1330 #define SCRLOCK_P 0x0010
1331 #define NUMLOCK_P 0x0020
1332 #define CAPSLOCK_P 0x0040
1333 #define ALT_GR_P 0x0800
1334 #define SUPER_P 0x4000 /* pseudo */
1335 #define HYPER_P 0x8000 /* pseudo */
1338 dos_get_modifiers (keymask
)
1345 /* Calculate modifier bits */
1346 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
1347 int86 (0x16, ®s
, ®s
);
1351 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
1352 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1356 mask
= regs
.h
.al
& (SHIFT_P
|
1357 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1359 /* Do not break international keyboard support. */
1360 /* When Keyb.Com is loaded, the right Alt key is */
1361 /* used for accessing characters like { and } */
1362 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
1365 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
1368 if (dos_hyper_key
== 1)
1371 modifiers
|= hyper_modifier
;
1373 else if (dos_super_key
== 1)
1376 modifiers
|= super_modifier
;
1380 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
1383 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
1385 if (dos_hyper_key
== 2)
1388 modifiers
|= hyper_modifier
;
1390 else if (dos_super_key
== 2)
1393 modifiers
|= super_modifier
;
1401 modifiers
|= shift_modifier
;
1403 modifiers
|= ctrl_modifier
;
1405 modifiers
|= meta_modifier
;
1412 #define NUM_RECENT_DOSKEYS (100)
1413 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
1414 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
1415 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
1417 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
1418 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1419 Each input key receives two values in this vector: first the ASCII code,\n\
1420 and then the scan code.")
1423 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
1426 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
1427 return Fvector (total_doskeys
, keys
);
1430 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
1431 bcopy (keys
+ recent_doskeys_index
,
1432 XVECTOR (val
)->contents
,
1433 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
1435 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
1436 recent_doskeys_index
* sizeof (Lisp_Object
));
1441 /* Get a char from keyboard. Function keys are put into the event queue. */
1446 struct input_event event
;
1449 #ifndef HAVE_X_WINDOWS
1450 SCREEN_SET_CURSOR ();
1451 if (!mouse_visible
) mouse_on ();
1454 /* The following condition is equivalent to `kbhit ()', except that
1455 it uses the bios to do its job. This pleases DESQview/X. */
1456 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
1457 int86 (0x16, ®s
, ®s
),
1458 (regs
.x
.flags
& 0x40) == 0)
1461 register unsigned char c
;
1462 int sc
, code
, mask
, kp_mode
;
1465 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
1466 int86 (0x16, ®s
, ®s
);
1471 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1473 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1474 recent_doskeys_index
= 0;
1475 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1477 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1478 recent_doskeys_index
= 0;
1480 modifiers
= dos_get_modifiers (&mask
);
1482 #ifndef HAVE_X_WINDOWS
1483 if (!NILP (Vdos_display_scancodes
))
1486 sprintf (buf
, "%02x:%02x*%04x",
1487 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
1488 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
1496 case 10: /* Ctrl Grey Enter */
1497 code
= Ctrl
| Grey
| 4;
1499 case 13: /* Grey Enter */
1502 case '/': /* Grey / */
1512 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
1514 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
1521 modifiers
|= meta_modifier
;
1523 modifiers
|= ctrl_modifier
;
1525 modifiers
|= shift_modifier
;
1528 switch (code
& 0xf000)
1531 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
1533 c
= 0; /* Special */
1546 if (c
== 0) /* ctrl-break */
1548 return c
; /* ALT-nnn */
1550 if (!keyboard_map_all
)
1559 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
1560 if (!keyboard_map_all
)
1564 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
1565 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
1569 code
= keyboard
->shifted
[code
];
1571 modifiers
&= ~shift_modifier
;
1574 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
1575 code
= keyboard
->alt_gr
[code
];
1577 code
= keyboard
->unshifted
[code
];
1582 if (c
== 0xe0) /* edit key */
1585 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
1586 kp_mode
= dos_keypad_mode
& 0x03;
1588 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
1593 if (code
== 10 && dos_decimal_point
)
1594 return dos_decimal_point
;
1595 return keypad_translate_map
[code
].char_code
;
1598 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
1602 code
= keypad_translate_map
[code
].meta_code
;
1603 modifiers
= meta_modifier
;
1607 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
1614 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
1615 if (dos_keypad_mode
& kp_mode
)
1616 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
1618 code
= grey_key_translate_map
[code
].char_code
;
1627 event
.kind
= non_ascii_keystroke
;
1629 event
.kind
= ascii_keystroke
;
1631 event
.modifiers
= modifiers
;
1632 XSETFRAME (event
.frame_or_window
, selected_frame
);
1633 event
.timestamp
= event_timestamp ();
1634 kbd_buffer_store_event (&event
);
1639 int but
, press
, x
, y
, ok
;
1641 /* Check for mouse movement *before* buttons. */
1642 mouse_check_moved ();
1644 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
1645 for (press
= 0; press
< 2; press
++)
1647 int button_num
= but
;
1650 ok
= mouse_pressed (but
, &x
, &y
);
1652 ok
= mouse_released (but
, &x
, &y
);
1655 /* Allow a simultaneous press/release of Mouse-1 and
1656 Mouse-2 to simulate Mouse-3 on two-button mice. */
1657 if (mouse_button_count
== 2 && but
< 2)
1659 int x2
, y2
; /* don't clobber original coordinates */
1661 /* If only one button is pressed, wait 100 msec and
1662 check again. This way, Speedy Gonzales isn't
1663 punished, while the slow get their chance. */
1664 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
1665 || !press
&& mouse_released (1-but
, &x2
, &y2
))
1670 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
1671 || !press
&& mouse_released (1-but
, &x2
, &y2
))
1676 event
.kind
= mouse_click
;
1677 event
.code
= button_num
;
1678 event
.modifiers
= dos_get_modifiers (0)
1679 | (press
? down_modifier
: up_modifier
);
1682 XSETFRAME (event
.frame_or_window
, selected_frame
);
1683 event
.timestamp
= event_timestamp ();
1684 kbd_buffer_store_event (&event
);
1692 static int prev_get_char
= -1;
1694 /* Return 1 if a key is ready to be read without suspending execution. */
1698 if (prev_get_char
!= -1)
1701 return ((prev_get_char
= dos_rawgetc ()) != -1);
1704 /* Read a key. Return -1 if no key is ready. */
1708 if (prev_get_char
!= -1)
1710 int c
= prev_get_char
;
1715 return dos_rawgetc ();
1718 #ifndef HAVE_X_WINDOWS
1719 /* See xterm.c for more info. */
1721 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
1723 register int pix_x
, pix_y
;
1724 register int *x
, *y
;
1725 void /* XRectangle */ *bounds
;
1728 if (bounds
) abort ();
1730 /* Ignore clipping. */
1737 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
1740 register int *pix_x
, *pix_y
;
1746 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1749 Actually, I don't know the meaning of all the parameters of the functions
1750 here -- I only know how they are called by xmenu.c. I could of course
1751 grab the nearest Xlib manual (down the hall, second-to-last door on the
1752 left), but I don't think it's worth the effort. */
1759 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
1760 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
1764 /* Allocate some (more) memory for MENU ensuring that there is room for one
1768 IT_menu_make_room (XMenu
*menu
)
1770 if (menu
->allocated
== 0)
1772 int count
= menu
->allocated
= 10;
1773 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
1774 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
1775 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
1777 else if (menu
->allocated
== menu
->count
)
1779 int count
= menu
->allocated
= menu
->allocated
+ 10;
1781 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
1783 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
1785 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
1789 /* Search the given menu structure for a given pane number. */
1792 IT_menu_search_pane (XMenu
*menu
, int pane
)
1797 for (i
= 0; i
< menu
->count
; i
++)
1798 if (menu
->submenu
[i
])
1800 if (pane
== menu
->panenumber
[i
])
1801 return menu
->submenu
[i
];
1802 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
1808 /* Determine how much screen space a given menu needs. */
1811 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
1813 int i
, h2
, w2
, maxsubwidth
, maxheight
;
1816 maxheight
= menu
->count
;
1817 for (i
= 0; i
< menu
->count
; i
++)
1819 if (menu
->submenu
[i
])
1821 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
1822 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
1823 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
1826 *width
= menu
->width
+ maxsubwidth
;
1827 *height
= maxheight
;
1830 /* Display MENU at (X,Y) using FACES. */
1833 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
)
1835 int i
, j
, face
, width
;
1839 int enabled
, mousehere
;
1842 width
= menu
->width
;
1843 text
= (GLYPH
*) xmalloc ((width
+ 2) * sizeof (GLYPH
));
1844 ScreenGetCursor (&row
, &col
);
1845 mouse_get_xy (&mx
, &my
);
1847 for (i
= 0; i
< menu
->count
; i
++)
1849 IT_cursor_to (y
+ i
, x
);
1851 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
1852 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
1853 face
= faces
[enabled
+ mousehere
* 2];
1855 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1856 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
1857 *p
++ = FAST_MAKE_GLYPH (*q
++, face
);
1858 for (; j
< width
; j
++)
1859 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1860 *p
++ = FAST_MAKE_GLYPH (menu
->submenu
[i
] ? 16 : ' ', face
);
1861 IT_write_glyphs (text
, width
+ 2);
1864 IT_cursor_to (row
, col
);
1868 /* --------------------------- X Menu emulation ---------------------- */
1870 /* Report availability of menus. */
1878 /* Create a brand new menu structure. */
1881 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
1883 return IT_menu_create ();
1886 /* Create a new pane and place it on the outer-most level. It is not
1887 clear that it should be placed out there, but I don't know what else
1891 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
1898 IT_menu_make_room (menu
);
1899 menu
->submenu
[menu
->count
] = IT_menu_create ();
1900 menu
->text
[menu
->count
] = txt
;
1901 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
1903 if ((len
= strlen (txt
)) > menu
->width
)
1905 return menu
->panecount
;
1908 /* Create a new item in a menu pane. */
1911 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
1912 int foo
, char *txt
, int enable
)
1917 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
1919 IT_menu_make_room (menu
);
1920 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
1921 menu
->text
[menu
->count
] = txt
;
1922 menu
->panenumber
[menu
->count
] = enable
;
1924 if ((len
= strlen (txt
)) > menu
->width
)
1929 /* Decide where the menu would be placed if requested at (X,Y). */
1932 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
1933 int *ulx
, int *uly
, int *width
, int *height
)
1935 IT_menu_calc_size (menu
, width
, height
);
1941 struct IT_menu_state
1943 void *screen_behind
;
1950 /* Display menu, wait for user's response, and return that response. */
1953 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
1954 int x0
, int y0
, unsigned ButtonMask
, char **txt
)
1956 struct IT_menu_state
*state
;
1960 int faces
[4], selectface
;
1961 int leave
, result
, onepane
;
1962 int title_faces
[4]; /* face to display the menu title */
1963 int buffers_num_deleted
= 0;
1965 /* Just in case we got here without a mouse present... */
1966 if (have_mouse
<= 0)
1967 return XM_IA_SELECT
;
1969 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
1970 screensize
= screen_size
* 2;
1972 = compute_glyph_face (selected_frame
,
1975 intern ("msdos-menu-passive-face")),
1978 = compute_glyph_face (selected_frame
,
1981 intern ("msdos-menu-active-face")),
1984 = face_name_id_number (selected_frame
, intern ("msdos-menu-select-face"));
1985 faces
[2] = compute_glyph_face (selected_frame
, selectface
, faces
[0]);
1986 faces
[3] = compute_glyph_face (selected_frame
, selectface
, faces
[1]);
1988 /* Make sure the menu title is always displayed with
1989 `msdos-menu-active-face', no matter where the mouse pointer is. */
1990 for (i
= 0; i
< 4; i
++)
1991 title_faces
[i
] = faces
[3];
1995 /* Don't let the title for the "Buffers" popup menu include a
1996 digit (which is ugly).
1998 This is a terrible kludge, but I think the "Buffers" case is
1999 the only one where the title includes a number, so it doesn't
2000 seem to be necessary to make this more general. */
2001 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
2003 menu
->text
[0][7] = '\0';
2004 buffers_num_deleted
= 1;
2006 state
[0].menu
= menu
;
2008 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
2010 IT_menu_display (menu
, y0
- 1, x0
- 1, title_faces
); /* display menu title */
2011 if (buffers_num_deleted
)
2012 menu
->text
[0][7] = ' ';
2013 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
2015 menu
->width
= menu
->submenu
[0]->width
;
2016 state
[0].menu
= menu
->submenu
[0];
2020 state
[0].menu
= menu
;
2022 state
[0].x
= x0
- 1;
2024 state
[0].pane
= onepane
;
2026 mouse_last_x
= -1; /* A hack that forces display. */
2030 if (!mouse_visible
) mouse_on ();
2031 mouse_check_moved ();
2032 if (selected_frame
->mouse_moved
)
2034 selected_frame
->mouse_moved
= 0;
2035 result
= XM_IA_SELECT
;
2036 mouse_get_xy (&x
, &y
);
2037 for (i
= 0; i
< statecount
; i
++)
2038 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
2040 int dy
= y
- state
[i
].y
;
2041 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
2043 if (!state
[i
].menu
->submenu
[dy
])
2044 if (state
[i
].menu
->panenumber
[dy
])
2045 result
= XM_SUCCESS
;
2047 result
= XM_IA_SELECT
;
2048 *pane
= state
[i
].pane
- 1;
2050 /* We hit some part of a menu, so drop extra menus that
2051 have been opened. That does not include an open and
2053 if (i
!= statecount
- 2
2054 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
2055 while (i
!= statecount
- 1)
2059 ScreenUpdate (state
[statecount
].screen_behind
);
2060 xfree (state
[statecount
].screen_behind
);
2062 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
2064 IT_menu_display (state
[i
].menu
,
2068 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
2069 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
2071 ScreenRetrieve (state
[statecount
].screen_behind
2072 = xmalloc (screensize
));
2074 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
2075 state
[statecount
].y
= y
;
2080 IT_menu_display (state
[statecount
- 1].menu
,
2081 state
[statecount
- 1].y
,
2082 state
[statecount
- 1].x
,
2085 for (b
= 0; b
< mouse_button_count
; b
++)
2087 (void) mouse_pressed (b
, &x
, &y
);
2088 if (mouse_released (b
, &x
, &y
))
2094 ScreenUpdate (state
[0].screen_behind
);
2095 while (statecount
--)
2096 xfree (state
[statecount
].screen_behind
);
2100 /* Dispose of a menu. */
2103 XMenuDestroy (Display
*foo
, XMenu
*menu
)
2106 if (menu
->allocated
)
2108 for (i
= 0; i
< menu
->count
; i
++)
2109 if (menu
->submenu
[i
])
2110 XMenuDestroy (foo
, menu
->submenu
[i
]);
2112 xfree (menu
->submenu
);
2113 xfree (menu
->panenumber
);
2119 x_pixel_width (struct frame
*f
)
2121 return FRAME_WIDTH (f
);
2125 x_pixel_height (struct frame
*f
)
2127 return FRAME_HEIGHT (f
);
2129 #endif /* !HAVE_X_WINDOWS */
2131 /* ----------------------- DOS / UNIX conversion --------------------- */
2133 /* Destructively turn backslashes into slashes. */
2136 dostounix_filename (p
)
2147 /* Destructively turn slashes into backslashes. */
2150 unixtodos_filename (p
)
2161 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2162 void msdos_downcase_filename (unsigned char *);
2165 getdefdir (drive
, dst
)
2169 char in_path
[4], *p
= in_path
;
2172 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2175 *p
++ = drive
+ 'A' - 1;
2182 _fixpath (in_path
, dst
);
2186 msdos_downcase_filename (dst
);
2192 /* Remove all CR's that are followed by a LF. */
2197 register unsigned char *buf
;
2199 unsigned char *np
= buf
;
2200 unsigned char *startp
= buf
;
2201 unsigned char *endp
= buf
+ n
;
2206 while (buf
< endp
- 1)
2210 if (*(++buf
) != 0x0a)
2221 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
2223 /* In DJGPP v2.0, library `write' can call `malloc', which might
2224 cause relocation of the buffer whose address we get in ADDR.
2225 Here is a version of `write' that avoids calling `malloc',
2226 to serve us until such time as the library is fixed.
2227 Actually, what we define here is called `__write', because
2228 `write' is a stub that just jmp's to `__write' (to be
2229 POSIXLY-correct with respect to the global name-space). */
2231 #include <io.h> /* for _write */
2232 #include <libc/dosio.h> /* for __file_handle_modes[] */
2234 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
2236 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
2239 __write (int handle
, const void *buffer
, size_t count
)
2244 if(__file_handle_modes
[handle
] & O_BINARY
)
2245 return _write (handle
, buffer
, count
);
2249 const char *bp
= buffer
;
2250 int total_written
= 0;
2251 int nmoved
= 0, ncr
= 0;
2255 /* The next test makes sure there's space for at least 2 more
2256 characters in xbuf[], so both CR and LF can be put there. */
2268 if (xbp
>= XBUF_END
|| !count
)
2270 size_t to_write
= nmoved
+ ncr
;
2271 int written
= _write (handle
, xbuf
, to_write
);
2276 total_written
+= nmoved
; /* CRs aren't counted in ret value */
2278 /* If some, but not all were written (disk full?), return
2279 an estimate of the total written bytes not counting CRs. */
2280 if (written
< to_write
)
2281 return total_written
- (to_write
- written
) * nmoved
/to_write
;
2288 return total_written
;
2292 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
2294 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
2296 "Return non-nil if long file names are supported on MSDOS.")
2299 return (_USE_LFN
? Qt
: Qnil
);
2302 /* Convert alphabetic characters in a filename to lower-case. */
2305 msdos_downcase_filename (p
)
2306 register unsigned char *p
;
2308 /* Under LFN we expect to get pathnames in their true case. */
2309 if (NILP (Fmsdos_long_file_names ()))
2311 if (*p
>= 'A' && *p
<= 'Z')
2315 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
2317 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
2318 When long filenames are supported, doesn't change FILENAME.\n\
2319 If FILENAME is not a string, returns nil.\n\
2320 The argument object is never altered--the value is a copy.")
2322 Lisp_Object filename
;
2327 if (! STRINGP (filename
))
2330 tem
= Fcopy_sequence (filename
);
2331 msdos_downcase_filename (XSTRING (tem
)->data
);
2335 /* The Emacs root directory as determined by init_environment. */
2337 static char emacsroot
[MAXPATHLEN
];
2340 rootrelativepath (rel
)
2343 static char result
[MAXPATHLEN
+ 10];
2345 strcpy (result
, emacsroot
);
2346 strcat (result
, "/");
2347 strcat (result
, rel
);
2351 /* Define a lot of environment variables if not already defined. Don't
2352 remove anything unless you know what you're doing -- lots of code will
2353 break if one or more of these are missing. */
2356 init_environment (argc
, argv
, skip_args
)
2364 /* Find our root from argv[0]. Assuming argv[0] is, say,
2365 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
2366 root
= alloca (MAXPATHLEN
+ 20);
2367 _fixpath (argv
[0], root
);
2369 len
= strlen (root
);
2370 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
2373 if (len
> 4 && strcmp (root
+ len
- 4, "/bin") == 0)
2374 root
[len
- 4] = '\0';
2376 strcpy (root
, "c:/emacs"); /* Only under debuggers, I think. */
2377 len
= strlen (root
);
2378 strcpy (emacsroot
, root
);
2380 /* We default HOME to our root. */
2381 setenv ("HOME", root
, 0);
2383 /* We default EMACSPATH to root + "/bin". */
2384 strcpy (root
+ len
, "/bin");
2385 setenv ("EMACSPATH", root
, 0);
2387 /* I don't expect anybody to ever use other terminals so the internal
2388 terminal is the default. */
2389 setenv ("TERM", "internal", 0);
2391 #ifdef HAVE_X_WINDOWS
2392 /* Emacs expects DISPLAY to be set. */
2393 setenv ("DISPLAY", "unix:0.0", 0);
2396 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
2397 downcase it and mirror the backslashes. */
2398 s
= getenv ("COMSPEC");
2399 if (!s
) s
= "c:/command.com";
2400 t
= alloca (strlen (s
) + 1);
2403 dostounix_filename (t
);
2404 setenv ("SHELL", t
, 0);
2406 /* PATH is also downcased and backslashes mirrored. */
2407 s
= getenv ("PATH");
2409 t
= alloca (strlen (s
) + 3);
2410 /* Current directory is always considered part of MsDos's path but it is
2411 not normally mentioned. Now it is. */
2412 strcat (strcpy (t
, ".;"), s
);
2414 dostounix_filename (t
); /* Not a single file name, but this should work. */
2415 setenv ("PATH", t
, 1);
2417 /* In some sense all dos users have root privileges, so... */
2418 setenv ("USER", "root", 0);
2419 setenv ("NAME", getenv ("USER"), 0);
2421 /* Time zone determined from country code. To make this possible, the
2422 country code may not span more than one time zone. In other words,
2423 in the USA, you lose. */
2425 switch (dos_country_code
)
2427 case 31: /* Belgium */
2428 case 32: /* The Netherlands */
2429 case 33: /* France */
2430 case 34: /* Spain */
2431 case 36: /* Hungary */
2432 case 38: /* Yugoslavia (or what's left of it?) */
2433 case 39: /* Italy */
2434 case 41: /* Switzerland */
2435 case 42: /* Tjekia */
2436 case 45: /* Denmark */
2437 case 46: /* Sweden */
2438 case 47: /* Norway */
2439 case 48: /* Poland */
2440 case 49: /* Germany */
2441 /* Daylight saving from last Sunday in March to last Sunday in
2442 September, both at 2AM. */
2443 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2445 case 44: /* United Kingdom */
2446 case 351: /* Portugal */
2447 case 354: /* Iceland */
2448 setenv ("TZ", "GMT+00", 0);
2450 case 81: /* Japan */
2451 case 82: /* Korea */
2452 setenv ("TZ", "JST-09", 0);
2454 case 90: /* Turkey */
2455 case 358: /* Finland */
2456 setenv ("TZ", "EET-02", 0);
2458 case 972: /* Israel */
2459 /* This is an approximation. (For exact rules, use the
2460 `zoneinfo/israel' file which comes with DJGPP, but you need
2461 to install it in `/usr/share/zoneinfo/' directory first.) */
2462 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2470 static int break_stat
; /* BREAK check mode status. */
2471 static int stdin_stat
; /* stdin IOCTL status. */
2475 /* These must be global. */
2476 static _go32_dpmi_seginfo ctrl_break_vector
;
2477 static _go32_dpmi_registers ctrl_break_regs
;
2478 static int ctrlbreakinstalled
= 0;
2480 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2483 ctrl_break_func (regs
)
2484 _go32_dpmi_registers
*regs
;
2490 install_ctrl_break_check ()
2492 if (!ctrlbreakinstalled
)
2494 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2495 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2496 ctrlbreakinstalled
= 1;
2497 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
2498 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
2500 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
2504 #endif /* __DJGPP__ < 2 */
2506 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
2507 control chars by DOS. Determine the keyboard type. */
2512 union REGS inregs
, outregs
;
2513 static int first_time
= 1;
2515 break_stat
= getcbrk ();
2518 install_ctrl_break_check ();
2524 int86 (0x15, &inregs
, &outregs
);
2525 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
2529 if (internal_terminal
2530 #ifdef HAVE_X_WINDOWS
2531 && inhibit_window_system
2535 inregs
.x
.ax
= 0x0021;
2536 int86 (0x33, &inregs
, &outregs
);
2537 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2540 /* Reportedly, the above doesn't work for some mouse drivers. There
2541 is an additional detection method that should work, but might be
2542 a little slower. Use that as an alternative. */
2543 inregs
.x
.ax
= 0x0000;
2544 int86 (0x33, &inregs
, &outregs
);
2545 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2550 have_mouse
= 1; /* enable mouse */
2553 if (outregs
.x
.bx
== 3)
2555 mouse_button_count
= 3;
2556 mouse_button_translate
[0] = 0; /* Left */
2557 mouse_button_translate
[1] = 2; /* Middle */
2558 mouse_button_translate
[2] = 1; /* Right */
2562 mouse_button_count
= 2;
2563 mouse_button_translate
[0] = 0;
2564 mouse_button_translate
[1] = 1;
2566 mouse_position_hook
= &mouse_get_pos
;
2575 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
2576 return (stdin_stat
!= -1);
2579 return (setmode (fileno (stdin
), O_BINARY
) != -1);
2581 #else /* __DJGPP__ < 2 */
2585 /* I think it is wrong to overwrite `stdin_stat' every time
2586 but the first one this function is called, but I don't
2587 want to change the way it used to work in v1.x.--EZ */
2589 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
2590 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2591 intdos (&inregs
, &outregs
);
2592 stdin_stat
= outregs
.h
.dl
;
2594 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
2595 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
2596 intdos (&inregs
, &outregs
);
2597 return !outregs
.x
.cflag
;
2599 #endif /* __DJGPP__ < 2 */
2602 /* Restore status of standard input and Ctrl-C checking. */
2607 union REGS inregs
, outregs
;
2609 setcbrk (break_stat
);
2614 return (setmode (fileno (stdin
), stdin_stat
) != -1);
2616 #else /* not __DJGPP__ >= 2 */
2618 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
2619 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2620 inregs
.x
.dx
= stdin_stat
;
2621 intdos (&inregs
, &outregs
);
2622 return !outregs
.x
.cflag
;
2624 #endif /* not __DJGPP__ >= 2 */
2628 /* Run command as specified by ARGV in directory DIR.
2629 The command is run with input from TEMPIN, output to
2630 file TEMPOUT and stderr to TEMPERR. */
2633 run_msdos_command (argv
, dir
, tempin
, tempout
, temperr
)
2634 unsigned char **argv
;
2636 int tempin
, tempout
, temperr
;
2638 char *saveargv1
, *saveargv2
, **envv
;
2639 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
2640 int msshell
, result
= -1;
2641 int in
, out
, inbak
, outbak
, errbak
;
2645 /* Get current directory as MSDOS cwd is not per-process. */
2648 cmd
= Ffile_name_nondirectory (build_string (argv
[0]));
2649 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
2650 && !strcmp ("-c", argv
[1]);
2653 saveargv1
= argv
[1];
2654 saveargv2
= argv
[2];
2658 char *p
= alloca (strlen (argv
[2]) + 1);
2660 strcpy (argv
[2] = p
, saveargv2
);
2661 while (*p
&& isspace (*p
))
2663 while (*p
&& !isspace (*p
))
2671 /* Build the environment array. */
2673 extern Lisp_Object Vprocess_environment
;
2674 Lisp_Object tmp
, lst
;
2677 lst
= Vprocess_environment
;
2678 len
= XFASTINT (Flength (lst
));
2680 envv
= alloca ((len
+ 1) * sizeof (char *));
2681 for (i
= 0; i
< len
; i
++)
2685 CHECK_STRING (tmp
, 0);
2686 envv
[i
] = alloca (XSTRING (tmp
)->size
+ 1);
2687 strcpy (envv
[i
], XSTRING (tmp
)->data
);
2689 envv
[len
] = (char *) 0;
2693 chdir (XSTRING (dir
)->data
);
2697 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
2698 goto done
; /* Allocation might fail due to lack of descriptors. */
2701 mouse_get_xy (&x
, &y
);
2703 dos_ttcooked (); /* do it here while 0 = stdin */
2711 if (msshell
&& !argv
[3])
2713 /* MS-DOS native shells are too restrictive. For starters, they
2714 cannot grok commands longer than 126 characters. In DJGPP v2
2715 and later, `system' is much smarter, so we'll call it instead. */
2717 extern char **environ
;
2720 /* A shell gets a single argument--its full command
2721 line--whose original was saved in `saveargv2'. */
2722 result
= system (saveargv2
);
2726 #endif /* __DJGPP__ > 1 */
2728 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
2741 mouse_moveto (x
, y
);
2748 argv
[1] = saveargv1
;
2749 argv
[2] = saveargv2
;
2757 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
2764 /* ------------------------- Compatibility functions -------------------
2769 /* Hostnames for a pc are not really funny,
2770 but they are used in change log so we emulate the best we can. */
2772 gethostname (p
, size
)
2776 char *q
= egetenv ("HOSTNAME");
2783 /* When time zones are set from Ms-Dos too many C-libraries are playing
2784 tricks with time values. We solve this by defining our own version
2785 of `gettimeofday' bypassing GO32. Our version needs to be initialized
2786 once and after each call to `tzset' with TZ changed. That is
2787 accomplished by aliasing tzset to init_gettimeofday. */
2789 static struct tm time_rec
;
2792 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
2800 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
2804 time_rec
.tm_year
= d
.da_year
- 1900;
2805 time_rec
.tm_mon
= d
.da_mon
- 1;
2806 time_rec
.tm_mday
= d
.da_day
;
2809 time_rec
.tm_hour
= t
.ti_hour
;
2810 time_rec
.tm_min
= t
.ti_min
;
2811 time_rec
.tm_sec
= t
.ti_sec
;
2814 tm
.tm_gmtoff
= dos_timezone_offset
;
2816 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
2817 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
2819 /* Ignore tzp; it's obsolescent. */
2823 #endif /* __DJGPP__ < 2 */
2826 * A list of unimplemented functions that we silently ignore.
2830 unsigned alarm (s
) unsigned s
; {}
2831 fork () { return 0; }
2832 int kill (x
, y
) int x
, y
; { return -1; }
2834 void volatile pause () {}
2835 sigsetmask (x
) int x
; { return 0; }
2839 setpgrp () {return 0; }
2840 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
2841 sigblock (mask
) int mask
; { return 0; }
2842 unrequest_sigio () {}
2845 #include "sysselect.h"
2847 #ifndef EMACS_TIME_ZERO_OR_NEG_P
2848 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
2849 ((long)(time).tv_sec < 0 \
2850 || ((time).tv_sec == 0 \
2851 && (long)(time).tv_usec <= 0))
2855 /* Only event queue is checked. */
2856 /* We don't have to call timer_check here
2857 because wait_reading_process_input takes care of that. */
2859 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
2861 SELECT_TYPE
*rfds
, *wfds
, *efds
;
2862 EMACS_TIME
*timeout
;
2870 check_input
= FD_ISSET (0, rfds
);
2881 /* If we are looking only for the terminal, with no timeout,
2882 just read it and wait -- that's more efficient. */
2885 while (!detect_input_pending ())
2894 EMACS_TIME clnow
, cllast
, cldiff
;
2897 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
2899 while (!check_input
|| !detect_input_pending ())
2902 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
2903 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
2905 /* When seconds wrap around, we assume that no more than
2906 1 minute passed since last `gettime'. */
2907 if (EMACS_TIME_NEG_P (cldiff
))
2908 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
2909 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
2911 /* Stop when timeout value crosses zero. */
2912 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
2927 * Define overlaid functions:
2929 * chdir -> sys_chdir
2930 * tzset -> init_gettimeofday
2931 * abort -> dos_abort
2936 extern int chdir ();
2942 int len
= strlen (path
);
2943 char *tmp
= (char *)path
;
2945 if (*tmp
&& tmp
[1] == ':')
2947 if (getdisk () != tolower (tmp
[0]) - 'a')
2948 setdisk (tolower (tmp
[0]) - 'a');
2949 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
2953 if (len
> 1 && (tmp
[len
- 1] == '/'))
2955 char *tmp1
= (char *) alloca (len
+ 1);
2966 extern void tzset (void);
2969 init_gettimeofday ()
2975 ltm
= gtm
= time (NULL
);
2976 ltm
= mktime (lstm
= localtime (<m
));
2977 gtm
= mktime (gmtime (>m
));
2978 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
2979 time_rec
.tm_isdst
= lstm
->tm_isdst
;
2980 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
2987 dos_abort (file
, line
)
2991 char buffer1
[200], buffer2
[400];
2994 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
2995 for (i
= j
= 0; buffer1
[i
]; i
++) {
2996 buffer2
[j
++] = buffer1
[i
];
2997 buffer2
[j
++] = 0x70;
2999 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
3000 ScreenSetCursor (2, 0);
3008 ScreenSetCursor (10, 0);
3009 cputs ("\r\n\nEmacs aborted!\r\n");
3011 /* Generate traceback, so we could tell whodunit. */
3012 signal (SIGINT
, SIG_DFL
);
3013 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
3021 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
3022 staticpro (&recent_doskeys
);
3024 defsubr (&Srecent_doskeys
);
3025 defsubr (&Smsdos_long_file_names
);
3026 defsubr (&Smsdos_downcase_filename
);