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
);
161 mouse_get_xy (int *x
, int *y
)
166 int86 (0x33, ®s
, ®s
);
178 fprintf (termscript
, "<M_XY=%dx%d>", x
, y
);
180 mouse_last_x
= regs
.x
.cx
= x
* 8;
181 mouse_last_y
= regs
.x
.dx
= y
* 8;
182 int86 (0x33, ®s
, ®s
);
186 mouse_pressed (b
, xp
, yp
)
191 if (b
>= mouse_button_count
)
194 regs
.x
.bx
= mouse_button_translate
[b
];
195 int86 (0x33, ®s
, ®s
);
197 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
198 return (regs
.x
.bx
!= 0);
202 mouse_released (b
, xp
, yp
)
207 if (b
>= mouse_button_count
)
210 regs
.x
.bx
= mouse_button_translate
[b
];
211 int86 (0x33, ®s
, ®s
);
213 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
214 return (regs
.x
.bx
!= 0);
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
;
226 Lisp_Object frame
, tail
;
228 /* Clear the mouse-moved flag for every frame on this display. */
229 FOR_EACH_FRAME (tail
, frame
)
230 XFRAME (frame
)->mouse_moved
= 0;
234 mouse_get_xy (&ix
, &iy
);
235 *time
= event_timestamp ();
236 *x
= make_number (mouse_last_x
= ix
);
237 *y
= make_number (mouse_last_y
= iy
);
245 mouse_get_xy (&x
, &y
);
246 selected_frame
->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
257 fprintf (termscript
, "<M_INIT>");
260 int86 (0x33, ®s
, ®s
);
264 regs
.x
.dx
= 8 * (ScreenCols () - 1);
265 int86 (0x33, ®s
, ®s
);
269 regs
.x
.dx
= 8 * (ScreenRows () - 1);
270 int86 (0x33, ®s
, ®s
);
276 /* ------------------------- Screen control ----------------------
280 static int internal_terminal
= 0;
282 #ifndef HAVE_X_WINDOWS
283 extern unsigned char ScreenAttrib
;
284 static int screen_face
;
285 static int highlight
;
287 static int screen_size_X
;
288 static int screen_size_Y
;
289 static int screen_size
;
291 static int current_pos_X
;
292 static int current_pos_Y
;
293 static int new_pos_X
;
294 static int new_pos_Y
;
296 static void *startup_screen_buffer
;
297 static int startup_screen_size_X
;
298 static int startup_screen_size_Y
;
299 static int startup_pos_X
;
300 static int startup_pos_Y
;
301 static unsigned char startup_screen_attrib
;
303 static int term_setup_done
;
305 /* Similar to the_only_frame. */
306 struct x_output the_only_x_display
;
308 /* This is never dereferenced. */
309 Display
*x_current_display
;
311 /* Support for DOS/V (allows Japanese characters to be displayed on
312 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
314 /* Holds the address of the text-mode screen buffer. */
315 static unsigned long screen_old_address
= 0;
316 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
317 static unsigned short screen_virtual_segment
= 0;
318 static unsigned short screen_virtual_offset
= 0;
321 /* Update the screen from a part of relocated DOS/V screen buffer which
322 begins at OFFSET and includes COUNT characters. */
324 dosv_refresh_virtual_screen (int offset
, int count
)
328 if (offset
< 0 || count
< 0) /* paranoia; illegal values crash DOS/V */
331 regs
.h
.ah
= 0xff; /* update relocated screen */
332 regs
.x
.es
= screen_virtual_segment
;
333 regs
.x
.di
= screen_virtual_offset
+ offset
;
335 __dpmi_int (0x10, ®s
);
340 dos_direct_output (y
, x
, buf
, len
)
346 int t0
= 2 * (x
+ y
* screen_size_X
);
347 int t
= t0
+ (int) ScreenPrimary
;
352 dosmemput (buf
++, 1, t
);
356 /* This is faster. */
357 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
358 _farnspokeb (t
, *buf
);
360 if (screen_virtual_segment
)
361 dosv_refresh_virtual_screen (t0
, l0
);
366 /* Flash the screen as a substitute for BEEPs. */
370 do_visible_bell (xorattr
)
371 unsigned char xorattr
;
376 movl _ScreenPrimary,%%eax
383 xorb %%al,%%gs:(%%ebx)
399 : "m" (xorattr
), "g" (screen_size
)
400 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
404 ScreenVisualBell (void)
406 /* This creates an xor-mask that will swap the default fore- and
407 background colors. */
408 do_visible_bell (((the_only_x_display
.foreground_pixel
409 ^ the_only_x_display
.background_pixel
)
414 #ifndef HAVE_X_WINDOWS
416 static int blink_bit
= -1; /* the state of the blink bit at startup */
418 /* Enable bright background colors. */
424 /* Remember the original state of the blink/bright-background bit.
425 It is stored at 0040:0065h in the BIOS data area. */
427 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
431 int86 (0x10, ®s
, ®s
);
434 /* Disable bright background colors (and enable blinking) if we found
435 the video system in that state at startup. */
437 maybe_enable_blinking (void)
445 int86 (0x10, ®s
, ®s
);
449 /* Set the screen dimensions so that it can show no less than
450 ROWS x COLS frame. */
453 dos_set_window_size (rows
, cols
)
457 Lisp_Object video_mode
;
458 int video_mode_value
;
461 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
463 if (*rows
== current_rows
&& *cols
== current_cols
)
466 /* Do we have a VGA? */
468 int86 (0x10, ®s
, ®s
);
469 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
474 /* If the user specified a special video mode for these dimensions,
476 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
477 video_mode
= XSYMBOL (Fintern_soft (build_string (video_name
),
480 if (INTEGERP (video_mode
)
481 && (video_mode_value
= XINT (video_mode
)) > 0)
483 regs
.x
.ax
= video_mode_value
;
484 int86 (0x10, ®s
, ®s
);
488 /* Must hardware-reset the mouse, or else it won't update
489 its notion of screen dimensions for some non-standard
490 video modes. This is *painfully* slow... */
492 int86 (0x33, ®s
, ®s
);
496 /* Find one of the dimensions supported by standard EGA/VGA
497 which gives us at least the required dimensions. */
506 } std_dimension
[] = {
516 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
518 if (std_dimension
[i
].need_vga
<= have_vga
519 && std_dimension
[i
].rows
>= *rows
)
521 if (std_dimension
[i
].rows
!= current_rows
522 || *cols
!= current_cols
)
523 _set_screen_lines (std_dimension
[i
].rows
);
530 #else /* not __DJGPP__ > 1 */
532 else if (*rows
<= 25)
534 if (current_rows
!= 25 || current_cols
!= 80)
537 int86 (0x10, ®s
, ®s
);
540 int86 (0x10, ®s
, ®s
);
543 int86 (0x10, ®s
, ®s
);
545 int86 (0x10, ®s
, ®s
);
548 else if (*rows
<= 50)
549 if (have_vga
&& (current_rows
!= 50 || current_cols
!= 80)
550 || *rows
<= 43 && (current_rows
!= 43 || current_cols
!= 80))
553 int86 (0x10, ®s
, ®s
);
556 int86 (0x10, ®s
, ®s
);
559 int86 (0x10, ®s
, ®s
);
562 int86 (0x10, ®s
, ®s
);
564 #endif /* not __DJGPP__ > 1 */
572 /* Tell the caller what dimensions have been REALLY set. */
573 *rows
= ScreenRows ();
574 *cols
= ScreenCols ();
576 /* Enable bright background colors. */
579 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
580 be defensive anyway. */
581 if (screen_virtual_segment
)
582 dosv_refresh_virtual_screen (0, *cols
* *rows
);
585 /* If we write a character in the position where the mouse is,
586 the mouse cursor may need to be refreshed. */
596 mouse_get_xy (&x
, &y
);
597 if (y
!= new_pos_Y
|| x
< new_pos_X
)
613 union REGS inregs
, outregs
;
616 intdos (&inregs
, &outregs
);
621 IT_set_face (int face
)
624 extern struct face
*intern_face (/* FRAME_PTR, struct face * */);
626 if (face
== 1 || (face
== 0 && highlight
))
627 fp
= FRAME_MODE_LINE_FACE (foo
);
628 else if (face
<= 0 || face
>= FRAME_N_COMPUTED_FACES (foo
))
629 fp
= FRAME_DEFAULT_FACE (foo
);
631 fp
= intern_face (selected_frame
, FRAME_COMPUTED_FACES (foo
)[face
]);
633 fprintf (termscript
, "<FACE %d: %d/%d>",
634 face
, FACE_FOREGROUND (fp
), FACE_BACKGROUND (fp
));
636 ScreenAttrib
= (FACE_BACKGROUND (fp
) << 4) | FACE_FOREGROUND (fp
);
640 IT_write_glyphs (GLYPH
*str
, int len
)
644 unsigned char *buf
, *bp
;
645 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
647 if (len
== 0) return;
649 buf
= bp
= alloca (len
* 2);
653 newface
= FAST_GLYPH_FACE (*str
);
654 if (newface
!= screen_face
)
655 IT_set_face (newface
);
656 ch
= FAST_GLYPH_CHAR (*str
);
657 *bp
++ = (unsigned char)ch
;
658 *bp
++ = ScreenAttrib
;
661 fputc (ch
, termscript
);
666 dosmemput (buf
, 2 * len
, (int)ScreenPrimary
+ offset
);
667 if (screen_virtual_segment
)
668 dosv_refresh_virtual_screen (offset
, len
);
673 IT_clear_end_of_line (int first_unused
)
677 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
681 fprintf (termscript
, "<CLR:EOL>");
682 i
= (j
= screen_size_X
- new_pos_X
) * 2;
683 spaces
= sp
= alloca (i
);
688 *sp
++ = ScreenAttrib
;
692 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
693 if (screen_virtual_segment
)
694 dosv_refresh_virtual_screen (offset
, i
/ 2);
698 IT_clear_screen (void)
701 fprintf (termscript
, "<CLR:SCR>");
705 if (screen_virtual_segment
)
706 dosv_refresh_virtual_screen (0, screen_size
);
707 new_pos_X
= new_pos_Y
= 0;
711 IT_clear_to_end (void)
714 fprintf (termscript
, "<CLR:EOS>");
716 while (new_pos_Y
< screen_size_Y
) {
718 IT_clear_end_of_line (0);
724 IT_cursor_to (int y
, int x
)
727 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
732 static int cursor_cleared
;
735 IT_display_cursor (int on
)
737 if (on
&& cursor_cleared
)
739 ScreenSetCursor (current_pos_Y
, current_pos_X
);
742 else if (!on
&& !cursor_cleared
)
744 ScreenSetCursor (-1, -1);
749 /* Emacs calls cursor-movement functions a lot when it updates the
750 display (probably a legacy of old terminals where you cannot
751 update a screen line without first moving the cursor there).
752 However, cursor movement is expensive on MSDOS (it calls a slow
753 BIOS function and requires 2 mode switches), while actual screen
754 updates access the video memory directly and don't depend on
755 cursor position. To avoid slowing down the redisplay, we cheat:
756 all functions that move the cursor only set internal variables
757 which record the cursor position, whereas the cursor is only
758 moved to its final position whenever screen update is complete.
760 `IT_cmgoto' is called from the keyboard reading loop and when the
761 frame update is complete. This means that we are ready for user
762 input, so we update the cursor position to show where the point is,
763 and also make the mouse pointer visible.
765 Special treatment is required when the cursor is in the echo area,
766 to put the cursor at the end of the text displayed there. */
769 IT_cmgoto (FRAME_PTR f
)
771 /* Only set the cursor to where it should be if the display is
772 already in sync with the window contents. */
773 int update_cursor_pos
= MODIFF
== unchanged_modified
;
775 /* If we are in the echo area, put the cursor at the end of text. */
776 if (!update_cursor_pos
777 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f
))->top
) <= new_pos_Y
)
779 new_pos_X
= FRAME_DESIRED_GLYPHS (f
)->used
[new_pos_Y
];
780 update_cursor_pos
= 1;
783 if (update_cursor_pos
784 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
786 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
788 fprintf (termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
791 /* Maybe cursor is invisible, so make it visible. */
792 IT_display_cursor (1);
794 /* Mouse pointer should be always visible if we are waiting for
801 IT_reassert_line_highlight (int new, int vpos
)
804 IT_set_face (0); /* To possibly clear the highlighting. */
808 IT_change_line_highlight (int new_highlight
, int vpos
, int first_unused_hpos
)
810 highlight
= new_highlight
;
811 IT_set_face (0); /* To possibly clear the highlighting. */
812 IT_cursor_to (vpos
, 0);
813 IT_clear_end_of_line (first_unused_hpos
);
817 IT_update_begin (struct frame
*foo
)
820 IT_set_face (0); /* To possibly clear the highlighting. */
825 IT_update_end (struct frame
*foo
)
829 /* set-window-configuration on window.c needs this. */
831 x_set_menu_bar_lines (f
, value
, oldval
)
833 Lisp_Object value
, oldval
;
835 set_menu_bar_lines (f
, value
, oldval
);
838 /* This was copied from xfns.c */
840 Lisp_Object Qbackground_color
;
841 Lisp_Object Qforeground_color
;
842 extern Lisp_Object Qtitle
;
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
;
870 /* Is DOS/V (or any other RSIS software which relocates
871 the screen) installed? */
873 unsigned short es_value
;
876 regs
.h
.ah
= 0xfe; /* get relocated screen address */
877 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
878 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
879 else if (screen_old_address
) /* already switched to Japanese mode once */
880 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
882 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
884 es_value
= regs
.x
.es
;
885 __dpmi_int (0x10, ®s
);
887 if (regs
.x
.es
!= es_value
&& regs
.x
.es
!= (ScreenPrimary
>> 4) & 0xffff)
889 screen_old_address
= ScreenPrimary
;
890 screen_virtual_segment
= regs
.x
.es
;
891 screen_virtual_offset
= regs
.x
.di
;
892 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
895 #endif /* __DJGPP__ > 1 */
897 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
898 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
901 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
902 screen_size_X
, screen_size_Y
);
907 /* IT_reset_terminal_modes is called when emacs is
908 suspended or killed. */
911 IT_reset_terminal_modes (void)
913 int display_row_start
= (int) ScreenPrimary
;
914 int saved_row_len
= startup_screen_size_X
* 2;
915 int update_row_len
= ScreenCols () * 2;
916 int current_rows
= ScreenRows ();
917 int to_next_row
= update_row_len
;
918 unsigned char *saved_row
= startup_screen_buffer
;
919 int cursor_pos_X
= ScreenCols () - 1;
920 int cursor_pos_Y
= ScreenRows () - 1;
923 fprintf (termscript
, "\n<RESET_TERM>");
927 if (!term_setup_done
)
932 /* Leave the video system in the same state as we found it,
933 as far as the blink/bright-background bit is concerned. */
934 maybe_enable_blinking ();
936 /* We have a situation here.
937 We cannot just do ScreenUpdate(startup_screen_buffer) because
938 the luser could have changed screen dimensions inside Emacs
939 and failed (or didn't want) to restore them before killing
940 Emacs. ScreenUpdate() uses the *current* screen dimensions and
941 thus will happily use memory outside what was allocated for
942 `startup_screen_buffer'.
943 Thus we only restore as much as the current screen dimensions
944 can hold, and clear the rest (if the saved screen is smaller than
945 the current) with the color attribute saved at startup. The cursor
946 is also restored within the visible dimensions. */
948 ScreenAttrib
= startup_screen_attrib
;
950 if (screen_virtual_segment
)
951 dosv_refresh_virtual_screen (0, screen_size
);
953 if (update_row_len
> saved_row_len
)
954 update_row_len
= saved_row_len
;
955 if (current_rows
> startup_screen_size_Y
)
956 current_rows
= startup_screen_size_Y
;
959 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
960 update_row_len
/ 2, current_rows
);
962 while (current_rows
--)
964 dosmemput (saved_row
, update_row_len
, display_row_start
);
965 if (screen_virtual_segment
)
966 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
968 saved_row
+= saved_row_len
;
969 display_row_start
+= to_next_row
;
971 if (startup_pos_X
< cursor_pos_X
)
972 cursor_pos_X
= startup_pos_X
;
973 if (startup_pos_Y
< cursor_pos_Y
)
974 cursor_pos_Y
= startup_pos_Y
;
976 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
977 xfree (startup_screen_buffer
);
983 IT_set_terminal_window (int foo
)
988 IT_set_frame_parameters (f
, alist
)
993 int length
= XINT (Flength (alist
));
996 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
998 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
1000 extern unsigned long load_color ();
1004 /* Extract parm names and values into those vectors. */
1006 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
1011 parms
[i
] = Fcar (elt
);
1012 CHECK_SYMBOL (parms
[i
], 1);
1013 values
[i
] = Fcdr (elt
);
1018 /* Now process them in reverse of specified order. */
1019 for (i
--; i
>= 0; i
--)
1021 Lisp_Object prop
= parms
[i
];
1022 Lisp_Object val
= values
[i
];
1024 if (EQ (prop
, Qforeground_color
))
1026 unsigned long new_color
= load_color (f
, val
);
1027 if (new_color
!= ~0)
1029 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
1032 fprintf (termscript
, "<FGCOLOR %lu>\n", new_color
);
1035 else if (EQ (prop
, Qbackground_color
))
1037 unsigned long new_color
= load_color (f
, val
);
1038 if (new_color
!= ~0)
1040 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
1043 fprintf (termscript
, "<BGCOLOR %lu>\n", new_color
);
1046 else if (EQ (prop
, Qtitle
))
1048 x_set_title (f
, val
);
1050 fprintf (termscript
, "<TITLE: %s>\n", XSTRING (val
)->data
);
1052 else if (EQ (prop
, intern ("reverse")) && EQ (val
, Qt
))
1054 unsigned long fg
= FRAME_FOREGROUND_PIXEL (f
);
1056 FRAME_FOREGROUND_PIXEL (f
) = FRAME_BACKGROUND_PIXEL (f
);
1057 FRAME_BACKGROUND_PIXEL (f
) = fg
;
1059 fprintf (termscript
, "<INVERSE-VIDEO>\n");
1061 store_frame_param (f
, prop
, val
);
1067 extern void recompute_basic_faces (FRAME_PTR
);
1068 extern void redraw_frame (FRAME_PTR
);
1070 recompute_basic_faces (f
);
1071 if (f
== selected_frame
)
1076 extern void init_frame_faces (FRAME_PTR
);
1078 #endif /* !HAVE_X_WINDOWS */
1081 /* Do we need the internal terminal? */
1084 internal_terminal_init ()
1086 char *term
= getenv ("TERM");
1089 #ifdef HAVE_X_WINDOWS
1090 if (!inhibit_window_system
)
1095 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
1097 if (getenv ("EMACSTEST"))
1098 termscript
= fopen (getenv ("EMACSTEST"), "wt");
1100 #ifndef HAVE_X_WINDOWS
1101 if (!internal_terminal
|| inhibit_window_system
)
1103 selected_frame
->output_method
= output_termcap
;
1107 Vwindow_system
= intern ("pc");
1108 Vwindow_system_version
= make_number (1);
1110 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
1111 screen_old_address
= 0;
1113 bzero (&the_only_x_display
, sizeof the_only_x_display
);
1114 the_only_x_display
.background_pixel
= 7; /* White */
1115 the_only_x_display
.foreground_pixel
= 0; /* Black */
1117 colors
= getenv ("EMACSCOLORS");
1118 if (colors
&& strlen (colors
) >= 2)
1120 /* The colors use 4 bits each (we enable bright background). */
1121 if (isdigit (colors
[0]))
1123 else if (isxdigit (colors
[0]))
1124 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
1125 if (colors
[0] >= 0 && colors
[0] < 16)
1126 the_only_x_display
.foreground_pixel
= colors
[0];
1127 if (isdigit (colors
[1]))
1129 else if (isxdigit (colors
[1]))
1130 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
1131 if (colors
[1] >= 0 && colors
[1] < 16)
1132 the_only_x_display
.background_pixel
= colors
[1];
1134 the_only_x_display
.line_height
= 1;
1135 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
1137 init_frame_faces (selected_frame
);
1139 ring_bell_hook
= IT_ring_bell
;
1140 write_glyphs_hook
= IT_write_glyphs
;
1141 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
1142 clear_to_end_hook
= IT_clear_to_end
;
1143 clear_end_of_line_hook
= IT_clear_end_of_line
;
1144 clear_frame_hook
= IT_clear_screen
;
1145 change_line_highlight_hook
= IT_change_line_highlight
;
1146 update_begin_hook
= IT_update_begin
;
1147 update_end_hook
= IT_update_end
;
1148 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
1149 frame_up_to_date_hook
= IT_cmgoto
; /* position cursor when update is done */
1151 /* These hooks are called by term.c without being checked. */
1152 set_terminal_modes_hook
= IT_set_terminal_modes
;
1153 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
1154 set_terminal_window_hook
= IT_set_terminal_window
;
1158 dos_get_saved_screen (screen
, rows
, cols
)
1163 #ifndef HAVE_X_WINDOWS
1164 *screen
= startup_screen_buffer
;
1165 *cols
= startup_screen_size_X
;
1166 *rows
= startup_screen_size_Y
;
1167 return *screen
!= (char *)0;
1173 #ifndef HAVE_X_WINDOWS
1175 /* We are not X, but we can emulate it well enough for our needs... */
1179 if (! FRAME_MSDOS_P (selected_frame
))
1180 error ("Not running under a windows system");
1186 /* ----------------------- Keyboard control ----------------------
1188 * Keymaps reflect the following keyboard layout:
1190 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1191 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1192 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1193 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1197 static int extended_kbd
; /* 101 (102) keyboard present. */
1199 struct dos_keyboard_map
1207 static struct dos_keyboard_map us_keyboard
= {
1209 /* 01234567890123456789012345678901234567890 12345678901234 */
1210 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1211 /* 0123456789012345678901234567890123456789 012345678901234 */
1212 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1213 0 /* no Alt-Gr key */
1216 static struct dos_keyboard_map fr_keyboard
= {
1218 /* 012 3456789012345678901234567890123456789012345678901234 */
1219 "ý&\82\",(-\8a_\80\85)= azertyuiop^$ qsdfghjklm\97* wxcvbnm;:! ",
1220 /* 0123456789012345678901234567890123456789012345678901234 */
1221 " 1234567890ø+ AZERTYUIOPù\9c QSDFGHJKLM%æ WXCVBN?./õ ",
1222 /* 01234567 89012345678901234567890123456789012345678901234 */
1227 * Italian keyboard support, country code 39.
1230 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
1231 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
1233 static struct dos_keyboard_map it_keyboard
= {
1235 /* 0 123456789012345678901234567890123456789012345678901234 */
1236 "\\1234567890'\8d qwertyuiop\8a+ asdfghjkl\95\85\97 zxcvbnm,.- ",
1237 /* 01 23456789012345678901234567890123456789012345678901234 */
1238 "|!\"\9c$%&/()=?^ QWERTYUIOP\82* ASDFGHJKL\87øõ ZXCVBNM;:_ ",
1239 /* 0123456789012345678901234567890123456789012345678901234 */
1243 static struct dos_keyboard_map dk_keyboard
= {
1245 /* 0123456789012345678901234567890123456789012345678901234 */
1246 "«1234567890+| qwertyuiop\86~ asdfghjkl\91\9b' zxcvbnm,.- ",
1247 /* 01 23456789012345678901234567890123456789012345678901234 */
1248 "õ!\"#$%&/()=?` QWERTYUIOP\8f^ ASDFGHJKL\92\9d* ZXCVBNM;:_ ",
1249 /* 0123456789012345678901234567890123456789012345678901234 */
1253 static struct keyboard_layout_list
1256 struct dos_keyboard_map
*keyboard_map
;
1257 } keyboard_layout_list
[] =
1265 static struct dos_keyboard_map
*keyboard
;
1266 static int keyboard_map_all
;
1267 static int international_keyboard
;
1270 dos_set_keyboard (code
, always
)
1277 /* See if Keyb.Com is installed (for international keyboard support). */
1279 int86 (0x2f, ®s
, ®s
);
1280 if (regs
.h
.al
== 0xff)
1281 international_keyboard
= 1;
1283 /* Initialize to US settings, for countries that don't have their own. */
1284 keyboard
= keyboard_layout_list
[0].keyboard_map
;
1285 keyboard_map_all
= always
;
1286 dos_keyboard_layout
= 1;
1288 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
1289 if (code
== keyboard_layout_list
[i
].country_code
)
1291 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
1292 keyboard_map_all
= always
;
1293 dos_keyboard_layout
= code
;
1299 #define Ignore 0x0000
1300 #define Normal 0x0000 /* normal key - alt changes scan-code */
1301 #define FctKey 0x1000 /* func key if c == 0, else c */
1302 #define Special 0x2000 /* func key even if c != 0 */
1303 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1304 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1305 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1306 #define Grey 0x6000 /* Grey keypad key */
1308 #define Alt 0x0100 /* alt scan-code */
1309 #define Ctrl 0x0200 /* ctrl scan-code */
1310 #define Shift 0x0400 /* shift scan-code */
1314 unsigned char char_code
; /* normal code */
1315 unsigned char meta_code
; /* M- code */
1316 unsigned char keypad_code
; /* keypad code */
1317 unsigned char editkey_code
; /* edit key */
1318 } keypad_translate_map
[] = {
1319 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1320 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1321 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1322 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1323 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1324 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1325 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1326 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1327 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1328 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1329 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1334 unsigned char char_code
; /* normal code */
1335 unsigned char keypad_code
; /* keypad code */
1336 } grey_key_translate_map
[] = {
1337 '/', 0xaf, /* kp-decimal */
1338 '*', 0xaa, /* kp-multiply */
1339 '-', 0xad, /* kp-subtract */
1340 '+', 0xab, /* kp-add */
1341 '\r', 0x8d /* kp-enter */
1344 static unsigned short
1345 ibmpc_translate_map
[] =
1347 /* --------------- 00 to 0f --------------- */
1348 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
1349 Alt
| ModFct
| 0x1b, /* Escape */
1350 Normal
| 1, /* '1' */
1351 Normal
| 2, /* '2' */
1352 Normal
| 3, /* '3' */
1353 Normal
| 4, /* '4' */
1354 Normal
| 5, /* '5' */
1355 Normal
| 6, /* '6' */
1356 Normal
| 7, /* '7' */
1357 Normal
| 8, /* '8' */
1358 Normal
| 9, /* '9' */
1359 Normal
| 10, /* '0' */
1360 Normal
| 11, /* '-' */
1361 Normal
| 12, /* '=' */
1362 Special
| 0x08, /* Backspace */
1363 ModFct
| 0x74, /* Tab/Backtab */
1365 /* --------------- 10 to 1f --------------- */
1378 ModFct
| 0x0d, /* Return */
1383 /* --------------- 20 to 2f --------------- */
1392 Map
| 40, /* '\'' */
1394 Ignore
, /* Left shift */
1395 Map
| 41, /* '\\' */
1401 /* --------------- 30 to 3f --------------- */
1408 Ignore
, /* Right shift */
1409 Grey
| 1, /* Grey * */
1411 Normal
| ' ', /* ' ' */
1412 Ignore
, /* Caps Lock */
1413 FctKey
| 0xbe, /* F1 */
1414 FctKey
| 0xbf, /* F2 */
1415 FctKey
| 0xc0, /* F3 */
1416 FctKey
| 0xc1, /* F4 */
1417 FctKey
| 0xc2, /* F5 */
1419 /* --------------- 40 to 4f --------------- */
1420 FctKey
| 0xc3, /* F6 */
1421 FctKey
| 0xc4, /* F7 */
1422 FctKey
| 0xc5, /* F8 */
1423 FctKey
| 0xc6, /* F9 */
1424 FctKey
| 0xc7, /* F10 */
1425 Ignore
, /* Num Lock */
1426 Ignore
, /* Scroll Lock */
1427 KeyPad
| 7, /* Home */
1428 KeyPad
| 8, /* Up */
1429 KeyPad
| 9, /* Page Up */
1430 Grey
| 2, /* Grey - */
1431 KeyPad
| 4, /* Left */
1432 KeyPad
| 5, /* Keypad 5 */
1433 KeyPad
| 6, /* Right */
1434 Grey
| 3, /* Grey + */
1435 KeyPad
| 1, /* End */
1437 /* --------------- 50 to 5f --------------- */
1438 KeyPad
| 2, /* Down */
1439 KeyPad
| 3, /* Page Down */
1440 KeyPad
| 0, /* Insert */
1441 KeyPad
| 10, /* Delete */
1442 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
1443 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
1444 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
1445 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
1446 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
1447 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
1448 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
1449 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
1450 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
1451 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
1452 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
1453 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
1455 /* --------------- 60 to 6f --------------- */
1456 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
1457 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
1458 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
1459 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
1460 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
1461 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
1462 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
1463 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
1464 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
1465 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
1466 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
1467 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
1468 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
1469 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
1470 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
1471 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
1473 /* --------------- 70 to 7f --------------- */
1474 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
1475 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
1476 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
1477 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
1478 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
1479 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
1480 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
1481 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
1482 Alt
| Map
| 1, /* '1' */
1483 Alt
| Map
| 2, /* '2' */
1484 Alt
| Map
| 3, /* '3' */
1485 Alt
| Map
| 4, /* '4' */
1486 Alt
| Map
| 5, /* '5' */
1487 Alt
| Map
| 6, /* '6' */
1488 Alt
| Map
| 7, /* '7' */
1489 Alt
| Map
| 8, /* '8' */
1491 /* --------------- 80 to 8f --------------- */
1492 Alt
| Map
| 9, /* '9' */
1493 Alt
| Map
| 10, /* '0' */
1494 Alt
| Map
| 11, /* '-' */
1495 Alt
| Map
| 12, /* '=' */
1496 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
1497 FctKey
| 0xc8, /* F11 */
1498 FctKey
| 0xc9, /* F12 */
1499 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
1500 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
1501 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
1502 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
1503 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
1504 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
1505 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
1506 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
1507 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
1509 /* --------------- 90 to 9f --------------- */
1510 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
1511 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
1512 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
1513 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
1514 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
1515 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
1516 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
1517 Alt
| FctKey
| 0x50, /* (Alt) Home */
1518 Alt
| FctKey
| 0x52, /* (Alt) Up */
1519 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
1520 Ignore
, /* NO KEY */
1521 Alt
| FctKey
| 0x51, /* (Alt) Left */
1522 Ignore
, /* NO KEY */
1523 Alt
| FctKey
| 0x53, /* (Alt) Right */
1524 Ignore
, /* NO KEY */
1525 Alt
| FctKey
| 0x57, /* (Alt) End */
1527 /* --------------- a0 to af --------------- */
1528 Alt
| KeyPad
| 2, /* (Alt) Down */
1529 Alt
| KeyPad
| 3, /* (Alt) Page Down */
1530 Alt
| KeyPad
| 0, /* (Alt) Insert */
1531 Alt
| KeyPad
| 10, /* (Alt) Delete */
1532 Alt
| Grey
| 0, /* (Alt) Grey / */
1533 Alt
| FctKey
| 0x09, /* (Alt) Tab */
1534 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
1537 /* These bit-positions corresponds to values returned by BIOS */
1538 #define SHIFT_P 0x0003 /* two bits! */
1539 #define CTRL_P 0x0004
1540 #define ALT_P 0x0008
1541 #define SCRLOCK_P 0x0010
1542 #define NUMLOCK_P 0x0020
1543 #define CAPSLOCK_P 0x0040
1544 #define ALT_GR_P 0x0800
1545 #define SUPER_P 0x4000 /* pseudo */
1546 #define HYPER_P 0x8000 /* pseudo */
1549 dos_get_modifiers (keymask
)
1556 /* Calculate modifier bits */
1557 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
1558 int86 (0x16, ®s
, ®s
);
1562 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
1563 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1567 mask
= regs
.h
.al
& (SHIFT_P
|
1568 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1570 /* Do not break international keyboard support. */
1571 /* When Keyb.Com is loaded, the right Alt key is */
1572 /* used for accessing characters like { and } */
1573 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
1576 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
1579 if (dos_hyper_key
== 1)
1582 modifiers
|= hyper_modifier
;
1584 else if (dos_super_key
== 1)
1587 modifiers
|= super_modifier
;
1589 else if (!international_keyboard
)
1591 /* If Keyb.Com is NOT installed, let Right Alt behave
1592 like the Left Alt. */
1598 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
1601 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
1603 if (dos_hyper_key
== 2)
1606 modifiers
|= hyper_modifier
;
1608 else if (dos_super_key
== 2)
1611 modifiers
|= super_modifier
;
1619 modifiers
|= shift_modifier
;
1621 modifiers
|= ctrl_modifier
;
1623 modifiers
|= meta_modifier
;
1630 #define NUM_RECENT_DOSKEYS (100)
1631 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
1632 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
1633 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
1635 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
1636 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1637 Each input key receives two values in this vector: first the ASCII code,\n\
1638 and then the scan code.")
1641 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
1644 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
1645 return Fvector (total_doskeys
, keys
);
1648 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
1649 bcopy (keys
+ recent_doskeys_index
,
1650 XVECTOR (val
)->contents
,
1651 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
1653 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
1654 recent_doskeys_index
* sizeof (Lisp_Object
));
1659 /* Get a char from keyboard. Function keys are put into the event queue. */
1661 extern void kbd_buffer_store_event (struct input_event
*);
1666 struct input_event event
;
1669 #ifndef HAVE_X_WINDOWS
1670 /* Maybe put the cursor where it should be. */
1671 IT_cmgoto (selected_frame
);
1674 /* The following condition is equivalent to `kbhit ()', except that
1675 it uses the bios to do its job. This pleases DESQview/X. */
1676 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
1677 int86 (0x16, ®s
, ®s
),
1678 (regs
.x
.flags
& 0x40) == 0)
1681 register unsigned char c
;
1682 int sc
, code
, mask
, kp_mode
;
1685 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
1686 int86 (0x16, ®s
, ®s
);
1691 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1693 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1694 recent_doskeys_index
= 0;
1695 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1697 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1698 recent_doskeys_index
= 0;
1700 modifiers
= dos_get_modifiers (&mask
);
1702 #ifndef HAVE_X_WINDOWS
1703 if (!NILP (Vdos_display_scancodes
))
1706 sprintf (buf
, "%02x:%02x*%04x",
1707 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
1708 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
1716 case 10: /* Ctrl Grey Enter */
1717 code
= Ctrl
| Grey
| 4;
1719 case 13: /* Grey Enter */
1722 case '/': /* Grey / */
1732 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
1734 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
1740 /* We only look at the keyboard Ctrl/Shift/Alt keys when
1741 Emacs is ready to read a key. Therefore, if they press
1742 `Alt-x' when Emacs is busy, by the time we get to
1743 `dos_get_modifiers', they might have already released the
1744 Alt key, and Emacs gets just `x', which is BAD.
1745 However, for keys with the `Map' property set, the ASCII
1746 code returns zero iff Alt is pressed. So, when we DON'T
1747 have to support international_keyboard, we don't have to
1748 distinguish between the left and right Alt keys, and we
1749 can set the META modifier for any keys with the `Map'
1750 property if they return zero ASCII code (c = 0). */
1752 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
1753 modifiers
|= meta_modifier
;
1755 modifiers
|= ctrl_modifier
;
1757 modifiers
|= shift_modifier
;
1760 switch (code
& 0xf000)
1763 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
1765 c
= 0; /* Special */
1778 if (c
== 0) /* ctrl-break */
1780 return c
; /* ALT-nnn */
1782 if (!keyboard_map_all
)
1791 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
1792 if (!keyboard_map_all
)
1796 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
1797 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
1801 code
= keyboard
->shifted
[code
];
1803 modifiers
&= ~shift_modifier
;
1806 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
1807 code
= keyboard
->alt_gr
[code
];
1809 code
= keyboard
->unshifted
[code
];
1814 if (c
== 0xe0) /* edit key */
1817 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
1818 kp_mode
= dos_keypad_mode
& 0x03;
1820 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
1825 if (code
== 10 && dos_decimal_point
)
1826 return dos_decimal_point
;
1827 return keypad_translate_map
[code
].char_code
;
1830 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
1834 code
= keypad_translate_map
[code
].meta_code
;
1835 modifiers
= meta_modifier
;
1839 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
1846 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
1847 if (dos_keypad_mode
& kp_mode
)
1848 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
1850 code
= grey_key_translate_map
[code
].char_code
;
1859 event
.kind
= non_ascii_keystroke
;
1861 event
.kind
= ascii_keystroke
;
1863 event
.modifiers
= modifiers
;
1864 XSETFRAME (event
.frame_or_window
, selected_frame
);
1865 event
.timestamp
= event_timestamp ();
1866 kbd_buffer_store_event (&event
);
1871 int but
, press
, x
, y
, ok
;
1873 /* Check for mouse movement *before* buttons. */
1874 mouse_check_moved ();
1876 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
1877 for (press
= 0; press
< 2; press
++)
1879 int button_num
= but
;
1882 ok
= mouse_pressed (but
, &x
, &y
);
1884 ok
= mouse_released (but
, &x
, &y
);
1887 /* Allow a simultaneous press/release of Mouse-1 and
1888 Mouse-2 to simulate Mouse-3 on two-button mice. */
1889 if (mouse_button_count
== 2 && but
< 2)
1891 int x2
, y2
; /* don't clobber original coordinates */
1893 /* If only one button is pressed, wait 100 msec and
1894 check again. This way, Speedy Gonzales isn't
1895 punished, while the slow get their chance. */
1896 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
1897 || !press
&& mouse_released (1-but
, &x2
, &y2
))
1902 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
1903 || !press
&& mouse_released (1-but
, &x2
, &y2
))
1908 event
.kind
= mouse_click
;
1909 event
.code
= button_num
;
1910 event
.modifiers
= dos_get_modifiers (0)
1911 | (press
? down_modifier
: up_modifier
);
1914 XSETFRAME (event
.frame_or_window
, selected_frame
);
1915 event
.timestamp
= event_timestamp ();
1916 kbd_buffer_store_event (&event
);
1924 static int prev_get_char
= -1;
1926 /* Return 1 if a key is ready to be read without suspending execution. */
1930 if (prev_get_char
!= -1)
1933 return ((prev_get_char
= dos_rawgetc ()) != -1);
1936 /* Read a key. Return -1 if no key is ready. */
1940 if (prev_get_char
!= -1)
1942 int c
= prev_get_char
;
1947 return dos_rawgetc ();
1950 #ifndef HAVE_X_WINDOWS
1951 /* See xterm.c for more info. */
1953 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
1955 register int pix_x
, pix_y
;
1956 register int *x
, *y
;
1960 if (bounds
) abort ();
1962 /* Ignore clipping. */
1969 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
1972 register int *pix_x
, *pix_y
;
1978 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1981 Actually, I don't know the meaning of all the parameters of the functions
1982 here -- I only know how they are called by xmenu.c. I could of course
1983 grab the nearest Xlib manual (down the hall, second-to-last door on the
1984 left), but I don't think it's worth the effort. */
1991 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
1992 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
1996 /* Allocate some (more) memory for MENU ensuring that there is room for one
2000 IT_menu_make_room (XMenu
*menu
)
2002 if (menu
->allocated
== 0)
2004 int count
= menu
->allocated
= 10;
2005 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
2006 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
2007 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
2009 else if (menu
->allocated
== menu
->count
)
2011 int count
= menu
->allocated
= menu
->allocated
+ 10;
2013 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
2015 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
2017 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
2021 /* Search the given menu structure for a given pane number. */
2024 IT_menu_search_pane (XMenu
*menu
, int pane
)
2029 for (i
= 0; i
< menu
->count
; i
++)
2030 if (menu
->submenu
[i
])
2032 if (pane
== menu
->panenumber
[i
])
2033 return menu
->submenu
[i
];
2034 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
2040 /* Determine how much screen space a given menu needs. */
2043 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
2045 int i
, h2
, w2
, maxsubwidth
, maxheight
;
2048 maxheight
= menu
->count
;
2049 for (i
= 0; i
< menu
->count
; i
++)
2051 if (menu
->submenu
[i
])
2053 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
2054 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
2055 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
2058 *width
= menu
->width
+ maxsubwidth
;
2059 *height
= maxheight
;
2062 /* Display MENU at (X,Y) using FACES. */
2065 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
)
2067 int i
, j
, face
, width
;
2071 int enabled
, mousehere
;
2074 width
= menu
->width
;
2075 text
= (GLYPH
*) xmalloc ((width
+ 2) * sizeof (GLYPH
));
2076 ScreenGetCursor (&row
, &col
);
2077 mouse_get_xy (&mx
, &my
);
2078 IT_update_begin (selected_frame
);
2079 for (i
= 0; i
< menu
->count
; i
++)
2081 IT_cursor_to (y
+ i
, x
);
2083 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
2084 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
2085 face
= faces
[enabled
+ mousehere
* 2];
2087 *p
++ = FAST_MAKE_GLYPH (' ', face
);
2088 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
2091 *p
++ = FAST_MAKE_GLYPH (*q
++, face
);
2092 else /* make '^x' */
2094 *p
++ = FAST_MAKE_GLYPH ('^', face
);
2096 *p
++ = FAST_MAKE_GLYPH (*q
++ + 64, face
);
2100 for (; j
< width
; j
++)
2101 *p
++ = FAST_MAKE_GLYPH (' ', face
);
2102 *p
++ = FAST_MAKE_GLYPH (menu
->submenu
[i
] ? 16 : ' ', face
);
2103 IT_write_glyphs (text
, width
+ 2);
2105 IT_update_end (selected_frame
);
2106 IT_cursor_to (row
, col
);
2110 /* --------------------------- X Menu emulation ---------------------- */
2112 /* Report availability of menus. */
2120 /* Create a brand new menu structure. */
2123 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
2125 return IT_menu_create ();
2128 /* Create a new pane and place it on the outer-most level. It is not
2129 clear that it should be placed out there, but I don't know what else
2133 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
2141 IT_menu_make_room (menu
);
2142 menu
->submenu
[menu
->count
] = IT_menu_create ();
2143 menu
->text
[menu
->count
] = txt
;
2144 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
2147 /* Adjust length for possible control characters (which will
2148 be written as ^x). */
2149 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
2153 if (len
> menu
->width
)
2156 return menu
->panecount
;
2159 /* Create a new item in a menu pane. */
2162 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
2163 int foo
, char *txt
, int enable
)
2169 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
2171 IT_menu_make_room (menu
);
2172 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
2173 menu
->text
[menu
->count
] = txt
;
2174 menu
->panenumber
[menu
->count
] = enable
;
2177 /* Adjust length for possible control characters (which will
2178 be written as ^x). */
2179 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
2183 if (len
> menu
->width
)
2189 /* Decide where the menu would be placed if requested at (X,Y). */
2192 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
2193 int *ulx
, int *uly
, int *width
, int *height
)
2195 IT_menu_calc_size (menu
, width
, height
);
2201 struct IT_menu_state
2203 void *screen_behind
;
2210 /* Display menu, wait for user's response, and return that response. */
2213 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
2214 int x0
, int y0
, unsigned ButtonMask
, char **txt
)
2216 struct IT_menu_state
*state
;
2220 int faces
[4], selectface
;
2221 int leave
, result
, onepane
;
2222 int title_faces
[4]; /* face to display the menu title */
2223 int buffers_num_deleted
= 0;
2225 /* Just in case we got here without a mouse present... */
2226 if (have_mouse
<= 0)
2227 return XM_IA_SELECT
;
2228 /* Don't allow non-positive x0 and y0, lest the menu will wrap
2229 around the display. */
2235 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
2236 screensize
= screen_size
* 2;
2238 = compute_glyph_face (selected_frame
,
2241 intern ("msdos-menu-passive-face")),
2244 = compute_glyph_face (selected_frame
,
2247 intern ("msdos-menu-active-face")),
2250 = face_name_id_number (selected_frame
, intern ("msdos-menu-select-face"));
2251 faces
[2] = compute_glyph_face (selected_frame
, selectface
, faces
[0]);
2252 faces
[3] = compute_glyph_face (selected_frame
, selectface
, faces
[1]);
2254 /* Make sure the menu title is always displayed with
2255 `msdos-menu-active-face', no matter where the mouse pointer is. */
2256 for (i
= 0; i
< 4; i
++)
2257 title_faces
[i
] = faces
[3];
2261 /* Don't let the title for the "Buffers" popup menu include a
2262 digit (which is ugly).
2264 This is a terrible kludge, but I think the "Buffers" case is
2265 the only one where the title includes a number, so it doesn't
2266 seem to be necessary to make this more general. */
2267 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
2269 menu
->text
[0][7] = '\0';
2270 buffers_num_deleted
= 1;
2272 state
[0].menu
= menu
;
2274 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
2276 /* Turn off the cursor. Otherwise it shows through the menu
2277 panes, which is ugly. */
2278 IT_display_cursor (0);
2280 IT_menu_display (menu
, y0
- 1, x0
- 1, title_faces
); /* display menu title */
2281 if (buffers_num_deleted
)
2282 menu
->text
[0][7] = ' ';
2283 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
2285 menu
->width
= menu
->submenu
[0]->width
;
2286 state
[0].menu
= menu
->submenu
[0];
2290 state
[0].menu
= menu
;
2292 state
[0].x
= x0
- 1;
2294 state
[0].pane
= onepane
;
2296 mouse_last_x
= -1; /* A hack that forces display. */
2300 if (!mouse_visible
) mouse_on ();
2301 mouse_check_moved ();
2302 if (selected_frame
->mouse_moved
)
2304 selected_frame
->mouse_moved
= 0;
2305 result
= XM_IA_SELECT
;
2306 mouse_get_xy (&x
, &y
);
2307 for (i
= 0; i
< statecount
; i
++)
2308 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
2310 int dy
= y
- state
[i
].y
;
2311 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
2313 if (!state
[i
].menu
->submenu
[dy
])
2314 if (state
[i
].menu
->panenumber
[dy
])
2315 result
= XM_SUCCESS
;
2317 result
= XM_IA_SELECT
;
2318 *pane
= state
[i
].pane
- 1;
2320 /* We hit some part of a menu, so drop extra menus that
2321 have been opened. That does not include an open and
2323 if (i
!= statecount
- 2
2324 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
2325 while (i
!= statecount
- 1)
2329 ScreenUpdate (state
[statecount
].screen_behind
);
2330 if (screen_virtual_segment
)
2331 dosv_refresh_virtual_screen (0, screen_size
);
2332 xfree (state
[statecount
].screen_behind
);
2334 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
2336 IT_menu_display (state
[i
].menu
,
2340 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
2341 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
2343 ScreenRetrieve (state
[statecount
].screen_behind
2344 = xmalloc (screensize
));
2346 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
2347 state
[statecount
].y
= y
;
2352 IT_menu_display (state
[statecount
- 1].menu
,
2353 state
[statecount
- 1].y
,
2354 state
[statecount
- 1].x
,
2357 for (b
= 0; b
< mouse_button_count
; b
++)
2359 (void) mouse_pressed (b
, &x
, &y
);
2360 if (mouse_released (b
, &x
, &y
))
2366 ScreenUpdate (state
[0].screen_behind
);
2367 if (screen_virtual_segment
)
2368 dosv_refresh_virtual_screen (0, screen_size
);
2369 while (statecount
--)
2370 xfree (state
[statecount
].screen_behind
);
2371 IT_display_cursor (1); /* turn cursor back on */
2375 /* Dispose of a menu. */
2378 XMenuDestroy (Display
*foo
, XMenu
*menu
)
2381 if (menu
->allocated
)
2383 for (i
= 0; i
< menu
->count
; i
++)
2384 if (menu
->submenu
[i
])
2385 XMenuDestroy (foo
, menu
->submenu
[i
]);
2387 xfree (menu
->submenu
);
2388 xfree (menu
->panenumber
);
2394 x_pixel_width (struct frame
*f
)
2396 return FRAME_WIDTH (f
);
2400 x_pixel_height (struct frame
*f
)
2402 return FRAME_HEIGHT (f
);
2404 #endif /* !HAVE_X_WINDOWS */
2406 /* ----------------------- DOS / UNIX conversion --------------------- */
2408 void msdos_downcase_filename (unsigned char *);
2410 /* Destructively turn backslashes into slashes. */
2413 dostounix_filename (p
)
2416 msdos_downcase_filename (p
);
2426 /* Destructively turn slashes into backslashes. */
2429 unixtodos_filename (p
)
2432 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
2446 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2449 getdefdir (drive
, dst
)
2453 char in_path
[4], *p
= in_path
;
2456 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2459 *p
++ = drive
+ 'A' - 1;
2466 _fixpath (in_path
, dst
);
2470 msdos_downcase_filename (dst
);
2476 /* Remove all CR's that are followed by a LF. */
2481 register unsigned char *buf
;
2483 unsigned char *np
= buf
;
2484 unsigned char *startp
= buf
;
2485 unsigned char *endp
= buf
+ n
;
2489 while (buf
< endp
- 1)
2493 if (*(++buf
) != 0x0a)
2504 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
2506 /* In DJGPP v2.0, library `write' can call `malloc', which might
2507 cause relocation of the buffer whose address we get in ADDR.
2508 Here is a version of `write' that avoids calling `malloc',
2509 to serve us until such time as the library is fixed.
2510 Actually, what we define here is called `__write', because
2511 `write' is a stub that just jmp's to `__write' (to be
2512 POSIXLY-correct with respect to the global name-space). */
2514 #include <io.h> /* for _write */
2515 #include <libc/dosio.h> /* for __file_handle_modes[] */
2517 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
2519 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
2522 __write (int handle
, const void *buffer
, size_t count
)
2527 if(__file_handle_modes
[handle
] & O_BINARY
)
2528 return _write (handle
, buffer
, count
);
2532 const char *bp
= buffer
;
2533 int total_written
= 0;
2534 int nmoved
= 0, ncr
= 0;
2538 /* The next test makes sure there's space for at least 2 more
2539 characters in xbuf[], so both CR and LF can be put there. */
2551 if (xbp
>= XBUF_END
|| !count
)
2553 size_t to_write
= nmoved
+ ncr
;
2554 int written
= _write (handle
, xbuf
, to_write
);
2559 total_written
+= nmoved
; /* CRs aren't counted in ret value */
2561 /* If some, but not all were written (disk full?), return
2562 an estimate of the total written bytes not counting CRs. */
2563 if (written
< to_write
)
2564 return total_written
- (to_write
- written
) * nmoved
/to_write
;
2571 return total_written
;
2575 /* A low-level file-renaming function which works around Windows 95 bug.
2576 This is pulled directly out of DJGPP v2.01 library sources, and only
2577 used when you compile with DJGPP v2.0. */
2581 int _rename(const char *old
, const char *new)
2584 int olen
= strlen(old
) + 1;
2586 int use_lfn
= _USE_LFN
;
2587 char tempfile
[FILENAME_MAX
];
2588 const char *orig
= old
;
2591 r
.x
.dx
= __tb_offset
;
2592 r
.x
.di
= __tb_offset
+ olen
;
2593 r
.x
.ds
= r
.x
.es
= __tb_segment
;
2597 /* Windows 95 bug: for some filenames, when you rename
2598 file -> file~ (as in Emacs, to leave a backup), the
2599 short 8+3 alias doesn't change, which effectively
2600 makes OLD and NEW the same file. We must rename
2601 through a temporary file to work around this. */
2603 char *pbase
= 0, *p
;
2604 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
2605 int idx
= sizeof(try_char
) - 1;
2607 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
2608 might point to another drive, which will fail the DOS call. */
2609 strcpy(tempfile
, old
);
2610 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
2611 if (*p
== '/' || *p
== '\\' || *p
== ':')
2617 strcpy(pbase
, "X$$djren$$.$$temp$$");
2623 *pbase
= try_char
[--idx
];
2624 } while (_chmod(tempfile
, 0) != -1);
2627 _put_path2(tempfile
, olen
);
2629 __dpmi_int(0x21, &r
);
2632 errno
= __doserr_to_errno(r
.x
.ax
);
2636 /* Now create a file with the original name. This will
2637 ensure that NEW will always have a 8+3 alias
2638 different from that of OLD. (Seems to be required
2639 when NameNumericTail in the Registry is set to 0.) */
2640 lfn_fd
= _creat(old
, 0);
2642 olen
= strlen(tempfile
) + 1;
2644 r
.x
.di
= __tb_offset
+ olen
;
2653 _put_path2(new, olen
);
2655 __dpmi_int(0x21, &r
);
2658 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
2659 remove(new); /* and try again */
2662 errno
= __doserr_to_errno(r
.x
.ax
);
2664 /* Restore to original name if we renamed it to temporary. */
2672 _put_path2(orig
, olen
);
2673 _put_path(tempfile
);
2675 __dpmi_int(0x21, &r
);
2684 /* Success. Delete the file possibly created to work
2685 around the Windows 95 bug. */
2687 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
2691 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
2693 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
2695 "Return non-nil if long file names are supported on MSDOS.")
2698 return (_USE_LFN
? Qt
: Qnil
);
2701 /* Convert alphabetic characters in a filename to lower-case. */
2704 msdos_downcase_filename (p
)
2705 register unsigned char *p
;
2707 /* Always lower-case drive letters a-z, even if the filesystem
2708 preserves case in filenames.
2709 This is so MSDOS filenames could be compared by string comparison
2710 functions that are case-sensitive. Even case-preserving filesystems
2711 do not distinguish case in drive letters. */
2712 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
2718 /* Under LFN we expect to get pathnames in their true case. */
2719 if (NILP (Fmsdos_long_file_names ()))
2721 if (*p
>= 'A' && *p
<= 'Z')
2725 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
2727 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
2728 When long filenames are supported, doesn't change FILENAME.\n\
2729 If FILENAME is not a string, returns nil.\n\
2730 The argument object is never altered--the value is a copy.")
2732 Lisp_Object filename
;
2736 if (! STRINGP (filename
))
2739 tem
= Fcopy_sequence (filename
);
2740 msdos_downcase_filename (XSTRING (tem
)->data
);
2744 /* The Emacs root directory as determined by init_environment. */
2746 static char emacsroot
[MAXPATHLEN
];
2749 rootrelativepath (rel
)
2752 static char result
[MAXPATHLEN
+ 10];
2754 strcpy (result
, emacsroot
);
2755 strcat (result
, "/");
2756 strcat (result
, rel
);
2760 /* Define a lot of environment variables if not already defined. Don't
2761 remove anything unless you know what you're doing -- lots of code will
2762 break if one or more of these are missing. */
2765 init_environment (argc
, argv
, skip_args
)
2773 /* Find our root from argv[0]. Assuming argv[0] is, say,
2774 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
2775 root
= alloca (MAXPATHLEN
+ 20);
2776 _fixpath (argv
[0], root
);
2777 msdos_downcase_filename (root
);
2778 len
= strlen (root
);
2779 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
2783 && (strcmp (root
+ len
- 4, "/bin") == 0
2784 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
2785 root
[len
- 4] = '\0';
2787 strcpy (root
, "c:/emacs"); /* let's be defensive */
2788 len
= strlen (root
);
2789 strcpy (emacsroot
, root
);
2791 /* We default HOME to our root. */
2792 setenv ("HOME", root
, 0);
2794 /* We default EMACSPATH to root + "/bin". */
2795 strcpy (root
+ len
, "/bin");
2796 setenv ("EMACSPATH", root
, 0);
2798 /* I don't expect anybody to ever use other terminals so the internal
2799 terminal is the default. */
2800 setenv ("TERM", "internal", 0);
2802 #ifdef HAVE_X_WINDOWS
2803 /* Emacs expects DISPLAY to be set. */
2804 setenv ("DISPLAY", "unix:0.0", 0);
2807 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
2808 downcase it and mirror the backslashes. */
2809 s
= getenv ("COMSPEC");
2810 if (!s
) s
= "c:/command.com";
2811 t
= alloca (strlen (s
) + 1);
2813 dostounix_filename (t
);
2814 setenv ("SHELL", t
, 0);
2816 /* PATH is also downcased and backslashes mirrored. */
2817 s
= getenv ("PATH");
2819 t
= alloca (strlen (s
) + 3);
2820 /* Current directory is always considered part of MsDos's path but it is
2821 not normally mentioned. Now it is. */
2822 strcat (strcpy (t
, ".;"), s
);
2823 dostounix_filename (t
); /* Not a single file name, but this should work. */
2824 setenv ("PATH", t
, 1);
2826 /* In some sense all dos users have root privileges, so... */
2827 setenv ("USER", "root", 0);
2828 setenv ("NAME", getenv ("USER"), 0);
2830 /* Time zone determined from country code. To make this possible, the
2831 country code may not span more than one time zone. In other words,
2832 in the USA, you lose. */
2834 switch (dos_country_code
)
2836 case 31: /* Belgium */
2837 case 32: /* The Netherlands */
2838 case 33: /* France */
2839 case 34: /* Spain */
2840 case 36: /* Hungary */
2841 case 38: /* Yugoslavia (or what's left of it?) */
2842 case 39: /* Italy */
2843 case 41: /* Switzerland */
2844 case 42: /* Tjekia */
2845 case 45: /* Denmark */
2846 case 46: /* Sweden */
2847 case 47: /* Norway */
2848 case 48: /* Poland */
2849 case 49: /* Germany */
2850 /* Daylight saving from last Sunday in March to last Sunday in
2851 September, both at 2AM. */
2852 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2854 case 44: /* United Kingdom */
2855 case 351: /* Portugal */
2856 case 354: /* Iceland */
2857 setenv ("TZ", "GMT+00", 0);
2859 case 81: /* Japan */
2860 case 82: /* Korea */
2861 setenv ("TZ", "JST-09", 0);
2863 case 90: /* Turkey */
2864 case 358: /* Finland */
2865 setenv ("TZ", "EET-02", 0);
2867 case 972: /* Israel */
2868 /* This is an approximation. (For exact rules, use the
2869 `zoneinfo/israel' file which comes with DJGPP, but you need
2870 to install it in `/usr/share/zoneinfo/' directory first.) */
2871 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2879 static int break_stat
; /* BREAK check mode status. */
2880 static int stdin_stat
; /* stdin IOCTL status. */
2884 /* These must be global. */
2885 static _go32_dpmi_seginfo ctrl_break_vector
;
2886 static _go32_dpmi_registers ctrl_break_regs
;
2887 static int ctrlbreakinstalled
= 0;
2889 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2892 ctrl_break_func (regs
)
2893 _go32_dpmi_registers
*regs
;
2899 install_ctrl_break_check ()
2901 if (!ctrlbreakinstalled
)
2903 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2904 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2905 ctrlbreakinstalled
= 1;
2906 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
2907 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
2909 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
2913 #endif /* __DJGPP__ < 2 */
2915 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
2916 control chars by DOS. Determine the keyboard type. */
2921 union REGS inregs
, outregs
;
2922 static int first_time
= 1;
2924 break_stat
= getcbrk ();
2927 install_ctrl_break_check ();
2933 int86 (0x15, &inregs
, &outregs
);
2934 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
2938 if (internal_terminal
2939 #ifdef HAVE_X_WINDOWS
2940 && inhibit_window_system
2944 inregs
.x
.ax
= 0x0021;
2945 int86 (0x33, &inregs
, &outregs
);
2946 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2949 /* Reportedly, the above doesn't work for some mouse drivers. There
2950 is an additional detection method that should work, but might be
2951 a little slower. Use that as an alternative. */
2952 inregs
.x
.ax
= 0x0000;
2953 int86 (0x33, &inregs
, &outregs
);
2954 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2959 have_mouse
= 1; /* enable mouse */
2962 if (outregs
.x
.bx
== 3)
2964 mouse_button_count
= 3;
2965 mouse_button_translate
[0] = 0; /* Left */
2966 mouse_button_translate
[1] = 2; /* Middle */
2967 mouse_button_translate
[2] = 1; /* Right */
2971 mouse_button_count
= 2;
2972 mouse_button_translate
[0] = 0;
2973 mouse_button_translate
[1] = 1;
2975 mouse_position_hook
= &mouse_get_pos
;
2984 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
2985 return (stdin_stat
!= -1);
2988 return (setmode (fileno (stdin
), O_BINARY
) != -1);
2990 #else /* __DJGPP__ < 2 */
2994 /* I think it is wrong to overwrite `stdin_stat' every time
2995 but the first one this function is called, but I don't
2996 want to change the way it used to work in v1.x.--EZ */
2998 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
2999 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
3000 intdos (&inregs
, &outregs
);
3001 stdin_stat
= outregs
.h
.dl
;
3003 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
3004 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
3005 intdos (&inregs
, &outregs
);
3006 return !outregs
.x
.cflag
;
3008 #endif /* __DJGPP__ < 2 */
3011 /* Restore status of standard input and Ctrl-C checking. */
3016 union REGS inregs
, outregs
;
3018 setcbrk (break_stat
);
3023 return (setmode (fileno (stdin
), stdin_stat
) != -1);
3025 #else /* not __DJGPP__ >= 2 */
3027 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
3028 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
3029 inregs
.x
.dx
= stdin_stat
;
3030 intdos (&inregs
, &outregs
);
3031 return !outregs
.x
.cflag
;
3033 #endif /* not __DJGPP__ >= 2 */
3037 /* Run command as specified by ARGV in directory DIR.
3038 The command is run with input from TEMPIN, output to
3039 file TEMPOUT and stderr to TEMPERR. */
3042 run_msdos_command (argv
, working_dir
, tempin
, tempout
, temperr
, envv
)
3043 unsigned char **argv
;
3044 const char *working_dir
;
3045 int tempin
, tempout
, temperr
;
3048 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
3049 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
3050 int msshell
, result
= -1;
3051 int inbak
, outbak
, errbak
;
3055 /* Get current directory as MSDOS cwd is not per-process. */
3058 /* If argv[0] is the shell, it might come in any lettercase.
3059 Since `Fmember' is case-sensitive, we need to downcase
3060 argv[0], even if we are on case-preserving filesystems. */
3061 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
3062 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
3065 if (*pl
>= 'A' && *pl
<= 'Z')
3070 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
3071 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
3072 && !strcmp ("-c", argv
[1]);
3075 saveargv1
= argv
[1];
3076 saveargv2
= argv
[2];
3080 char *p
= alloca (strlen (argv
[2]) + 1);
3082 strcpy (argv
[2] = p
, saveargv2
);
3083 while (*p
&& isspace (*p
))
3085 while (*p
&& !isspace (*p
))
3093 chdir (working_dir
);
3097 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
3098 goto done
; /* Allocation might fail due to lack of descriptors. */
3101 mouse_get_xy (&x
, &y
);
3103 dos_ttcooked (); /* do it here while 0 = stdin */
3111 if (msshell
&& !argv
[3])
3113 /* MS-DOS native shells are too restrictive. For starters, they
3114 cannot grok commands longer than 126 characters. In DJGPP v2
3115 and later, `system' is much smarter, so we'll call it instead. */
3119 /* A shell gets a single argument--its full command
3120 line--whose original was saved in `saveargv2'. */
3122 /* Don't let them pass empty command lines to `system', since
3123 with some shells it will try to invoke an interactive shell,
3124 which will hang Emacs. */
3125 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
3129 extern char **environ
;
3130 int save_system_flags
= __system_flags
;
3132 /* Request the most powerful version of `system'. We need
3133 all the help we can get to avoid calling stock DOS shells. */
3134 __system_flags
= (__system_redirect
3135 | __system_use_shell
3136 | __system_allow_multiple_cmds
3137 | __system_allow_long_cmds
3138 | __system_handle_null_commands
3139 | __system_emulate_chdir
);
3142 result
= system (cmnd
);
3143 __system_flags
= save_system_flags
;
3146 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
3150 #endif /* __DJGPP__ > 1 */
3152 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
3165 mouse_moveto (x
, y
);
3168 /* Some programs might change the meaning of the highest bit of the
3169 text attribute byte, so we get blinking characters instead of the
3170 bright background colors. Restore that. */
3177 argv
[1] = saveargv1
;
3178 argv
[2] = saveargv2
;
3186 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
3193 /* ------------------------- Compatibility functions -------------------
3198 /* Hostnames for a pc are not really funny,
3199 but they are used in change log so we emulate the best we can. */
3201 gethostname (p
, size
)
3205 char *q
= egetenv ("HOSTNAME");
3212 /* When time zones are set from Ms-Dos too many C-libraries are playing
3213 tricks with time values. We solve this by defining our own version
3214 of `gettimeofday' bypassing GO32. Our version needs to be initialized
3215 once and after each call to `tzset' with TZ changed. That is
3216 accomplished by aliasing tzset to init_gettimeofday. */
3218 static struct tm time_rec
;
3221 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
3229 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
3233 time_rec
.tm_year
= d
.da_year
- 1900;
3234 time_rec
.tm_mon
= d
.da_mon
- 1;
3235 time_rec
.tm_mday
= d
.da_day
;
3238 time_rec
.tm_hour
= t
.ti_hour
;
3239 time_rec
.tm_min
= t
.ti_min
;
3240 time_rec
.tm_sec
= t
.ti_sec
;
3243 tm
.tm_gmtoff
= dos_timezone_offset
;
3245 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
3246 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
3248 /* Ignore tzp; it's obsolescent. */
3252 #endif /* __DJGPP__ < 2 */
3255 * A list of unimplemented functions that we silently ignore.
3259 unsigned alarm (s
) unsigned s
; {}
3260 fork () { return 0; }
3261 int kill (x
, y
) int x
, y
; { return -1; }
3263 void volatile pause () {}
3264 sigsetmask (x
) int x
; { return 0; }
3265 sigblock (mask
) int mask
; { return 0; }
3268 void request_sigio (void) {}
3269 setpgrp () {return 0; }
3270 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
3271 void unrequest_sigio (void) {}
3275 #ifdef POSIX_SIGNALS
3277 /* Augment DJGPP library POSIX signal functions. This is needed
3278 as of DJGPP v2.01, but might be in the library in later releases. */
3280 #include <libc/bss.h>
3282 /* A counter to know when to re-initialize the static sets. */
3283 static int sigprocmask_count
= -1;
3285 /* Which signals are currently blocked (initially none). */
3286 static sigset_t current_mask
;
3288 /* Which signals are pending (initially none). */
3289 static sigset_t pending_signals
;
3291 /* Previous handlers to restore when the blocked signals are unblocked. */
3292 typedef void (*sighandler_t
)(int);
3293 static sighandler_t prev_handlers
[320];
3295 /* A signal handler which just records that a signal occured
3296 (it will be raised later, if and when the signal is unblocked). */
3298 sig_suspender (signo
)
3301 sigaddset (&pending_signals
, signo
);
3305 sigprocmask (how
, new_set
, old_set
)
3307 const sigset_t
*new_set
;
3313 /* If called for the first time, initialize. */
3314 if (sigprocmask_count
!= __bss_count
)
3316 sigprocmask_count
= __bss_count
;
3317 sigemptyset (&pending_signals
);
3318 sigemptyset (¤t_mask
);
3319 for (signo
= 0; signo
< 320; signo
++)
3320 prev_handlers
[signo
] = SIG_ERR
;
3324 *old_set
= current_mask
;
3329 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
3335 sigemptyset (&new_mask
);
3337 /* DJGPP supports upto 320 signals. */
3338 for (signo
= 0; signo
< 320; signo
++)
3340 if (sigismember (¤t_mask
, signo
))
3341 sigaddset (&new_mask
, signo
);
3342 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
3344 sigaddset (&new_mask
, signo
);
3346 /* SIGKILL is silently ignored, as on other platforms. */
3347 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
3348 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
3350 if (( how
== SIG_UNBLOCK
3351 && sigismember (&new_mask
, signo
)
3352 && sigismember (new_set
, signo
))
3353 || (how
== SIG_SETMASK
3354 && sigismember (&new_mask
, signo
)
3355 && !sigismember (new_set
, signo
)))
3357 sigdelset (&new_mask
, signo
);
3358 if (prev_handlers
[signo
] != SIG_ERR
)
3360 signal (signo
, prev_handlers
[signo
]);
3361 prev_handlers
[signo
] = SIG_ERR
;
3363 if (sigismember (&pending_signals
, signo
))
3365 sigdelset (&pending_signals
, signo
);
3370 current_mask
= new_mask
;
3374 #else /* not POSIX_SIGNALS */
3376 sigsetmask (x
) int x
; { return 0; }
3377 sigblock (mask
) int mask
; { return 0; }
3379 #endif /* not POSIX_SIGNALS */
3380 #endif /* __DJGPP__ > 1 */
3383 #include "sysselect.h"
3385 #ifndef EMACS_TIME_ZERO_OR_NEG_P
3386 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
3387 ((long)(time).tv_sec < 0 \
3388 || ((time).tv_sec == 0 \
3389 && (long)(time).tv_usec <= 0))
3393 /* Only event queue is checked. */
3394 /* We don't have to call timer_check here
3395 because wait_reading_process_input takes care of that. */
3397 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
3399 SELECT_TYPE
*rfds
, *wfds
, *efds
;
3400 EMACS_TIME
*timeout
;
3408 check_input
= FD_ISSET (0, rfds
);
3419 /* If we are looking only for the terminal, with no timeout,
3420 just read it and wait -- that's more efficient. */
3423 while (!detect_input_pending ())
3432 EMACS_TIME clnow
, cllast
, cldiff
;
3435 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
3437 while (!check_input
|| !detect_input_pending ())
3440 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
3441 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
3443 /* When seconds wrap around, we assume that no more than
3444 1 minute passed since last `gettime'. */
3445 if (EMACS_TIME_NEG_P (cldiff
))
3446 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
3447 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
3449 /* Stop when timeout value crosses zero. */
3450 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
3465 * Define overlaid functions:
3467 * chdir -> sys_chdir
3468 * tzset -> init_gettimeofday
3469 * abort -> dos_abort
3474 extern int chdir ();
3480 int len
= strlen (path
);
3481 char *tmp
= (char *)path
;
3483 if (*tmp
&& tmp
[1] == ':')
3485 if (getdisk () != tolower (tmp
[0]) - 'a')
3486 setdisk (tolower (tmp
[0]) - 'a');
3487 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
3491 if (len
> 1 && (tmp
[len
- 1] == '/'))
3493 char *tmp1
= (char *) alloca (len
+ 1);
3504 extern void tzset (void);
3507 init_gettimeofday ()
3513 ltm
= gtm
= time (NULL
);
3514 ltm
= mktime (lstm
= localtime (<m
));
3515 gtm
= mktime (gmtime (>m
));
3516 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
3517 time_rec
.tm_isdst
= lstm
->tm_isdst
;
3518 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
3525 dos_abort (file
, line
)
3529 char buffer1
[200], buffer2
[400];
3532 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
3533 for (i
= j
= 0; buffer1
[i
]; i
++) {
3534 buffer2
[j
++] = buffer1
[i
];
3535 buffer2
[j
++] = 0x70;
3537 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
3538 ScreenSetCursor (2, 0);
3546 ScreenSetCursor (10, 0);
3547 cputs ("\r\n\nEmacs aborted!\r\n");
3549 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
3550 if (screen_virtual_segment
)
3551 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
3552 #endif /* __DJGPP_MINOR__ < 2 */
3553 /* Generate traceback, so we could tell whodunit. */
3554 signal (SIGINT
, SIG_DFL
);
3555 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
3561 /* The following two are required so that customization feature
3562 won't complain about unbound variables. */
3563 #ifndef HAVE_X_WINDOWS
3564 /* Search path for bitmap files (xfns.c). */
3565 Lisp_Object Vx_bitmap_file_path
;
3567 #ifndef subprocesses
3568 /* Nonzero means delete a process right away if it exits (process.c). */
3569 static int delete_exited_processes
;
3574 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
3575 staticpro (&recent_doskeys
);
3576 #ifndef HAVE_X_WINDOWS
3577 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path
,
3578 "List of directories to search for bitmap files for X.");
3579 Vx_bitmap_file_path
= decode_env_path ((char *) 0, ".");
3581 /* The following two are from xfns.c: */
3582 Qbackground_color
= intern ("background-color");
3583 staticpro (&Qbackground_color
);
3584 Qforeground_color
= intern ("foreground-color");
3585 staticpro (&Qforeground_color
);
3587 #ifndef subprocesses
3588 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
3589 "*Non-nil means delete processes immediately when they exit.\n\
3590 nil means don't delete them until `list-processes' is run.");
3591 delete_exited_processes
= 0;
3594 defsubr (&Srecent_doskeys
);
3595 defsubr (&Smsdos_long_file_names
);
3596 defsubr (&Smsdos_downcase_filename
);