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
->last_overlay_modified
, 0);
694 XSETFASTINT (w
->top
, XFASTINT (w
->top
) + n
);
695 XSETFASTINT (w
->height
, XFASTINT (w
->height
) - n
);
697 /* Handle just the top child in a vertical split. */
698 if (!NILP (w
->vchild
))
699 IT_set_menu_bar_lines (w
->vchild
, n
);
701 /* Adjust all children in a horizontal split. */
702 for (window
= w
->hchild
; !NILP (window
); window
= w
->next
)
704 w
= XWINDOW (window
);
705 IT_set_menu_bar_lines (window
, n
);
709 /* This was copied from xfns.c */
712 x_set_menu_bar_lines (f
, value
, oldval
)
714 Lisp_Object value
, oldval
;
717 int olines
= FRAME_MENU_BAR_LINES (f
);
719 /* Right now, menu bars don't work properly in minibuf-only frames;
720 most of the commands try to apply themselves to the minibuffer
721 frame itslef, and get an error because you can't switch buffers
722 in or split the minibuffer window. */
723 if (FRAME_MINIBUF_ONLY_P (f
))
726 if (INTEGERP (value
))
727 nlines
= XINT (value
);
731 FRAME_MENU_BAR_LINES (f
) = nlines
;
732 IT_set_menu_bar_lines (f
->root_window
, nlines
- olines
);
735 /* IT_set_terminal_modes is called when emacs is started,
736 resumed, and whenever the screen is redrawn! */
739 IT_set_terminal_modes (void)
746 fprintf (termscript
, "\n<SET_TERM>");
749 screen_size_X
= ScreenCols ();
750 screen_size_Y
= ScreenRows ();
751 screen_size
= screen_size_X
* screen_size_Y
;
753 new_pos_X
= new_pos_Y
= 0;
754 current_pos_X
= current_pos_Y
= -1;
760 startup_screen_size_X
= screen_size_X
;
761 startup_screen_size_Y
= screen_size_Y
;
762 startup_screen_attrib
= ScreenAttrib
;
764 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
765 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
768 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
769 screen_size_X
, screen_size_Y
);
774 /* IT_reset_terminal_modes is called when emacs is
775 suspended or killed. */
778 IT_reset_terminal_modes (void)
780 int display_row_start
= (int) ScreenPrimary
;
781 int saved_row_len
= startup_screen_size_X
* 2;
782 int update_row_len
= ScreenCols () * 2;
783 int current_rows
= ScreenRows ();
784 int to_next_row
= update_row_len
;
785 unsigned char *saved_row
= startup_screen_buffer
;
786 int cursor_pos_X
= ScreenCols () - 1;
787 int cursor_pos_Y
= ScreenRows () - 1;
790 fprintf (termscript
, "\n<RESET_TERM>");
794 if (!term_setup_done
)
799 /* We have a situation here.
800 We cannot just do ScreenUpdate(startup_screen_buffer) because
801 the luser could have changed screen dimensions inside Emacs
802 and failed (or didn't want) to restore them before killing
803 Emacs. ScreenUpdate() uses the *current* screen dimensions and
804 thus will happily use memory outside what was allocated for
805 `startup_screen_buffer'.
806 Thus we only restore as much as the current screen dimensions
807 can hold, and clear the rest (if the saved screen is smaller than
808 the current) with the color attribute saved at startup. The cursor
809 is also restored within the visible dimensions. */
811 ScreenAttrib
= startup_screen_attrib
;
814 if (update_row_len
> saved_row_len
)
815 update_row_len
= saved_row_len
;
816 if (current_rows
> startup_screen_size_Y
)
817 current_rows
= startup_screen_size_Y
;
820 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
821 update_row_len
/ 2, current_rows
);
823 while (current_rows
--)
825 dosmemput (saved_row
, update_row_len
, display_row_start
);
826 saved_row
+= saved_row_len
;
827 display_row_start
+= to_next_row
;
829 if (startup_pos_X
< cursor_pos_X
)
830 cursor_pos_X
= startup_pos_X
;
831 if (startup_pos_Y
< cursor_pos_Y
)
832 cursor_pos_Y
= startup_pos_Y
;
834 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
835 xfree (startup_screen_buffer
);
841 IT_set_terminal_window (void)
846 IT_set_frame_parameters (f
, alist
)
852 extern unsigned long load_color ();
855 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
857 Lisp_Object elt
, prop
, val
;
862 CHECK_SYMBOL (prop
, 1);
864 if (EQ (prop
, intern ("foreground-color")))
866 unsigned long new_color
= load_color (f
, val
);
869 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
872 fprintf (termscript
, "<FGCOLOR %d>\n", new_color
);
875 else if (EQ (prop
, intern ("background-color")))
877 unsigned long new_color
= load_color (f
, val
);
880 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
883 fprintf (termscript
, "<BGCOLOR %d>\n", new_color
);
886 else if (EQ (prop
, intern ("menu-bar-lines")))
887 x_set_menu_bar_lines (f
, val
, 0);
892 recompute_basic_faces (f
);
893 if (f
== selected_frame
)
898 #endif /* !HAVE_X_WINDOWS */
901 /* Do we need the internal terminal? */
904 internal_terminal_init ()
906 char *term
= getenv ("TERM");
909 #ifdef HAVE_X_WINDOWS
910 if (!inhibit_window_system
)
915 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
917 if (getenv ("EMACSTEST"))
918 termscript
= fopen (getenv ("EMACSTEST"), "wt");
920 #ifndef HAVE_X_WINDOWS
921 if (!internal_terminal
|| inhibit_window_system
)
923 selected_frame
->output_method
= output_termcap
;
927 Vwindow_system
= intern ("pc");
928 Vwindow_system_version
= make_number (1);
930 bzero (&the_only_x_display
, sizeof the_only_x_display
);
931 the_only_x_display
.background_pixel
= 7; /* White */
932 the_only_x_display
.foreground_pixel
= 0; /* Black */
934 colors
= getenv ("EMACSCOLORS");
935 if (colors
&& strlen (colors
) >= 2)
937 /* The colors use 4 bits each (we enable bright background). */
938 if (isdigit (colors
[0]))
940 else if (isxdigit (colors
[0]))
941 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
942 if (colors
[0] >= 0 && colors
[0] < 16)
943 the_only_x_display
.foreground_pixel
= colors
[0];
944 if (isdigit (colors
[1]))
946 else if (isxdigit (colors
[1]))
947 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
948 if (colors
[1] >= 0 && colors
[1] < 16)
949 the_only_x_display
.background_pixel
= colors
[1];
951 the_only_x_display
.line_height
= 1;
952 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
954 init_frame_faces (selected_frame
);
956 ring_bell_hook
= IT_ring_bell
;
957 write_glyphs_hook
= IT_write_glyphs
;
958 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
959 clear_to_end_hook
= IT_clear_to_end
;
960 clear_end_of_line_hook
= IT_clear_end_of_line
;
961 clear_frame_hook
= IT_clear_screen
;
962 change_line_highlight_hook
= IT_change_line_highlight
;
963 update_begin_hook
= IT_update_begin
;
964 update_end_hook
= IT_update_end
;
965 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
967 /* These hooks are called by term.c without being checked. */
968 set_terminal_modes_hook
= IT_set_terminal_modes
;
969 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
970 set_terminal_window_hook
= IT_set_terminal_window
;
974 dos_get_saved_screen (screen
, rows
, cols
)
979 #ifndef HAVE_X_WINDOWS
980 *screen
= startup_screen_buffer
;
981 *cols
= startup_screen_size_X
;
982 *rows
= startup_screen_size_Y
;
989 #ifndef HAVE_X_WINDOWS
991 /* We are not X, but we can emulate it well enough for our needs... */
995 if (! FRAME_MSDOS_P (selected_frame
))
996 error ("Not running under a windows system");
1002 /* ----------------------- Keyboard control ----------------------
1004 * Keymaps reflect the following keyboard layout:
1006 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1007 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1008 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1009 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1013 static int extended_kbd
; /* 101 (102) keyboard present. */
1015 struct dos_keyboard_map
1023 static struct dos_keyboard_map us_keyboard
= {
1025 /* 01234567890123456789012345678901234567890 12345678901234 */
1026 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1027 /* 0123456789012345678901234567890123456789 012345678901234 */
1028 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1029 0 /* no Alt-Gr key */
1032 static struct dos_keyboard_map fr_keyboard
= {
1034 /* 012 3456789012345678901234567890123456789012345678901234 */
1035 "ý&\82\",(-\8a_\80\85)= azertyuiop^$ qsdfghjklm\97* wxcvbnm;:! ",
1036 /* 0123456789012345678901234567890123456789012345678901234 */
1037 " 1234567890ø+ AZERTYUIOPù\9c QSDFGHJKLM%æ WXCVBN?./õ ",
1038 /* 01234567 89012345678901234567890123456789012345678901234 */
1042 static struct dos_keyboard_map dk_keyboard
= {
1044 /* 0123456789012345678901234567890123456789012345678901234 */
1045 "«1234567890+| qwertyuiop\86~ asdfghjkl\91\9b' zxcvbnm,.- ",
1046 /* 01 23456789012345678901234567890123456789012345678901234 */
1047 "õ!\"#$%&/()=?` QWERTYUIOP\8f^ ASDFGHJKL\92\9d* ZXCVBNM;:_ ",
1048 /* 0123456789012345678901234567890123456789012345678901234 */
1052 static struct keyboard_layout_list
1055 struct dos_keyboard_map
*keyboard_map
;
1056 } keyboard_layout_list
[] =
1063 static struct dos_keyboard_map
*keyboard
;
1064 static int keyboard_map_all
;
1067 dos_set_keyboard (code
, always
)
1073 /* Initialize to US settings, for countries that don't have their own. */
1074 keyboard
= keyboard_layout_list
[0].keyboard_map
;
1075 keyboard_map_all
= always
;
1076 dos_keyboard_layout
= 1;
1078 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
1079 if (code
== keyboard_layout_list
[i
].country_code
)
1081 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
1082 keyboard_map_all
= always
;
1083 dos_keyboard_layout
= code
;
1089 #define Ignore 0x0000
1090 #define Normal 0x0000 /* normal key - alt changes scan-code */
1091 #define FctKey 0x1000 /* func key if c == 0, else c */
1092 #define Special 0x2000 /* func key even if c != 0 */
1093 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1094 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1095 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1096 #define Grey 0x6000 /* Grey keypad key */
1098 #define Alt 0x0100 /* alt scan-code */
1099 #define Ctrl 0x0200 /* ctrl scan-code */
1100 #define Shift 0x0400 /* shift scan-code */
1104 unsigned char char_code
; /* normal code */
1105 unsigned char meta_code
; /* M- code */
1106 unsigned char keypad_code
; /* keypad code */
1107 unsigned char editkey_code
; /* edit key */
1108 } keypad_translate_map
[] = {
1109 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1110 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1111 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1112 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1113 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1114 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1115 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1116 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1117 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1118 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1119 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1124 unsigned char char_code
; /* normal code */
1125 unsigned char keypad_code
; /* keypad code */
1126 } grey_key_translate_map
[] = {
1127 '/', 0xaf, /* kp-decimal */
1128 '*', 0xaa, /* kp-multiply */
1129 '-', 0xad, /* kp-subtract */
1130 '+', 0xab, /* kp-add */
1131 '\r', 0x8d /* kp-enter */
1134 static unsigned short
1135 ibmpc_translate_map
[] =
1137 /* --------------- 00 to 0f --------------- */
1138 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
1139 Alt
| ModFct
| 0x1b, /* Escape */
1140 Normal
| 1, /* '1' */
1141 Normal
| 2, /* '2' */
1142 Normal
| 3, /* '3' */
1143 Normal
| 4, /* '4' */
1144 Normal
| 5, /* '5' */
1145 Normal
| 6, /* '6' */
1146 Normal
| 7, /* '7' */
1147 Normal
| 8, /* '8' */
1148 Normal
| 9, /* '9' */
1149 Normal
| 10, /* '0' */
1150 Normal
| 11, /* '-' */
1151 Normal
| 12, /* '=' */
1152 Special
| 0x08, /* Backspace */
1153 ModFct
| 0x74, /* Tab/Backtab */
1155 /* --------------- 10 to 1f --------------- */
1168 ModFct
| 0x0d, /* Return */
1173 /* --------------- 20 to 2f --------------- */
1182 Map
| 40, /* '\'' */
1184 Ignore
, /* Left shift */
1185 Map
| 41, /* '\\' */
1191 /* --------------- 30 to 3f --------------- */
1198 Ignore
, /* Right shift */
1199 Grey
| 1, /* Grey * */
1201 Normal
| ' ', /* ' ' */
1202 Ignore
, /* Caps Lock */
1203 FctKey
| 0xbe, /* F1 */
1204 FctKey
| 0xbf, /* F2 */
1205 FctKey
| 0xc0, /* F3 */
1206 FctKey
| 0xc1, /* F4 */
1207 FctKey
| 0xc2, /* F5 */
1209 /* --------------- 40 to 4f --------------- */
1210 FctKey
| 0xc3, /* F6 */
1211 FctKey
| 0xc4, /* F7 */
1212 FctKey
| 0xc5, /* F8 */
1213 FctKey
| 0xc6, /* F9 */
1214 FctKey
| 0xc7, /* F10 */
1215 Ignore
, /* Num Lock */
1216 Ignore
, /* Scroll Lock */
1217 KeyPad
| 7, /* Home */
1218 KeyPad
| 8, /* Up */
1219 KeyPad
| 9, /* Page Up */
1220 Grey
| 2, /* Grey - */
1221 KeyPad
| 4, /* Left */
1222 KeyPad
| 5, /* Keypad 5 */
1223 KeyPad
| 6, /* Right */
1224 Grey
| 3, /* Grey + */
1225 KeyPad
| 1, /* End */
1227 /* --------------- 50 to 5f --------------- */
1228 KeyPad
| 2, /* Down */
1229 KeyPad
| 3, /* Page Down */
1230 KeyPad
| 0, /* Insert */
1231 KeyPad
| 10, /* Delete */
1232 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
1233 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
1234 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
1235 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
1236 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
1237 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
1238 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
1239 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
1240 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
1241 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
1242 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
1243 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
1245 /* --------------- 60 to 6f --------------- */
1246 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
1247 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
1248 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
1249 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
1250 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
1251 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
1252 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
1253 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
1254 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
1255 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
1256 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
1257 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
1258 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
1259 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
1260 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
1261 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
1263 /* --------------- 70 to 7f --------------- */
1264 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
1265 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
1266 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
1267 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
1268 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
1269 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
1270 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
1271 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
1272 Alt
| Map
| 1, /* '1' */
1273 Alt
| Map
| 2, /* '2' */
1274 Alt
| Map
| 3, /* '3' */
1275 Alt
| Map
| 4, /* '4' */
1276 Alt
| Map
| 5, /* '5' */
1277 Alt
| Map
| 6, /* '6' */
1278 Alt
| Map
| 7, /* '7' */
1279 Alt
| Map
| 8, /* '8' */
1281 /* --------------- 80 to 8f --------------- */
1282 Alt
| Map
| 9, /* '9' */
1283 Alt
| Map
| 10, /* '0' */
1284 Alt
| Map
| 11, /* '-' */
1285 Alt
| Map
| 12, /* '=' */
1286 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
1287 FctKey
| 0xc8, /* F11 */
1288 FctKey
| 0xc9, /* F12 */
1289 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
1290 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
1291 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
1292 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
1293 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
1294 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
1295 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
1296 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
1297 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
1299 /* --------------- 90 to 9f --------------- */
1300 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
1301 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
1302 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
1303 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
1304 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
1305 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
1306 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
1307 Alt
| FctKey
| 0x50, /* (Alt) Home */
1308 Alt
| FctKey
| 0x52, /* (Alt) Up */
1309 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
1310 Ignore
, /* NO KEY */
1311 Alt
| FctKey
| 0x51, /* (Alt) Left */
1312 Ignore
, /* NO KEY */
1313 Alt
| FctKey
| 0x53, /* (Alt) Right */
1314 Ignore
, /* NO KEY */
1315 Alt
| FctKey
| 0x57, /* (Alt) End */
1317 /* --------------- a0 to af --------------- */
1318 Alt
| KeyPad
| 2, /* (Alt) Down */
1319 Alt
| KeyPad
| 3, /* (Alt) Page Down */
1320 Alt
| KeyPad
| 0, /* (Alt) Insert */
1321 Alt
| KeyPad
| 10, /* (Alt) Delete */
1322 Alt
| Grey
| 0, /* (Alt) Grey / */
1323 Alt
| FctKey
| 0x09, /* (Alt) Tab */
1324 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
1327 /* These bit-positions corresponds to values returned by BIOS */
1328 #define SHIFT_P 0x0003 /* two bits! */
1329 #define CTRL_P 0x0004
1330 #define ALT_P 0x0008
1331 #define SCRLOCK_P 0x0010
1332 #define NUMLOCK_P 0x0020
1333 #define CAPSLOCK_P 0x0040
1334 #define ALT_GR_P 0x0800
1335 #define SUPER_P 0x4000 /* pseudo */
1336 #define HYPER_P 0x8000 /* pseudo */
1339 dos_get_modifiers (keymask
)
1346 /* Calculate modifier bits */
1347 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
1348 int86 (0x16, ®s
, ®s
);
1352 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
1353 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1357 mask
= regs
.h
.al
& (SHIFT_P
|
1358 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1360 /* Do not break international keyboard support. */
1361 /* When Keyb.Com is loaded, the right Alt key is */
1362 /* used for accessing characters like { and } */
1363 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
1366 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
1369 if (dos_hyper_key
== 1)
1372 modifiers
|= hyper_modifier
;
1374 else if (dos_super_key
== 1)
1377 modifiers
|= super_modifier
;
1381 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
1384 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
1386 if (dos_hyper_key
== 2)
1389 modifiers
|= hyper_modifier
;
1391 else if (dos_super_key
== 2)
1394 modifiers
|= super_modifier
;
1402 modifiers
|= shift_modifier
;
1404 modifiers
|= ctrl_modifier
;
1406 modifiers
|= meta_modifier
;
1413 #define NUM_RECENT_DOSKEYS (100)
1414 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
1415 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
1416 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
1418 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
1419 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1420 Each input key receives two values in this vector: first the ASCII code,\n\
1421 and then the scan code.")
1424 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
1427 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
1428 return Fvector (total_doskeys
, keys
);
1431 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
1432 bcopy (keys
+ recent_doskeys_index
,
1433 XVECTOR (val
)->contents
,
1434 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
1436 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
1437 recent_doskeys_index
* sizeof (Lisp_Object
));
1442 /* Get a char from keyboard. Function keys are put into the event queue. */
1447 struct input_event event
;
1450 #ifndef HAVE_X_WINDOWS
1451 SCREEN_SET_CURSOR ();
1452 if (!mouse_visible
) mouse_on ();
1455 /* The following condition is equivalent to `kbhit ()', except that
1456 it uses the bios to do its job. This pleases DESQview/X. */
1457 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
1458 int86 (0x16, ®s
, ®s
),
1459 (regs
.x
.flags
& 0x40) == 0)
1462 register unsigned char c
;
1463 int sc
, code
, mask
, kp_mode
;
1466 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
1467 int86 (0x16, ®s
, ®s
);
1472 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1474 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1475 recent_doskeys_index
= 0;
1476 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1478 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1479 recent_doskeys_index
= 0;
1481 modifiers
= dos_get_modifiers (&mask
);
1483 #ifndef HAVE_X_WINDOWS
1484 if (!NILP (Vdos_display_scancodes
))
1487 sprintf (buf
, "%02x:%02x*%04x",
1488 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
1489 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
1497 case 10: /* Ctrl Grey Enter */
1498 code
= Ctrl
| Grey
| 4;
1500 case 13: /* Grey Enter */
1503 case '/': /* Grey / */
1513 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
1515 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
1522 modifiers
|= meta_modifier
;
1524 modifiers
|= ctrl_modifier
;
1526 modifiers
|= shift_modifier
;
1529 switch (code
& 0xf000)
1532 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
1534 c
= 0; /* Special */
1547 if (c
== 0) /* ctrl-break */
1549 return c
; /* ALT-nnn */
1551 if (!keyboard_map_all
)
1560 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
1561 if (!keyboard_map_all
)
1565 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
1566 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
1570 code
= keyboard
->shifted
[code
];
1572 modifiers
&= ~shift_modifier
;
1575 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
1576 code
= keyboard
->alt_gr
[code
];
1578 code
= keyboard
->unshifted
[code
];
1583 if (c
== 0xe0) /* edit key */
1586 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
1587 kp_mode
= dos_keypad_mode
& 0x03;
1589 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
1594 if (code
== 10 && dos_decimal_point
)
1595 return dos_decimal_point
;
1596 return keypad_translate_map
[code
].char_code
;
1599 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
1603 code
= keypad_translate_map
[code
].meta_code
;
1604 modifiers
= meta_modifier
;
1608 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
1615 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
1616 if (dos_keypad_mode
& kp_mode
)
1617 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
1619 code
= grey_key_translate_map
[code
].char_code
;
1628 event
.kind
= non_ascii_keystroke
;
1630 event
.kind
= ascii_keystroke
;
1632 event
.modifiers
= modifiers
;
1633 XSETFRAME (event
.frame_or_window
, selected_frame
);
1634 event
.timestamp
= event_timestamp ();
1635 kbd_buffer_store_event (&event
);
1640 int but
, press
, x
, y
, ok
;
1642 /* Check for mouse movement *before* buttons. */
1643 mouse_check_moved ();
1645 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
1646 for (press
= 0; press
< 2; press
++)
1648 int button_num
= but
;
1651 ok
= mouse_pressed (but
, &x
, &y
);
1653 ok
= mouse_released (but
, &x
, &y
);
1656 /* Allow a simultaneous press/release of Mouse-1 and
1657 Mouse-2 to simulate Mouse-3 on two-button mice. */
1658 if (mouse_button_count
== 2 && but
< 2)
1660 int x2
, y2
; /* don't clobber original coordinates */
1662 /* If only one button is pressed, wait 100 msec and
1663 check again. This way, Speedy Gonzales isn't
1664 punished, while the slow get their chance. */
1665 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
1666 || !press
&& mouse_released (1-but
, &x2
, &y2
))
1671 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
1672 || !press
&& mouse_released (1-but
, &x2
, &y2
))
1677 event
.kind
= mouse_click
;
1678 event
.code
= button_num
;
1679 event
.modifiers
= dos_get_modifiers (0)
1680 | (press
? down_modifier
: up_modifier
);
1683 XSETFRAME (event
.frame_or_window
, selected_frame
);
1684 event
.timestamp
= event_timestamp ();
1685 kbd_buffer_store_event (&event
);
1693 static int prev_get_char
= -1;
1695 /* Return 1 if a key is ready to be read without suspending execution. */
1699 if (prev_get_char
!= -1)
1702 return ((prev_get_char
= dos_rawgetc ()) != -1);
1705 /* Read a key. Return -1 if no key is ready. */
1709 if (prev_get_char
!= -1)
1711 int c
= prev_get_char
;
1716 return dos_rawgetc ();
1719 #ifndef HAVE_X_WINDOWS
1720 /* See xterm.c for more info. */
1722 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
1724 register int pix_x
, pix_y
;
1725 register int *x
, *y
;
1726 void /* XRectangle */ *bounds
;
1729 if (bounds
) abort ();
1731 /* Ignore clipping. */
1738 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
1741 register int *pix_x
, *pix_y
;
1747 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1750 Actually, I don't know the meaning of all the parameters of the functions
1751 here -- I only know how they are called by xmenu.c. I could of course
1752 grab the nearest Xlib manual (down the hall, second-to-last door on the
1753 left), but I don't think it's worth the effort. */
1760 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
1761 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
1765 /* Allocate some (more) memory for MENU ensuring that there is room for one
1769 IT_menu_make_room (XMenu
*menu
)
1771 if (menu
->allocated
== 0)
1773 int count
= menu
->allocated
= 10;
1774 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
1775 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
1776 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
1778 else if (menu
->allocated
== menu
->count
)
1780 int count
= menu
->allocated
= menu
->allocated
+ 10;
1782 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
1784 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
1786 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
1790 /* Search the given menu structure for a given pane number. */
1793 IT_menu_search_pane (XMenu
*menu
, int pane
)
1798 for (i
= 0; i
< menu
->count
; i
++)
1799 if (menu
->submenu
[i
])
1801 if (pane
== menu
->panenumber
[i
])
1802 return menu
->submenu
[i
];
1803 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
1809 /* Determine how much screen space a given menu needs. */
1812 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
1814 int i
, h2
, w2
, maxsubwidth
, maxheight
;
1817 maxheight
= menu
->count
;
1818 for (i
= 0; i
< menu
->count
; i
++)
1820 if (menu
->submenu
[i
])
1822 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
1823 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
1824 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
1827 *width
= menu
->width
+ maxsubwidth
;
1828 *height
= maxheight
;
1831 /* Display MENU at (X,Y) using FACES. */
1834 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
)
1836 int i
, j
, face
, width
;
1840 int enabled
, mousehere
;
1843 width
= menu
->width
;
1844 text
= (GLYPH
*) xmalloc ((width
+ 2) * sizeof (GLYPH
));
1845 ScreenGetCursor (&row
, &col
);
1846 mouse_get_xy (&mx
, &my
);
1848 for (i
= 0; i
< menu
->count
; i
++)
1850 IT_cursor_to (y
+ i
, x
);
1852 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
1853 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
1854 face
= faces
[enabled
+ mousehere
* 2];
1856 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1857 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
1860 *p
++ = FAST_MAKE_GLYPH (*q
++, face
);
1861 else /* make '^x' */
1863 *p
++ = FAST_MAKE_GLYPH ('^', face
);
1865 *p
++ = FAST_MAKE_GLYPH (*q
++ + 64, face
);
1869 for (; j
< width
; j
++)
1870 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1871 *p
++ = FAST_MAKE_GLYPH (menu
->submenu
[i
] ? 16 : ' ', face
);
1872 IT_write_glyphs (text
, width
+ 2);
1875 IT_cursor_to (row
, col
);
1879 /* --------------------------- X Menu emulation ---------------------- */
1881 /* Report availability of menus. */
1889 /* Create a brand new menu structure. */
1892 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
1894 return IT_menu_create ();
1897 /* Create a new pane and place it on the outer-most level. It is not
1898 clear that it should be placed out there, but I don't know what else
1902 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
1910 IT_menu_make_room (menu
);
1911 menu
->submenu
[menu
->count
] = IT_menu_create ();
1912 menu
->text
[menu
->count
] = txt
;
1913 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
1916 /* Adjust length for possible control characters (which will
1917 be written as ^x). */
1918 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
1922 if (len
> menu
->width
)
1925 return menu
->panecount
;
1928 /* Create a new item in a menu pane. */
1931 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
1932 int foo
, char *txt
, int enable
)
1938 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
1940 IT_menu_make_room (menu
);
1941 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
1942 menu
->text
[menu
->count
] = txt
;
1943 menu
->panenumber
[menu
->count
] = enable
;
1946 /* Adjust length for possible control characters (which will
1947 be written as ^x). */
1948 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
1952 if (len
> menu
->width
)
1958 /* Decide where the menu would be placed if requested at (X,Y). */
1961 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
1962 int *ulx
, int *uly
, int *width
, int *height
)
1964 IT_menu_calc_size (menu
, width
, height
);
1970 struct IT_menu_state
1972 void *screen_behind
;
1979 /* Display menu, wait for user's response, and return that response. */
1982 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
1983 int x0
, int y0
, unsigned ButtonMask
, char **txt
)
1985 struct IT_menu_state
*state
;
1989 int faces
[4], selectface
;
1990 int leave
, result
, onepane
;
1991 int title_faces
[4]; /* face to display the menu title */
1992 int buffers_num_deleted
= 0;
1994 /* Just in case we got here without a mouse present... */
1995 if (have_mouse
<= 0)
1996 return XM_IA_SELECT
;
1998 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
1999 screensize
= screen_size
* 2;
2001 = compute_glyph_face (selected_frame
,
2004 intern ("msdos-menu-passive-face")),
2007 = compute_glyph_face (selected_frame
,
2010 intern ("msdos-menu-active-face")),
2013 = face_name_id_number (selected_frame
, intern ("msdos-menu-select-face"));
2014 faces
[2] = compute_glyph_face (selected_frame
, selectface
, faces
[0]);
2015 faces
[3] = compute_glyph_face (selected_frame
, selectface
, faces
[1]);
2017 /* Make sure the menu title is always displayed with
2018 `msdos-menu-active-face', no matter where the mouse pointer is. */
2019 for (i
= 0; i
< 4; i
++)
2020 title_faces
[i
] = faces
[3];
2024 /* Don't let the title for the "Buffers" popup menu include a
2025 digit (which is ugly).
2027 This is a terrible kludge, but I think the "Buffers" case is
2028 the only one where the title includes a number, so it doesn't
2029 seem to be necessary to make this more general. */
2030 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
2032 menu
->text
[0][7] = '\0';
2033 buffers_num_deleted
= 1;
2035 state
[0].menu
= menu
;
2037 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
2039 IT_menu_display (menu
, y0
- 1, x0
- 1, title_faces
); /* display menu title */
2040 if (buffers_num_deleted
)
2041 menu
->text
[0][7] = ' ';
2042 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
2044 menu
->width
= menu
->submenu
[0]->width
;
2045 state
[0].menu
= menu
->submenu
[0];
2049 state
[0].menu
= menu
;
2051 state
[0].x
= x0
- 1;
2053 state
[0].pane
= onepane
;
2055 mouse_last_x
= -1; /* A hack that forces display. */
2059 if (!mouse_visible
) mouse_on ();
2060 mouse_check_moved ();
2061 if (selected_frame
->mouse_moved
)
2063 selected_frame
->mouse_moved
= 0;
2064 result
= XM_IA_SELECT
;
2065 mouse_get_xy (&x
, &y
);
2066 for (i
= 0; i
< statecount
; i
++)
2067 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
2069 int dy
= y
- state
[i
].y
;
2070 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
2072 if (!state
[i
].menu
->submenu
[dy
])
2073 if (state
[i
].menu
->panenumber
[dy
])
2074 result
= XM_SUCCESS
;
2076 result
= XM_IA_SELECT
;
2077 *pane
= state
[i
].pane
- 1;
2079 /* We hit some part of a menu, so drop extra menus that
2080 have been opened. That does not include an open and
2082 if (i
!= statecount
- 2
2083 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
2084 while (i
!= statecount
- 1)
2088 ScreenUpdate (state
[statecount
].screen_behind
);
2089 xfree (state
[statecount
].screen_behind
);
2091 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
2093 IT_menu_display (state
[i
].menu
,
2097 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
2098 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
2100 ScreenRetrieve (state
[statecount
].screen_behind
2101 = xmalloc (screensize
));
2103 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
2104 state
[statecount
].y
= y
;
2109 IT_menu_display (state
[statecount
- 1].menu
,
2110 state
[statecount
- 1].y
,
2111 state
[statecount
- 1].x
,
2114 for (b
= 0; b
< mouse_button_count
; b
++)
2116 (void) mouse_pressed (b
, &x
, &y
);
2117 if (mouse_released (b
, &x
, &y
))
2123 ScreenUpdate (state
[0].screen_behind
);
2124 while (statecount
--)
2125 xfree (state
[statecount
].screen_behind
);
2129 /* Dispose of a menu. */
2132 XMenuDestroy (Display
*foo
, XMenu
*menu
)
2135 if (menu
->allocated
)
2137 for (i
= 0; i
< menu
->count
; i
++)
2138 if (menu
->submenu
[i
])
2139 XMenuDestroy (foo
, menu
->submenu
[i
]);
2141 xfree (menu
->submenu
);
2142 xfree (menu
->panenumber
);
2148 x_pixel_width (struct frame
*f
)
2150 return FRAME_WIDTH (f
);
2154 x_pixel_height (struct frame
*f
)
2156 return FRAME_HEIGHT (f
);
2158 #endif /* !HAVE_X_WINDOWS */
2160 /* ----------------------- DOS / UNIX conversion --------------------- */
2162 void msdos_downcase_filename (unsigned char *);
2164 /* Destructively turn backslashes into slashes. */
2167 dostounix_filename (p
)
2170 msdos_downcase_filename (p
);
2180 /* Destructively turn slashes into backslashes. */
2183 unixtodos_filename (p
)
2186 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
2200 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2203 getdefdir (drive
, dst
)
2207 char in_path
[4], *p
= in_path
;
2210 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2213 *p
++ = drive
+ 'A' - 1;
2220 _fixpath (in_path
, dst
);
2224 msdos_downcase_filename (dst
);
2230 /* Remove all CR's that are followed by a LF. */
2235 register unsigned char *buf
;
2237 unsigned char *np
= buf
;
2238 unsigned char *startp
= buf
;
2239 unsigned char *endp
= buf
+ n
;
2244 while (buf
< endp
- 1)
2248 if (*(++buf
) != 0x0a)
2259 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
2261 /* In DJGPP v2.0, library `write' can call `malloc', which might
2262 cause relocation of the buffer whose address we get in ADDR.
2263 Here is a version of `write' that avoids calling `malloc',
2264 to serve us until such time as the library is fixed.
2265 Actually, what we define here is called `__write', because
2266 `write' is a stub that just jmp's to `__write' (to be
2267 POSIXLY-correct with respect to the global name-space). */
2269 #include <io.h> /* for _write */
2270 #include <libc/dosio.h> /* for __file_handle_modes[] */
2272 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
2274 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
2277 __write (int handle
, const void *buffer
, size_t count
)
2282 if(__file_handle_modes
[handle
] & O_BINARY
)
2283 return _write (handle
, buffer
, count
);
2287 const char *bp
= buffer
;
2288 int total_written
= 0;
2289 int nmoved
= 0, ncr
= 0;
2293 /* The next test makes sure there's space for at least 2 more
2294 characters in xbuf[], so both CR and LF can be put there. */
2306 if (xbp
>= XBUF_END
|| !count
)
2308 size_t to_write
= nmoved
+ ncr
;
2309 int written
= _write (handle
, xbuf
, to_write
);
2314 total_written
+= nmoved
; /* CRs aren't counted in ret value */
2316 /* If some, but not all were written (disk full?), return
2317 an estimate of the total written bytes not counting CRs. */
2318 if (written
< to_write
)
2319 return total_written
- (to_write
- written
) * nmoved
/to_write
;
2326 return total_written
;
2330 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
2332 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
2334 "Return non-nil if long file names are supported on MSDOS.")
2337 return (_USE_LFN
? Qt
: Qnil
);
2340 /* Convert alphabetic characters in a filename to lower-case. */
2343 msdos_downcase_filename (p
)
2344 register unsigned char *p
;
2346 /* Always lower-case drive letters a-z, even if the filesystem
2347 preserves case in filenames.
2348 This is so MSDOS filenames could be compared by string comparison
2349 functions that are case-sensitive. Even case-preserving filesystems
2350 do not distinguish case in drive letters. */
2351 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
2357 /* Under LFN we expect to get pathnames in their true case. */
2358 if (NILP (Fmsdos_long_file_names ()))
2360 if (*p
>= 'A' && *p
<= 'Z')
2364 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
2366 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
2367 When long filenames are supported, doesn't change FILENAME.\n\
2368 If FILENAME is not a string, returns nil.\n\
2369 The argument object is never altered--the value is a copy.")
2371 Lisp_Object filename
;
2376 if (! STRINGP (filename
))
2379 tem
= Fcopy_sequence (filename
);
2380 msdos_downcase_filename (XSTRING (tem
)->data
);
2384 /* The Emacs root directory as determined by init_environment. */
2386 static char emacsroot
[MAXPATHLEN
];
2389 rootrelativepath (rel
)
2392 static char result
[MAXPATHLEN
+ 10];
2394 strcpy (result
, emacsroot
);
2395 strcat (result
, "/");
2396 strcat (result
, rel
);
2400 /* Define a lot of environment variables if not already defined. Don't
2401 remove anything unless you know what you're doing -- lots of code will
2402 break if one or more of these are missing. */
2405 init_environment (argc
, argv
, skip_args
)
2413 /* Find our root from argv[0]. Assuming argv[0] is, say,
2414 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
2415 root
= alloca (MAXPATHLEN
+ 20);
2416 _fixpath (argv
[0], root
);
2417 msdos_downcase_filename (root
);
2418 len
= strlen (root
);
2419 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
2422 if (len
> 4 && strcmp (root
+ len
- 4, "/bin") == 0)
2423 root
[len
- 4] = '\0';
2425 strcpy (root
, "c:/emacs"); /* Only under debuggers, I think. */
2426 len
= strlen (root
);
2427 strcpy (emacsroot
, root
);
2429 /* We default HOME to our root. */
2430 setenv ("HOME", root
, 0);
2432 /* We default EMACSPATH to root + "/bin". */
2433 strcpy (root
+ len
, "/bin");
2434 setenv ("EMACSPATH", root
, 0);
2436 /* I don't expect anybody to ever use other terminals so the internal
2437 terminal is the default. */
2438 setenv ("TERM", "internal", 0);
2440 #ifdef HAVE_X_WINDOWS
2441 /* Emacs expects DISPLAY to be set. */
2442 setenv ("DISPLAY", "unix:0.0", 0);
2445 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
2446 downcase it and mirror the backslashes. */
2447 s
= getenv ("COMSPEC");
2448 if (!s
) s
= "c:/command.com";
2449 t
= alloca (strlen (s
) + 1);
2451 dostounix_filename (t
);
2452 setenv ("SHELL", t
, 0);
2454 /* PATH is also downcased and backslashes mirrored. */
2455 s
= getenv ("PATH");
2457 t
= alloca (strlen (s
) + 3);
2458 /* Current directory is always considered part of MsDos's path but it is
2459 not normally mentioned. Now it is. */
2460 strcat (strcpy (t
, ".;"), s
);
2461 dostounix_filename (t
); /* Not a single file name, but this should work. */
2462 setenv ("PATH", t
, 1);
2464 /* In some sense all dos users have root privileges, so... */
2465 setenv ("USER", "root", 0);
2466 setenv ("NAME", getenv ("USER"), 0);
2468 /* Time zone determined from country code. To make this possible, the
2469 country code may not span more than one time zone. In other words,
2470 in the USA, you lose. */
2472 switch (dos_country_code
)
2474 case 31: /* Belgium */
2475 case 32: /* The Netherlands */
2476 case 33: /* France */
2477 case 34: /* Spain */
2478 case 36: /* Hungary */
2479 case 38: /* Yugoslavia (or what's left of it?) */
2480 case 39: /* Italy */
2481 case 41: /* Switzerland */
2482 case 42: /* Tjekia */
2483 case 45: /* Denmark */
2484 case 46: /* Sweden */
2485 case 47: /* Norway */
2486 case 48: /* Poland */
2487 case 49: /* Germany */
2488 /* Daylight saving from last Sunday in March to last Sunday in
2489 September, both at 2AM. */
2490 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2492 case 44: /* United Kingdom */
2493 case 351: /* Portugal */
2494 case 354: /* Iceland */
2495 setenv ("TZ", "GMT+00", 0);
2497 case 81: /* Japan */
2498 case 82: /* Korea */
2499 setenv ("TZ", "JST-09", 0);
2501 case 90: /* Turkey */
2502 case 358: /* Finland */
2503 setenv ("TZ", "EET-02", 0);
2505 case 972: /* Israel */
2506 /* This is an approximation. (For exact rules, use the
2507 `zoneinfo/israel' file which comes with DJGPP, but you need
2508 to install it in `/usr/share/zoneinfo/' directory first.) */
2509 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2517 static int break_stat
; /* BREAK check mode status. */
2518 static int stdin_stat
; /* stdin IOCTL status. */
2522 /* These must be global. */
2523 static _go32_dpmi_seginfo ctrl_break_vector
;
2524 static _go32_dpmi_registers ctrl_break_regs
;
2525 static int ctrlbreakinstalled
= 0;
2527 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2530 ctrl_break_func (regs
)
2531 _go32_dpmi_registers
*regs
;
2537 install_ctrl_break_check ()
2539 if (!ctrlbreakinstalled
)
2541 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2542 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2543 ctrlbreakinstalled
= 1;
2544 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
2545 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
2547 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
2551 #endif /* __DJGPP__ < 2 */
2553 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
2554 control chars by DOS. Determine the keyboard type. */
2559 union REGS inregs
, outregs
;
2560 static int first_time
= 1;
2562 break_stat
= getcbrk ();
2565 install_ctrl_break_check ();
2571 int86 (0x15, &inregs
, &outregs
);
2572 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
2576 if (internal_terminal
2577 #ifdef HAVE_X_WINDOWS
2578 && inhibit_window_system
2582 inregs
.x
.ax
= 0x0021;
2583 int86 (0x33, &inregs
, &outregs
);
2584 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2587 /* Reportedly, the above doesn't work for some mouse drivers. There
2588 is an additional detection method that should work, but might be
2589 a little slower. Use that as an alternative. */
2590 inregs
.x
.ax
= 0x0000;
2591 int86 (0x33, &inregs
, &outregs
);
2592 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2597 have_mouse
= 1; /* enable mouse */
2600 if (outregs
.x
.bx
== 3)
2602 mouse_button_count
= 3;
2603 mouse_button_translate
[0] = 0; /* Left */
2604 mouse_button_translate
[1] = 2; /* Middle */
2605 mouse_button_translate
[2] = 1; /* Right */
2609 mouse_button_count
= 2;
2610 mouse_button_translate
[0] = 0;
2611 mouse_button_translate
[1] = 1;
2613 mouse_position_hook
= &mouse_get_pos
;
2622 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
2623 return (stdin_stat
!= -1);
2626 return (setmode (fileno (stdin
), O_BINARY
) != -1);
2628 #else /* __DJGPP__ < 2 */
2632 /* I think it is wrong to overwrite `stdin_stat' every time
2633 but the first one this function is called, but I don't
2634 want to change the way it used to work in v1.x.--EZ */
2636 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
2637 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2638 intdos (&inregs
, &outregs
);
2639 stdin_stat
= outregs
.h
.dl
;
2641 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
2642 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
2643 intdos (&inregs
, &outregs
);
2644 return !outregs
.x
.cflag
;
2646 #endif /* __DJGPP__ < 2 */
2649 /* Restore status of standard input and Ctrl-C checking. */
2654 union REGS inregs
, outregs
;
2656 setcbrk (break_stat
);
2661 return (setmode (fileno (stdin
), stdin_stat
) != -1);
2663 #else /* not __DJGPP__ >= 2 */
2665 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
2666 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2667 inregs
.x
.dx
= stdin_stat
;
2668 intdos (&inregs
, &outregs
);
2669 return !outregs
.x
.cflag
;
2671 #endif /* not __DJGPP__ >= 2 */
2675 /* Run command as specified by ARGV in directory DIR.
2676 The command is run with input from TEMPIN, output to
2677 file TEMPOUT and stderr to TEMPERR. */
2680 run_msdos_command (argv
, dir
, tempin
, tempout
, temperr
)
2681 unsigned char **argv
;
2683 int tempin
, tempout
, temperr
;
2685 char *saveargv1
, *saveargv2
, **envv
;
2686 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
2687 int msshell
, result
= -1;
2688 int in
, out
, inbak
, outbak
, errbak
;
2692 /* Get current directory as MSDOS cwd is not per-process. */
2695 cmd
= Ffile_name_nondirectory (build_string (argv
[0]));
2696 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
2697 && !strcmp ("-c", argv
[1]);
2700 saveargv1
= argv
[1];
2701 saveargv2
= argv
[2];
2705 char *p
= alloca (strlen (argv
[2]) + 1);
2707 strcpy (argv
[2] = p
, saveargv2
);
2708 while (*p
&& isspace (*p
))
2710 while (*p
&& !isspace (*p
))
2718 /* Build the environment array. */
2720 extern Lisp_Object Vprocess_environment
;
2721 Lisp_Object tmp
, lst
;
2724 lst
= Vprocess_environment
;
2725 len
= XFASTINT (Flength (lst
));
2727 envv
= alloca ((len
+ 1) * sizeof (char *));
2728 for (i
= 0; i
< len
; i
++)
2732 CHECK_STRING (tmp
, 0);
2733 envv
[i
] = alloca (XSTRING (tmp
)->size
+ 1);
2734 strcpy (envv
[i
], XSTRING (tmp
)->data
);
2736 envv
[len
] = (char *) 0;
2740 chdir (XSTRING (dir
)->data
);
2744 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
2745 goto done
; /* Allocation might fail due to lack of descriptors. */
2748 mouse_get_xy (&x
, &y
);
2750 dos_ttcooked (); /* do it here while 0 = stdin */
2758 if (msshell
&& !argv
[3])
2760 /* MS-DOS native shells are too restrictive. For starters, they
2761 cannot grok commands longer than 126 characters. In DJGPP v2
2762 and later, `system' is much smarter, so we'll call it instead. */
2764 extern char **environ
;
2767 /* A shell gets a single argument--its full command
2768 line--whose original was saved in `saveargv2'. */
2769 result
= system (saveargv2
);
2773 #endif /* __DJGPP__ > 1 */
2775 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
2788 mouse_moveto (x
, y
);
2795 argv
[1] = saveargv1
;
2796 argv
[2] = saveargv2
;
2804 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
2811 /* ------------------------- Compatibility functions -------------------
2816 /* Hostnames for a pc are not really funny,
2817 but they are used in change log so we emulate the best we can. */
2819 gethostname (p
, size
)
2823 char *q
= egetenv ("HOSTNAME");
2830 /* When time zones are set from Ms-Dos too many C-libraries are playing
2831 tricks with time values. We solve this by defining our own version
2832 of `gettimeofday' bypassing GO32. Our version needs to be initialized
2833 once and after each call to `tzset' with TZ changed. That is
2834 accomplished by aliasing tzset to init_gettimeofday. */
2836 static struct tm time_rec
;
2839 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
2847 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
2851 time_rec
.tm_year
= d
.da_year
- 1900;
2852 time_rec
.tm_mon
= d
.da_mon
- 1;
2853 time_rec
.tm_mday
= d
.da_day
;
2856 time_rec
.tm_hour
= t
.ti_hour
;
2857 time_rec
.tm_min
= t
.ti_min
;
2858 time_rec
.tm_sec
= t
.ti_sec
;
2861 tm
.tm_gmtoff
= dos_timezone_offset
;
2863 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
2864 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
2866 /* Ignore tzp; it's obsolescent. */
2870 #endif /* __DJGPP__ < 2 */
2873 * A list of unimplemented functions that we silently ignore.
2877 unsigned alarm (s
) unsigned s
; {}
2878 fork () { return 0; }
2879 int kill (x
, y
) int x
, y
; { return -1; }
2881 void volatile pause () {}
2882 sigsetmask (x
) int x
; { return 0; }
2886 setpgrp () {return 0; }
2887 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
2888 sigblock (mask
) int mask
; { return 0; }
2889 unrequest_sigio () {}
2892 #include "sysselect.h"
2894 #ifndef EMACS_TIME_ZERO_OR_NEG_P
2895 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
2896 ((long)(time).tv_sec < 0 \
2897 || ((time).tv_sec == 0 \
2898 && (long)(time).tv_usec <= 0))
2902 /* Only event queue is checked. */
2903 /* We don't have to call timer_check here
2904 because wait_reading_process_input takes care of that. */
2906 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
2908 SELECT_TYPE
*rfds
, *wfds
, *efds
;
2909 EMACS_TIME
*timeout
;
2917 check_input
= FD_ISSET (0, rfds
);
2928 /* If we are looking only for the terminal, with no timeout,
2929 just read it and wait -- that's more efficient. */
2932 while (!detect_input_pending ())
2941 EMACS_TIME clnow
, cllast
, cldiff
;
2944 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
2946 while (!check_input
|| !detect_input_pending ())
2949 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
2950 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
2952 /* When seconds wrap around, we assume that no more than
2953 1 minute passed since last `gettime'. */
2954 if (EMACS_TIME_NEG_P (cldiff
))
2955 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
2956 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
2958 /* Stop when timeout value crosses zero. */
2959 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
2974 * Define overlaid functions:
2976 * chdir -> sys_chdir
2977 * tzset -> init_gettimeofday
2978 * abort -> dos_abort
2983 extern int chdir ();
2989 int len
= strlen (path
);
2990 char *tmp
= (char *)path
;
2992 if (*tmp
&& tmp
[1] == ':')
2994 if (getdisk () != tolower (tmp
[0]) - 'a')
2995 setdisk (tolower (tmp
[0]) - 'a');
2996 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
3000 if (len
> 1 && (tmp
[len
- 1] == '/'))
3002 char *tmp1
= (char *) alloca (len
+ 1);
3013 extern void tzset (void);
3016 init_gettimeofday ()
3022 ltm
= gtm
= time (NULL
);
3023 ltm
= mktime (lstm
= localtime (<m
));
3024 gtm
= mktime (gmtime (>m
));
3025 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
3026 time_rec
.tm_isdst
= lstm
->tm_isdst
;
3027 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
3034 dos_abort (file
, line
)
3038 char buffer1
[200], buffer2
[400];
3041 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
3042 for (i
= j
= 0; buffer1
[i
]; i
++) {
3043 buffer2
[j
++] = buffer1
[i
];
3044 buffer2
[j
++] = 0x70;
3046 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
3047 ScreenSetCursor (2, 0);
3055 ScreenSetCursor (10, 0);
3056 cputs ("\r\n\nEmacs aborted!\r\n");
3058 /* Generate traceback, so we could tell whodunit. */
3059 signal (SIGINT
, SIG_DFL
);
3060 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
3068 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
3069 staticpro (&recent_doskeys
);
3071 defsubr (&Srecent_doskeys
);
3072 defsubr (&Smsdos_long_file_names
);
3073 defsubr (&Smsdos_downcase_filename
);