X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/67d98d33afce21cbae01cf1a9ac43492b1e74049..9a5114ac7e384d28a13c99725380b6024abde5cf:/src/msdos.c diff --git a/src/msdos.c b/src/msdos.c index 075f8bfa50..94b75a5efc 100644 --- a/src/msdos.c +++ b/src/msdos.c @@ -1,5 +1,5 @@ /* MS-DOS specific C utilities. - Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -15,7 +15,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ /* Contributed by Morten Welinder */ /* New display, keyboard, and mouse control by Kim F. Storm */ @@ -31,6 +32,19 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include +#include +#include /* for bzero and string functions */ +#include /* for _fixpath */ +#include /* for chdir, dup, dup2, etc. */ +#if __DJGPP__ >= 2 +#include +#include /* for setmode */ +#include /* for __dpmi_xxx stuff */ +#include /* for _farsetsel, _farnspokeb */ +#include /* for _USE_LFN */ +#include /* for cputs */ +#endif + #include "dosfns.h" #include "msdos.h" #include "systime.h" @@ -39,6 +53,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "termopts.h" #include "frame.h" #include "window.h" +#include "buffer.h" +#include "commands.h" #include #include #include @@ -46,6 +62,38 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Damn that local process.h! Instead we can define P_WAIT ourselves. */ #define P_WAIT 1 +#ifndef _USE_LFN +#define _USE_LFN 0 +#endif + +#ifndef _dos_ds +#define _dos_ds _go32_info_block.selector_for_linear_memory +#endif + +#if __DJGPP__ > 1 + +#include +#include "syssignal.h" + +#ifndef SYSTEM_MALLOC + +#ifdef GNU_MALLOC + +/* If other `malloc' than ours is used, force our `sbrk' behave like + Unix programs expect (resize memory blocks to keep them contiguous). + If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory, + because that's what `gmalloc' expects to get. */ +#include + +#ifdef REL_ALLOC +int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK; +#else /* not REL_ALLOC */ +int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY); +#endif /* not REL_ALLOC */ +#endif /* GNU_MALLOC */ + +#endif /* not SYSTEM_MALLOC */ +#endif /* __DJGPP__ > 1 */ static unsigned long event_timestamp () @@ -223,7 +271,7 @@ mouse_init () mouse_moveto (0, 0); mouse_visible = 0; } - + /* ------------------------- Screen control ---------------------- * */ @@ -259,11 +307,6 @@ struct x_output the_only_x_display; /* This is never dereferenced. */ Display *x_current_display; - -#define SCREEN_SET_CURSOR() \ - if (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y) \ - ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X) - static dos_direct_output (y, x, buf, len) int y; @@ -272,11 +315,17 @@ dos_direct_output (y, x, buf, len) int len; { int t = (int) ScreenPrimary + 2 * (x + y * screen_size_X); - + +#if (__DJGPP__ < 2) while (--len >= 0) { dosmemput (buf++, 1, t); t += 2; } +#else + /* This is faster. */ + for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++) + _farnspokeb (t, *buf); +#endif } #endif @@ -330,10 +379,172 @@ ScreenVisualBell (void) #ifndef HAVE_X_WINDOWS -/* - * If we write a character in the position where the mouse is, - * the mouse cursor may need to be refreshed. - */ +static int blink_bit = -1; /* the state of the blink bit at startup */ + +/* Enable bright background colors. */ +static void +bright_bg (void) +{ + union REGS regs; + + /* Remember the original state of the blink/bright-background bit. + It is stored at 0040:0065h in the BIOS data area. */ + if (blink_bit == -1) + blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20; + + regs.h.bl = 0; + regs.x.ax = 0x1003; + int86 (0x10, ®s, ®s); +} + +/* Disable bright background colors (and enable blinking) if we found + the video system in that state at startup. */ +static void +maybe_enable_blinking (void) +{ + if (blink_bit == 1) + { + union REGS regs; + + regs.h.bl = 1; + regs.x.ax = 0x1003; + int86 (0x10, ®s, ®s); + } +} + +/* Set the screen dimensions so that it can show no less than + ROWS x COLS frame. */ + +void +dos_set_window_size (rows, cols) + int *rows, *cols; +{ + char video_name[30]; + Lisp_Object video_mode; + int video_mode_value; + int have_vga = 0; + union REGS regs; + int current_rows = ScreenRows (), current_cols = ScreenCols (); + + if (*rows == current_rows && *cols == current_cols) + return; + + /* Do we have a VGA? */ + regs.x.ax = 0x1a00; + int86 (0x10, ®s, ®s); + if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13) + have_vga = 1; + + mouse_off (); + + /* If the user specified a special video mode for these dimensions, + use that mode. */ + sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols); + video_mode = XSYMBOL (Fintern_soft (build_string (video_name), + Qnil))-> value; + + if (INTEGERP (video_mode) + && (video_mode_value = XINT (video_mode)) > 0) + { + regs.x.ax = video_mode_value; + int86 (0x10, ®s, ®s); + + if (have_mouse) + { + /* Must hardware-reset the mouse, or else it won't update + its notion of screen dimensions for some non-standard + video modes. This is *painfully* slow... */ + regs.x.ax = 0; + int86 (0x33, ®s, ®s); + } + } + + /* Find one of the dimensions supported by standard EGA/VGA + which gives us at least the required dimensions. */ + +#if __DJGPP__ > 1 + + else + { + static struct { + int rows; + int need_vga; + } std_dimension[] = { + {25, 0}, + {28, 1}, + {35, 0}, + {40, 1}, + {43, 0}, + {50, 1} + }; + int i = 0; + + while (i < sizeof (std_dimension) / sizeof (std_dimension[0])) + { + if (std_dimension[i].need_vga <= have_vga + && std_dimension[i].rows >= *rows) + { + if (std_dimension[i].rows != current_rows + || *cols != current_cols) + _set_screen_lines (std_dimension[i].rows); + break; + } + i++; + } + } + +#else /* not __DJGPP__ > 1 */ + + else if (*rows <= 25) + { + if (current_rows != 25 || current_cols != 80) + { + regs.x.ax = 3; + int86 (0x10, ®s, ®s); + regs.x.ax = 0x1101; + regs.h.bl = 0; + int86 (0x10, ®s, ®s); + regs.x.ax = 0x1200; + regs.h.bl = 32; + int86 (0x10, ®s, ®s); + regs.x.ax = 3; + int86 (0x10, ®s, ®s); + } + } + else if (*rows <= 50) + if (have_vga && (current_rows != 50 || current_cols != 80) + || *rows <= 43 && (current_rows != 43 || current_cols != 80)) + { + regs.x.ax = 3; + int86 (0x10, ®s, ®s); + regs.x.ax = 0x1112; + regs.h.bl = 0; + int86 (0x10, ®s, ®s); + regs.x.ax = 0x1200; + regs.h.bl = 32; + int86 (0x10, ®s, ®s); + regs.x.ax = 0x0100; + regs.x.cx = 7; + int86 (0x10, ®s, ®s); + } +#endif /* not __DJGPP__ > 1 */ + + if (have_mouse) + { + mouse_init (); + mouse_on (); + } + + /* Tell the caller what dimensions have been REALLY set. */ + *rows = ScreenRows (); + *cols = ScreenCols (); + + /* Enable bright background colors. */ + bright_bg (); +} + +/* If we write a character in the position where the mouse is, + the mouse cursor may need to be refreshed. */ static void mouse_off_maybe () @@ -472,6 +683,75 @@ IT_cursor_to (int y, int x) new_pos_Y = y; } +static int cursor_cleared; + +static +IT_display_cursor (int on) +{ + if (on && cursor_cleared) + { + ScreenSetCursor (current_pos_Y, current_pos_X); + cursor_cleared = 0; + } + else if (!on && !cursor_cleared) + { + ScreenSetCursor (-1, -1); + cursor_cleared = 1; + } +} + +/* Emacs calls cursor-movement functions a lot when it updates the + display (probably a legacy of old terminals where you cannot + update a screen line without first moving the cursor there). + However, cursor movement is expensive on MSDOS (it calls a slow + BIOS function and requires 2 mode switches), while actual screen + updates access the video memory directly and don't depend on + cursor position. To avoid slowing down the redisplay, we cheat: + all functions that move the cursor only set internal variables + which record the cursor position, whereas the cursor is only + moved to its final position whenever screen update is complete. + + `IT_cmgoto' is called from the keyboard reading loop and when the + frame update is complete. This means that we are ready for user + input, so we update the cursor position to show where the point is, + and also make the mouse pointer visible. + + Special treatment is required when the cursor is in the echo area, + to put the cursor at the end of the text displayed there. */ + +static +IT_cmgoto (f) + FRAME_PTR f; +{ + /* Only set the cursor to where it should be if the display is + already in sync with the window contents. */ + int update_cursor_pos = MODIFF == unchanged_modified; + + /* If we are in the echo area, put the cursor at the end of text. */ + if (!update_cursor_pos + && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y) + { + new_pos_X = FRAME_DESIRED_GLYPHS (f)->used[new_pos_Y]; + update_cursor_pos = 1; + } + + if (update_cursor_pos + && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y)) + { + ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X); + if (termscript) + fprintf (termscript, "\n", current_pos_X, current_pos_Y); + } + + /* Maybe cursor is invisible, so make it visible. */ + IT_display_cursor (1); + + /* Mouse pointer should be always visible if we are waiting for + keyboard input. */ + if (!mouse_visible) + mouse_on (); +} + static IT_reassert_line_highlight (new, vpos) int new, vpos; @@ -502,15 +782,20 @@ IT_update_end () { } -/* This was more or less copied from xterm.c */ +/* This was more or less copied from xterm.c + + Nowadays, the corresponding function under X is `x_set_menu_bar_lines_1' + on xfns.c */ + static void IT_set_menu_bar_lines (window, n) - Lisp_Object window; - int n; + Lisp_Object window; + int n; { struct window *w = XWINDOW (window); XSETFASTINT (w->last_modified, 0); + XSETFASTINT (w->last_overlay_modified, 0); XSETFASTINT (w->top, XFASTINT (w->top) + n); XSETFASTINT (w->height, XFASTINT (w->height) - n); @@ -526,18 +811,38 @@ IT_set_menu_bar_lines (window, n) } } -/* - * IT_set_terminal_modes is called when emacs is started, - * resumed, and whenever the screen is redrawn! - */ +/* This was copied from xfns.c */ + +void +x_set_menu_bar_lines (f, value, oldval) + struct frame *f; + Lisp_Object value, oldval; +{ + int nlines; + int olines = FRAME_MENU_BAR_LINES (f); + + /* Right now, menu bars don't work properly in minibuf-only frames; + most of the commands try to apply themselves to the minibuffer + frame itslef, and get an error because you can't switch buffers + in or split the minibuffer window. */ + if (FRAME_MINIBUF_ONLY_P (f)) + return; + + if (INTEGERP (value)) + nlines = XINT (value); + else + nlines = 0; + + FRAME_MENU_BAR_LINES (f) = nlines; + IT_set_menu_bar_lines (f->root_window, nlines - olines); +} + +/* IT_set_terminal_modes is called when emacs is started, + resumed, and whenever the screen is redrawn! */ static IT_set_terminal_modes (void) { - char *colors; - FRAME_PTR f; - struct face *fp; - if (termscript) fprintf (termscript, "\n"); highlight = 0; @@ -563,12 +868,12 @@ IT_set_terminal_modes (void) if (termscript) fprintf (termscript, "\n", screen_size_X, screen_size_Y); + + bright_bg (); } -/* - * IT_reset_terminal_modes is called when emacs is - * suspended or killed. - */ +/* IT_reset_terminal_modes is called when emacs is + suspended or killed. */ static IT_reset_terminal_modes (void) @@ -591,6 +896,10 @@ IT_reset_terminal_modes (void) return; mouse_off (); + + /* Leave the video system in the same state as we found it, + as far as the blink/bright-background bit is concerned. */ + maybe_enable_blinking (); /* We have a situation here. We cannot just do ScreenUpdate(startup_screen_buffer) because @@ -639,14 +948,13 @@ IT_set_terminal_window (void) } void -IT_set_frame_parameters (frame, alist) - FRAME_PTR frame; +IT_set_frame_parameters (f, alist) + FRAME_PTR f; Lisp_Object alist; { Lisp_Object tail; int redraw; extern unsigned long load_color (); - FRAME_PTR f = (FRAME_PTR) &the_only_frame; redraw = 0; for (tail = alist; CONSP (tail); tail = Fcdr (tail)) @@ -665,6 +973,8 @@ IT_set_frame_parameters (frame, alist) { FRAME_FOREGROUND_PIXEL (f) = new_color; redraw = 1; + if (termscript) + fprintf (termscript, "\n", new_color); } } else if (EQ (prop, intern ("background-color"))) @@ -672,35 +982,34 @@ IT_set_frame_parameters (frame, alist) unsigned long new_color = load_color (f, val); if (new_color != ~0) { - FRAME_BACKGROUND_PIXEL (f) = new_color & ~8; + FRAME_BACKGROUND_PIXEL (f) = new_color; redraw = 1; + if (termscript) + fprintf (termscript, "\n", new_color); } } else if (EQ (prop, intern ("menu-bar-lines"))) - { - int new; - int old = FRAME_MENU_BAR_LINES (the_only_frame); - - if (INTEGERP (val)) - new = XINT (val); - else - new = 0; - FRAME_MENU_BAR_LINES (f) = new; - IT_set_menu_bar_lines (the_only_frame.root_window, new - old); - } + x_set_menu_bar_lines (f, val, 0); } if (redraw) { + extern void recompute_basic_faces (FRAME_PTR); + extern void redraw_frame (FRAME_PTR); + recompute_basic_faces (f); - Fredraw_frame (Fselected_frame ()); + if (f == selected_frame) + redraw_frame (f); } } +extern void init_frame_faces (FRAME_PTR); + #endif /* !HAVE_X_WINDOWS */ -/* Do we need the internal terminal? */ +/* Do we need the internal terminal? */ + void internal_terminal_init () { @@ -721,7 +1030,7 @@ internal_terminal_init () #ifndef HAVE_X_WINDOWS if (!internal_terminal || inhibit_window_system) { - the_only_frame.output_method = output_termcap; + selected_frame->output_method = output_termcap; return; } @@ -731,18 +1040,28 @@ internal_terminal_init () bzero (&the_only_x_display, sizeof the_only_x_display); the_only_x_display.background_pixel = 7; /* White */ the_only_x_display.foreground_pixel = 0; /* Black */ + bright_bg (); colors = getenv ("EMACSCOLORS"); if (colors && strlen (colors) >= 2) { - the_only_x_display.foreground_pixel = colors[0] & 0x07; - the_only_x_display.background_pixel = colors[1] & 0x07; + /* The colors use 4 bits each (we enable bright background). */ + if (isdigit (colors[0])) + colors[0] -= '0'; + else if (isxdigit (colors[0])) + colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10; + if (colors[0] >= 0 && colors[0] < 16) + the_only_x_display.foreground_pixel = colors[0]; + if (isdigit (colors[1])) + colors[1] -= '0'; + else if (isxdigit (colors[1])) + colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10; + if (colors[1] >= 0 && colors[1] < 16) + the_only_x_display.background_pixel = colors[1]; } the_only_x_display.line_height = 1; - the_only_frame.output_data.x = &the_only_x_display; - the_only_frame.output_method = output_msdos_raw; the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */ - init_frame_faces ((FRAME_PTR) &the_only_frame); + init_frame_faces (selected_frame); ring_bell_hook = IT_ring_bell; write_glyphs_hook = IT_write_glyphs; @@ -754,6 +1073,7 @@ internal_terminal_init () update_begin_hook = IT_update_begin; update_end_hook = IT_update_end; reassert_line_highlight_hook = IT_reassert_line_highlight; + frame_up_to_date_hook = IT_cmgoto; /* position cursor when update is done */ /* These hooks are called by term.c without being checked. */ set_terminal_modes_hook = IT_set_terminal_modes; @@ -777,6 +1097,17 @@ dos_get_saved_screen (screen, rows, cols) #endif } +#ifndef HAVE_X_WINDOWS + +/* We are not X, but we can emulate it well enough for our needs... */ +void +check_x (void) +{ + if (! FRAME_MSDOS_P (selected_frame)) + error ("Not running under a windows system"); +} + +#endif /* ----------------------- Keyboard control ---------------------- @@ -842,6 +1173,7 @@ static struct keyboard_layout_list static struct dos_keyboard_map *keyboard; static int keyboard_map_all; +static int international_keyboard; int dos_set_keyboard (code, always) @@ -849,6 +1181,13 @@ dos_set_keyboard (code, always) int always; { int i; + union REGS regs; + + /* See if Keyb.Com is installed (for international keyboard support). */ + regs.x.ax = 0xad80; + int86 (0x2f, ®s, ®s); + if (regs.h.al == 0xff) + international_keyboard = 1; /* Initialize to US settings, for countries that don't have their own. */ keyboard = keyboard_layout_list[0].keyboard_map; @@ -1156,9 +1495,16 @@ dos_get_modifiers (keymask) mask |= SUPER_P; modifiers |= super_modifier; } + else if (!international_keyboard) + { + /* If Keyb.Com is NOT installed, let Right Alt behave + like the Left Alt. */ + mask &= ~ALT_GR_P; + mask |= ALT_P; + } } - if (regs.h.ah & 1) /* Left CTRL pressed + if (regs.h.ah & 1) /* Left CTRL pressed ? */ mask |= CTRL_P; if (regs.h.ah & 4) /* Right CTRL pressed ? */ @@ -1220,6 +1566,9 @@ and then the scan code.") } /* Get a char from keyboard. Function keys are put into the event queue. */ + +extern void kbd_buffer_store_event (struct input_event *); + static int dos_rawgetc () { @@ -1227,10 +1576,10 @@ dos_rawgetc () union REGS regs; #ifndef HAVE_X_WINDOWS - SCREEN_SET_CURSOR (); - if (!mouse_visible) mouse_on (); + /* Maybe put the cursor where it should be. */ + IT_cmgoto (selected_frame); #endif - + /* The following condition is equivalent to `kbhit ()', except that it uses the bios to do its job. This pleases DESQview/X. */ while ((regs.h.ah = extended_kbd ? 0x11 : 0x01), @@ -1262,7 +1611,7 @@ dos_rawgetc () #ifndef HAVE_X_WINDOWS if (!NILP (Vdos_display_scancodes)) { - char buf[10]; + char buf[11]; sprintf (buf, "%02x:%02x*%04x", (unsigned) (sc&0xff), (unsigned) c, mask); dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10); @@ -1297,7 +1646,19 @@ dos_rawgetc () if (c == 0) { - if (code & Alt) + /* We only look at the keyboard Ctrl/Shift/Alt keys when + Emacs is ready to read a key. Therefore, if they press + `Alt-x' when Emacs is busy, by the time we get to + `dos_get_modifiers', they might have already released the + Alt key, and Emacs gets just `x', which is BAD. + However, for keys with the `Map' property set, the ASCII + code returns zero iff Alt is pressed. So, when we DON'T + have to support international_keyboard, we don't have to + distinguish between the left and right Alt keys, and we + can set the META modifier for any keys with the `Map' + property if they return zero ASCII code (c = 0). */ + if ( (code & Alt) + || ( (code & 0xf000) == Map && !international_keyboard)) modifiers |= meta_modifier; if (code & Ctrl) modifiers |= ctrl_modifier; @@ -1424,14 +1785,37 @@ dos_rawgetc () for (but = 0; but < NUM_MOUSE_BUTTONS; but++) for (press = 0; press < 2; press++) { + int button_num = but; + if (press) ok = mouse_pressed (but, &x, &y); else ok = mouse_released (but, &x, &y); if (ok) { + /* Allow a simultaneous press/release of Mouse-1 and + Mouse-2 to simulate Mouse-3 on two-button mice. */ + if (mouse_button_count == 2 && but < 2) + { + int x2, y2; /* don't clobber original coordinates */ + + /* If only one button is pressed, wait 100 msec and + check again. This way, Speedy Gonzales isn't + punished, while the slow get their chance. */ + if (press && mouse_pressed (1-but, &x2, &y2) + || !press && mouse_released (1-but, &x2, &y2)) + button_num = 2; + else + { + delay (100); + if (press && mouse_pressed (1-but, &x2, &y2) + || !press && mouse_released (1-but, &x2, &y2)) + button_num = 2; + } + } + event.kind = mouse_click; - event.code = but; + event.code = button_num; event.modifiers = dos_get_modifiers (0) | (press ? down_modifier : up_modifier); event.x = x; @@ -1449,6 +1833,7 @@ dos_rawgetc () static int prev_get_char = -1; /* Return 1 if a key is ready to be read without suspending execution. */ + dos_keysns () { if (prev_get_char != -1) @@ -1458,6 +1843,7 @@ dos_keysns () } /* Read a key. Return -1 if no key is ready. */ + dos_keyread () { if (prev_get_char != -1) @@ -1582,7 +1968,7 @@ IT_menu_calc_size (XMenu *menu, int *width, int *height) *height = maxheight; } -/* Display MENU at (X,Y) using FACES. */ +/* Display MENU at (X,Y) using FACES. */ static void IT_menu_display (XMenu *menu, int y, int x, int *faces) @@ -1609,7 +1995,17 @@ IT_menu_display (XMenu *menu, int y, int x, int *faces) p = text; *p++ = FAST_MAKE_GLYPH (' ', face); for (j = 0, q = menu->text[i]; *q; j++) - *p++ = FAST_MAKE_GLYPH (*q++, face); + { + if (*q > 26) + *p++ = FAST_MAKE_GLYPH (*q++, face); + else /* make '^x' */ + { + *p++ = FAST_MAKE_GLYPH ('^', face); + j++; + *p++ = FAST_MAKE_GLYPH (*q++ + 64, face); + } + } + for (; j < width; j++) *p++ = FAST_MAKE_GLYPH (' ', face); *p++ = FAST_MAKE_GLYPH (menu->submenu[i] ? 16 : ' ', face); @@ -1619,9 +2015,17 @@ IT_menu_display (XMenu *menu, int y, int x, int *faces) IT_cursor_to (row, col); xfree (text); } - + /* --------------------------- X Menu emulation ---------------------- */ +/* Report availability of menus. */ + +int +have_menus_p () +{ + return 1; +} + /* Create a brand new menu structure. */ XMenu * @@ -1638,6 +2042,7 @@ int XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable) { int len; + char *p; if (!enable) abort (); @@ -1647,8 +2052,16 @@ XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable) menu->text[menu->count] = txt; menu->panenumber[menu->count] = ++menu->panecount; menu->count++; - if ((len = strlen (txt)) > menu->width) + + /* Adjust length for possible control characters (which will + be written as ^x). */ + for (len = strlen (txt), p = txt; *p; p++) + if (*p < 27) + len++; + + if (len > menu->width) menu->width = len; + return menu->panecount; } @@ -1659,6 +2072,7 @@ XMenuAddSelection (Display *bar, XMenu *menu, int pane, int foo, char *txt, int enable) { int len; + char *p; if (pane) if (!(menu = IT_menu_search_pane (menu, pane))) @@ -1668,8 +2082,16 @@ XMenuAddSelection (Display *bar, XMenu *menu, int pane, menu->text[menu->count] = txt; menu->panenumber[menu->count] = enable; menu->count++; - if ((len = strlen (txt)) > menu->width) + + /* Adjust length for possible control characters (which will + be written as ^x). */ + for (len = strlen (txt), p = txt; *p; p++) + if (*p < 27) + len++; + + if (len > menu->width) menu->width = len; + return XM_SUCCESS; } @@ -1706,36 +2128,67 @@ XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx, int screensize; int faces[4], selectface; int leave, result, onepane; + int title_faces[4]; /* face to display the menu title */ + int buffers_num_deleted = 0; /* Just in case we got here without a mouse present... */ if (have_mouse <= 0) return XM_IA_SELECT; + /* Don't allow non-positive x0 and y0, lest the menu will wrap + around the display. */ + if (x0 <= 0) + x0 = 1; + if (y0 <= 0) + y0 = 1; state = alloca (menu->panecount * sizeof (struct IT_menu_state)); screensize = screen_size * 2; faces[0] - = compute_glyph_face (&the_only_frame, + = compute_glyph_face (selected_frame, face_name_id_number - (&the_only_frame, + (selected_frame, intern ("msdos-menu-passive-face")), 0); faces[1] - = compute_glyph_face (&the_only_frame, + = compute_glyph_face (selected_frame, face_name_id_number - (&the_only_frame, + (selected_frame, intern ("msdos-menu-active-face")), 0); selectface - = face_name_id_number (&the_only_frame, intern ("msdos-menu-select-face")); - faces[2] = compute_glyph_face (&the_only_frame, selectface, faces[0]); - faces[3] = compute_glyph_face (&the_only_frame, selectface, faces[1]); + = face_name_id_number (selected_frame, intern ("msdos-menu-select-face")); + faces[2] = compute_glyph_face (selected_frame, selectface, faces[0]); + faces[3] = compute_glyph_face (selected_frame, selectface, faces[1]); + + /* Make sure the menu title is always displayed with + `msdos-menu-active-face', no matter where the mouse pointer is. */ + for (i = 0; i < 4; i++) + title_faces[i] = faces[3]; statecount = 1; + + /* Don't let the title for the "Buffers" popup menu include a + digit (which is ugly). + + This is a terrible kludge, but I think the "Buffers" case is + the only one where the title includes a number, so it doesn't + seem to be necessary to make this more general. */ + if (strncmp (menu->text[0], "Buffers 1", 9) == 0) + { + menu->text[0][7] = '\0'; + buffers_num_deleted = 1; + } state[0].menu = menu; mouse_off (); ScreenRetrieve (state[0].screen_behind = xmalloc (screensize)); - IT_menu_display (menu, y0 - 1, x0 - 1, faces); /* display the menu title */ + /* Turn off the cursor. Otherwise it shows through the menu + panes, which is ugly. */ + IT_display_cursor (0); + + IT_menu_display (menu, y0 - 1, x0 - 1, title_faces); /* display menu title */ + if (buffers_num_deleted) + menu->text[0][7] = ' '; if ((onepane = menu->count == 1 && menu->submenu[0])) { menu->width = menu->submenu[0]->width; @@ -1773,7 +2226,7 @@ XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx, result = XM_IA_SELECT; *pane = state[i].pane - 1; *selidx = dy; - /* We hit some part of a menu, so drop extra menues that + /* We hit some part of a menu, so drop extra menus that have been opened. That does not include an open and active submenu. */ if (i != statecount - 2 @@ -1820,6 +2273,7 @@ XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx, ScreenUpdate (state[0].screen_behind); while (statecount--) xfree (state[statecount].screen_behind); + IT_display_cursor (1); /* turn cursor back on */ return result; } @@ -1853,16 +2307,19 @@ x_pixel_height (struct frame *f) return FRAME_HEIGHT (f); } #endif /* !HAVE_X_WINDOWS */ - - + /* ----------------------- DOS / UNIX conversion --------------------- */ +void msdos_downcase_filename (unsigned char *); + /* Destructively turn backslashes into slashes. */ void dostounix_filename (p) register char *p; { + msdos_downcase_filename (p); + while (*p) { if (*p == '\\') @@ -1877,6 +2334,12 @@ void unixtodos_filename (p) register char *p; { + if (p[1] == ':' && *p >= 'A' && *p <= 'Z') + { + *p += 'a' - 'A'; + p += 2; + } + while (*p) { if (*p == '/') @@ -1892,14 +2355,27 @@ getdefdir (drive, dst) int drive; char *dst; { - union REGS regs; + char in_path[4], *p = in_path; + int e = errno; + + /* Generate "X:." (when drive is X) or "." (when drive is 0). */ + if (drive != 0) + { + *p++ = drive + 'A' - 1; + *p++ = ':'; + } - *dst++ = '/'; - regs.h.dl = drive; - regs.x.si = (int) dst; - regs.h.ah = 0x47; - intdos (®s, ®s); - return !regs.x.cflag; + *p++ = '.'; + *p = '\0'; + errno = 0; + _fixpath (in_path, dst); + if (errno) + return 0; + + msdos_downcase_filename (dst); + + errno = e; + return 1; } /* Remove all CR's that are followed by a LF. */ @@ -1912,7 +2388,6 @@ crlf_to_lf (n, buf) unsigned char *np = buf; unsigned char *startp = buf; unsigned char *endp = buf + n; - unsigned char c; if (n == 0) return n; @@ -1930,6 +2405,246 @@ crlf_to_lf (n, buf) *np++ = *buf++; return np - startp; } + +#if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 + +/* In DJGPP v2.0, library `write' can call `malloc', which might + cause relocation of the buffer whose address we get in ADDR. + Here is a version of `write' that avoids calling `malloc', + to serve us until such time as the library is fixed. + Actually, what we define here is called `__write', because + `write' is a stub that just jmp's to `__write' (to be + POSIXLY-correct with respect to the global name-space). */ + +#include /* for _write */ +#include /* for __file_handle_modes[] */ + +static char xbuf[64 * 1024]; /* DOS cannot write more in one chunk */ + +#define XBUF_END (xbuf + sizeof (xbuf) - 1) + +int +__write (int handle, const void *buffer, size_t count) +{ + if (count == 0) + return 0; + + if(__file_handle_modes[handle] & O_BINARY) + return _write (handle, buffer, count); + else + { + char *xbp = xbuf; + const char *bp = buffer; + int total_written = 0; + int nmoved = 0, ncr = 0; + + while (count) + { + /* The next test makes sure there's space for at least 2 more + characters in xbuf[], so both CR and LF can be put there. */ + if (xbp < XBUF_END) + { + if (*bp == '\n') + { + ncr++; + *xbp++ = '\r'; + } + *xbp++ = *bp++; + nmoved++; + count--; + } + if (xbp >= XBUF_END || !count) + { + size_t to_write = nmoved + ncr; + int written = _write (handle, xbuf, to_write); + + if (written == -1) + return -1; + else + total_written += nmoved; /* CRs aren't counted in ret value */ + + /* If some, but not all were written (disk full?), return + an estimate of the total written bytes not counting CRs. */ + if (written < to_write) + return total_written - (to_write - written) * nmoved/to_write; + + nmoved = 0; + ncr = 0; + xbp = xbuf; + } + } + return total_written; + } +} + +/* A low-level file-renaming function which works around Windows 95 bug. + This is pulled directly out of DJGPP v2.01 library sources, and only + used when you compile with DJGPP v2.0. */ + +#include + +int _rename(const char *old, const char *new) +{ + __dpmi_regs r; + int olen = strlen(old) + 1; + int i; + int use_lfn = _USE_LFN; + char tempfile[FILENAME_MAX]; + const char *orig = old; + int lfn_fd = -1; + + r.x.dx = __tb_offset; + r.x.di = __tb_offset + olen; + r.x.ds = r.x.es = __tb_segment; + + if (use_lfn) + { + /* Windows 95 bug: for some filenames, when you rename + file -> file~ (as in Emacs, to leave a backup), the + short 8+3 alias doesn't change, which effectively + makes OLD and NEW the same file. We must rename + through a temporary file to work around this. */ + + char *pbase = 0, *p; + static char try_char[] = "abcdefghijklmnopqrstuvwxyz012345789"; + int idx = sizeof(try_char) - 1; + + /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR + might point to another drive, which will fail the DOS call. */ + strcpy(tempfile, old); + for (p = tempfile; *p; p++) /* ensure temporary is on the same drive */ + if (*p == '/' || *p == '\\' || *p == ':') + pbase = p; + if (pbase) + pbase++; + else + pbase = tempfile; + strcpy(pbase, "X$$djren$$.$$temp$$"); + + do + { + if (idx <= 0) + return -1; + *pbase = try_char[--idx]; + } while (_chmod(tempfile, 0) != -1); + + r.x.ax = 0x7156; + _put_path2(tempfile, olen); + _put_path(old); + __dpmi_int(0x21, &r); + if (r.x.flags & 1) + { + errno = __doserr_to_errno(r.x.ax); + return -1; + } + + /* Now create a file with the original name. This will + ensure that NEW will always have a 8+3 alias + different from that of OLD. (Seems to be required + when NameNumericTail in the Registry is set to 0.) */ + lfn_fd = _creat(old, 0); + + olen = strlen(tempfile) + 1; + old = tempfile; + r.x.di = __tb_offset + olen; + } + + for (i=0; i<2; i++) + { + if(use_lfn) + r.x.ax = 0x7156; + else + r.h.ah = 0x56; + _put_path2(new, olen); + _put_path(old); + __dpmi_int(0x21, &r); + if(r.x.flags & 1) + { + if (r.x.ax == 5 && i == 0) /* access denied */ + remove(new); /* and try again */ + else + { + errno = __doserr_to_errno(r.x.ax); + + /* Restore to original name if we renamed it to temporary. */ + if (use_lfn) + { + if (lfn_fd != -1) + { + _close (lfn_fd); + remove (orig); + } + _put_path2(orig, olen); + _put_path(tempfile); + r.x.ax = 0x7156; + __dpmi_int(0x21, &r); + } + return -1; + } + } + else + break; + } + + /* Success. Delete the file possibly created to work + around the Windows 95 bug. */ + if (lfn_fd != -1) + return (_close (lfn_fd) == 0) ? remove (orig) : -1; + return 0; +} + +#endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */ + +DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names, + 0, 0, 0, + "Return non-nil if long file names are supported on MSDOS.") + () +{ + return (_USE_LFN ? Qt : Qnil); +} + +/* Convert alphabetic characters in a filename to lower-case. */ + +void +msdos_downcase_filename (p) + register unsigned char *p; +{ + /* Always lower-case drive letters a-z, even if the filesystem + preserves case in filenames. + This is so MSDOS filenames could be compared by string comparison + functions that are case-sensitive. Even case-preserving filesystems + do not distinguish case in drive letters. */ + if (p[1] == ':' && *p >= 'A' && *p <= 'Z') + { + *p += 'a' - 'A'; + p += 2; + } + + /* Under LFN we expect to get pathnames in their true case. */ + if (NILP (Fmsdos_long_file_names ())) + for ( ; *p; p++) + if (*p >= 'A' && *p <= 'Z') + *p += 'a' - 'A'; +} + +DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename, + 1, 1, 0, + "Convert alphabetic characters in FILENAME to lower case and return that.\n\ +When long filenames are supported, doesn't change FILENAME.\n\ +If FILENAME is not a string, returns nil.\n\ +The argument object is never altered--the value is a copy.") + (filename) + Lisp_Object filename; +{ + Lisp_Object tem; + + if (! STRINGP (filename)) + return Qnil; + + tem = Fcopy_sequence (filename); + msdos_downcase_filename (XSTRING (tem)->data); + return tem; +} /* The Emacs root directory as determined by init_environment. */ @@ -1964,7 +2679,7 @@ init_environment (argc, argv, skip_args) "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */ root = alloca (MAXPATHLEN + 20); _fixpath (argv[0], root); - strlwr (root); + msdos_downcase_filename (root); len = strlen (root); while (len > 0 && root[len] != '/' && root[len] != ':') len--; @@ -1998,7 +2713,6 @@ init_environment (argc, argv, skip_args) if (!s) s = "c:/command.com"; t = alloca (strlen (s) + 1); strcpy (t, s); - strlwr (t); dostounix_filename (t); setenv ("SHELL", t, 0); @@ -2009,7 +2723,6 @@ init_environment (argc, argv, skip_args) /* Current directory is always considered part of MsDos's path but it is not normally mentioned. Now it is. */ strcat (strcpy (t, ".;"), s); - strlwr (t); dostounix_filename (t); /* Not a single file name, but this should work. */ setenv ("PATH", t, 1); @@ -2061,7 +2774,7 @@ init_environment (argc, argv, skip_args) setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0); break; } - init_gettimeofday (); + tzset (); } @@ -2069,6 +2782,8 @@ init_environment (argc, argv, skip_args) static int break_stat; /* BREAK check mode status. */ static int stdin_stat; /* stdin IOCTL status. */ +#if __DJGPP__ < 2 + /* These must be global. */ static _go32_dpmi_seginfo ctrl_break_vector; static _go32_dpmi_registers ctrl_break_regs; @@ -2098,11 +2813,10 @@ install_ctrl_break_check () } } -/* - * Turn off Dos' Ctrl-C checking and inhibit interpretation of - * control chars by Dos. - * Determine the keyboard type. - */ +#endif /* __DJGPP__ < 2 */ + +/* Turn off Dos' Ctrl-C checking and inhibit interpretation of + control chars by DOS. Determine the keyboard type. */ int dos_ttraw () @@ -2112,7 +2826,9 @@ dos_ttraw () break_stat = getcbrk (); setcbrk (0); +#if __DJGPP__ < 2 install_ctrl_break_check (); +#endif if (first_time) { @@ -2163,10 +2879,25 @@ dos_ttraw () mouse_init (); } } - + first_time = 0; + +#if __DJGPP__ >= 2 + + stdin_stat = setmode (fileno (stdin), O_BINARY); + return (stdin_stat != -1); + } + else + return (setmode (fileno (stdin), O_BINARY) != -1); + +#else /* __DJGPP__ < 2 */ + } + /* I think it is wrong to overwrite `stdin_stat' every time + but the first one this function is called, but I don't + want to change the way it used to work in v1.x.--EZ */ + inregs.x.ax = 0x4400; /* Get IOCTL status. */ inregs.x.bx = 0x00; /* 0 = stdin. */ intdos (&inregs, &outregs); @@ -2176,9 +2907,12 @@ dos_ttraw () inregs.x.ax = 0x4401; /* Set IOCTL status */ intdos (&inregs, &outregs); return !outregs.x.cflag; + +#endif /* __DJGPP__ < 2 */ } /* Restore status of standard input and Ctrl-C checking. */ + int dos_ttcooked () { @@ -2187,34 +2921,55 @@ dos_ttcooked () setcbrk (break_stat); mouse_off (); +#if __DJGPP__ >= 2 + + return (setmode (fileno (stdin), stdin_stat) != -1); + +#else /* not __DJGPP__ >= 2 */ + inregs.x.ax = 0x4401; /* Set IOCTL status. */ inregs.x.bx = 0x00; /* 0 = stdin. */ inregs.x.dx = stdin_stat; intdos (&inregs, &outregs); return !outregs.x.cflag; + +#endif /* not __DJGPP__ >= 2 */ } /* Run command as specified by ARGV in directory DIR. The command is run with input from TEMPIN, output to file TEMPOUT and stderr to TEMPERR. */ + int run_msdos_command (argv, dir, tempin, tempout, temperr) unsigned char **argv; Lisp_Object dir; int tempin, tempout, temperr; { - char *saveargv1, *saveargv2, **envv; + char *saveargv1, *saveargv2, **envv, *lowcase_argv0, *pa, *pl; char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */ int msshell, result = -1; - int in, out, inbak, outbak, errbak; + int inbak, outbak, errbak; int x, y; Lisp_Object cmd; /* Get current directory as MSDOS cwd is not per-process. */ getwd (oldwd); - cmd = Ffile_name_nondirectory (build_string (argv[0])); + /* If argv[0] is the shell, it might come in any lettercase. + Since `Fmember' is case-sensitive, we need to downcase + argv[0], even if we are on case-preserving filesystems. */ + lowcase_argv0 = alloca (strlen (argv[0]) + 1); + for (pa = argv[0], pl = lowcase_argv0; *pa; pl++) + { + *pl = *pa++; + if (*pl >= 'A' && *pl <= 'Z') + *pl += 'a' - 'A'; + } + *pl = '\0'; + + cmd = Ffile_name_nondirectory (build_string (lowcase_argv0)); msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells")))) && !strcmp ("-c", argv[1]); if (msshell) @@ -2275,6 +3030,25 @@ run_msdos_command (argv, dir, tempin, tempout, temperr) dup2 (tempout, 1); dup2 (temperr, 2); +#if __DJGPP__ > 1 + + if (msshell && !argv[3]) + { + /* MS-DOS native shells are too restrictive. For starters, they + cannot grok commands longer than 126 characters. In DJGPP v2 + and later, `system' is much smarter, so we'll call it instead. */ + + extern char **environ; + environ = envv; + + /* A shell gets a single argument--its full command + line--whose original was saved in `saveargv2'. */ + result = system (saveargv2); + } + else + +#endif /* __DJGPP__ > 1 */ + result = spawnve (P_WAIT, argv[0], argv, envv); dup2 (inbak, 0); @@ -2290,6 +3064,11 @@ run_msdos_command (argv, dir, tempin, tempout, temperr) mouse_init (); mouse_moveto (x, y); } + + /* Some programs might change the meaning of the highest bit of the + text attribute byte, so we get blinking characters instead of the + bright background colors. Restore that. */ + bright_bg (); done: chdir (oldwd); @@ -2308,17 +3087,16 @@ croak (badfunc) reset_sys_modes (); exit (1); } - + +#if __DJGPP__ < 2 /* ------------------------- Compatibility functions ------------------- * gethostname * gettimeofday */ -/* - * Hostnames for a pc are not really funny, - * but they are used in change log so we emulate the best we can. - */ +/* Hostnames for a pc are not really funny, + but they are used in change log so we emulate the best we can. */ gethostname (p, size) char *p; @@ -2371,85 +3149,150 @@ gettimeofday (struct timeval *tp, struct timezone *tzp) return 0; } +#endif /* __DJGPP__ < 2 */ /* * A list of unimplemented functions that we silently ignore. */ +#if __DJGPP__ < 2 unsigned alarm (s) unsigned s; {} fork () { return 0; } int kill (x, y) int x, y; { return -1; } nice (p) int p; {} void volatile pause () {} +sigsetmask (x) int x; { return 0; } +sigblock (mask) int mask; { return 0; } +#endif + request_sigio () {} setpgrp () {return 0; } setpriority (x,y,z) int x,y,z; { return 0; } -sigsetmask (x) int x; { return 0; } unrequest_sigio () {} -int run_dos_timer_hooks = 0; +#if __DJGPP__ > 1 -#ifndef HAVE_SELECT -#include "sysselect.h" +#ifdef POSIX_SIGNALS + +/* Augment DJGPP library POSIX signal functions. This is needed + as of DJGPP v2.01, but might be in the library in later releases. */ + +#include + +/* A counter to know when to re-initialize the static sets. */ +static int sigprocmask_count = -1; -static int last_ti_sec = -1; -static int dos_menubar_clock_displayed = 0; +/* Which signals are currently blocked (initially none). */ +static sigset_t current_mask; +/* Which signals are pending (initially none). */ +static sigset_t pending_signals; + +/* Previous handlers to restore when the blocked signals are unblocked. */ +typedef void (*sighandler_t)(int); +static sighandler_t prev_handlers[320]; + +/* A signal handler which just records that a signal occured + (it will be raised later, if and when the signal is unblocked). */ static void -check_timer (t) - struct time *t; +sig_suspender (signo) + int signo; { - gettime (t); - - if (t->ti_sec == last_ti_sec) - return; - last_ti_sec = t->ti_sec; + sigaddset (&pending_signals, signo); +} - if (!NILP (Vdos_menubar_clock)) +int +sigprocmask (how, new_set, old_set) + int how; + const sigset_t *new_set; + sigset_t *old_set; +{ + int signo; + sigset_t new_mask; + + /* If called for the first time, initialize. */ + if (sigprocmask_count != __bss_count) + { + sigprocmask_count = __bss_count; + sigemptyset (&pending_signals); + sigemptyset (¤t_mask); + for (signo = 0; signo < 320; signo++) + prev_handlers[signo] = SIG_ERR; + } + + if (old_set) + *old_set = current_mask; + + if (new_set == 0) + return 0; + + if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK) { - char clock_str[16]; - int len; - int min = t->ti_min; - int hour = t->ti_hour; + errno = EINVAL; + return -1; + } + + sigemptyset (&new_mask); - if (dos_timezone_offset) + /* DJGPP supports upto 320 signals. */ + for (signo = 0; signo < 320; signo++) + { + if (sigismember (¤t_mask, signo)) + sigaddset (&new_mask, signo); + else if (sigismember (new_set, signo) && how != SIG_UNBLOCK) { - int tz = dos_timezone_offset; - min -= tz % 60; - if (min < 0) - min += 60, hour--; - else - if (min >= 60) - min -= 60, hour++; - - if ((hour -= (tz / 60)) < 0) - hour += 24; - else - hour %= 24; + sigaddset (&new_mask, signo); + + /* SIGKILL is silently ignored, as on other platforms. */ + if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR) + prev_handlers[signo] = signal (signo, sig_suspender); } - - if ((dos_country_info[0x11] & 0x01) == 0) /* 12 hour clock */ + if (( how == SIG_UNBLOCK + && sigismember (&new_mask, signo) + && sigismember (new_set, signo)) + || (how == SIG_SETMASK + && sigismember (&new_mask, signo) + && !sigismember (new_set, signo))) { - hour %= 12; - if (hour == 0) hour = 12; + sigdelset (&new_mask, signo); + if (prev_handlers[signo] != SIG_ERR) + { + signal (signo, prev_handlers[signo]); + prev_handlers[signo] = SIG_ERR; + } + if (sigismember (&pending_signals, signo)) + { + sigdelset (&pending_signals, signo); + raise (signo); + } } - - len = sprintf (clock_str, "%2d.%02d.%02d", hour, min, t->ti_sec); - dos_direct_output (0, screen_size_X - len - 1, clock_str, len); - dos_menubar_clock_displayed = 1; - } - else if (dos_menubar_clock_displayed) - { - /* Erase last displayed time. */ - dos_direct_output (0, screen_size_X - 9, " ", 8); - dos_menubar_clock_displayed = 0; } - - if (!NILP (Vdos_timer_hooks)) - run_dos_timer_hooks++; + current_mask = new_mask; + return 0; } +#else /* not POSIX_SIGNALS */ + +sigsetmask (x) int x; { return 0; } +sigblock (mask) int mask; { return 0; } + +#endif /* not POSIX_SIGNALS */ +#endif /* __DJGPP__ > 1 */ + +#ifndef HAVE_SELECT +#include "sysselect.h" + +#ifndef EMACS_TIME_ZERO_OR_NEG_P +#define EMACS_TIME_ZERO_OR_NEG_P(time) \ + ((long)(time).tv_sec < 0 \ + || ((time).tv_sec == 0 \ + && (long)(time).tv_usec <= 0)) +#endif + + /* Only event queue is checked. */ +/* We don't have to call timer_check here + because wait_reading_process_input takes care of that. */ int sys_select (nfds, rfds, wfds, efds, timeout) int nfds; @@ -2457,7 +3300,6 @@ sys_select (nfds, rfds, wfds, efds, timeout) EMACS_TIME *timeout; { int check_input; - long timeoutval, clnow, cllast; struct time t; check_input = 0; @@ -2478,27 +3320,39 @@ sys_select (nfds, rfds, wfds, efds, timeout) just read it and wait -- that's more efficient. */ if (!timeout) { - do - check_timer (&t); /* check timer even if some input is pending */ - while (!detect_input_pending ()); + while (!detect_input_pending ()) + { +#if __DJGPP__ >= 2 + __dpmi_yield (); +#endif + } } else { - timeoutval = EMACS_SECS (*timeout) * 100 + EMACS_USECS (*timeout) / 10000; - check_timer (&t); - cllast = t.ti_sec * 100 + t.ti_hund; + EMACS_TIME clnow, cllast, cldiff; + + gettime (&t); + EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L); while (!check_input || !detect_input_pending ()) { - check_timer (&t); - clnow = t.ti_sec * 100 + t.ti_hund; - if (clnow < cllast) /* time wrap */ - timeoutval -= clnow + 6000 - cllast; - else - timeoutval -= clnow - cllast; - if (timeoutval <= 0) /* Stop on timer being cleared */ + gettime (&t); + EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L); + EMACS_SUB_TIME (cldiff, clnow, cllast); + + /* When seconds wrap around, we assume that no more than + 1 minute passed since last `gettime'. */ + if (EMACS_TIME_NEG_P (cldiff)) + EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60); + EMACS_SUB_TIME (*timeout, *timeout, cldiff); + + /* Stop when timeout value crosses zero. */ + if (EMACS_TIME_ZERO_OR_NEG_P (*timeout)) return 0; cllast = clnow; +#if __DJGPP__ >= 2 + __dpmi_yield (); +#endif } } @@ -2508,7 +3362,7 @@ sys_select (nfds, rfds, wfds, efds, timeout) #endif /* - * Define overlayed functions: + * Define overlaid functions: * * chdir -> sys_chdir * tzset -> init_gettimeofday @@ -2584,6 +3438,20 @@ dos_abort (file, line) ScreenSetCursor (2, 0); abort (); } +#else +void +abort () +{ + dos_ttcooked (); + ScreenSetCursor (10, 0); + cputs ("\r\n\nEmacs aborted!\r\n"); +#if __DJGPP__ > 1 + /* Generate traceback, so we could tell whodunit. */ + signal (SIGINT, SIG_DFL); + __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception"); +#endif + exit (2); +} #endif syms_of_msdos () @@ -2592,6 +3460,8 @@ syms_of_msdos () staticpro (&recent_doskeys); defsubr (&Srecent_doskeys); + defsubr (&Smsdos_long_file_names); + defsubr (&Smsdos_downcase_filename); } #endif /* MSDOS */