1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 1994, 1995, 1996, 1997 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 <string.h> /* for bzero and string functions */
37 #include <sys/stat.h> /* for _fixpath */
38 #include <unistd.h> /* for chdir, dup, dup2, etc. */
41 #include <io.h> /* for setmode */
42 #include <dpmi.h> /* for __dpmi_xxx stuff */
43 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
44 #include <libc/dosio.h> /* for _USE_LFN */
45 #include <conio.h> /* for cputs */
51 #include "termhooks.h"
52 #include "dispextern.h"
61 /* #include <process.h> */
62 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
70 #define _dos_ds _go32_info_block.selector_for_linear_memory
76 #include "syssignal.h"
82 /* If other `malloc' than ours is used, force our `sbrk' behave like
83 Unix programs expect (resize memory blocks to keep them contiguous).
84 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
85 because that's what `gmalloc' expects to get. */
89 int _crt0_startup_flags
= _CRT0_FLAG_UNIX_SBRK
;
90 #else /* not REL_ALLOC */
91 int _crt0_startup_flags
= (_CRT0_FLAG_UNIX_SBRK
| _CRT0_FLAG_FILL_SBRK_MEMORY
);
92 #endif /* not REL_ALLOC */
93 #endif /* GNU_MALLOC */
95 #endif /* not SYSTEM_MALLOC */
96 #endif /* __DJGPP__ > 1 */
115 /* ------------------------ Mouse control ---------------------------
117 * Coordinates are in screen positions and zero based.
118 * Mouse buttons are numbered from left to right and also zero based.
121 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
122 static int mouse_visible
;
124 static int mouse_last_x
;
125 static int mouse_last_y
;
127 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
128 static int mouse_button_count
;
135 if (have_mouse
> 0 && !mouse_visible
)
138 fprintf (termscript
, "<M_ON>");
140 int86 (0x33, ®s
, ®s
);
150 if (have_mouse
> 0 && mouse_visible
)
153 fprintf (termscript
, "<M_OFF>");
155 int86 (0x33, ®s
, ®s
);
167 fprintf (termscript
, "<M_XY=%dx%d>", x
, y
);
169 mouse_last_x
= regs
.x
.cx
= x
* 8;
170 mouse_last_y
= regs
.x
.dx
= y
* 8;
171 int86 (0x33, ®s
, ®s
);
175 mouse_pressed (b
, xp
, yp
)
180 if (b
>= mouse_button_count
)
183 regs
.x
.bx
= mouse_button_translate
[b
];
184 int86 (0x33, ®s
, ®s
);
186 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
187 return (regs
.x
.bx
!= 0);
191 mouse_released (b
, xp
, yp
)
196 if (b
>= mouse_button_count
)
199 regs
.x
.bx
= mouse_button_translate
[b
];
200 int86 (0x33, ®s
, ®s
);
202 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
203 return (regs
.x
.bx
!= 0);
207 mouse_get_xy (int *x
, int *y
)
212 int86 (0x33, ®s
, ®s
);
218 mouse_get_pos (f
, insist
, bar_window
, part
, x
, y
, time
)
221 Lisp_Object
*bar_window
, *x
, *y
;
222 enum scroll_bar_part
*part
;
229 int86 (0x33, ®s
, ®s
);
232 mouse_get_xy (&ix
, &iy
);
233 selected_frame
->mouse_moved
= 0;
234 *x
= make_number (ix
);
235 *y
= make_number (iy
);
236 *time
= event_timestamp ();
244 mouse_get_xy (&x
, &y
);
245 selected_frame
->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
256 fprintf (termscript
, "<M_INIT>");
259 int86 (0x33, ®s
, ®s
);
263 regs
.x
.dx
= 8 * (ScreenCols () - 1);
264 int86 (0x33, ®s
, ®s
);
268 regs
.x
.dx
= 8 * (ScreenRows () - 1);
269 int86 (0x33, ®s
, ®s
);
275 /* ------------------------- Screen control ----------------------
279 static int internal_terminal
= 0;
281 #ifndef HAVE_X_WINDOWS
282 extern unsigned char ScreenAttrib
;
283 static int screen_face
;
284 static int highlight
;
286 static int screen_size_X
;
287 static int screen_size_Y
;
288 static int screen_size
;
290 static int current_pos_X
;
291 static int current_pos_Y
;
292 static int new_pos_X
;
293 static int new_pos_Y
;
295 static void *startup_screen_buffer
;
296 static int startup_screen_size_X
;
297 static int startup_screen_size_Y
;
298 static int startup_pos_X
;
299 static int startup_pos_Y
;
300 static unsigned char startup_screen_attrib
;
302 static int term_setup_done
;
304 /* Similar to the_only_frame. */
305 struct x_output the_only_x_display
;
307 /* This is never dereferenced. */
308 Display
*x_current_display
;
311 dos_direct_output (y
, x
, buf
, len
)
317 int t
= (int) ScreenPrimary
+ 2 * (x
+ y
* screen_size_X
);
321 dosmemput (buf
++, 1, t
);
325 /* This is faster. */
326 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
327 _farnspokeb (t
, *buf
);
332 /* Flash the screen as a substitute for BEEPs. */
336 do_visible_bell (xorattr
)
337 unsigned char xorattr
;
342 movl _ScreenPrimary,%%eax
349 xorb %%al,%%gs:(%%ebx)
365 : "m" (xorattr
), "g" (screen_size
)
366 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
370 ScreenVisualBell (void)
372 /* This creates an xor-mask that will swap the default fore- and
373 background colors. */
374 do_visible_bell (((the_only_x_display
.foreground_pixel
375 ^ the_only_x_display
.background_pixel
)
380 #ifndef HAVE_X_WINDOWS
382 static int blink_bit
= -1; /* the state of the blink bit at startup */
384 /* Enable bright background colors. */
390 /* Remember the original state of the blink/bright-background bit.
391 It is stored at 0040:0065h in the BIOS data area. */
393 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
397 int86 (0x10, ®s
, ®s
);
400 /* Disable bright background colors (and enable blinking) if we found
401 the video system in that state at startup. */
403 maybe_enable_blinking (void)
411 int86 (0x10, ®s
, ®s
);
415 /* Set the screen dimensions so that it can show no less than
416 ROWS x COLS frame. */
419 dos_set_window_size (rows
, cols
)
423 Lisp_Object video_mode
;
424 int video_mode_value
;
427 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
429 if (*rows
== current_rows
&& *cols
== current_cols
)
432 /* Do we have a VGA? */
434 int86 (0x10, ®s
, ®s
);
435 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
440 /* If the user specified a special video mode for these dimensions,
442 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
443 video_mode
= XSYMBOL (Fintern_soft (build_string (video_name
),
446 if (INTEGERP (video_mode
)
447 && (video_mode_value
= XINT (video_mode
)) > 0)
449 regs
.x
.ax
= video_mode_value
;
450 int86 (0x10, ®s
, ®s
);
454 /* Must hardware-reset the mouse, or else it won't update
455 its notion of screen dimensions for some non-standard
456 video modes. This is *painfully* slow... */
458 int86 (0x33, ®s
, ®s
);
462 /* Find one of the dimensions supported by standard EGA/VGA
463 which gives us at least the required dimensions. */
472 } std_dimension
[] = {
482 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
484 if (std_dimension
[i
].need_vga
<= have_vga
485 && std_dimension
[i
].rows
>= *rows
)
487 if (std_dimension
[i
].rows
!= current_rows
488 || *cols
!= current_cols
)
489 _set_screen_lines (std_dimension
[i
].rows
);
496 #else /* not __DJGPP__ > 1 */
498 else if (*rows
<= 25)
500 if (current_rows
!= 25 || current_cols
!= 80)
503 int86 (0x10, ®s
, ®s
);
506 int86 (0x10, ®s
, ®s
);
509 int86 (0x10, ®s
, ®s
);
511 int86 (0x10, ®s
, ®s
);
514 else if (*rows
<= 50)
515 if (have_vga
&& (current_rows
!= 50 || current_cols
!= 80)
516 || *rows
<= 43 && (current_rows
!= 43 || current_cols
!= 80))
519 int86 (0x10, ®s
, ®s
);
522 int86 (0x10, ®s
, ®s
);
525 int86 (0x10, ®s
, ®s
);
528 int86 (0x10, ®s
, ®s
);
530 #endif /* not __DJGPP__ > 1 */
538 /* Tell the caller what dimensions have been REALLY set. */
539 *rows
= ScreenRows ();
540 *cols
= ScreenCols ();
542 /* Enable bright background colors. */
546 /* If we write a character in the position where the mouse is,
547 the mouse cursor may need to be refreshed. */
557 mouse_get_xy (&x
, &y
);
558 if (y
!= new_pos_Y
|| x
< new_pos_X
)
574 union REGS inregs
, outregs
;
577 intdos (&inregs
, &outregs
);
582 IT_set_face (int face
)
585 extern struct face
*intern_face (/* FRAME_PTR, struct face * */);
587 if (face
== 1 || (face
== 0 && highlight
))
588 fp
= FRAME_MODE_LINE_FACE (foo
);
589 else if (face
<= 0 || face
>= FRAME_N_COMPUTED_FACES (foo
))
590 fp
= FRAME_DEFAULT_FACE (foo
);
592 fp
= intern_face (selected_frame
, FRAME_COMPUTED_FACES (foo
)[face
]);
594 fprintf (termscript
, "<FACE %d: %d/%d>",
595 face
, FACE_FOREGROUND (fp
), FACE_BACKGROUND (fp
));
597 ScreenAttrib
= (FACE_BACKGROUND (fp
) << 4) | FACE_FOREGROUND (fp
);
601 IT_write_glyphs (GLYPH
*str
, int len
)
605 unsigned char *buf
, *bp
;
607 if (len
== 0) return;
609 buf
= bp
= alloca (len
* 2);
613 newface
= FAST_GLYPH_FACE (*str
);
614 if (newface
!= screen_face
)
615 IT_set_face (newface
);
616 ch
= FAST_GLYPH_CHAR (*str
);
617 *bp
++ = (unsigned char)ch
;
618 *bp
++ = ScreenAttrib
;
621 fputc (ch
, termscript
);
626 dosmemput (buf
, 2 * len
,
627 (int)ScreenPrimary
+ 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
));
632 IT_clear_end_of_line (first_unused
)
639 fprintf (termscript
, "<CLR:EOL>");
640 i
= (j
= screen_size_X
- new_pos_X
) * 2;
641 spaces
= sp
= alloca (i
);
646 *sp
++ = ScreenAttrib
;
650 dosmemput (spaces
, i
,
651 (int)ScreenPrimary
+ 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
));
655 IT_clear_screen (void)
658 fprintf (termscript
, "<CLR:SCR>");
662 new_pos_X
= new_pos_Y
= 0;
666 IT_clear_to_end (void)
669 fprintf (termscript
, "<CLR:EOS>");
671 while (new_pos_Y
< screen_size_Y
) {
673 IT_clear_end_of_line (0);
679 IT_cursor_to (int y
, int x
)
682 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
687 static int cursor_cleared
;
690 IT_display_cursor (int on
)
692 if (on
&& cursor_cleared
)
694 ScreenSetCursor (current_pos_Y
, current_pos_X
);
697 else if (!on
&& !cursor_cleared
)
699 ScreenSetCursor (-1, -1);
704 /* Emacs calls cursor-movement functions a lot when it updates the
705 display (probably a legacy of old terminals where you cannot
706 update a screen line without first moving the cursor there).
707 However, cursor movement is expensive on MSDOS (it calls a slow
708 BIOS function and requires 2 mode switches), while actual screen
709 updates access the video memory directly and don't depend on
710 cursor position. To avoid slowing down the redisplay, we cheat:
711 all functions that move the cursor only set internal variables
712 which record the cursor position, whereas the cursor is only
713 moved to its final position whenever screen update is complete.
715 `IT_cmgoto' is called from the keyboard reading loop and when the
716 frame update is complete. This means that we are ready for user
717 input, so we update the cursor position to show where the point is,
718 and also make the mouse pointer visible.
720 Special treatment is required when the cursor is in the echo area,
721 to put the cursor at the end of the text displayed there. */
727 /* Only set the cursor to where it should be if the display is
728 already in sync with the window contents. */
729 int update_cursor_pos
= MODIFF
== unchanged_modified
;
731 /* If we are in the echo area, put the cursor at the end of text. */
732 if (!update_cursor_pos
733 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f
))->top
) <= new_pos_Y
)
735 new_pos_X
= FRAME_DESIRED_GLYPHS (f
)->used
[new_pos_Y
];
736 update_cursor_pos
= 1;
739 if (update_cursor_pos
740 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
742 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
744 fprintf (termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
747 /* Maybe cursor is invisible, so make it visible. */
748 IT_display_cursor (1);
750 /* Mouse pointer should be always visible if we are waiting for
757 IT_reassert_line_highlight (new, vpos
)
761 IT_set_face (0); /* To possibly clear the highlighting. */
765 IT_change_line_highlight (new_highlight
, vpos
, first_unused_hpos
)
767 highlight
= new_highlight
;
768 IT_set_face (0); /* To possibly clear the highlighting. */
769 IT_cursor_to (vpos
, 0);
770 IT_clear_end_of_line (first_unused_hpos
);
777 IT_set_face (0); /* To possibly clear the highlighting. */
786 /* This was more or less copied from xterm.c
788 Nowadays, the corresponding function under X is `x_set_menu_bar_lines_1'
792 IT_set_menu_bar_lines (window
, n
)
796 struct window
*w
= XWINDOW (window
);
798 XSETFASTINT (w
->last_modified
, 0);
799 XSETFASTINT (w
->last_overlay_modified
, 0);
800 XSETFASTINT (w
->top
, XFASTINT (w
->top
) + n
);
801 XSETFASTINT (w
->height
, XFASTINT (w
->height
) - n
);
803 /* Handle just the top child in a vertical split. */
804 if (!NILP (w
->vchild
))
805 IT_set_menu_bar_lines (w
->vchild
, n
);
807 /* Adjust all children in a horizontal split. */
808 for (window
= w
->hchild
; !NILP (window
); window
= w
->next
)
810 w
= XWINDOW (window
);
811 IT_set_menu_bar_lines (window
, n
);
815 /* This was copied from xfns.c */
817 Lisp_Object Qbackground_color
;
818 Lisp_Object Qforeground_color
;
821 x_set_menu_bar_lines (f
, value
, oldval
)
823 Lisp_Object value
, oldval
;
826 int olines
= FRAME_MENU_BAR_LINES (f
);
828 /* Right now, menu bars don't work properly in minibuf-only frames;
829 most of the commands try to apply themselves to the minibuffer
830 frame itslef, and get an error because you can't switch buffers
831 in or split the minibuffer window. */
832 if (FRAME_MINIBUF_ONLY_P (f
))
835 if (INTEGERP (value
))
836 nlines
= XINT (value
);
840 FRAME_MENU_BAR_LINES (f
) = nlines
;
841 IT_set_menu_bar_lines (f
->root_window
, nlines
- olines
);
844 /* IT_set_terminal_modes is called when emacs is started,
845 resumed, and whenever the screen is redrawn! */
848 IT_set_terminal_modes (void)
851 fprintf (termscript
, "\n<SET_TERM>");
854 screen_size_X
= ScreenCols ();
855 screen_size_Y
= ScreenRows ();
856 screen_size
= screen_size_X
* screen_size_Y
;
858 new_pos_X
= new_pos_Y
= 0;
859 current_pos_X
= current_pos_Y
= -1;
865 startup_screen_size_X
= screen_size_X
;
866 startup_screen_size_Y
= screen_size_Y
;
867 startup_screen_attrib
= ScreenAttrib
;
869 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
870 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
873 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
874 screen_size_X
, screen_size_Y
);
879 /* IT_reset_terminal_modes is called when emacs is
880 suspended or killed. */
883 IT_reset_terminal_modes (void)
885 int display_row_start
= (int) ScreenPrimary
;
886 int saved_row_len
= startup_screen_size_X
* 2;
887 int update_row_len
= ScreenCols () * 2;
888 int current_rows
= ScreenRows ();
889 int to_next_row
= update_row_len
;
890 unsigned char *saved_row
= startup_screen_buffer
;
891 int cursor_pos_X
= ScreenCols () - 1;
892 int cursor_pos_Y
= ScreenRows () - 1;
895 fprintf (termscript
, "\n<RESET_TERM>");
899 if (!term_setup_done
)
904 /* Leave the video system in the same state as we found it,
905 as far as the blink/bright-background bit is concerned. */
906 maybe_enable_blinking ();
908 /* We have a situation here.
909 We cannot just do ScreenUpdate(startup_screen_buffer) because
910 the luser could have changed screen dimensions inside Emacs
911 and failed (or didn't want) to restore them before killing
912 Emacs. ScreenUpdate() uses the *current* screen dimensions and
913 thus will happily use memory outside what was allocated for
914 `startup_screen_buffer'.
915 Thus we only restore as much as the current screen dimensions
916 can hold, and clear the rest (if the saved screen is smaller than
917 the current) with the color attribute saved at startup. The cursor
918 is also restored within the visible dimensions. */
920 ScreenAttrib
= startup_screen_attrib
;
923 if (update_row_len
> saved_row_len
)
924 update_row_len
= saved_row_len
;
925 if (current_rows
> startup_screen_size_Y
)
926 current_rows
= startup_screen_size_Y
;
929 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
930 update_row_len
/ 2, current_rows
);
932 while (current_rows
--)
934 dosmemput (saved_row
, update_row_len
, display_row_start
);
935 saved_row
+= saved_row_len
;
936 display_row_start
+= to_next_row
;
938 if (startup_pos_X
< cursor_pos_X
)
939 cursor_pos_X
= startup_pos_X
;
940 if (startup_pos_Y
< cursor_pos_Y
)
941 cursor_pos_Y
= startup_pos_Y
;
943 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
944 xfree (startup_screen_buffer
);
950 IT_set_terminal_window (void)
955 IT_set_frame_parameters (f
, alist
)
960 int length
= XINT (Flength (alist
));
963 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
965 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
967 extern unsigned long load_color ();
971 /* Extract parm names and values into those vectors. */
973 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
978 parms
[i
] = Fcar (elt
);
979 CHECK_SYMBOL (parms
[i
], 1);
980 values
[i
] = Fcdr (elt
);
985 /* Now process them in reverse of specified order. */
986 for (i
--; i
>= 0; i
--)
988 Lisp_Object prop
= parms
[i
];
989 Lisp_Object val
= values
[i
];
991 if (EQ (prop
, Qforeground_color
))
993 unsigned long new_color
= load_color (f
, val
);
996 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
999 fprintf (termscript
, "<FGCOLOR %lu>\n", new_color
);
1002 else if (EQ (prop
, Qbackground_color
))
1004 unsigned long new_color
= load_color (f
, val
);
1005 if (new_color
!= ~0)
1007 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
1010 fprintf (termscript
, "<BGCOLOR %lu>\n", new_color
);
1013 else if (EQ (prop
, intern ("menu-bar-lines")))
1014 x_set_menu_bar_lines (f
, val
, 0);
1016 store_frame_param (f
, prop
, val
);
1022 extern void recompute_basic_faces (FRAME_PTR
);
1023 extern void redraw_frame (FRAME_PTR
);
1025 recompute_basic_faces (f
);
1026 if (f
== selected_frame
)
1031 extern void init_frame_faces (FRAME_PTR
);
1033 #endif /* !HAVE_X_WINDOWS */
1036 /* Do we need the internal terminal? */
1039 internal_terminal_init ()
1041 char *term
= getenv ("TERM");
1044 #ifdef HAVE_X_WINDOWS
1045 if (!inhibit_window_system
)
1050 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
1052 if (getenv ("EMACSTEST"))
1053 termscript
= fopen (getenv ("EMACSTEST"), "wt");
1055 #ifndef HAVE_X_WINDOWS
1056 if (!internal_terminal
|| inhibit_window_system
)
1058 selected_frame
->output_method
= output_termcap
;
1062 Vwindow_system
= intern ("pc");
1063 Vwindow_system_version
= make_number (1);
1065 bzero (&the_only_x_display
, sizeof the_only_x_display
);
1066 the_only_x_display
.background_pixel
= 7; /* White */
1067 the_only_x_display
.foreground_pixel
= 0; /* Black */
1069 colors
= getenv ("EMACSCOLORS");
1070 if (colors
&& strlen (colors
) >= 2)
1072 /* The colors use 4 bits each (we enable bright background). */
1073 if (isdigit (colors
[0]))
1075 else if (isxdigit (colors
[0]))
1076 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
1077 if (colors
[0] >= 0 && colors
[0] < 16)
1078 the_only_x_display
.foreground_pixel
= colors
[0];
1079 if (isdigit (colors
[1]))
1081 else if (isxdigit (colors
[1]))
1082 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
1083 if (colors
[1] >= 0 && colors
[1] < 16)
1084 the_only_x_display
.background_pixel
= colors
[1];
1086 the_only_x_display
.line_height
= 1;
1087 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
1089 init_frame_faces (selected_frame
);
1091 ring_bell_hook
= IT_ring_bell
;
1092 write_glyphs_hook
= IT_write_glyphs
;
1093 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
1094 clear_to_end_hook
= IT_clear_to_end
;
1095 clear_end_of_line_hook
= IT_clear_end_of_line
;
1096 clear_frame_hook
= IT_clear_screen
;
1097 change_line_highlight_hook
= IT_change_line_highlight
;
1098 update_begin_hook
= IT_update_begin
;
1099 update_end_hook
= IT_update_end
;
1100 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
1101 frame_up_to_date_hook
= IT_cmgoto
; /* position cursor when update is done */
1103 /* These hooks are called by term.c without being checked. */
1104 set_terminal_modes_hook
= IT_set_terminal_modes
;
1105 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
1106 set_terminal_window_hook
= IT_set_terminal_window
;
1110 dos_get_saved_screen (screen
, rows
, cols
)
1115 #ifndef HAVE_X_WINDOWS
1116 *screen
= startup_screen_buffer
;
1117 *cols
= startup_screen_size_X
;
1118 *rows
= startup_screen_size_Y
;
1125 #ifndef HAVE_X_WINDOWS
1127 /* We are not X, but we can emulate it well enough for our needs... */
1131 if (! FRAME_MSDOS_P (selected_frame
))
1132 error ("Not running under a windows system");
1138 /* ----------------------- Keyboard control ----------------------
1140 * Keymaps reflect the following keyboard layout:
1142 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1143 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1144 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1145 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1149 static int extended_kbd
; /* 101 (102) keyboard present. */
1151 struct dos_keyboard_map
1159 static struct dos_keyboard_map us_keyboard
= {
1161 /* 01234567890123456789012345678901234567890 12345678901234 */
1162 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1163 /* 0123456789012345678901234567890123456789 012345678901234 */
1164 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1165 0 /* no Alt-Gr key */
1168 static struct dos_keyboard_map fr_keyboard
= {
1170 /* 012 3456789012345678901234567890123456789012345678901234 */
1171 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
1172 /* 0123456789012345678901234567890123456789012345678901234 */
1173 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
1174 /* 01234567 89012345678901234567890123456789012345678901234 */
1178 static struct dos_keyboard_map dk_keyboard
= {
1180 /* 0123456789012345678901234567890123456789012345678901234 */
1181 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
1182 /* 01 23456789012345678901234567890123456789012345678901234 */
1183 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
1184 /* 0123456789012345678901234567890123456789012345678901234 */
1188 static struct keyboard_layout_list
1191 struct dos_keyboard_map
*keyboard_map
;
1192 } keyboard_layout_list
[] =
1199 static struct dos_keyboard_map
*keyboard
;
1200 static int keyboard_map_all
;
1201 static int international_keyboard
;
1204 dos_set_keyboard (code
, always
)
1211 /* See if Keyb.Com is installed (for international keyboard support). */
1213 int86 (0x2f, ®s
, ®s
);
1214 if (regs
.h
.al
== 0xff)
1215 international_keyboard
= 1;
1217 /* Initialize to US settings, for countries that don't have their own. */
1218 keyboard
= keyboard_layout_list
[0].keyboard_map
;
1219 keyboard_map_all
= always
;
1220 dos_keyboard_layout
= 1;
1222 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
1223 if (code
== keyboard_layout_list
[i
].country_code
)
1225 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
1226 keyboard_map_all
= always
;
1227 dos_keyboard_layout
= code
;
1233 #define Ignore 0x0000
1234 #define Normal 0x0000 /* normal key - alt changes scan-code */
1235 #define FctKey 0x1000 /* func key if c == 0, else c */
1236 #define Special 0x2000 /* func key even if c != 0 */
1237 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1238 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1239 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1240 #define Grey 0x6000 /* Grey keypad key */
1242 #define Alt 0x0100 /* alt scan-code */
1243 #define Ctrl 0x0200 /* ctrl scan-code */
1244 #define Shift 0x0400 /* shift scan-code */
1248 unsigned char char_code
; /* normal code */
1249 unsigned char meta_code
; /* M- code */
1250 unsigned char keypad_code
; /* keypad code */
1251 unsigned char editkey_code
; /* edit key */
1252 } keypad_translate_map
[] = {
1253 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1254 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1255 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1256 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1257 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1258 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1259 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1260 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1261 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1262 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1263 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1268 unsigned char char_code
; /* normal code */
1269 unsigned char keypad_code
; /* keypad code */
1270 } grey_key_translate_map
[] = {
1271 '/', 0xaf, /* kp-decimal */
1272 '*', 0xaa, /* kp-multiply */
1273 '-', 0xad, /* kp-subtract */
1274 '+', 0xab, /* kp-add */
1275 '\r', 0x8d /* kp-enter */
1278 static unsigned short
1279 ibmpc_translate_map
[] =
1281 /* --------------- 00 to 0f --------------- */
1282 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
1283 Alt
| ModFct
| 0x1b, /* Escape */
1284 Normal
| 1, /* '1' */
1285 Normal
| 2, /* '2' */
1286 Normal
| 3, /* '3' */
1287 Normal
| 4, /* '4' */
1288 Normal
| 5, /* '5' */
1289 Normal
| 6, /* '6' */
1290 Normal
| 7, /* '7' */
1291 Normal
| 8, /* '8' */
1292 Normal
| 9, /* '9' */
1293 Normal
| 10, /* '0' */
1294 Normal
| 11, /* '-' */
1295 Normal
| 12, /* '=' */
1296 Special
| 0x08, /* Backspace */
1297 ModFct
| 0x74, /* Tab/Backtab */
1299 /* --------------- 10 to 1f --------------- */
1312 ModFct
| 0x0d, /* Return */
1317 /* --------------- 20 to 2f --------------- */
1326 Map
| 40, /* '\'' */
1328 Ignore
, /* Left shift */
1329 Map
| 41, /* '\\' */
1335 /* --------------- 30 to 3f --------------- */
1342 Ignore
, /* Right shift */
1343 Grey
| 1, /* Grey * */
1345 Normal
| ' ', /* ' ' */
1346 Ignore
, /* Caps Lock */
1347 FctKey
| 0xbe, /* F1 */
1348 FctKey
| 0xbf, /* F2 */
1349 FctKey
| 0xc0, /* F3 */
1350 FctKey
| 0xc1, /* F4 */
1351 FctKey
| 0xc2, /* F5 */
1353 /* --------------- 40 to 4f --------------- */
1354 FctKey
| 0xc3, /* F6 */
1355 FctKey
| 0xc4, /* F7 */
1356 FctKey
| 0xc5, /* F8 */
1357 FctKey
| 0xc6, /* F9 */
1358 FctKey
| 0xc7, /* F10 */
1359 Ignore
, /* Num Lock */
1360 Ignore
, /* Scroll Lock */
1361 KeyPad
| 7, /* Home */
1362 KeyPad
| 8, /* Up */
1363 KeyPad
| 9, /* Page Up */
1364 Grey
| 2, /* Grey - */
1365 KeyPad
| 4, /* Left */
1366 KeyPad
| 5, /* Keypad 5 */
1367 KeyPad
| 6, /* Right */
1368 Grey
| 3, /* Grey + */
1369 KeyPad
| 1, /* End */
1371 /* --------------- 50 to 5f --------------- */
1372 KeyPad
| 2, /* Down */
1373 KeyPad
| 3, /* Page Down */
1374 KeyPad
| 0, /* Insert */
1375 KeyPad
| 10, /* Delete */
1376 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
1377 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
1378 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
1379 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
1380 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
1381 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
1382 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
1383 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
1384 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
1385 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
1386 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
1387 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
1389 /* --------------- 60 to 6f --------------- */
1390 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
1391 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
1392 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
1393 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
1394 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
1395 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
1396 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
1397 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
1398 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
1399 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
1400 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
1401 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
1402 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
1403 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
1404 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
1405 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
1407 /* --------------- 70 to 7f --------------- */
1408 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
1409 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
1410 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
1411 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
1412 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
1413 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
1414 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
1415 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
1416 Alt
| Map
| 1, /* '1' */
1417 Alt
| Map
| 2, /* '2' */
1418 Alt
| Map
| 3, /* '3' */
1419 Alt
| Map
| 4, /* '4' */
1420 Alt
| Map
| 5, /* '5' */
1421 Alt
| Map
| 6, /* '6' */
1422 Alt
| Map
| 7, /* '7' */
1423 Alt
| Map
| 8, /* '8' */
1425 /* --------------- 80 to 8f --------------- */
1426 Alt
| Map
| 9, /* '9' */
1427 Alt
| Map
| 10, /* '0' */
1428 Alt
| Map
| 11, /* '-' */
1429 Alt
| Map
| 12, /* '=' */
1430 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
1431 FctKey
| 0xc8, /* F11 */
1432 FctKey
| 0xc9, /* F12 */
1433 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
1434 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
1435 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
1436 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
1437 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
1438 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
1439 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
1440 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
1441 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
1443 /* --------------- 90 to 9f --------------- */
1444 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
1445 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
1446 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
1447 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
1448 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
1449 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
1450 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
1451 Alt
| FctKey
| 0x50, /* (Alt) Home */
1452 Alt
| FctKey
| 0x52, /* (Alt) Up */
1453 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
1454 Ignore
, /* NO KEY */
1455 Alt
| FctKey
| 0x51, /* (Alt) Left */
1456 Ignore
, /* NO KEY */
1457 Alt
| FctKey
| 0x53, /* (Alt) Right */
1458 Ignore
, /* NO KEY */
1459 Alt
| FctKey
| 0x57, /* (Alt) End */
1461 /* --------------- a0 to af --------------- */
1462 Alt
| KeyPad
| 2, /* (Alt) Down */
1463 Alt
| KeyPad
| 3, /* (Alt) Page Down */
1464 Alt
| KeyPad
| 0, /* (Alt) Insert */
1465 Alt
| KeyPad
| 10, /* (Alt) Delete */
1466 Alt
| Grey
| 0, /* (Alt) Grey / */
1467 Alt
| FctKey
| 0x09, /* (Alt) Tab */
1468 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
1471 /* These bit-positions corresponds to values returned by BIOS */
1472 #define SHIFT_P 0x0003 /* two bits! */
1473 #define CTRL_P 0x0004
1474 #define ALT_P 0x0008
1475 #define SCRLOCK_P 0x0010
1476 #define NUMLOCK_P 0x0020
1477 #define CAPSLOCK_P 0x0040
1478 #define ALT_GR_P 0x0800
1479 #define SUPER_P 0x4000 /* pseudo */
1480 #define HYPER_P 0x8000 /* pseudo */
1483 dos_get_modifiers (keymask
)
1490 /* Calculate modifier bits */
1491 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
1492 int86 (0x16, ®s
, ®s
);
1496 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
1497 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1501 mask
= regs
.h
.al
& (SHIFT_P
|
1502 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1504 /* Do not break international keyboard support. */
1505 /* When Keyb.Com is loaded, the right Alt key is */
1506 /* used for accessing characters like { and } */
1507 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
1510 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
1513 if (dos_hyper_key
== 1)
1516 modifiers
|= hyper_modifier
;
1518 else if (dos_super_key
== 1)
1521 modifiers
|= super_modifier
;
1523 else if (!international_keyboard
)
1525 /* If Keyb.Com is NOT installed, let Right Alt behave
1526 like the Left Alt. */
1532 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
1535 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
1537 if (dos_hyper_key
== 2)
1540 modifiers
|= hyper_modifier
;
1542 else if (dos_super_key
== 2)
1545 modifiers
|= super_modifier
;
1553 modifiers
|= shift_modifier
;
1555 modifiers
|= ctrl_modifier
;
1557 modifiers
|= meta_modifier
;
1564 #define NUM_RECENT_DOSKEYS (100)
1565 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
1566 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
1567 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
1569 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
1570 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1571 Each input key receives two values in this vector: first the ASCII code,\n\
1572 and then the scan code.")
1575 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
1578 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
1579 return Fvector (total_doskeys
, keys
);
1582 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
1583 bcopy (keys
+ recent_doskeys_index
,
1584 XVECTOR (val
)->contents
,
1585 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
1587 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
1588 recent_doskeys_index
* sizeof (Lisp_Object
));
1593 /* Get a char from keyboard. Function keys are put into the event queue. */
1595 extern void kbd_buffer_store_event (struct input_event
*);
1600 struct input_event event
;
1603 #ifndef HAVE_X_WINDOWS
1604 /* Maybe put the cursor where it should be. */
1605 IT_cmgoto (selected_frame
);
1608 /* The following condition is equivalent to `kbhit ()', except that
1609 it uses the bios to do its job. This pleases DESQview/X. */
1610 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
1611 int86 (0x16, ®s
, ®s
),
1612 (regs
.x
.flags
& 0x40) == 0)
1615 register unsigned char c
;
1616 int sc
, code
, mask
, kp_mode
;
1619 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
1620 int86 (0x16, ®s
, ®s
);
1625 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1627 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1628 recent_doskeys_index
= 0;
1629 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1631 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1632 recent_doskeys_index
= 0;
1634 modifiers
= dos_get_modifiers (&mask
);
1636 #ifndef HAVE_X_WINDOWS
1637 if (!NILP (Vdos_display_scancodes
))
1640 sprintf (buf
, "%02x:%02x*%04x",
1641 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
1642 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
1650 case 10: /* Ctrl Grey Enter */
1651 code
= Ctrl
| Grey
| 4;
1653 case 13: /* Grey Enter */
1656 case '/': /* Grey / */
1666 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
1668 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
1674 /* We only look at the keyboard Ctrl/Shift/Alt keys when
1675 Emacs is ready to read a key. Therefore, if they press
1676 `Alt-x' when Emacs is busy, by the time we get to
1677 `dos_get_modifiers', they might have already released the
1678 Alt key, and Emacs gets just `x', which is BAD.
1679 However, for keys with the `Map' property set, the ASCII
1680 code returns zero iff Alt is pressed. So, when we DON'T
1681 have to support international_keyboard, we don't have to
1682 distinguish between the left and right Alt keys, and we
1683 can set the META modifier for any keys with the `Map'
1684 property if they return zero ASCII code (c = 0). */
1686 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
1687 modifiers
|= meta_modifier
;
1689 modifiers
|= ctrl_modifier
;
1691 modifiers
|= shift_modifier
;
1694 switch (code
& 0xf000)
1697 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
1699 c
= 0; /* Special */
1712 if (c
== 0) /* ctrl-break */
1714 return c
; /* ALT-nnn */
1716 if (!keyboard_map_all
)
1725 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
1726 if (!keyboard_map_all
)
1730 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
1731 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
1735 code
= keyboard
->shifted
[code
];
1737 modifiers
&= ~shift_modifier
;
1740 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
1741 code
= keyboard
->alt_gr
[code
];
1743 code
= keyboard
->unshifted
[code
];
1748 if (c
== 0xe0) /* edit key */
1751 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
1752 kp_mode
= dos_keypad_mode
& 0x03;
1754 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
1759 if (code
== 10 && dos_decimal_point
)
1760 return dos_decimal_point
;
1761 return keypad_translate_map
[code
].char_code
;
1764 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
1768 code
= keypad_translate_map
[code
].meta_code
;
1769 modifiers
= meta_modifier
;
1773 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
1780 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
1781 if (dos_keypad_mode
& kp_mode
)
1782 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
1784 code
= grey_key_translate_map
[code
].char_code
;
1793 event
.kind
= non_ascii_keystroke
;
1795 event
.kind
= ascii_keystroke
;
1797 event
.modifiers
= modifiers
;
1798 XSETFRAME (event
.frame_or_window
, selected_frame
);
1799 event
.timestamp
= event_timestamp ();
1800 kbd_buffer_store_event (&event
);
1805 int but
, press
, x
, y
, ok
;
1807 /* Check for mouse movement *before* buttons. */
1808 mouse_check_moved ();
1810 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
1811 for (press
= 0; press
< 2; press
++)
1813 int button_num
= but
;
1816 ok
= mouse_pressed (but
, &x
, &y
);
1818 ok
= mouse_released (but
, &x
, &y
);
1821 /* Allow a simultaneous press/release of Mouse-1 and
1822 Mouse-2 to simulate Mouse-3 on two-button mice. */
1823 if (mouse_button_count
== 2 && but
< 2)
1825 int x2
, y2
; /* don't clobber original coordinates */
1827 /* If only one button is pressed, wait 100 msec and
1828 check again. This way, Speedy Gonzales isn't
1829 punished, while the slow get their chance. */
1830 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
1831 || !press
&& mouse_released (1-but
, &x2
, &y2
))
1836 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
1837 || !press
&& mouse_released (1-but
, &x2
, &y2
))
1842 event
.kind
= mouse_click
;
1843 event
.code
= button_num
;
1844 event
.modifiers
= dos_get_modifiers (0)
1845 | (press
? down_modifier
: up_modifier
);
1848 XSETFRAME (event
.frame_or_window
, selected_frame
);
1849 event
.timestamp
= event_timestamp ();
1850 kbd_buffer_store_event (&event
);
1858 static int prev_get_char
= -1;
1860 /* Return 1 if a key is ready to be read without suspending execution. */
1864 if (prev_get_char
!= -1)
1867 return ((prev_get_char
= dos_rawgetc ()) != -1);
1870 /* Read a key. Return -1 if no key is ready. */
1874 if (prev_get_char
!= -1)
1876 int c
= prev_get_char
;
1881 return dos_rawgetc ();
1884 #ifndef HAVE_X_WINDOWS
1885 /* See xterm.c for more info. */
1887 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
1889 register int pix_x
, pix_y
;
1890 register int *x
, *y
;
1891 void /* XRectangle */ *bounds
;
1894 if (bounds
) abort ();
1896 /* Ignore clipping. */
1903 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
1906 register int *pix_x
, *pix_y
;
1912 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1915 Actually, I don't know the meaning of all the parameters of the functions
1916 here -- I only know how they are called by xmenu.c. I could of course
1917 grab the nearest Xlib manual (down the hall, second-to-last door on the
1918 left), but I don't think it's worth the effort. */
1925 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
1926 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
1930 /* Allocate some (more) memory for MENU ensuring that there is room for one
1934 IT_menu_make_room (XMenu
*menu
)
1936 if (menu
->allocated
== 0)
1938 int count
= menu
->allocated
= 10;
1939 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
1940 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
1941 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
1943 else if (menu
->allocated
== menu
->count
)
1945 int count
= menu
->allocated
= menu
->allocated
+ 10;
1947 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
1949 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
1951 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
1955 /* Search the given menu structure for a given pane number. */
1958 IT_menu_search_pane (XMenu
*menu
, int pane
)
1963 for (i
= 0; i
< menu
->count
; i
++)
1964 if (menu
->submenu
[i
])
1966 if (pane
== menu
->panenumber
[i
])
1967 return menu
->submenu
[i
];
1968 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
1974 /* Determine how much screen space a given menu needs. */
1977 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
1979 int i
, h2
, w2
, maxsubwidth
, maxheight
;
1982 maxheight
= menu
->count
;
1983 for (i
= 0; i
< menu
->count
; i
++)
1985 if (menu
->submenu
[i
])
1987 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
1988 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
1989 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
1992 *width
= menu
->width
+ maxsubwidth
;
1993 *height
= maxheight
;
1996 /* Display MENU at (X,Y) using FACES. */
1999 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
)
2001 int i
, j
, face
, width
;
2005 int enabled
, mousehere
;
2008 width
= menu
->width
;
2009 text
= (GLYPH
*) xmalloc ((width
+ 2) * sizeof (GLYPH
));
2010 ScreenGetCursor (&row
, &col
);
2011 mouse_get_xy (&mx
, &my
);
2013 for (i
= 0; i
< menu
->count
; i
++)
2015 IT_cursor_to (y
+ i
, x
);
2017 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
2018 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
2019 face
= faces
[enabled
+ mousehere
* 2];
2021 *p
++ = FAST_MAKE_GLYPH (' ', face
);
2022 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
2025 *p
++ = FAST_MAKE_GLYPH (*q
++, face
);
2026 else /* make '^x' */
2028 *p
++ = FAST_MAKE_GLYPH ('^', face
);
2030 *p
++ = FAST_MAKE_GLYPH (*q
++ + 64, face
);
2034 for (; j
< width
; j
++)
2035 *p
++ = FAST_MAKE_GLYPH (' ', face
);
2036 *p
++ = FAST_MAKE_GLYPH (menu
->submenu
[i
] ? 16 : ' ', face
);
2037 IT_write_glyphs (text
, width
+ 2);
2040 IT_cursor_to (row
, col
);
2044 /* --------------------------- X Menu emulation ---------------------- */
2046 /* Report availability of menus. */
2054 /* Create a brand new menu structure. */
2057 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
2059 return IT_menu_create ();
2062 /* Create a new pane and place it on the outer-most level. It is not
2063 clear that it should be placed out there, but I don't know what else
2067 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
2075 IT_menu_make_room (menu
);
2076 menu
->submenu
[menu
->count
] = IT_menu_create ();
2077 menu
->text
[menu
->count
] = txt
;
2078 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
2081 /* Adjust length for possible control characters (which will
2082 be written as ^x). */
2083 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
2087 if (len
> menu
->width
)
2090 return menu
->panecount
;
2093 /* Create a new item in a menu pane. */
2096 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
2097 int foo
, char *txt
, int enable
)
2103 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
2105 IT_menu_make_room (menu
);
2106 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
2107 menu
->text
[menu
->count
] = txt
;
2108 menu
->panenumber
[menu
->count
] = enable
;
2111 /* Adjust length for possible control characters (which will
2112 be written as ^x). */
2113 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
2117 if (len
> menu
->width
)
2123 /* Decide where the menu would be placed if requested at (X,Y). */
2126 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
2127 int *ulx
, int *uly
, int *width
, int *height
)
2129 IT_menu_calc_size (menu
, width
, height
);
2135 struct IT_menu_state
2137 void *screen_behind
;
2144 /* Display menu, wait for user's response, and return that response. */
2147 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
2148 int x0
, int y0
, unsigned ButtonMask
, char **txt
)
2150 struct IT_menu_state
*state
;
2154 int faces
[4], selectface
;
2155 int leave
, result
, onepane
;
2156 int title_faces
[4]; /* face to display the menu title */
2157 int buffers_num_deleted
= 0;
2159 /* Just in case we got here without a mouse present... */
2160 if (have_mouse
<= 0)
2161 return XM_IA_SELECT
;
2162 /* Don't allow non-positive x0 and y0, lest the menu will wrap
2163 around the display. */
2169 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
2170 screensize
= screen_size
* 2;
2172 = compute_glyph_face (selected_frame
,
2175 intern ("msdos-menu-passive-face")),
2178 = compute_glyph_face (selected_frame
,
2181 intern ("msdos-menu-active-face")),
2184 = face_name_id_number (selected_frame
, intern ("msdos-menu-select-face"));
2185 faces
[2] = compute_glyph_face (selected_frame
, selectface
, faces
[0]);
2186 faces
[3] = compute_glyph_face (selected_frame
, selectface
, faces
[1]);
2188 /* Make sure the menu title is always displayed with
2189 `msdos-menu-active-face', no matter where the mouse pointer is. */
2190 for (i
= 0; i
< 4; i
++)
2191 title_faces
[i
] = faces
[3];
2195 /* Don't let the title for the "Buffers" popup menu include a
2196 digit (which is ugly).
2198 This is a terrible kludge, but I think the "Buffers" case is
2199 the only one where the title includes a number, so it doesn't
2200 seem to be necessary to make this more general. */
2201 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
2203 menu
->text
[0][7] = '\0';
2204 buffers_num_deleted
= 1;
2206 state
[0].menu
= menu
;
2208 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
2210 /* Turn off the cursor. Otherwise it shows through the menu
2211 panes, which is ugly. */
2212 IT_display_cursor (0);
2214 IT_menu_display (menu
, y0
- 1, x0
- 1, title_faces
); /* display menu title */
2215 if (buffers_num_deleted
)
2216 menu
->text
[0][7] = ' ';
2217 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
2219 menu
->width
= menu
->submenu
[0]->width
;
2220 state
[0].menu
= menu
->submenu
[0];
2224 state
[0].menu
= menu
;
2226 state
[0].x
= x0
- 1;
2228 state
[0].pane
= onepane
;
2230 mouse_last_x
= -1; /* A hack that forces display. */
2234 if (!mouse_visible
) mouse_on ();
2235 mouse_check_moved ();
2236 if (selected_frame
->mouse_moved
)
2238 selected_frame
->mouse_moved
= 0;
2239 result
= XM_IA_SELECT
;
2240 mouse_get_xy (&x
, &y
);
2241 for (i
= 0; i
< statecount
; i
++)
2242 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
2244 int dy
= y
- state
[i
].y
;
2245 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
2247 if (!state
[i
].menu
->submenu
[dy
])
2248 if (state
[i
].menu
->panenumber
[dy
])
2249 result
= XM_SUCCESS
;
2251 result
= XM_IA_SELECT
;
2252 *pane
= state
[i
].pane
- 1;
2254 /* We hit some part of a menu, so drop extra menus that
2255 have been opened. That does not include an open and
2257 if (i
!= statecount
- 2
2258 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
2259 while (i
!= statecount
- 1)
2263 ScreenUpdate (state
[statecount
].screen_behind
);
2264 xfree (state
[statecount
].screen_behind
);
2266 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
2268 IT_menu_display (state
[i
].menu
,
2272 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
2273 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
2275 ScreenRetrieve (state
[statecount
].screen_behind
2276 = xmalloc (screensize
));
2278 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
2279 state
[statecount
].y
= y
;
2284 IT_menu_display (state
[statecount
- 1].menu
,
2285 state
[statecount
- 1].y
,
2286 state
[statecount
- 1].x
,
2289 for (b
= 0; b
< mouse_button_count
; b
++)
2291 (void) mouse_pressed (b
, &x
, &y
);
2292 if (mouse_released (b
, &x
, &y
))
2298 ScreenUpdate (state
[0].screen_behind
);
2299 while (statecount
--)
2300 xfree (state
[statecount
].screen_behind
);
2301 IT_display_cursor (1); /* turn cursor back on */
2305 /* Dispose of a menu. */
2308 XMenuDestroy (Display
*foo
, XMenu
*menu
)
2311 if (menu
->allocated
)
2313 for (i
= 0; i
< menu
->count
; i
++)
2314 if (menu
->submenu
[i
])
2315 XMenuDestroy (foo
, menu
->submenu
[i
]);
2317 xfree (menu
->submenu
);
2318 xfree (menu
->panenumber
);
2324 x_pixel_width (struct frame
*f
)
2326 return FRAME_WIDTH (f
);
2330 x_pixel_height (struct frame
*f
)
2332 return FRAME_HEIGHT (f
);
2334 #endif /* !HAVE_X_WINDOWS */
2336 /* ----------------------- DOS / UNIX conversion --------------------- */
2338 void msdos_downcase_filename (unsigned char *);
2340 /* Destructively turn backslashes into slashes. */
2343 dostounix_filename (p
)
2346 msdos_downcase_filename (p
);
2356 /* Destructively turn slashes into backslashes. */
2359 unixtodos_filename (p
)
2362 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
2376 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2379 getdefdir (drive
, dst
)
2383 char in_path
[4], *p
= in_path
;
2386 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2389 *p
++ = drive
+ 'A' - 1;
2396 _fixpath (in_path
, dst
);
2400 msdos_downcase_filename (dst
);
2406 /* Remove all CR's that are followed by a LF. */
2411 register unsigned char *buf
;
2413 unsigned char *np
= buf
;
2414 unsigned char *startp
= buf
;
2415 unsigned char *endp
= buf
+ n
;
2419 while (buf
< endp
- 1)
2423 if (*(++buf
) != 0x0a)
2434 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
2436 /* In DJGPP v2.0, library `write' can call `malloc', which might
2437 cause relocation of the buffer whose address we get in ADDR.
2438 Here is a version of `write' that avoids calling `malloc',
2439 to serve us until such time as the library is fixed.
2440 Actually, what we define here is called `__write', because
2441 `write' is a stub that just jmp's to `__write' (to be
2442 POSIXLY-correct with respect to the global name-space). */
2444 #include <io.h> /* for _write */
2445 #include <libc/dosio.h> /* for __file_handle_modes[] */
2447 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
2449 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
2452 __write (int handle
, const void *buffer
, size_t count
)
2457 if(__file_handle_modes
[handle
] & O_BINARY
)
2458 return _write (handle
, buffer
, count
);
2462 const char *bp
= buffer
;
2463 int total_written
= 0;
2464 int nmoved
= 0, ncr
= 0;
2468 /* The next test makes sure there's space for at least 2 more
2469 characters in xbuf[], so both CR and LF can be put there. */
2481 if (xbp
>= XBUF_END
|| !count
)
2483 size_t to_write
= nmoved
+ ncr
;
2484 int written
= _write (handle
, xbuf
, to_write
);
2489 total_written
+= nmoved
; /* CRs aren't counted in ret value */
2491 /* If some, but not all were written (disk full?), return
2492 an estimate of the total written bytes not counting CRs. */
2493 if (written
< to_write
)
2494 return total_written
- (to_write
- written
) * nmoved
/to_write
;
2501 return total_written
;
2505 /* A low-level file-renaming function which works around Windows 95 bug.
2506 This is pulled directly out of DJGPP v2.01 library sources, and only
2507 used when you compile with DJGPP v2.0. */
2511 int _rename(const char *old
, const char *new)
2514 int olen
= strlen(old
) + 1;
2516 int use_lfn
= _USE_LFN
;
2517 char tempfile
[FILENAME_MAX
];
2518 const char *orig
= old
;
2521 r
.x
.dx
= __tb_offset
;
2522 r
.x
.di
= __tb_offset
+ olen
;
2523 r
.x
.ds
= r
.x
.es
= __tb_segment
;
2527 /* Windows 95 bug: for some filenames, when you rename
2528 file -> file~ (as in Emacs, to leave a backup), the
2529 short 8+3 alias doesn't change, which effectively
2530 makes OLD and NEW the same file. We must rename
2531 through a temporary file to work around this. */
2533 char *pbase
= 0, *p
;
2534 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
2535 int idx
= sizeof(try_char
) - 1;
2537 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
2538 might point to another drive, which will fail the DOS call. */
2539 strcpy(tempfile
, old
);
2540 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
2541 if (*p
== '/' || *p
== '\\' || *p
== ':')
2547 strcpy(pbase
, "X$$djren$$.$$temp$$");
2553 *pbase
= try_char
[--idx
];
2554 } while (_chmod(tempfile
, 0) != -1);
2557 _put_path2(tempfile
, olen
);
2559 __dpmi_int(0x21, &r
);
2562 errno
= __doserr_to_errno(r
.x
.ax
);
2566 /* Now create a file with the original name. This will
2567 ensure that NEW will always have a 8+3 alias
2568 different from that of OLD. (Seems to be required
2569 when NameNumericTail in the Registry is set to 0.) */
2570 lfn_fd
= _creat(old
, 0);
2572 olen
= strlen(tempfile
) + 1;
2574 r
.x
.di
= __tb_offset
+ olen
;
2583 _put_path2(new, olen
);
2585 __dpmi_int(0x21, &r
);
2588 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
2589 remove(new); /* and try again */
2592 errno
= __doserr_to_errno(r
.x
.ax
);
2594 /* Restore to original name if we renamed it to temporary. */
2602 _put_path2(orig
, olen
);
2603 _put_path(tempfile
);
2605 __dpmi_int(0x21, &r
);
2614 /* Success. Delete the file possibly created to work
2615 around the Windows 95 bug. */
2617 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
2621 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
2623 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
2625 "Return non-nil if long file names are supported on MSDOS.")
2628 return (_USE_LFN
? Qt
: Qnil
);
2631 /* Convert alphabetic characters in a filename to lower-case. */
2634 msdos_downcase_filename (p
)
2635 register unsigned char *p
;
2637 /* Always lower-case drive letters a-z, even if the filesystem
2638 preserves case in filenames.
2639 This is so MSDOS filenames could be compared by string comparison
2640 functions that are case-sensitive. Even case-preserving filesystems
2641 do not distinguish case in drive letters. */
2642 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
2648 /* Under LFN we expect to get pathnames in their true case. */
2649 if (NILP (Fmsdos_long_file_names ()))
2651 if (*p
>= 'A' && *p
<= 'Z')
2655 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
2657 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
2658 When long filenames are supported, doesn't change FILENAME.\n\
2659 If FILENAME is not a string, returns nil.\n\
2660 The argument object is never altered--the value is a copy.")
2662 Lisp_Object filename
;
2666 if (! STRINGP (filename
))
2669 tem
= Fcopy_sequence (filename
);
2670 msdos_downcase_filename (XSTRING (tem
)->data
);
2674 /* The Emacs root directory as determined by init_environment. */
2676 static char emacsroot
[MAXPATHLEN
];
2679 rootrelativepath (rel
)
2682 static char result
[MAXPATHLEN
+ 10];
2684 strcpy (result
, emacsroot
);
2685 strcat (result
, "/");
2686 strcat (result
, rel
);
2690 /* Define a lot of environment variables if not already defined. Don't
2691 remove anything unless you know what you're doing -- lots of code will
2692 break if one or more of these are missing. */
2695 init_environment (argc
, argv
, skip_args
)
2703 /* Find our root from argv[0]. Assuming argv[0] is, say,
2704 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
2705 root
= alloca (MAXPATHLEN
+ 20);
2706 _fixpath (argv
[0], root
);
2707 msdos_downcase_filename (root
);
2708 len
= strlen (root
);
2709 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
2713 && (strcmp (root
+ len
- 4, "/bin") == 0
2714 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
2715 root
[len
- 4] = '\0';
2717 strcpy (root
, "c:/emacs"); /* let's be defensive */
2718 len
= strlen (root
);
2719 strcpy (emacsroot
, root
);
2721 /* We default HOME to our root. */
2722 setenv ("HOME", root
, 0);
2724 /* We default EMACSPATH to root + "/bin". */
2725 strcpy (root
+ len
, "/bin");
2726 setenv ("EMACSPATH", root
, 0);
2728 /* I don't expect anybody to ever use other terminals so the internal
2729 terminal is the default. */
2730 setenv ("TERM", "internal", 0);
2732 #ifdef HAVE_X_WINDOWS
2733 /* Emacs expects DISPLAY to be set. */
2734 setenv ("DISPLAY", "unix:0.0", 0);
2737 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
2738 downcase it and mirror the backslashes. */
2739 s
= getenv ("COMSPEC");
2740 if (!s
) s
= "c:/command.com";
2741 t
= alloca (strlen (s
) + 1);
2743 dostounix_filename (t
);
2744 setenv ("SHELL", t
, 0);
2746 /* PATH is also downcased and backslashes mirrored. */
2747 s
= getenv ("PATH");
2749 t
= alloca (strlen (s
) + 3);
2750 /* Current directory is always considered part of MsDos's path but it is
2751 not normally mentioned. Now it is. */
2752 strcat (strcpy (t
, ".;"), s
);
2753 dostounix_filename (t
); /* Not a single file name, but this should work. */
2754 setenv ("PATH", t
, 1);
2756 /* In some sense all dos users have root privileges, so... */
2757 setenv ("USER", "root", 0);
2758 setenv ("NAME", getenv ("USER"), 0);
2760 /* Time zone determined from country code. To make this possible, the
2761 country code may not span more than one time zone. In other words,
2762 in the USA, you lose. */
2764 switch (dos_country_code
)
2766 case 31: /* Belgium */
2767 case 32: /* The Netherlands */
2768 case 33: /* France */
2769 case 34: /* Spain */
2770 case 36: /* Hungary */
2771 case 38: /* Yugoslavia (or what's left of it?) */
2772 case 39: /* Italy */
2773 case 41: /* Switzerland */
2774 case 42: /* Tjekia */
2775 case 45: /* Denmark */
2776 case 46: /* Sweden */
2777 case 47: /* Norway */
2778 case 48: /* Poland */
2779 case 49: /* Germany */
2780 /* Daylight saving from last Sunday in March to last Sunday in
2781 September, both at 2AM. */
2782 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2784 case 44: /* United Kingdom */
2785 case 351: /* Portugal */
2786 case 354: /* Iceland */
2787 setenv ("TZ", "GMT+00", 0);
2789 case 81: /* Japan */
2790 case 82: /* Korea */
2791 setenv ("TZ", "JST-09", 0);
2793 case 90: /* Turkey */
2794 case 358: /* Finland */
2795 setenv ("TZ", "EET-02", 0);
2797 case 972: /* Israel */
2798 /* This is an approximation. (For exact rules, use the
2799 `zoneinfo/israel' file which comes with DJGPP, but you need
2800 to install it in `/usr/share/zoneinfo/' directory first.) */
2801 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2809 static int break_stat
; /* BREAK check mode status. */
2810 static int stdin_stat
; /* stdin IOCTL status. */
2814 /* These must be global. */
2815 static _go32_dpmi_seginfo ctrl_break_vector
;
2816 static _go32_dpmi_registers ctrl_break_regs
;
2817 static int ctrlbreakinstalled
= 0;
2819 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2822 ctrl_break_func (regs
)
2823 _go32_dpmi_registers
*regs
;
2829 install_ctrl_break_check ()
2831 if (!ctrlbreakinstalled
)
2833 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2834 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2835 ctrlbreakinstalled
= 1;
2836 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
2837 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
2839 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
2843 #endif /* __DJGPP__ < 2 */
2845 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
2846 control chars by DOS. Determine the keyboard type. */
2851 union REGS inregs
, outregs
;
2852 static int first_time
= 1;
2854 break_stat
= getcbrk ();
2857 install_ctrl_break_check ();
2863 int86 (0x15, &inregs
, &outregs
);
2864 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
2868 if (internal_terminal
2869 #ifdef HAVE_X_WINDOWS
2870 && inhibit_window_system
2874 inregs
.x
.ax
= 0x0021;
2875 int86 (0x33, &inregs
, &outregs
);
2876 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2879 /* Reportedly, the above doesn't work for some mouse drivers. There
2880 is an additional detection method that should work, but might be
2881 a little slower. Use that as an alternative. */
2882 inregs
.x
.ax
= 0x0000;
2883 int86 (0x33, &inregs
, &outregs
);
2884 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2889 have_mouse
= 1; /* enable mouse */
2892 if (outregs
.x
.bx
== 3)
2894 mouse_button_count
= 3;
2895 mouse_button_translate
[0] = 0; /* Left */
2896 mouse_button_translate
[1] = 2; /* Middle */
2897 mouse_button_translate
[2] = 1; /* Right */
2901 mouse_button_count
= 2;
2902 mouse_button_translate
[0] = 0;
2903 mouse_button_translate
[1] = 1;
2905 mouse_position_hook
= &mouse_get_pos
;
2914 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
2915 return (stdin_stat
!= -1);
2918 return (setmode (fileno (stdin
), O_BINARY
) != -1);
2920 #else /* __DJGPP__ < 2 */
2924 /* I think it is wrong to overwrite `stdin_stat' every time
2925 but the first one this function is called, but I don't
2926 want to change the way it used to work in v1.x.--EZ */
2928 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
2929 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2930 intdos (&inregs
, &outregs
);
2931 stdin_stat
= outregs
.h
.dl
;
2933 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
2934 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
2935 intdos (&inregs
, &outregs
);
2936 return !outregs
.x
.cflag
;
2938 #endif /* __DJGPP__ < 2 */
2941 /* Restore status of standard input and Ctrl-C checking. */
2946 union REGS inregs
, outregs
;
2948 setcbrk (break_stat
);
2953 return (setmode (fileno (stdin
), stdin_stat
) != -1);
2955 #else /* not __DJGPP__ >= 2 */
2957 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
2958 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2959 inregs
.x
.dx
= stdin_stat
;
2960 intdos (&inregs
, &outregs
);
2961 return !outregs
.x
.cflag
;
2963 #endif /* not __DJGPP__ >= 2 */
2967 /* Run command as specified by ARGV in directory DIR.
2968 The command is run with input from TEMPIN, output to
2969 file TEMPOUT and stderr to TEMPERR. */
2972 run_msdos_command (argv
, dir
, tempin
, tempout
, temperr
)
2973 unsigned char **argv
;
2975 int tempin
, tempout
, temperr
;
2977 char *saveargv1
, *saveargv2
, **envv
, *lowcase_argv0
, *pa
, *pl
;
2978 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
2979 int msshell
, result
= -1;
2980 int inbak
, outbak
, errbak
;
2984 /* Get current directory as MSDOS cwd is not per-process. */
2987 /* If argv[0] is the shell, it might come in any lettercase.
2988 Since `Fmember' is case-sensitive, we need to downcase
2989 argv[0], even if we are on case-preserving filesystems. */
2990 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
2991 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
2994 if (*pl
>= 'A' && *pl
<= 'Z')
2999 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
3000 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
3001 && !strcmp ("-c", argv
[1]);
3004 saveargv1
= argv
[1];
3005 saveargv2
= argv
[2];
3009 char *p
= alloca (strlen (argv
[2]) + 1);
3011 strcpy (argv
[2] = p
, saveargv2
);
3012 while (*p
&& isspace (*p
))
3014 while (*p
&& !isspace (*p
))
3022 /* Build the environment array. */
3024 extern Lisp_Object Vprocess_environment
;
3025 Lisp_Object tmp
, lst
;
3028 lst
= Vprocess_environment
;
3029 len
= XFASTINT (Flength (lst
));
3031 envv
= alloca ((len
+ 1) * sizeof (char *));
3032 for (i
= 0; i
< len
; i
++)
3036 CHECK_STRING (tmp
, 0);
3037 envv
[i
] = alloca (XSTRING (tmp
)->size
+ 1);
3038 strcpy (envv
[i
], XSTRING (tmp
)->data
);
3040 envv
[len
] = (char *) 0;
3044 chdir (XSTRING (dir
)->data
);
3048 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
3049 goto done
; /* Allocation might fail due to lack of descriptors. */
3052 mouse_get_xy (&x
, &y
);
3054 dos_ttcooked (); /* do it here while 0 = stdin */
3062 if (msshell
&& !argv
[3])
3064 /* MS-DOS native shells are too restrictive. For starters, they
3065 cannot grok commands longer than 126 characters. In DJGPP v2
3066 and later, `system' is much smarter, so we'll call it instead. */
3068 extern char **environ
;
3071 /* A shell gets a single argument--its full command
3072 line--whose original was saved in `saveargv2'. */
3073 result
= system (saveargv2
);
3077 #endif /* __DJGPP__ > 1 */
3079 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
3092 mouse_moveto (x
, y
);
3095 /* Some programs might change the meaning of the highest bit of the
3096 text attribute byte, so we get blinking characters instead of the
3097 bright background colors. Restore that. */
3104 argv
[1] = saveargv1
;
3105 argv
[2] = saveargv2
;
3113 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
3120 /* ------------------------- Compatibility functions -------------------
3125 /* Hostnames for a pc are not really funny,
3126 but they are used in change log so we emulate the best we can. */
3128 gethostname (p
, size
)
3132 char *q
= egetenv ("HOSTNAME");
3139 /* When time zones are set from Ms-Dos too many C-libraries are playing
3140 tricks with time values. We solve this by defining our own version
3141 of `gettimeofday' bypassing GO32. Our version needs to be initialized
3142 once and after each call to `tzset' with TZ changed. That is
3143 accomplished by aliasing tzset to init_gettimeofday. */
3145 static struct tm time_rec
;
3148 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
3156 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
3160 time_rec
.tm_year
= d
.da_year
- 1900;
3161 time_rec
.tm_mon
= d
.da_mon
- 1;
3162 time_rec
.tm_mday
= d
.da_day
;
3165 time_rec
.tm_hour
= t
.ti_hour
;
3166 time_rec
.tm_min
= t
.ti_min
;
3167 time_rec
.tm_sec
= t
.ti_sec
;
3170 tm
.tm_gmtoff
= dos_timezone_offset
;
3172 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
3173 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
3175 /* Ignore tzp; it's obsolescent. */
3179 #endif /* __DJGPP__ < 2 */
3182 * A list of unimplemented functions that we silently ignore.
3186 unsigned alarm (s
) unsigned s
; {}
3187 fork () { return 0; }
3188 int kill (x
, y
) int x
, y
; { return -1; }
3190 void volatile pause () {}
3191 sigsetmask (x
) int x
; { return 0; }
3192 sigblock (mask
) int mask
; { return 0; }
3196 setpgrp () {return 0; }
3197 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
3198 unrequest_sigio () {}
3202 #ifdef POSIX_SIGNALS
3204 /* Augment DJGPP library POSIX signal functions. This is needed
3205 as of DJGPP v2.01, but might be in the library in later releases. */
3207 #include <libc/bss.h>
3209 /* A counter to know when to re-initialize the static sets. */
3210 static int sigprocmask_count
= -1;
3212 /* Which signals are currently blocked (initially none). */
3213 static sigset_t current_mask
;
3215 /* Which signals are pending (initially none). */
3216 static sigset_t pending_signals
;
3218 /* Previous handlers to restore when the blocked signals are unblocked. */
3219 typedef void (*sighandler_t
)(int);
3220 static sighandler_t prev_handlers
[320];
3222 /* A signal handler which just records that a signal occured
3223 (it will be raised later, if and when the signal is unblocked). */
3225 sig_suspender (signo
)
3228 sigaddset (&pending_signals
, signo
);
3232 sigprocmask (how
, new_set
, old_set
)
3234 const sigset_t
*new_set
;
3240 /* If called for the first time, initialize. */
3241 if (sigprocmask_count
!= __bss_count
)
3243 sigprocmask_count
= __bss_count
;
3244 sigemptyset (&pending_signals
);
3245 sigemptyset (¤t_mask
);
3246 for (signo
= 0; signo
< 320; signo
++)
3247 prev_handlers
[signo
] = SIG_ERR
;
3251 *old_set
= current_mask
;
3256 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
3262 sigemptyset (&new_mask
);
3264 /* DJGPP supports upto 320 signals. */
3265 for (signo
= 0; signo
< 320; signo
++)
3267 if (sigismember (¤t_mask
, signo
))
3268 sigaddset (&new_mask
, signo
);
3269 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
3271 sigaddset (&new_mask
, signo
);
3273 /* SIGKILL is silently ignored, as on other platforms. */
3274 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
3275 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
3277 if (( how
== SIG_UNBLOCK
3278 && sigismember (&new_mask
, signo
)
3279 && sigismember (new_set
, signo
))
3280 || (how
== SIG_SETMASK
3281 && sigismember (&new_mask
, signo
)
3282 && !sigismember (new_set
, signo
)))
3284 sigdelset (&new_mask
, signo
);
3285 if (prev_handlers
[signo
] != SIG_ERR
)
3287 signal (signo
, prev_handlers
[signo
]);
3288 prev_handlers
[signo
] = SIG_ERR
;
3290 if (sigismember (&pending_signals
, signo
))
3292 sigdelset (&pending_signals
, signo
);
3297 current_mask
= new_mask
;
3301 #else /* not POSIX_SIGNALS */
3303 sigsetmask (x
) int x
; { return 0; }
3304 sigblock (mask
) int mask
; { return 0; }
3306 #endif /* not POSIX_SIGNALS */
3307 #endif /* __DJGPP__ > 1 */
3310 #include "sysselect.h"
3312 #ifndef EMACS_TIME_ZERO_OR_NEG_P
3313 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
3314 ((long)(time).tv_sec < 0 \
3315 || ((time).tv_sec == 0 \
3316 && (long)(time).tv_usec <= 0))
3320 /* Only event queue is checked. */
3321 /* We don't have to call timer_check here
3322 because wait_reading_process_input takes care of that. */
3324 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
3326 SELECT_TYPE
*rfds
, *wfds
, *efds
;
3327 EMACS_TIME
*timeout
;
3335 check_input
= FD_ISSET (0, rfds
);
3346 /* If we are looking only for the terminal, with no timeout,
3347 just read it and wait -- that's more efficient. */
3350 while (!detect_input_pending ())
3359 EMACS_TIME clnow
, cllast
, cldiff
;
3362 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
3364 while (!check_input
|| !detect_input_pending ())
3367 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
3368 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
3370 /* When seconds wrap around, we assume that no more than
3371 1 minute passed since last `gettime'. */
3372 if (EMACS_TIME_NEG_P (cldiff
))
3373 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
3374 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
3376 /* Stop when timeout value crosses zero. */
3377 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
3392 * Define overlaid functions:
3394 * chdir -> sys_chdir
3395 * tzset -> init_gettimeofday
3396 * abort -> dos_abort
3401 extern int chdir ();
3407 int len
= strlen (path
);
3408 char *tmp
= (char *)path
;
3410 if (*tmp
&& tmp
[1] == ':')
3412 if (getdisk () != tolower (tmp
[0]) - 'a')
3413 setdisk (tolower (tmp
[0]) - 'a');
3414 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
3418 if (len
> 1 && (tmp
[len
- 1] == '/'))
3420 char *tmp1
= (char *) alloca (len
+ 1);
3431 extern void tzset (void);
3434 init_gettimeofday ()
3440 ltm
= gtm
= time (NULL
);
3441 ltm
= mktime (lstm
= localtime (<m
));
3442 gtm
= mktime (gmtime (>m
));
3443 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
3444 time_rec
.tm_isdst
= lstm
->tm_isdst
;
3445 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
3452 dos_abort (file
, line
)
3456 char buffer1
[200], buffer2
[400];
3459 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
3460 for (i
= j
= 0; buffer1
[i
]; i
++) {
3461 buffer2
[j
++] = buffer1
[i
];
3462 buffer2
[j
++] = 0x70;
3464 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
3465 ScreenSetCursor (2, 0);
3473 ScreenSetCursor (10, 0);
3474 cputs ("\r\n\nEmacs aborted!\r\n");
3476 /* Generate traceback, so we could tell whodunit. */
3477 signal (SIGINT
, SIG_DFL
);
3478 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
3484 /* The following two are required so that customization feature
3485 won't complain about unbound variables. */
3486 #ifndef HAVE_X_WINDOWS
3487 /* Search path for bitmap files (xfns.c). */
3488 Lisp_Object Vx_bitmap_file_path
;
3490 #ifndef subprocesses
3491 /* Nonzero means delete a process right away if it exits (process.c). */
3492 static int delete_exited_processes
;
3497 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
3498 staticpro (&recent_doskeys
);
3499 #ifndef HAVE_X_WINDOWS
3500 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path
,
3501 "List of directories to search for bitmap files for X.");
3502 Vx_bitmap_file_path
= decode_env_path ((char *) 0, ".");
3504 /* The following two are from xfns.c: */
3505 Qbackground_color
= intern ("background-color");
3506 staticpro (&Qbackground_color
);
3507 Qforeground_color
= intern ("foreground-color");
3508 staticpro (&Qforeground_color
);
3510 #ifndef subprocesses
3511 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
3512 "*Non-nil means delete processes immediately when they exit.\n\
3513 nil means don't delete them until `list-processes' is run.");
3514 delete_exited_processes
= 0;
3517 defsubr (&Srecent_doskeys
);
3518 defsubr (&Smsdos_long_file_names
);
3519 defsubr (&Smsdos_downcase_filename
);