#include <sys/time.h>
#include <dos.h>
#include <errno.h>
+#include <string.h> /* for bzero and string functions */
#include <sys/stat.h> /* for _fixpath */
+#include <unistd.h> /* for chdir, dup, dup2, etc. */
#if __DJGPP__ >= 2
#include <fcntl.h>
+#include <io.h> /* for setmode */
+#include <dpmi.h> /* for __dpmi_xxx stuff */
+#include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
#include <libc/dosio.h> /* for _USE_LFN */
+#include <conio.h> /* for cputs */
#endif
#include "dosfns.h"
#include "termopts.h"
#include "frame.h"
#include "window.h"
+#include "buffer.h"
+#include "commands.h"
#include <go32.h>
#include <pc.h>
#include <ctype.h>
#define _USE_LFN 0
#endif
+#ifndef _dos_ds
+#define _dos_ds _go32_info_block.selector_for_linear_memory
+#endif
+
#if __DJGPP__ > 1
#include <signal.h>
+#include "syssignal.h"
#ifndef SYSTEM_MALLOC
/* 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;
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
#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. */
{
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)
{
/* 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,
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<CURSOR:%dx%d>", 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;
{
}
-/* 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)
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);
}
}
+/* 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<SET_TERM>");
highlight = 0;
if (termscript)
fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
screen_size_X, screen_size_Y);
+
+ bright_bg ();
}
/* IT_reset_terminal_modes is called when emacs is
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
}
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))
{
FRAME_FOREGROUND_PIXEL (f) = new_color;
redraw = 1;
+ if (termscript)
+ fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
}
}
else if (EQ (prop, intern ("background-color")))
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, "<BGCOLOR %lu>\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 */
#ifndef HAVE_X_WINDOWS
if (!internal_terminal || inhibit_window_system)
{
- the_only_frame.output_method = output_termcap;
+ selected_frame->output_method = output_termcap;
return;
}
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;
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;
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
+
\f
/* ----------------------- Keyboard control ----------------------
*
static struct dos_keyboard_map *keyboard;
static int keyboard_map_all;
+static int international_keyboard;
int
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;
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 ? */
/* 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 ()
{
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),
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;
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);
XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
{
int len;
+ char *p;
if (!enable)
abort ();
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;
}
int foo, char *txt, int enable)
{
int len;
+ char *p;
if (pane)
if (!(menu = IT_menu_search_pane (menu, 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;
}
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. */
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;
ScreenUpdate (state[0].screen_behind);
while (statecount--)
xfree (state[statecount].screen_behind);
+ IT_display_cursor (1); /* turn cursor back on */
return result;
}
\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 == '\\')
unixtodos_filename (p)
register char *p;
{
+ if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
+ {
+ *p += 'a' - 'A';
+ p += 2;
+ }
+
while (*p)
{
if (*p == '/')
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;
unsigned char *np = buf;
unsigned char *startp = buf;
unsigned char *endp = buf + n;
- unsigned char c;
if (n == 0)
return n;
}
}
+/* 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 <io.h>
+
+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,
{
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;
+}
\f
/* The Emacs root directory as determined by init_environment. */
"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--;
if (!s) s = "c:/command.com";
t = alloca (strlen (s) + 1);
strcpy (t, s);
- strlwr (t);
dostounix_filename (t);
setenv ("SHELL", t, 0);
/* 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);
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)
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);
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 <libc/bss.h>
+
+/* 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"
staticpro (&recent_doskeys);
defsubr (&Srecent_doskeys);
- defsubt (&Smsdos_long_file_names);
+ defsubr (&Smsdos_long_file_names);
+ defsubr (&Smsdos_downcase_filename);
}
#endif /* MSDOS */