X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/345dd8f75a4c772e970df02014bcb42ac437d7de..9a5114ac7e384d28a13c99725380b6024abde5cf:/src/msdos.c diff --git a/src/msdos.c b/src/msdos.c index cc05323c97..94b75a5efc 100644 --- a/src/msdos.c +++ b/src/msdos.c @@ -33,10 +33,16 @@ Boston, MA 02111-1307, USA. */ #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" @@ -47,6 +53,8 @@ Boston, MA 02111-1307, USA. */ #include "termopts.h" #include "frame.h" #include "window.h" +#include "buffer.h" +#include "commands.h" #include #include #include @@ -58,9 +66,14 @@ Boston, MA 02111-1307, USA. */ #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 @@ -294,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; @@ -307,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 @@ -365,6 +379,39 @@ ScreenVisualBell (void) #ifndef HAVE_X_WINDOWS +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. */ @@ -401,9 +448,6 @@ dos_set_window_size (rows, cols) { regs.x.ax = video_mode_value; int86 (0x10, ®s, ®s); - regs.h.bl = 0; - regs.x.ax = 0x1003; - int86 (0x10, ®s, ®s); if (have_mouse) { @@ -494,6 +538,9 @@ dos_set_window_size (rows, cols) /* 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, @@ -636,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; @@ -666,7 +782,10 @@ 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) @@ -676,6 +795,7 @@ IT_set_menu_bar_lines (window, 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); @@ -691,16 +811,38 @@ IT_set_menu_bar_lines (window, n) } } +/* 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; @@ -726,6 +868,8 @@ 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 @@ -752,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 @@ -800,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)) @@ -826,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"))) @@ -833,31 +982,29 @@ 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 */ @@ -883,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; } @@ -893,23 +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) { - /* Foreground colrs use 4 bits, background only 3. */ - if (isxdigit (colors[0]) && !isdigit (colors[0])) - colors[0] += 10 - (isupper (colors[0]) ? 'A' : 'a'); + /* 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 (colors[1] >= 0 && colors[1] < 8) + 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; @@ -921,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; @@ -943,6 +1096,19 @@ dos_get_saved_screen (screen, rows, cols) return 0; #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 ---------------------- * @@ -1007,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) @@ -1014,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; @@ -1321,6 +1495,13 @@ 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 ? */ @@ -1386,6 +1567,8 @@ 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 () { @@ -1393,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), @@ -1463,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; @@ -1800,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); @@ -1837,6 +2042,7 @@ int XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable) { int len; + char *p; if (!enable) abort (); @@ -1846,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; } @@ -1858,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))) @@ -1867,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; } @@ -1906,29 +2129,36 @@ XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx, 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. */ @@ -1936,11 +2166,29 @@ XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx, 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)); + /* 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; @@ -2025,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; } @@ -2061,12 +2310,16 @@ x_pixel_height (struct frame *f) /* ----------------------- 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 == '\\') @@ -2081,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 == '/') @@ -2113,11 +2372,7 @@ getdefdir (drive, dst) if (errno) return 0; - /* Under LFN we expect to get pathnames in their true case. */ - if (! (_USE_LFN)) - for (p = dst; *p; p++) - if (*p >= 'A' && *p <= 'Z') - *p += 'a' - 'A'; + msdos_downcase_filename (dst); errno = e; return 1; @@ -2133,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; @@ -2223,6 +2477,122 @@ __write (int handle, const void *buffer, size_t count) } } +/* 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, @@ -2232,6 +2602,49 @@ DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names, { 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. */ @@ -2266,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--; @@ -2300,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); @@ -2311,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); @@ -2536,17 +2947,29 @@ run_msdos_command (argv, dir, tempin, tempout, temperr) 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) @@ -2641,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); @@ -2734,14 +3162,123 @@ 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; } -sigblock (mask) int mask; { return 0; } unrequest_sigio () {} +#if __DJGPP__ > 1 + +#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; + +/* 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 +sig_suspender (signo) + int signo; +{ + sigaddset (&pending_signals, signo); +} + +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) + { + errno = EINVAL; + return -1; + } + + sigemptyset (&new_mask); + + /* 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) + { + 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 (( how == SIG_UNBLOCK + && sigismember (&new_mask, signo) + && sigismember (new_set, signo)) + || (how == SIG_SETMASK + && sigismember (&new_mask, signo) + && !sigismember (new_set, signo))) + { + 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); + } + } + } + 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" @@ -2923,7 +3460,8 @@ syms_of_msdos () staticpro (&recent_doskeys); defsubr (&Srecent_doskeys); - defsubt (&Smsdos_long_file_names); + defsubr (&Smsdos_long_file_names); + defsubr (&Smsdos_downcase_filename); } #endif /* MSDOS */