(server-visit-files): New argument NOWAIT.
[emacs.git] / src / msdos.c
blob447e6a5d2032f2a70ef535f59c4950d194e20c22
1 /* MS-DOS specific C utilities.
2 Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Contributed by Morten Welinder */
22 /* New display, keyboard, and mouse control by Kim F. Storm */
24 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
26 #include <config.h>
28 #ifdef MSDOS
29 #include "lisp.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/param.h>
33 #include <sys/time.h>
34 #include <dos.h>
35 #include <errno.h>
36 #include <sys/stat.h> /* for _fixpath */
37 #if __DJGPP__ >= 2
38 #include <fcntl.h>
39 #include <libc/dosio.h> /* for _USE_LFN */
40 #endif
42 #include "dosfns.h"
43 #include "msdos.h"
44 #include "systime.h"
45 #include "termhooks.h"
46 #include "dispextern.h"
47 #include "termopts.h"
48 #include "frame.h"
49 #include "window.h"
50 #include <go32.h>
51 #include <pc.h>
52 #include <ctype.h>
53 /* #include <process.h> */
54 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
55 #define P_WAIT 1
57 #ifndef _USE_LFN
58 #define _USE_LFN 0
59 #endif
61 #if __DJGPP__ > 1
63 #include <signal.h>
65 #ifndef SYSTEM_MALLOC
67 #ifdef GNU_MALLOC
69 /* If other `malloc' than ours is used, force our `sbrk' behave like
70 Unix programs expect (resize memory blocks to keep them contiguous).
71 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
72 because that's what `gmalloc' expects to get. */
73 #include <crt0.h>
75 #ifdef REL_ALLOC
76 int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
77 #else /* not REL_ALLOC */
78 int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
79 #endif /* not REL_ALLOC */
80 #endif /* GNU_MALLOC */
82 #endif /* not SYSTEM_MALLOC */
83 #endif /* __DJGPP__ > 1 */
85 static unsigned long
86 event_timestamp ()
88 struct time t;
89 unsigned long s;
91 gettime (&t);
92 s = t.ti_min;
93 s *= 60;
94 s += t.ti_sec;
95 s *= 1000;
96 s += t.ti_hund * 10;
98 return s;
102 /* ------------------------ Mouse control ---------------------------
104 * Coordinates are in screen positions and zero based.
105 * Mouse buttons are numbered from left to right and also zero based.
108 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
109 static int mouse_visible;
111 static int mouse_last_x;
112 static int mouse_last_y;
114 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
115 static int mouse_button_count;
117 void
118 mouse_on ()
120 union REGS regs;
122 if (have_mouse > 0 && !mouse_visible)
124 if (termscript)
125 fprintf (termscript, "<M_ON>");
126 regs.x.ax = 0x0001;
127 int86 (0x33, &regs, &regs);
128 mouse_visible = 1;
132 void
133 mouse_off ()
135 union REGS regs;
137 if (have_mouse > 0 && mouse_visible)
139 if (termscript)
140 fprintf (termscript, "<M_OFF>");
141 regs.x.ax = 0x0002;
142 int86 (0x33, &regs, &regs);
143 mouse_visible = 0;
147 void
148 mouse_moveto (x, y)
149 int x, y;
151 union REGS regs;
153 if (termscript)
154 fprintf (termscript, "<M_XY=%dx%d>", x, y);
155 regs.x.ax = 0x0004;
156 mouse_last_x = regs.x.cx = x * 8;
157 mouse_last_y = regs.x.dx = y * 8;
158 int86 (0x33, &regs, &regs);
161 static int
162 mouse_pressed (b, xp, yp)
163 int b, *xp, *yp;
165 union REGS regs;
167 if (b >= mouse_button_count)
168 return 0;
169 regs.x.ax = 0x0005;
170 regs.x.bx = mouse_button_translate[b];
171 int86 (0x33, &regs, &regs);
172 if (regs.x.bx)
173 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
174 return (regs.x.bx != 0);
177 static int
178 mouse_released (b, xp, yp)
179 int b, *xp, *yp;
181 union REGS regs;
183 if (b >= mouse_button_count)
184 return 0;
185 regs.x.ax = 0x0006;
186 regs.x.bx = mouse_button_translate[b];
187 int86 (0x33, &regs, &regs);
188 if (regs.x.bx)
189 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
190 return (regs.x.bx != 0);
193 static void
194 mouse_get_xy (int *x, int *y)
196 union REGS regs;
198 regs.x.ax = 0x0003;
199 int86 (0x33, &regs, &regs);
200 *x = regs.x.cx / 8;
201 *y = regs.x.dx / 8;
204 void
205 mouse_get_pos (f, insist, bar_window, part, x, y, time)
206 FRAME_PTR *f;
207 int insist;
208 Lisp_Object *bar_window, *x, *y;
209 enum scroll_bar_part *part;
210 unsigned long *time;
212 int ix, iy;
213 union REGS regs;
215 regs.x.ax = 0x0003;
216 int86 (0x33, &regs, &regs);
217 *f = selected_frame;
218 *bar_window = Qnil;
219 mouse_get_xy (&ix, &iy);
220 selected_frame->mouse_moved = 0;
221 *x = make_number (ix);
222 *y = make_number (iy);
223 *time = event_timestamp ();
226 static void
227 mouse_check_moved ()
229 int x, y;
231 mouse_get_xy (&x, &y);
232 selected_frame->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
233 mouse_last_x = x;
234 mouse_last_y = y;
237 void
238 mouse_init ()
240 union REGS regs;
242 if (termscript)
243 fprintf (termscript, "<M_INIT>");
245 regs.x.ax = 0x0021;
246 int86 (0x33, &regs, &regs);
248 regs.x.ax = 0x0007;
249 regs.x.cx = 0;
250 regs.x.dx = 8 * (ScreenCols () - 1);
251 int86 (0x33, &regs, &regs);
253 regs.x.ax = 0x0008;
254 regs.x.cx = 0;
255 regs.x.dx = 8 * (ScreenRows () - 1);
256 int86 (0x33, &regs, &regs);
258 mouse_moveto (0, 0);
259 mouse_visible = 0;
262 /* ------------------------- Screen control ----------------------
266 static int internal_terminal = 0;
268 #ifndef HAVE_X_WINDOWS
269 extern unsigned char ScreenAttrib;
270 static int screen_face;
271 static int highlight;
273 static int screen_size_X;
274 static int screen_size_Y;
275 static int screen_size;
277 static int current_pos_X;
278 static int current_pos_Y;
279 static int new_pos_X;
280 static int new_pos_Y;
282 static void *startup_screen_buffer;
283 static int startup_screen_size_X;
284 static int startup_screen_size_Y;
285 static int startup_pos_X;
286 static int startup_pos_Y;
287 static unsigned char startup_screen_attrib;
289 static int term_setup_done;
291 /* Similar to the_only_frame. */
292 struct x_output the_only_x_display;
294 /* This is never dereferenced. */
295 Display *x_current_display;
298 #define SCREEN_SET_CURSOR() \
299 if (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y) \
300 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X)
302 static
303 dos_direct_output (y, x, buf, len)
304 int y;
305 int x;
306 char *buf;
307 int len;
309 int t = (int) ScreenPrimary + 2 * (x + y * screen_size_X);
311 while (--len >= 0) {
312 dosmemput (buf++, 1, t);
313 t += 2;
316 #endif
318 /* Flash the screen as a substitute for BEEPs. */
320 #if (__DJGPP__ < 2)
321 static void
322 do_visible_bell (xorattr)
323 unsigned char xorattr;
325 asm volatile
326 (" movb $1,%%dl
327 visible_bell_0:
328 movl _ScreenPrimary,%%eax
329 call dosmemsetup
330 movl %%eax,%%ebx
331 movl %1,%%ecx
332 movb %0,%%al
333 incl %%ebx
334 visible_bell_1:
335 xorb %%al,%%gs:(%%ebx)
336 addl $2,%%ebx
337 decl %%ecx
338 jne visible_bell_1
339 decb %%dl
340 jne visible_bell_3
341 visible_bell_2:
342 movzwl %%ax,%%eax
343 movzwl %%ax,%%eax
344 movzwl %%ax,%%eax
345 movzwl %%ax,%%eax
346 decw %%cx
347 jne visible_bell_2
348 jmp visible_bell_0
349 visible_bell_3:"
350 : /* no output */
351 : "m" (xorattr), "g" (screen_size)
352 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
355 static void
356 ScreenVisualBell (void)
358 /* This creates an xor-mask that will swap the default fore- and
359 background colors. */
360 do_visible_bell (((the_only_x_display.foreground_pixel
361 ^ the_only_x_display.background_pixel)
362 * 0x11) & 0x7f);
364 #endif
366 #ifndef HAVE_X_WINDOWS
368 /* Enable bright background colors. */
369 static void
370 bright_bg (void)
372 union REGS regs;
374 regs.h.bl = 0;
375 regs.x.ax = 0x1003;
376 int86 (0x10, &regs, &regs);
379 /* Set the screen dimensions so that it can show no less than
380 ROWS x COLS frame. */
382 void
383 dos_set_window_size (rows, cols)
384 int *rows, *cols;
386 char video_name[30];
387 Lisp_Object video_mode;
388 int video_mode_value;
389 int have_vga = 0;
390 union REGS regs;
391 int current_rows = ScreenRows (), current_cols = ScreenCols ();
393 if (*rows == current_rows && *cols == current_cols)
394 return;
396 /* Do we have a VGA? */
397 regs.x.ax = 0x1a00;
398 int86 (0x10, &regs, &regs);
399 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
400 have_vga = 1;
402 mouse_off ();
404 /* If the user specified a special video mode for these dimensions,
405 use that mode. */
406 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
407 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
408 Qnil))-> value;
410 if (INTEGERP (video_mode)
411 && (video_mode_value = XINT (video_mode)) > 0)
413 regs.x.ax = video_mode_value;
414 int86 (0x10, &regs, &regs);
416 if (have_mouse)
418 /* Must hardware-reset the mouse, or else it won't update
419 its notion of screen dimensions for some non-standard
420 video modes. This is *painfully* slow... */
421 regs.x.ax = 0;
422 int86 (0x33, &regs, &regs);
426 /* Find one of the dimensions supported by standard EGA/VGA
427 which gives us at least the required dimensions. */
429 #if __DJGPP__ > 1
431 else
433 static struct {
434 int rows;
435 int need_vga;
436 } std_dimension[] = {
437 {25, 0},
438 {28, 1},
439 {35, 0},
440 {40, 1},
441 {43, 0},
442 {50, 1}
444 int i = 0;
446 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
448 if (std_dimension[i].need_vga <= have_vga
449 && std_dimension[i].rows >= *rows)
451 if (std_dimension[i].rows != current_rows
452 || *cols != current_cols)
453 _set_screen_lines (std_dimension[i].rows);
454 break;
456 i++;
460 #else /* not __DJGPP__ > 1 */
462 else if (*rows <= 25)
464 if (current_rows != 25 || current_cols != 80)
466 regs.x.ax = 3;
467 int86 (0x10, &regs, &regs);
468 regs.x.ax = 0x1101;
469 regs.h.bl = 0;
470 int86 (0x10, &regs, &regs);
471 regs.x.ax = 0x1200;
472 regs.h.bl = 32;
473 int86 (0x10, &regs, &regs);
474 regs.x.ax = 3;
475 int86 (0x10, &regs, &regs);
478 else if (*rows <= 50)
479 if (have_vga && (current_rows != 50 || current_cols != 80)
480 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
482 regs.x.ax = 3;
483 int86 (0x10, &regs, &regs);
484 regs.x.ax = 0x1112;
485 regs.h.bl = 0;
486 int86 (0x10, &regs, &regs);
487 regs.x.ax = 0x1200;
488 regs.h.bl = 32;
489 int86 (0x10, &regs, &regs);
490 regs.x.ax = 0x0100;
491 regs.x.cx = 7;
492 int86 (0x10, &regs, &regs);
494 #endif /* not __DJGPP__ > 1 */
496 if (have_mouse)
498 mouse_init ();
499 mouse_on ();
502 /* Tell the caller what dimensions have been REALLY set. */
503 *rows = ScreenRows ();
504 *cols = ScreenCols ();
506 /* Enable bright background colors. */
507 bright_bg ();
510 /* If we write a character in the position where the mouse is,
511 the mouse cursor may need to be refreshed. */
513 static void
514 mouse_off_maybe ()
516 int x, y;
518 if (!mouse_visible)
519 return;
521 mouse_get_xy (&x, &y);
522 if (y != new_pos_Y || x < new_pos_X)
523 return;
525 mouse_off ();
528 static
529 IT_ring_bell ()
531 if (visible_bell)
533 mouse_off ();
534 ScreenVisualBell ();
536 else
538 union REGS inregs, outregs;
539 inregs.h.ah = 2;
540 inregs.h.dl = 7;
541 intdos (&inregs, &outregs);
545 static void
546 IT_set_face (int face)
548 struct face *fp;
549 extern struct face *intern_face (/* FRAME_PTR, struct face * */);
551 if (face == 1 || (face == 0 && highlight))
552 fp = FRAME_MODE_LINE_FACE (foo);
553 else if (face <= 0 || face >= FRAME_N_COMPUTED_FACES (foo))
554 fp = FRAME_DEFAULT_FACE (foo);
555 else
556 fp = intern_face (selected_frame, FRAME_COMPUTED_FACES (foo)[face]);
557 if (termscript)
558 fprintf (termscript, "<FACE:%d:%d>", FACE_FOREGROUND (fp), FACE_BACKGROUND (fp));
559 screen_face = face;
560 ScreenAttrib = (FACE_BACKGROUND (fp) << 4) | FACE_FOREGROUND (fp);
563 static
564 IT_write_glyphs (GLYPH *str, int len)
566 int newface;
567 int ch, l = len;
568 unsigned char *buf, *bp;
570 if (len == 0) return;
572 buf = bp = alloca (len * 2);
574 while (--l >= 0)
576 newface = FAST_GLYPH_FACE (*str);
577 if (newface != screen_face)
578 IT_set_face (newface);
579 ch = FAST_GLYPH_CHAR (*str);
580 *bp++ = (unsigned char)ch;
581 *bp++ = ScreenAttrib;
583 if (termscript)
584 fputc (ch, termscript);
585 str++;
588 mouse_off_maybe ();
589 dosmemput (buf, 2 * len,
590 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
591 new_pos_X += len;
594 static
595 IT_clear_end_of_line (first_unused)
597 char *spaces, *sp;
598 int i, j;
600 IT_set_face (0);
601 if (termscript)
602 fprintf (termscript, "<CLR:EOL>");
603 i = (j = screen_size_X - new_pos_X) * 2;
604 spaces = sp = alloca (i);
606 while (--j >= 0)
608 *sp++ = ' ';
609 *sp++ = ScreenAttrib;
612 mouse_off_maybe ();
613 dosmemput (spaces, i,
614 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
617 static
618 IT_clear_screen (void)
620 if (termscript)
621 fprintf (termscript, "<CLR:SCR>");
622 IT_set_face (0);
623 mouse_off ();
624 ScreenClear ();
625 new_pos_X = new_pos_Y = 0;
628 static
629 IT_clear_to_end (void)
631 if (termscript)
632 fprintf (termscript, "<CLR:EOS>");
634 while (new_pos_Y < screen_size_Y) {
635 new_pos_X = 0;
636 IT_clear_end_of_line (0);
637 new_pos_Y++;
641 static
642 IT_cursor_to (int y, int x)
644 if (termscript)
645 fprintf (termscript, "\n<XY=%dx%d>", x, y);
646 new_pos_X = x;
647 new_pos_Y = y;
650 static
651 IT_reassert_line_highlight (new, vpos)
652 int new, vpos;
654 highlight = new;
655 IT_set_face (0); /* To possibly clear the highlighting. */
658 static
659 IT_change_line_highlight (new_highlight, vpos, first_unused_hpos)
661 highlight = new_highlight;
662 IT_set_face (0); /* To possibly clear the highlighting. */
663 IT_cursor_to (vpos, 0);
664 IT_clear_end_of_line (first_unused_hpos);
667 static
668 IT_update_begin ()
670 highlight = 0;
671 IT_set_face (0); /* To possibly clear the highlighting. */
672 screen_face = -1;
675 static
676 IT_update_end ()
680 /* This was more or less copied from xterm.c
682 Nowadays, the corresponding function under X is `x_set_menu_bar_lines_1'
683 on xfns.c */
685 static void
686 IT_set_menu_bar_lines (window, n)
687 Lisp_Object window;
688 int n;
690 struct window *w = XWINDOW (window);
692 XSETFASTINT (w->last_modified, 0);
693 XSETFASTINT (w->top, XFASTINT (w->top) + n);
694 XSETFASTINT (w->height, XFASTINT (w->height) - n);
696 /* Handle just the top child in a vertical split. */
697 if (!NILP (w->vchild))
698 IT_set_menu_bar_lines (w->vchild, n);
700 /* Adjust all children in a horizontal split. */
701 for (window = w->hchild; !NILP (window); window = w->next)
703 w = XWINDOW (window);
704 IT_set_menu_bar_lines (window, n);
708 /* This was copied from xfns.c */
710 void
711 x_set_menu_bar_lines (f, value, oldval)
712 struct frame *f;
713 Lisp_Object value, oldval;
715 int nlines;
716 int olines = FRAME_MENU_BAR_LINES (f);
718 /* Right now, menu bars don't work properly in minibuf-only frames;
719 most of the commands try to apply themselves to the minibuffer
720 frame itslef, and get an error because you can't switch buffers
721 in or split the minibuffer window. */
722 if (FRAME_MINIBUF_ONLY_P (f))
723 return;
725 if (INTEGERP (value))
726 nlines = XINT (value);
727 else
728 nlines = 0;
730 FRAME_MENU_BAR_LINES (f) = nlines;
731 IT_set_menu_bar_lines (f->root_window, nlines - olines);
734 /* IT_set_terminal_modes is called when emacs is started,
735 resumed, and whenever the screen is redrawn! */
737 static
738 IT_set_terminal_modes (void)
740 char *colors;
741 FRAME_PTR f;
742 struct face *fp;
744 if (termscript)
745 fprintf (termscript, "\n<SET_TERM>");
746 highlight = 0;
748 screen_size_X = ScreenCols ();
749 screen_size_Y = ScreenRows ();
750 screen_size = screen_size_X * screen_size_Y;
752 new_pos_X = new_pos_Y = 0;
753 current_pos_X = current_pos_Y = -1;
755 if (term_setup_done)
756 return;
757 term_setup_done = 1;
759 startup_screen_size_X = screen_size_X;
760 startup_screen_size_Y = screen_size_Y;
761 startup_screen_attrib = ScreenAttrib;
763 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
764 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
766 if (termscript)
767 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
768 screen_size_X, screen_size_Y);
770 bright_bg ();
773 /* IT_reset_terminal_modes is called when emacs is
774 suspended or killed. */
776 static
777 IT_reset_terminal_modes (void)
779 int display_row_start = (int) ScreenPrimary;
780 int saved_row_len = startup_screen_size_X * 2;
781 int update_row_len = ScreenCols () * 2;
782 int current_rows = ScreenRows ();
783 int to_next_row = update_row_len;
784 unsigned char *saved_row = startup_screen_buffer;
785 int cursor_pos_X = ScreenCols () - 1;
786 int cursor_pos_Y = ScreenRows () - 1;
788 if (termscript)
789 fprintf (termscript, "\n<RESET_TERM>");
791 highlight = 0;
793 if (!term_setup_done)
794 return;
796 mouse_off ();
798 /* We have a situation here.
799 We cannot just do ScreenUpdate(startup_screen_buffer) because
800 the luser could have changed screen dimensions inside Emacs
801 and failed (or didn't want) to restore them before killing
802 Emacs. ScreenUpdate() uses the *current* screen dimensions and
803 thus will happily use memory outside what was allocated for
804 `startup_screen_buffer'.
805 Thus we only restore as much as the current screen dimensions
806 can hold, and clear the rest (if the saved screen is smaller than
807 the current) with the color attribute saved at startup. The cursor
808 is also restored within the visible dimensions. */
810 ScreenAttrib = startup_screen_attrib;
811 ScreenClear ();
813 if (update_row_len > saved_row_len)
814 update_row_len = saved_row_len;
815 if (current_rows > startup_screen_size_Y)
816 current_rows = startup_screen_size_Y;
818 if (termscript)
819 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
820 update_row_len / 2, current_rows);
822 while (current_rows--)
824 dosmemput (saved_row, update_row_len, display_row_start);
825 saved_row += saved_row_len;
826 display_row_start += to_next_row;
828 if (startup_pos_X < cursor_pos_X)
829 cursor_pos_X = startup_pos_X;
830 if (startup_pos_Y < cursor_pos_Y)
831 cursor_pos_Y = startup_pos_Y;
833 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
834 xfree (startup_screen_buffer);
836 term_setup_done = 0;
839 static
840 IT_set_terminal_window (void)
844 void
845 IT_set_frame_parameters (f, alist)
846 FRAME_PTR f;
847 Lisp_Object alist;
849 Lisp_Object tail;
850 int redraw;
851 extern unsigned long load_color ();
853 redraw = 0;
854 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
856 Lisp_Object elt, prop, val;
858 elt = Fcar (tail);
859 prop = Fcar (elt);
860 val = Fcdr (elt);
861 CHECK_SYMBOL (prop, 1);
863 if (EQ (prop, intern ("foreground-color")))
865 unsigned long new_color = load_color (f, val);
866 if (new_color != ~0)
868 FRAME_FOREGROUND_PIXEL (f) = new_color;
869 redraw = 1;
870 if (termscript)
871 fprintf (termscript, "<FGCOLOR %d>\n", new_color);
874 else if (EQ (prop, intern ("background-color")))
876 unsigned long new_color = load_color (f, val);
877 if (new_color != ~0)
879 FRAME_BACKGROUND_PIXEL (f) = new_color;
880 redraw = 1;
881 if (termscript)
882 fprintf (termscript, "<BGCOLOR %d>\n", new_color);
885 else if (EQ (prop, intern ("menu-bar-lines")))
886 x_set_menu_bar_lines (f, val, 0);
889 if (redraw)
891 recompute_basic_faces (f);
892 if (f == selected_frame)
893 redraw_frame (f);
897 #endif /* !HAVE_X_WINDOWS */
900 /* Do we need the internal terminal? */
902 void
903 internal_terminal_init ()
905 char *term = getenv ("TERM");
906 char *colors;
908 #ifdef HAVE_X_WINDOWS
909 if (!inhibit_window_system)
910 return;
911 #endif
913 internal_terminal
914 = (!noninteractive) && term && !strcmp (term, "internal");
916 if (getenv ("EMACSTEST"))
917 termscript = fopen (getenv ("EMACSTEST"), "wt");
919 #ifndef HAVE_X_WINDOWS
920 if (!internal_terminal || inhibit_window_system)
922 selected_frame->output_method = output_termcap;
923 return;
926 Vwindow_system = intern ("pc");
927 Vwindow_system_version = make_number (1);
929 bzero (&the_only_x_display, sizeof the_only_x_display);
930 the_only_x_display.background_pixel = 7; /* White */
931 the_only_x_display.foreground_pixel = 0; /* Black */
932 bright_bg ();
933 colors = getenv ("EMACSCOLORS");
934 if (colors && strlen (colors) >= 2)
936 /* The colors use 4 bits each (we enable bright background). */
937 if (isdigit (colors[0]))
938 colors[0] -= '0';
939 else if (isxdigit (colors[0]))
940 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
941 if (colors[0] >= 0 && colors[0] < 16)
942 the_only_x_display.foreground_pixel = colors[0];
943 if (isdigit (colors[1]))
944 colors[1] -= '0';
945 else if (isxdigit (colors[1]))
946 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
947 if (colors[1] >= 0 && colors[1] < 16)
948 the_only_x_display.background_pixel = colors[1];
950 the_only_x_display.line_height = 1;
951 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
953 init_frame_faces (selected_frame);
955 ring_bell_hook = IT_ring_bell;
956 write_glyphs_hook = IT_write_glyphs;
957 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
958 clear_to_end_hook = IT_clear_to_end;
959 clear_end_of_line_hook = IT_clear_end_of_line;
960 clear_frame_hook = IT_clear_screen;
961 change_line_highlight_hook = IT_change_line_highlight;
962 update_begin_hook = IT_update_begin;
963 update_end_hook = IT_update_end;
964 reassert_line_highlight_hook = IT_reassert_line_highlight;
966 /* These hooks are called by term.c without being checked. */
967 set_terminal_modes_hook = IT_set_terminal_modes;
968 reset_terminal_modes_hook = IT_reset_terminal_modes;
969 set_terminal_window_hook = IT_set_terminal_window;
970 #endif
973 dos_get_saved_screen (screen, rows, cols)
974 char **screen;
975 int *rows;
976 int *cols;
978 #ifndef HAVE_X_WINDOWS
979 *screen = startup_screen_buffer;
980 *cols = startup_screen_size_X;
981 *rows = startup_screen_size_Y;
982 return 1;
983 #else
984 return 0;
985 #endif
988 #ifndef HAVE_X_WINDOWS
990 /* We are not X, but we can emulate it well enough for our needs... */
991 void
992 check_x (void)
994 if (! FRAME_MSDOS_P (selected_frame))
995 error ("Not running under a windows system");
998 #endif
1001 /* ----------------------- Keyboard control ----------------------
1003 * Keymaps reflect the following keyboard layout:
1005 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1006 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1007 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1008 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1009 * SPACE
1012 static int extended_kbd; /* 101 (102) keyboard present. */
1014 struct dos_keyboard_map
1016 char *unshifted;
1017 char *shifted;
1018 char *alt_gr;
1022 static struct dos_keyboard_map us_keyboard = {
1023 /* 0 1 2 3 4 5 */
1024 /* 01234567890123456789012345678901234567890 12345678901234 */
1025 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1026 /* 0123456789012345678901234567890123456789 012345678901234 */
1027 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1028 0 /* no Alt-Gr key */
1031 static struct dos_keyboard_map fr_keyboard = {
1032 /* 0 1 2 3 4 5 */
1033 /* 012 3456789012345678901234567890123456789012345678901234 */
1034 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
1035 /* 0123456789012345678901234567890123456789012345678901234 */
1036 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
1037 /* 01234567 89012345678901234567890123456789012345678901234 */
1038 " ~#{[|`\\^@]} Ï "
1041 static struct dos_keyboard_map dk_keyboard = {
1042 /* 0 1 2 3 4 5 */
1043 /* 0123456789012345678901234567890123456789012345678901234 */
1044 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
1045 /* 01 23456789012345678901234567890123456789012345678901234 */
1046 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
1047 /* 0123456789012345678901234567890123456789012345678901234 */
1048 " @œ$ {[]} | "
1051 static struct keyboard_layout_list
1053 int country_code;
1054 struct dos_keyboard_map *keyboard_map;
1055 } keyboard_layout_list[] =
1057 1, &us_keyboard,
1058 33, &fr_keyboard,
1059 45, &dk_keyboard
1062 static struct dos_keyboard_map *keyboard;
1063 static int keyboard_map_all;
1066 dos_set_keyboard (code, always)
1067 int code;
1068 int always;
1070 int i;
1072 /* Initialize to US settings, for countries that don't have their own. */
1073 keyboard = keyboard_layout_list[0].keyboard_map;
1074 keyboard_map_all = always;
1075 dos_keyboard_layout = 1;
1077 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
1078 if (code == keyboard_layout_list[i].country_code)
1080 keyboard = keyboard_layout_list[i].keyboard_map;
1081 keyboard_map_all = always;
1082 dos_keyboard_layout = code;
1083 return 1;
1085 return 0;
1088 #define Ignore 0x0000
1089 #define Normal 0x0000 /* normal key - alt changes scan-code */
1090 #define FctKey 0x1000 /* func key if c == 0, else c */
1091 #define Special 0x2000 /* func key even if c != 0 */
1092 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1093 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1094 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1095 #define Grey 0x6000 /* Grey keypad key */
1097 #define Alt 0x0100 /* alt scan-code */
1098 #define Ctrl 0x0200 /* ctrl scan-code */
1099 #define Shift 0x0400 /* shift scan-code */
1101 static struct
1103 unsigned char char_code; /* normal code */
1104 unsigned char meta_code; /* M- code */
1105 unsigned char keypad_code; /* keypad code */
1106 unsigned char editkey_code; /* edit key */
1107 } keypad_translate_map[] = {
1108 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1109 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1110 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1111 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1112 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1113 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1114 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1115 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1116 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1117 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1118 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1121 static struct
1123 unsigned char char_code; /* normal code */
1124 unsigned char keypad_code; /* keypad code */
1125 } grey_key_translate_map[] = {
1126 '/', 0xaf, /* kp-decimal */
1127 '*', 0xaa, /* kp-multiply */
1128 '-', 0xad, /* kp-subtract */
1129 '+', 0xab, /* kp-add */
1130 '\r', 0x8d /* kp-enter */
1133 static unsigned short
1134 ibmpc_translate_map[] =
1136 /* --------------- 00 to 0f --------------- */
1137 Normal | 0xff, /* Ctrl Break + Alt-NNN */
1138 Alt | ModFct | 0x1b, /* Escape */
1139 Normal | 1, /* '1' */
1140 Normal | 2, /* '2' */
1141 Normal | 3, /* '3' */
1142 Normal | 4, /* '4' */
1143 Normal | 5, /* '5' */
1144 Normal | 6, /* '6' */
1145 Normal | 7, /* '7' */
1146 Normal | 8, /* '8' */
1147 Normal | 9, /* '9' */
1148 Normal | 10, /* '0' */
1149 Normal | 11, /* '-' */
1150 Normal | 12, /* '=' */
1151 Special | 0x08, /* Backspace */
1152 ModFct | 0x74, /* Tab/Backtab */
1154 /* --------------- 10 to 1f --------------- */
1155 Map | 15, /* 'q' */
1156 Map | 16, /* 'w' */
1157 Map | 17, /* 'e' */
1158 Map | 18, /* 'r' */
1159 Map | 19, /* 't' */
1160 Map | 20, /* 'y' */
1161 Map | 21, /* 'u' */
1162 Map | 22, /* 'i' */
1163 Map | 23, /* 'o' */
1164 Map | 24, /* 'p' */
1165 Map | 25, /* '[' */
1166 Map | 26, /* ']' */
1167 ModFct | 0x0d, /* Return */
1168 Ignore, /* Ctrl */
1169 Map | 30, /* 'a' */
1170 Map | 31, /* 's' */
1172 /* --------------- 20 to 2f --------------- */
1173 Map | 32, /* 'd' */
1174 Map | 33, /* 'f' */
1175 Map | 34, /* 'g' */
1176 Map | 35, /* 'h' */
1177 Map | 36, /* 'j' */
1178 Map | 37, /* 'k' */
1179 Map | 38, /* 'l' */
1180 Map | 39, /* ';' */
1181 Map | 40, /* '\'' */
1182 Map | 0, /* '`' */
1183 Ignore, /* Left shift */
1184 Map | 41, /* '\\' */
1185 Map | 45, /* 'z' */
1186 Map | 46, /* 'x' */
1187 Map | 47, /* 'c' */
1188 Map | 48, /* 'v' */
1190 /* --------------- 30 to 3f --------------- */
1191 Map | 49, /* 'b' */
1192 Map | 50, /* 'n' */
1193 Map | 51, /* 'm' */
1194 Map | 52, /* ',' */
1195 Map | 53, /* '.' */
1196 Map | 54, /* '/' */
1197 Ignore, /* Right shift */
1198 Grey | 1, /* Grey * */
1199 Ignore, /* Alt */
1200 Normal | ' ', /* ' ' */
1201 Ignore, /* Caps Lock */
1202 FctKey | 0xbe, /* F1 */
1203 FctKey | 0xbf, /* F2 */
1204 FctKey | 0xc0, /* F3 */
1205 FctKey | 0xc1, /* F4 */
1206 FctKey | 0xc2, /* F5 */
1208 /* --------------- 40 to 4f --------------- */
1209 FctKey | 0xc3, /* F6 */
1210 FctKey | 0xc4, /* F7 */
1211 FctKey | 0xc5, /* F8 */
1212 FctKey | 0xc6, /* F9 */
1213 FctKey | 0xc7, /* F10 */
1214 Ignore, /* Num Lock */
1215 Ignore, /* Scroll Lock */
1216 KeyPad | 7, /* Home */
1217 KeyPad | 8, /* Up */
1218 KeyPad | 9, /* Page Up */
1219 Grey | 2, /* Grey - */
1220 KeyPad | 4, /* Left */
1221 KeyPad | 5, /* Keypad 5 */
1222 KeyPad | 6, /* Right */
1223 Grey | 3, /* Grey + */
1224 KeyPad | 1, /* End */
1226 /* --------------- 50 to 5f --------------- */
1227 KeyPad | 2, /* Down */
1228 KeyPad | 3, /* Page Down */
1229 KeyPad | 0, /* Insert */
1230 KeyPad | 10, /* Delete */
1231 Shift | FctKey | 0xbe, /* (Shift) F1 */
1232 Shift | FctKey | 0xbf, /* (Shift) F2 */
1233 Shift | FctKey | 0xc0, /* (Shift) F3 */
1234 Shift | FctKey | 0xc1, /* (Shift) F4 */
1235 Shift | FctKey | 0xc2, /* (Shift) F5 */
1236 Shift | FctKey | 0xc3, /* (Shift) F6 */
1237 Shift | FctKey | 0xc4, /* (Shift) F7 */
1238 Shift | FctKey | 0xc5, /* (Shift) F8 */
1239 Shift | FctKey | 0xc6, /* (Shift) F9 */
1240 Shift | FctKey | 0xc7, /* (Shift) F10 */
1241 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
1242 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
1244 /* --------------- 60 to 6f --------------- */
1245 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
1246 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
1247 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
1248 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
1249 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
1250 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
1251 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
1252 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
1253 Alt | FctKey | 0xbe, /* (Alt) F1 */
1254 Alt | FctKey | 0xbf, /* (Alt) F2 */
1255 Alt | FctKey | 0xc0, /* (Alt) F3 */
1256 Alt | FctKey | 0xc1, /* (Alt) F4 */
1257 Alt | FctKey | 0xc2, /* (Alt) F5 */
1258 Alt | FctKey | 0xc3, /* (Alt) F6 */
1259 Alt | FctKey | 0xc4, /* (Alt) F7 */
1260 Alt | FctKey | 0xc5, /* (Alt) F8 */
1262 /* --------------- 70 to 7f --------------- */
1263 Alt | FctKey | 0xc6, /* (Alt) F9 */
1264 Alt | FctKey | 0xc7, /* (Alt) F10 */
1265 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
1266 Ctrl | KeyPad | 4, /* (Ctrl) Left */
1267 Ctrl | KeyPad | 6, /* (Ctrl) Right */
1268 Ctrl | KeyPad | 1, /* (Ctrl) End */
1269 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
1270 Ctrl | KeyPad | 7, /* (Ctrl) Home */
1271 Alt | Map | 1, /* '1' */
1272 Alt | Map | 2, /* '2' */
1273 Alt | Map | 3, /* '3' */
1274 Alt | Map | 4, /* '4' */
1275 Alt | Map | 5, /* '5' */
1276 Alt | Map | 6, /* '6' */
1277 Alt | Map | 7, /* '7' */
1278 Alt | Map | 8, /* '8' */
1280 /* --------------- 80 to 8f --------------- */
1281 Alt | Map | 9, /* '9' */
1282 Alt | Map | 10, /* '0' */
1283 Alt | Map | 11, /* '-' */
1284 Alt | Map | 12, /* '=' */
1285 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
1286 FctKey | 0xc8, /* F11 */
1287 FctKey | 0xc9, /* F12 */
1288 Shift | FctKey | 0xc8, /* (Shift) F11 */
1289 Shift | FctKey | 0xc9, /* (Shift) F12 */
1290 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
1291 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
1292 Alt | FctKey | 0xc8, /* (Alt) F11 */
1293 Alt | FctKey | 0xc9, /* (Alt) F12 */
1294 Ctrl | KeyPad | 8, /* (Ctrl) Up */
1295 Ctrl | Grey | 2, /* (Ctrl) Grey - */
1296 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
1298 /* --------------- 90 to 9f --------------- */
1299 Ctrl | Grey | 3, /* (Ctrl) Grey + */
1300 Ctrl | KeyPad | 2, /* (Ctrl) Down */
1301 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
1302 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
1303 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
1304 Ctrl | Grey | 0, /* (Ctrl) Grey / */
1305 Ctrl | Grey | 1, /* (Ctrl) Grey * */
1306 Alt | FctKey | 0x50, /* (Alt) Home */
1307 Alt | FctKey | 0x52, /* (Alt) Up */
1308 Alt | FctKey | 0x55, /* (Alt) Page Up */
1309 Ignore, /* NO KEY */
1310 Alt | FctKey | 0x51, /* (Alt) Left */
1311 Ignore, /* NO KEY */
1312 Alt | FctKey | 0x53, /* (Alt) Right */
1313 Ignore, /* NO KEY */
1314 Alt | FctKey | 0x57, /* (Alt) End */
1316 /* --------------- a0 to af --------------- */
1317 Alt | KeyPad | 2, /* (Alt) Down */
1318 Alt | KeyPad | 3, /* (Alt) Page Down */
1319 Alt | KeyPad | 0, /* (Alt) Insert */
1320 Alt | KeyPad | 10, /* (Alt) Delete */
1321 Alt | Grey | 0, /* (Alt) Grey / */
1322 Alt | FctKey | 0x09, /* (Alt) Tab */
1323 Alt | Grey | 4 /* (Alt) Keypad Enter */
1326 /* These bit-positions corresponds to values returned by BIOS */
1327 #define SHIFT_P 0x0003 /* two bits! */
1328 #define CTRL_P 0x0004
1329 #define ALT_P 0x0008
1330 #define SCRLOCK_P 0x0010
1331 #define NUMLOCK_P 0x0020
1332 #define CAPSLOCK_P 0x0040
1333 #define ALT_GR_P 0x0800
1334 #define SUPER_P 0x4000 /* pseudo */
1335 #define HYPER_P 0x8000 /* pseudo */
1337 static int
1338 dos_get_modifiers (keymask)
1339 int *keymask;
1341 union REGS regs;
1342 int mask;
1343 int modifiers = 0;
1345 /* Calculate modifier bits */
1346 regs.h.ah = extended_kbd ? 0x12 : 0x02;
1347 int86 (0x16, &regs, &regs);
1349 if (!extended_kbd)
1351 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
1352 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1354 else
1356 mask = regs.h.al & (SHIFT_P |
1357 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1359 /* Do not break international keyboard support. */
1360 /* When Keyb.Com is loaded, the right Alt key is */
1361 /* used for accessing characters like { and } */
1362 if (regs.h.ah & 2) /* Left ALT pressed ? */
1363 mask |= ALT_P;
1365 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
1367 mask |= ALT_GR_P;
1368 if (dos_hyper_key == 1)
1370 mask |= HYPER_P;
1371 modifiers |= hyper_modifier;
1373 else if (dos_super_key == 1)
1375 mask |= SUPER_P;
1376 modifiers |= super_modifier;
1380 if (regs.h.ah & 1) /* Left CTRL pressed ? */
1381 mask |= CTRL_P;
1383 if (regs.h.ah & 4) /* Right CTRL pressed ? */
1385 if (dos_hyper_key == 2)
1387 mask |= HYPER_P;
1388 modifiers |= hyper_modifier;
1390 else if (dos_super_key == 2)
1392 mask |= SUPER_P;
1393 modifiers |= super_modifier;
1395 else
1396 mask |= CTRL_P;
1400 if (mask & SHIFT_P)
1401 modifiers |= shift_modifier;
1402 if (mask & CTRL_P)
1403 modifiers |= ctrl_modifier;
1404 if (mask & ALT_P)
1405 modifiers |= meta_modifier;
1407 if (keymask)
1408 *keymask = mask;
1409 return modifiers;
1412 #define NUM_RECENT_DOSKEYS (100)
1413 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
1414 int total_doskeys; /* Total number of elements stored into recent_doskeys */
1415 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
1417 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
1418 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1419 Each input key receives two values in this vector: first the ASCII code,\n\
1420 and then the scan code.")
1423 Lisp_Object *keys = XVECTOR (recent_doskeys)->contents;
1424 Lisp_Object val;
1426 if (total_doskeys < NUM_RECENT_DOSKEYS)
1427 return Fvector (total_doskeys, keys);
1428 else
1430 val = Fvector (NUM_RECENT_DOSKEYS, keys);
1431 bcopy (keys + recent_doskeys_index,
1432 XVECTOR (val)->contents,
1433 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
1434 bcopy (keys,
1435 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
1436 recent_doskeys_index * sizeof (Lisp_Object));
1437 return val;
1441 /* Get a char from keyboard. Function keys are put into the event queue. */
1443 static int
1444 dos_rawgetc ()
1446 struct input_event event;
1447 union REGS regs;
1449 #ifndef HAVE_X_WINDOWS
1450 SCREEN_SET_CURSOR ();
1451 if (!mouse_visible) mouse_on ();
1452 #endif
1454 /* The following condition is equivalent to `kbhit ()', except that
1455 it uses the bios to do its job. This pleases DESQview/X. */
1456 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
1457 int86 (0x16, &regs, &regs),
1458 (regs.x.flags & 0x40) == 0)
1460 union REGS regs;
1461 register unsigned char c;
1462 int sc, code, mask, kp_mode;
1463 int modifiers;
1465 regs.h.ah = extended_kbd ? 0x10 : 0x00;
1466 int86 (0x16, &regs, &regs);
1467 c = regs.h.al;
1468 sc = regs.h.ah;
1470 total_doskeys += 2;
1471 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1472 = make_number (c);
1473 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1474 recent_doskeys_index = 0;
1475 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1476 = make_number (sc);
1477 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1478 recent_doskeys_index = 0;
1480 modifiers = dos_get_modifiers (&mask);
1482 #ifndef HAVE_X_WINDOWS
1483 if (!NILP (Vdos_display_scancodes))
1485 char buf[11];
1486 sprintf (buf, "%02x:%02x*%04x",
1487 (unsigned) (sc&0xff), (unsigned) c, mask);
1488 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
1490 #endif
1492 if (sc == 0xe0)
1494 switch (c)
1496 case 10: /* Ctrl Grey Enter */
1497 code = Ctrl | Grey | 4;
1498 break;
1499 case 13: /* Grey Enter */
1500 code = Grey | 4;
1501 break;
1502 case '/': /* Grey / */
1503 code = Grey | 0;
1504 break;
1505 default:
1506 continue;
1508 c = 0;
1510 else
1512 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
1513 continue;
1514 if ((code = ibmpc_translate_map[sc]) == Ignore)
1515 continue;
1518 if (c == 0)
1520 if (code & Alt)
1521 modifiers |= meta_modifier;
1522 if (code & Ctrl)
1523 modifiers |= ctrl_modifier;
1524 if (code & Shift)
1525 modifiers |= shift_modifier;
1528 switch (code & 0xf000)
1530 case ModFct:
1531 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
1532 return c;
1533 c = 0; /* Special */
1535 case FctKey:
1536 if (c != 0)
1537 return c;
1539 case Special:
1540 code |= 0xff00;
1541 break;
1543 case Normal:
1544 if (sc == 0)
1546 if (c == 0) /* ctrl-break */
1547 continue;
1548 return c; /* ALT-nnn */
1550 if (!keyboard_map_all)
1552 if (c != ' ')
1553 return c;
1554 code = c;
1555 break;
1558 case Map:
1559 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
1560 if (!keyboard_map_all)
1561 return c;
1563 code &= 0xff;
1564 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
1565 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
1567 if (mask & SHIFT_P)
1569 code = keyboard->shifted[code];
1570 mask -= SHIFT_P;
1571 modifiers &= ~shift_modifier;
1573 else
1574 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
1575 code = keyboard->alt_gr[code];
1576 else
1577 code = keyboard->unshifted[code];
1578 break;
1580 case KeyPad:
1581 code &= 0xff;
1582 if (c == 0xe0) /* edit key */
1583 kp_mode = 3;
1584 else
1585 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
1586 kp_mode = dos_keypad_mode & 0x03;
1587 else
1588 kp_mode = (dos_keypad_mode >> 4) & 0x03;
1590 switch (kp_mode)
1592 case 0:
1593 if (code == 10 && dos_decimal_point)
1594 return dos_decimal_point;
1595 return keypad_translate_map[code].char_code;
1597 case 1:
1598 code = 0xff00 | keypad_translate_map[code].keypad_code;
1599 break;
1601 case 2:
1602 code = keypad_translate_map[code].meta_code;
1603 modifiers = meta_modifier;
1604 break;
1606 case 3:
1607 code = 0xff00 | keypad_translate_map[code].editkey_code;
1608 break;
1610 break;
1612 case Grey:
1613 code &= 0xff;
1614 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
1615 if (dos_keypad_mode & kp_mode)
1616 code = 0xff00 | grey_key_translate_map[code].keypad_code;
1617 else
1618 code = grey_key_translate_map[code].char_code;
1619 break;
1622 make_event:
1623 if (code == 0)
1624 continue;
1626 if (code >= 0x100)
1627 event.kind = non_ascii_keystroke;
1628 else
1629 event.kind = ascii_keystroke;
1630 event.code = code;
1631 event.modifiers = modifiers;
1632 XSETFRAME (event.frame_or_window, selected_frame);
1633 event.timestamp = event_timestamp ();
1634 kbd_buffer_store_event (&event);
1637 if (have_mouse > 0)
1639 int but, press, x, y, ok;
1641 /* Check for mouse movement *before* buttons. */
1642 mouse_check_moved ();
1644 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
1645 for (press = 0; press < 2; press++)
1647 int button_num = but;
1649 if (press)
1650 ok = mouse_pressed (but, &x, &y);
1651 else
1652 ok = mouse_released (but, &x, &y);
1653 if (ok)
1655 /* Allow a simultaneous press/release of Mouse-1 and
1656 Mouse-2 to simulate Mouse-3 on two-button mice. */
1657 if (mouse_button_count == 2 && but < 2)
1659 int x2, y2; /* don't clobber original coordinates */
1661 /* If only one button is pressed, wait 100 msec and
1662 check again. This way, Speedy Gonzales isn't
1663 punished, while the slow get their chance. */
1664 if (press && mouse_pressed (1-but, &x2, &y2)
1665 || !press && mouse_released (1-but, &x2, &y2))
1666 button_num = 2;
1667 else
1669 delay (100);
1670 if (press && mouse_pressed (1-but, &x2, &y2)
1671 || !press && mouse_released (1-but, &x2, &y2))
1672 button_num = 2;
1676 event.kind = mouse_click;
1677 event.code = button_num;
1678 event.modifiers = dos_get_modifiers (0)
1679 | (press ? down_modifier : up_modifier);
1680 event.x = x;
1681 event.y = y;
1682 XSETFRAME (event.frame_or_window, selected_frame);
1683 event.timestamp = event_timestamp ();
1684 kbd_buffer_store_event (&event);
1689 return -1;
1692 static int prev_get_char = -1;
1694 /* Return 1 if a key is ready to be read without suspending execution. */
1696 dos_keysns ()
1698 if (prev_get_char != -1)
1699 return 1;
1700 else
1701 return ((prev_get_char = dos_rawgetc ()) != -1);
1704 /* Read a key. Return -1 if no key is ready. */
1706 dos_keyread ()
1708 if (prev_get_char != -1)
1710 int c = prev_get_char;
1711 prev_get_char = -1;
1712 return c;
1714 else
1715 return dos_rawgetc ();
1718 #ifndef HAVE_X_WINDOWS
1719 /* See xterm.c for more info. */
1720 void
1721 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
1722 FRAME_PTR f;
1723 register int pix_x, pix_y;
1724 register int *x, *y;
1725 void /* XRectangle */ *bounds;
1726 int noclip;
1728 if (bounds) abort ();
1730 /* Ignore clipping. */
1732 *x = pix_x;
1733 *y = pix_y;
1736 void
1737 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1738 FRAME_PTR f;
1739 register int x, y;
1740 register int *pix_x, *pix_y;
1742 *pix_x = x;
1743 *pix_y = y;
1746 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1747 for now.
1749 Actually, I don't know the meaning of all the parameters of the functions
1750 here -- I only know how they are called by xmenu.c. I could of course
1751 grab the nearest Xlib manual (down the hall, second-to-last door on the
1752 left), but I don't think it's worth the effort. */
1754 static XMenu *
1755 IT_menu_create ()
1757 XMenu *menu;
1759 menu = (XMenu *) xmalloc (sizeof (XMenu));
1760 menu->allocated = menu->count = menu->panecount = menu->width = 0;
1761 return menu;
1764 /* Allocate some (more) memory for MENU ensuring that there is room for one
1765 for item. */
1767 static void
1768 IT_menu_make_room (XMenu *menu)
1770 if (menu->allocated == 0)
1772 int count = menu->allocated = 10;
1773 menu->text = (char **) xmalloc (count * sizeof (char *));
1774 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
1775 menu->panenumber = (int *) xmalloc (count * sizeof (int));
1777 else if (menu->allocated == menu->count)
1779 int count = menu->allocated = menu->allocated + 10;
1780 menu->text
1781 = (char **) xrealloc (menu->text, count * sizeof (char *));
1782 menu->submenu
1783 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
1784 menu->panenumber
1785 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
1789 /* Search the given menu structure for a given pane number. */
1791 static XMenu *
1792 IT_menu_search_pane (XMenu *menu, int pane)
1794 int i;
1795 XMenu *try;
1797 for (i = 0; i < menu->count; i++)
1798 if (menu->submenu[i])
1800 if (pane == menu->panenumber[i])
1801 return menu->submenu[i];
1802 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
1803 return try;
1805 return (XMenu *) 0;
1808 /* Determine how much screen space a given menu needs. */
1810 static void
1811 IT_menu_calc_size (XMenu *menu, int *width, int *height)
1813 int i, h2, w2, maxsubwidth, maxheight;
1815 maxsubwidth = 0;
1816 maxheight = menu->count;
1817 for (i = 0; i < menu->count; i++)
1819 if (menu->submenu[i])
1821 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
1822 if (w2 > maxsubwidth) maxsubwidth = w2;
1823 if (i + h2 > maxheight) maxheight = i + h2;
1826 *width = menu->width + maxsubwidth;
1827 *height = maxheight;
1830 /* Display MENU at (X,Y) using FACES. */
1832 static void
1833 IT_menu_display (XMenu *menu, int y, int x, int *faces)
1835 int i, j, face, width;
1836 GLYPH *text, *p;
1837 char *q;
1838 int mx, my;
1839 int enabled, mousehere;
1840 int row, col;
1842 width = menu->width;
1843 text = (GLYPH *) xmalloc ((width + 2) * sizeof (GLYPH));
1844 ScreenGetCursor (&row, &col);
1845 mouse_get_xy (&mx, &my);
1846 IT_update_begin ();
1847 for (i = 0; i < menu->count; i++)
1849 IT_cursor_to (y + i, x);
1850 enabled
1851 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
1852 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
1853 face = faces[enabled + mousehere * 2];
1854 p = text;
1855 *p++ = FAST_MAKE_GLYPH (' ', face);
1856 for (j = 0, q = menu->text[i]; *q; j++)
1858 if (*q > 26)
1859 *p++ = FAST_MAKE_GLYPH (*q++, face);
1860 else /* make '^x' */
1862 *p++ = FAST_MAKE_GLYPH ('^', face);
1863 j++;
1864 *p++ = FAST_MAKE_GLYPH (*q++ + 64, face);
1868 for (; j < width; j++)
1869 *p++ = FAST_MAKE_GLYPH (' ', face);
1870 *p++ = FAST_MAKE_GLYPH (menu->submenu[i] ? 16 : ' ', face);
1871 IT_write_glyphs (text, width + 2);
1873 IT_update_end ();
1874 IT_cursor_to (row, col);
1875 xfree (text);
1878 /* --------------------------- X Menu emulation ---------------------- */
1880 /* Report availability of menus. */
1883 have_menus_p ()
1885 return 1;
1888 /* Create a brand new menu structure. */
1890 XMenu *
1891 XMenuCreate (Display *foo1, Window foo2, char *foo3)
1893 return IT_menu_create ();
1896 /* Create a new pane and place it on the outer-most level. It is not
1897 clear that it should be placed out there, but I don't know what else
1898 to do. */
1901 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
1903 int len;
1904 char *p;
1906 if (!enable)
1907 abort ();
1909 IT_menu_make_room (menu);
1910 menu->submenu[menu->count] = IT_menu_create ();
1911 menu->text[menu->count] = txt;
1912 menu->panenumber[menu->count] = ++menu->panecount;
1913 menu->count++;
1915 /* Adjust length for possible control characters (which will
1916 be written as ^x). */
1917 for (len = strlen (txt), p = txt; *p; p++)
1918 if (*p < 27)
1919 len++;
1921 if (len > menu->width)
1922 menu->width = len;
1924 return menu->panecount;
1927 /* Create a new item in a menu pane. */
1930 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
1931 int foo, char *txt, int enable)
1933 int len;
1934 char *p;
1936 if (pane)
1937 if (!(menu = IT_menu_search_pane (menu, pane)))
1938 return XM_FAILURE;
1939 IT_menu_make_room (menu);
1940 menu->submenu[menu->count] = (XMenu *) 0;
1941 menu->text[menu->count] = txt;
1942 menu->panenumber[menu->count] = enable;
1943 menu->count++;
1945 /* Adjust length for possible control characters (which will
1946 be written as ^x). */
1947 for (len = strlen (txt), p = txt; *p; p++)
1948 if (*p < 27)
1949 len++;
1951 if (len > menu->width)
1952 menu->width = len;
1954 return XM_SUCCESS;
1957 /* Decide where the menu would be placed if requested at (X,Y). */
1959 void
1960 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
1961 int *ulx, int *uly, int *width, int *height)
1963 IT_menu_calc_size (menu, width, height);
1964 *ulx = x + 1;
1965 *uly = y;
1966 *width += 2;
1969 struct IT_menu_state
1971 void *screen_behind;
1972 XMenu *menu;
1973 int pane;
1974 int x, y;
1978 /* Display menu, wait for user's response, and return that response. */
1981 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
1982 int x0, int y0, unsigned ButtonMask, char **txt)
1984 struct IT_menu_state *state;
1985 int statecount;
1986 int x, y, i, b;
1987 int screensize;
1988 int faces[4], selectface;
1989 int leave, result, onepane;
1990 int title_faces[4]; /* face to display the menu title */
1991 int buffers_num_deleted = 0;
1993 /* Just in case we got here without a mouse present... */
1994 if (have_mouse <= 0)
1995 return XM_IA_SELECT;
1997 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
1998 screensize = screen_size * 2;
1999 faces[0]
2000 = compute_glyph_face (selected_frame,
2001 face_name_id_number
2002 (selected_frame,
2003 intern ("msdos-menu-passive-face")),
2005 faces[1]
2006 = compute_glyph_face (selected_frame,
2007 face_name_id_number
2008 (selected_frame,
2009 intern ("msdos-menu-active-face")),
2011 selectface
2012 = face_name_id_number (selected_frame, intern ("msdos-menu-select-face"));
2013 faces[2] = compute_glyph_face (selected_frame, selectface, faces[0]);
2014 faces[3] = compute_glyph_face (selected_frame, selectface, faces[1]);
2016 /* Make sure the menu title is always displayed with
2017 `msdos-menu-active-face', no matter where the mouse pointer is. */
2018 for (i = 0; i < 4; i++)
2019 title_faces[i] = faces[3];
2021 statecount = 1;
2023 /* Don't let the title for the "Buffers" popup menu include a
2024 digit (which is ugly).
2026 This is a terrible kludge, but I think the "Buffers" case is
2027 the only one where the title includes a number, so it doesn't
2028 seem to be necessary to make this more general. */
2029 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
2031 menu->text[0][7] = '\0';
2032 buffers_num_deleted = 1;
2034 state[0].menu = menu;
2035 mouse_off ();
2036 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
2038 IT_menu_display (menu, y0 - 1, x0 - 1, title_faces); /* display menu title */
2039 if (buffers_num_deleted)
2040 menu->text[0][7] = ' ';
2041 if ((onepane = menu->count == 1 && menu->submenu[0]))
2043 menu->width = menu->submenu[0]->width;
2044 state[0].menu = menu->submenu[0];
2046 else
2048 state[0].menu = menu;
2050 state[0].x = x0 - 1;
2051 state[0].y = y0;
2052 state[0].pane = onepane;
2054 mouse_last_x = -1; /* A hack that forces display. */
2055 leave = 0;
2056 while (!leave)
2058 if (!mouse_visible) mouse_on ();
2059 mouse_check_moved ();
2060 if (selected_frame->mouse_moved)
2062 selected_frame->mouse_moved = 0;
2063 result = XM_IA_SELECT;
2064 mouse_get_xy (&x, &y);
2065 for (i = 0; i < statecount; i++)
2066 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
2068 int dy = y - state[i].y;
2069 if (0 <= dy && dy < state[i].menu->count)
2071 if (!state[i].menu->submenu[dy])
2072 if (state[i].menu->panenumber[dy])
2073 result = XM_SUCCESS;
2074 else
2075 result = XM_IA_SELECT;
2076 *pane = state[i].pane - 1;
2077 *selidx = dy;
2078 /* We hit some part of a menu, so drop extra menus that
2079 have been opened. That does not include an open and
2080 active submenu. */
2081 if (i != statecount - 2
2082 || state[i].menu->submenu[dy] != state[i+1].menu)
2083 while (i != statecount - 1)
2085 statecount--;
2086 mouse_off ();
2087 ScreenUpdate (state[statecount].screen_behind);
2088 xfree (state[statecount].screen_behind);
2090 if (i == statecount - 1 && state[i].menu->submenu[dy])
2092 IT_menu_display (state[i].menu,
2093 state[i].y,
2094 state[i].x,
2095 faces);
2096 state[statecount].menu = state[i].menu->submenu[dy];
2097 state[statecount].pane = state[i].menu->panenumber[dy];
2098 mouse_off ();
2099 ScreenRetrieve (state[statecount].screen_behind
2100 = xmalloc (screensize));
2101 state[statecount].x
2102 = state[i].x + state[i].menu->width + 2;
2103 state[statecount].y = y;
2104 statecount++;
2108 IT_menu_display (state[statecount - 1].menu,
2109 state[statecount - 1].y,
2110 state[statecount - 1].x,
2111 faces);
2113 for (b = 0; b < mouse_button_count; b++)
2115 (void) mouse_pressed (b, &x, &y);
2116 if (mouse_released (b, &x, &y))
2117 leave = 1;
2121 mouse_off ();
2122 ScreenUpdate (state[0].screen_behind);
2123 while (statecount--)
2124 xfree (state[statecount].screen_behind);
2125 return result;
2128 /* Dispose of a menu. */
2130 void
2131 XMenuDestroy (Display *foo, XMenu *menu)
2133 int i;
2134 if (menu->allocated)
2136 for (i = 0; i < menu->count; i++)
2137 if (menu->submenu[i])
2138 XMenuDestroy (foo, menu->submenu[i]);
2139 xfree (menu->text);
2140 xfree (menu->submenu);
2141 xfree (menu->panenumber);
2143 xfree (menu);
2147 x_pixel_width (struct frame *f)
2149 return FRAME_WIDTH (f);
2153 x_pixel_height (struct frame *f)
2155 return FRAME_HEIGHT (f);
2157 #endif /* !HAVE_X_WINDOWS */
2159 /* ----------------------- DOS / UNIX conversion --------------------- */
2161 void msdos_downcase_filename (unsigned char *);
2163 /* Destructively turn backslashes into slashes. */
2165 void
2166 dostounix_filename (p)
2167 register char *p;
2169 msdos_downcase_filename (p);
2171 while (*p)
2173 if (*p == '\\')
2174 *p = '/';
2175 p++;
2179 /* Destructively turn slashes into backslashes. */
2181 void
2182 unixtodos_filename (p)
2183 register char *p;
2185 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
2187 *p += 'a' - 'A';
2188 p += 2;
2191 while (*p)
2193 if (*p == '/')
2194 *p = '\\';
2195 p++;
2199 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2202 getdefdir (drive, dst)
2203 int drive;
2204 char *dst;
2206 char in_path[4], *p = in_path;
2207 int e = errno;
2209 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2210 if (drive != 0)
2212 *p++ = drive + 'A' - 1;
2213 *p++ = ':';
2216 *p++ = '.';
2217 *p = '\0';
2218 errno = 0;
2219 _fixpath (in_path, dst);
2220 if (errno)
2221 return 0;
2223 msdos_downcase_filename (dst);
2225 errno = e;
2226 return 1;
2229 /* Remove all CR's that are followed by a LF. */
2232 crlf_to_lf (n, buf)
2233 register int n;
2234 register unsigned char *buf;
2236 unsigned char *np = buf;
2237 unsigned char *startp = buf;
2238 unsigned char *endp = buf + n;
2239 unsigned char c;
2241 if (n == 0)
2242 return n;
2243 while (buf < endp - 1)
2245 if (*buf == 0x0d)
2247 if (*(++buf) != 0x0a)
2248 *np++ = 0x0d;
2250 else
2251 *np++ = *buf++;
2253 if (buf < endp)
2254 *np++ = *buf++;
2255 return np - startp;
2258 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
2260 /* In DJGPP v2.0, library `write' can call `malloc', which might
2261 cause relocation of the buffer whose address we get in ADDR.
2262 Here is a version of `write' that avoids calling `malloc',
2263 to serve us until such time as the library is fixed.
2264 Actually, what we define here is called `__write', because
2265 `write' is a stub that just jmp's to `__write' (to be
2266 POSIXLY-correct with respect to the global name-space). */
2268 #include <io.h> /* for _write */
2269 #include <libc/dosio.h> /* for __file_handle_modes[] */
2271 static char xbuf[64 * 1024]; /* DOS cannot write more in one chunk */
2273 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
2276 __write (int handle, const void *buffer, size_t count)
2278 if (count == 0)
2279 return 0;
2281 if(__file_handle_modes[handle] & O_BINARY)
2282 return _write (handle, buffer, count);
2283 else
2285 char *xbp = xbuf;
2286 const char *bp = buffer;
2287 int total_written = 0;
2288 int nmoved = 0, ncr = 0;
2290 while (count)
2292 /* The next test makes sure there's space for at least 2 more
2293 characters in xbuf[], so both CR and LF can be put there. */
2294 if (xbp < XBUF_END)
2296 if (*bp == '\n')
2298 ncr++;
2299 *xbp++ = '\r';
2301 *xbp++ = *bp++;
2302 nmoved++;
2303 count--;
2305 if (xbp >= XBUF_END || !count)
2307 size_t to_write = nmoved + ncr;
2308 int written = _write (handle, xbuf, to_write);
2310 if (written == -1)
2311 return -1;
2312 else
2313 total_written += nmoved; /* CRs aren't counted in ret value */
2315 /* If some, but not all were written (disk full?), return
2316 an estimate of the total written bytes not counting CRs. */
2317 if (written < to_write)
2318 return total_written - (to_write - written) * nmoved/to_write;
2320 nmoved = 0;
2321 ncr = 0;
2322 xbp = xbuf;
2325 return total_written;
2329 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
2331 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
2332 0, 0, 0,
2333 "Return non-nil if long file names are supported on MSDOS.")
2336 return (_USE_LFN ? Qt : Qnil);
2339 /* Convert alphabetic characters in a filename to lower-case. */
2341 void
2342 msdos_downcase_filename (p)
2343 register unsigned char *p;
2345 /* Always lower-case drive letters a-z, even if the filesystem
2346 preserves case in filenames.
2347 This is so MSDOS filenames could be compared by string comparison
2348 functions that are case-sensitive. Even case-preserving filesystems
2349 do not distinguish case in drive letters. */
2350 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
2352 *p += 'a' - 'A';
2353 p += 2;
2356 /* Under LFN we expect to get pathnames in their true case. */
2357 if (NILP (Fmsdos_long_file_names ()))
2358 for ( ; *p; p++)
2359 if (*p >= 'A' && *p <= 'Z')
2360 *p += 'a' - 'A';
2363 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
2364 1, 1, 0,
2365 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
2366 When long filenames are supported, doesn't change FILENAME.\n\
2367 If FILENAME is not a string, returns nil.\n\
2368 The argument object is never altered--the value is a copy.")
2369 (filename)
2370 Lisp_Object filename;
2372 char *fname;
2373 Lisp_Object tem;
2375 if (! STRINGP (filename))
2376 return Qnil;
2378 tem = Fcopy_sequence (filename);
2379 msdos_downcase_filename (XSTRING (tem)->data);
2380 return tem;
2383 /* The Emacs root directory as determined by init_environment. */
2385 static char emacsroot[MAXPATHLEN];
2387 char *
2388 rootrelativepath (rel)
2389 char *rel;
2391 static char result[MAXPATHLEN + 10];
2393 strcpy (result, emacsroot);
2394 strcat (result, "/");
2395 strcat (result, rel);
2396 return result;
2399 /* Define a lot of environment variables if not already defined. Don't
2400 remove anything unless you know what you're doing -- lots of code will
2401 break if one or more of these are missing. */
2403 void
2404 init_environment (argc, argv, skip_args)
2405 int argc;
2406 char **argv;
2407 int skip_args;
2409 char *s, *t, *root;
2410 int len;
2412 /* Find our root from argv[0]. Assuming argv[0] is, say,
2413 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
2414 root = alloca (MAXPATHLEN + 20);
2415 _fixpath (argv[0], root);
2416 msdos_downcase_filename (root);
2417 len = strlen (root);
2418 while (len > 0 && root[len] != '/' && root[len] != ':')
2419 len--;
2420 root[len] = '\0';
2421 if (len > 4 && strcmp (root + len - 4, "/bin") == 0)
2422 root[len - 4] = '\0';
2423 else
2424 strcpy (root, "c:/emacs"); /* Only under debuggers, I think. */
2425 len = strlen (root);
2426 strcpy (emacsroot, root);
2428 /* We default HOME to our root. */
2429 setenv ("HOME", root, 0);
2431 /* We default EMACSPATH to root + "/bin". */
2432 strcpy (root + len, "/bin");
2433 setenv ("EMACSPATH", root, 0);
2435 /* I don't expect anybody to ever use other terminals so the internal
2436 terminal is the default. */
2437 setenv ("TERM", "internal", 0);
2439 #ifdef HAVE_X_WINDOWS
2440 /* Emacs expects DISPLAY to be set. */
2441 setenv ("DISPLAY", "unix:0.0", 0);
2442 #endif
2444 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
2445 downcase it and mirror the backslashes. */
2446 s = getenv ("COMSPEC");
2447 if (!s) s = "c:/command.com";
2448 t = alloca (strlen (s) + 1);
2449 strcpy (t, s);
2450 dostounix_filename (t);
2451 setenv ("SHELL", t, 0);
2453 /* PATH is also downcased and backslashes mirrored. */
2454 s = getenv ("PATH");
2455 if (!s) s = "";
2456 t = alloca (strlen (s) + 3);
2457 /* Current directory is always considered part of MsDos's path but it is
2458 not normally mentioned. Now it is. */
2459 strcat (strcpy (t, ".;"), s);
2460 dostounix_filename (t); /* Not a single file name, but this should work. */
2461 setenv ("PATH", t, 1);
2463 /* In some sense all dos users have root privileges, so... */
2464 setenv ("USER", "root", 0);
2465 setenv ("NAME", getenv ("USER"), 0);
2467 /* Time zone determined from country code. To make this possible, the
2468 country code may not span more than one time zone. In other words,
2469 in the USA, you lose. */
2470 if (!getenv ("TZ"))
2471 switch (dos_country_code)
2473 case 31: /* Belgium */
2474 case 32: /* The Netherlands */
2475 case 33: /* France */
2476 case 34: /* Spain */
2477 case 36: /* Hungary */
2478 case 38: /* Yugoslavia (or what's left of it?) */
2479 case 39: /* Italy */
2480 case 41: /* Switzerland */
2481 case 42: /* Tjekia */
2482 case 45: /* Denmark */
2483 case 46: /* Sweden */
2484 case 47: /* Norway */
2485 case 48: /* Poland */
2486 case 49: /* Germany */
2487 /* Daylight saving from last Sunday in March to last Sunday in
2488 September, both at 2AM. */
2489 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2490 break;
2491 case 44: /* United Kingdom */
2492 case 351: /* Portugal */
2493 case 354: /* Iceland */
2494 setenv ("TZ", "GMT+00", 0);
2495 break;
2496 case 81: /* Japan */
2497 case 82: /* Korea */
2498 setenv ("TZ", "JST-09", 0);
2499 break;
2500 case 90: /* Turkey */
2501 case 358: /* Finland */
2502 setenv ("TZ", "EET-02", 0);
2503 break;
2504 case 972: /* Israel */
2505 /* This is an approximation. (For exact rules, use the
2506 `zoneinfo/israel' file which comes with DJGPP, but you need
2507 to install it in `/usr/share/zoneinfo/' directory first.) */
2508 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2509 break;
2511 tzset ();
2516 static int break_stat; /* BREAK check mode status. */
2517 static int stdin_stat; /* stdin IOCTL status. */
2519 #if __DJGPP__ < 2
2521 /* These must be global. */
2522 static _go32_dpmi_seginfo ctrl_break_vector;
2523 static _go32_dpmi_registers ctrl_break_regs;
2524 static int ctrlbreakinstalled = 0;
2526 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2528 void
2529 ctrl_break_func (regs)
2530 _go32_dpmi_registers *regs;
2532 Vquit_flag = Qt;
2535 void
2536 install_ctrl_break_check ()
2538 if (!ctrlbreakinstalled)
2540 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2541 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2542 ctrlbreakinstalled = 1;
2543 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
2544 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
2545 &ctrl_break_regs);
2546 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
2550 #endif /* __DJGPP__ < 2 */
2552 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
2553 control chars by DOS. Determine the keyboard type. */
2556 dos_ttraw ()
2558 union REGS inregs, outregs;
2559 static int first_time = 1;
2561 break_stat = getcbrk ();
2562 setcbrk (0);
2563 #if __DJGPP__ < 2
2564 install_ctrl_break_check ();
2565 #endif
2567 if (first_time)
2569 inregs.h.ah = 0xc0;
2570 int86 (0x15, &inregs, &outregs);
2571 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
2573 have_mouse = 0;
2575 if (internal_terminal
2576 #ifdef HAVE_X_WINDOWS
2577 && inhibit_window_system
2578 #endif
2581 inregs.x.ax = 0x0021;
2582 int86 (0x33, &inregs, &outregs);
2583 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2584 if (!have_mouse)
2586 /* Reportedly, the above doesn't work for some mouse drivers. There
2587 is an additional detection method that should work, but might be
2588 a little slower. Use that as an alternative. */
2589 inregs.x.ax = 0x0000;
2590 int86 (0x33, &inregs, &outregs);
2591 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2594 if (have_mouse)
2596 have_mouse = 1; /* enable mouse */
2597 mouse_visible = 0;
2599 if (outregs.x.bx == 3)
2601 mouse_button_count = 3;
2602 mouse_button_translate[0] = 0; /* Left */
2603 mouse_button_translate[1] = 2; /* Middle */
2604 mouse_button_translate[2] = 1; /* Right */
2606 else
2608 mouse_button_count = 2;
2609 mouse_button_translate[0] = 0;
2610 mouse_button_translate[1] = 1;
2612 mouse_position_hook = &mouse_get_pos;
2613 mouse_init ();
2617 first_time = 0;
2619 #if __DJGPP__ >= 2
2621 stdin_stat = setmode (fileno (stdin), O_BINARY);
2622 return (stdin_stat != -1);
2624 else
2625 return (setmode (fileno (stdin), O_BINARY) != -1);
2627 #else /* __DJGPP__ < 2 */
2631 /* I think it is wrong to overwrite `stdin_stat' every time
2632 but the first one this function is called, but I don't
2633 want to change the way it used to work in v1.x.--EZ */
2635 inregs.x.ax = 0x4400; /* Get IOCTL status. */
2636 inregs.x.bx = 0x00; /* 0 = stdin. */
2637 intdos (&inregs, &outregs);
2638 stdin_stat = outregs.h.dl;
2640 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
2641 inregs.x.ax = 0x4401; /* Set IOCTL status */
2642 intdos (&inregs, &outregs);
2643 return !outregs.x.cflag;
2645 #endif /* __DJGPP__ < 2 */
2648 /* Restore status of standard input and Ctrl-C checking. */
2651 dos_ttcooked ()
2653 union REGS inregs, outregs;
2655 setcbrk (break_stat);
2656 mouse_off ();
2658 #if __DJGPP__ >= 2
2660 return (setmode (fileno (stdin), stdin_stat) != -1);
2662 #else /* not __DJGPP__ >= 2 */
2664 inregs.x.ax = 0x4401; /* Set IOCTL status. */
2665 inregs.x.bx = 0x00; /* 0 = stdin. */
2666 inregs.x.dx = stdin_stat;
2667 intdos (&inregs, &outregs);
2668 return !outregs.x.cflag;
2670 #endif /* not __DJGPP__ >= 2 */
2674 /* Run command as specified by ARGV in directory DIR.
2675 The command is run with input from TEMPIN, output to
2676 file TEMPOUT and stderr to TEMPERR. */
2679 run_msdos_command (argv, dir, tempin, tempout, temperr)
2680 unsigned char **argv;
2681 Lisp_Object dir;
2682 int tempin, tempout, temperr;
2684 char *saveargv1, *saveargv2, **envv;
2685 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
2686 int msshell, result = -1;
2687 int in, out, inbak, outbak, errbak;
2688 int x, y;
2689 Lisp_Object cmd;
2691 /* Get current directory as MSDOS cwd is not per-process. */
2692 getwd (oldwd);
2694 cmd = Ffile_name_nondirectory (build_string (argv[0]));
2695 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
2696 && !strcmp ("-c", argv[1]);
2697 if (msshell)
2699 saveargv1 = argv[1];
2700 saveargv2 = argv[2];
2701 argv[1] = "/c";
2702 if (argv[2])
2704 char *p = alloca (strlen (argv[2]) + 1);
2706 strcpy (argv[2] = p, saveargv2);
2707 while (*p && isspace (*p))
2708 p++;
2709 while (*p && !isspace (*p))
2710 if (*p == '/')
2711 *p++ = '\\';
2712 else
2713 p++;
2717 /* Build the environment array. */
2719 extern Lisp_Object Vprocess_environment;
2720 Lisp_Object tmp, lst;
2721 int i, len;
2723 lst = Vprocess_environment;
2724 len = XFASTINT (Flength (lst));
2726 envv = alloca ((len + 1) * sizeof (char *));
2727 for (i = 0; i < len; i++)
2729 tmp = Fcar (lst);
2730 lst = Fcdr (lst);
2731 CHECK_STRING (tmp, 0);
2732 envv[i] = alloca (XSTRING (tmp)->size + 1);
2733 strcpy (envv[i], XSTRING (tmp)->data);
2735 envv[len] = (char *) 0;
2738 if (STRINGP (dir))
2739 chdir (XSTRING (dir)->data);
2740 inbak = dup (0);
2741 outbak = dup (1);
2742 errbak = dup (2);
2743 if (inbak < 0 || outbak < 0 || errbak < 0)
2744 goto done; /* Allocation might fail due to lack of descriptors. */
2746 if (have_mouse > 0)
2747 mouse_get_xy (&x, &y);
2749 dos_ttcooked (); /* do it here while 0 = stdin */
2751 dup2 (tempin, 0);
2752 dup2 (tempout, 1);
2753 dup2 (temperr, 2);
2755 #if __DJGPP__ > 1
2757 if (msshell && !argv[3])
2759 /* MS-DOS native shells are too restrictive. For starters, they
2760 cannot grok commands longer than 126 characters. In DJGPP v2
2761 and later, `system' is much smarter, so we'll call it instead. */
2763 extern char **environ;
2764 environ = envv;
2766 /* A shell gets a single argument--its full command
2767 line--whose original was saved in `saveargv2'. */
2768 result = system (saveargv2);
2770 else
2772 #endif /* __DJGPP__ > 1 */
2774 result = spawnve (P_WAIT, argv[0], argv, envv);
2776 dup2 (inbak, 0);
2777 dup2 (outbak, 1);
2778 dup2 (errbak, 2);
2779 close (inbak);
2780 close (outbak);
2781 close (errbak);
2783 dos_ttraw ();
2784 if (have_mouse > 0)
2786 mouse_init ();
2787 mouse_moveto (x, y);
2790 done:
2791 chdir (oldwd);
2792 if (msshell)
2794 argv[1] = saveargv1;
2795 argv[2] = saveargv2;
2797 return result;
2800 croak (badfunc)
2801 char *badfunc;
2803 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
2804 reset_sys_modes ();
2805 exit (1);
2808 #if __DJGPP__ < 2
2810 /* ------------------------- Compatibility functions -------------------
2811 * gethostname
2812 * gettimeofday
2815 /* Hostnames for a pc are not really funny,
2816 but they are used in change log so we emulate the best we can. */
2818 gethostname (p, size)
2819 char *p;
2820 int size;
2822 char *q = egetenv ("HOSTNAME");
2824 if (!q) q = "pc";
2825 strcpy (p, q);
2826 return 0;
2829 /* When time zones are set from Ms-Dos too many C-libraries are playing
2830 tricks with time values. We solve this by defining our own version
2831 of `gettimeofday' bypassing GO32. Our version needs to be initialized
2832 once and after each call to `tzset' with TZ changed. That is
2833 accomplished by aliasing tzset to init_gettimeofday. */
2835 static struct tm time_rec;
2838 gettimeofday (struct timeval *tp, struct timezone *tzp)
2840 if (tp)
2842 struct time t;
2843 struct tm tm;
2845 gettime (&t);
2846 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
2848 struct date d;
2849 getdate (&d);
2850 time_rec.tm_year = d.da_year - 1900;
2851 time_rec.tm_mon = d.da_mon - 1;
2852 time_rec.tm_mday = d.da_day;
2855 time_rec.tm_hour = t.ti_hour;
2856 time_rec.tm_min = t.ti_min;
2857 time_rec.tm_sec = t.ti_sec;
2859 tm = time_rec;
2860 tm.tm_gmtoff = dos_timezone_offset;
2862 tp->tv_sec = mktime (&tm); /* may modify tm */
2863 tp->tv_usec = t.ti_hund * (1000000 / 100);
2865 /* Ignore tzp; it's obsolescent. */
2866 return 0;
2869 #endif /* __DJGPP__ < 2 */
2872 * A list of unimplemented functions that we silently ignore.
2875 #if __DJGPP__ < 2
2876 unsigned alarm (s) unsigned s; {}
2877 fork () { return 0; }
2878 int kill (x, y) int x, y; { return -1; }
2879 nice (p) int p; {}
2880 void volatile pause () {}
2881 sigsetmask (x) int x; { return 0; }
2882 #endif
2884 request_sigio () {}
2885 setpgrp () {return 0; }
2886 setpriority (x,y,z) int x,y,z; { return 0; }
2887 sigblock (mask) int mask; { return 0; }
2888 unrequest_sigio () {}
2890 #ifndef HAVE_SELECT
2891 #include "sysselect.h"
2893 #ifndef EMACS_TIME_ZERO_OR_NEG_P
2894 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
2895 ((long)(time).tv_sec < 0 \
2896 || ((time).tv_sec == 0 \
2897 && (long)(time).tv_usec <= 0))
2898 #endif
2901 /* Only event queue is checked. */
2902 /* We don't have to call timer_check here
2903 because wait_reading_process_input takes care of that. */
2905 sys_select (nfds, rfds, wfds, efds, timeout)
2906 int nfds;
2907 SELECT_TYPE *rfds, *wfds, *efds;
2908 EMACS_TIME *timeout;
2910 int check_input;
2911 struct time t;
2913 check_input = 0;
2914 if (rfds)
2916 check_input = FD_ISSET (0, rfds);
2917 FD_ZERO (rfds);
2919 if (wfds)
2920 FD_ZERO (wfds);
2921 if (efds)
2922 FD_ZERO (efds);
2924 if (nfds != 1)
2925 abort ();
2927 /* If we are looking only for the terminal, with no timeout,
2928 just read it and wait -- that's more efficient. */
2929 if (!timeout)
2931 while (!detect_input_pending ())
2933 #if __DJGPP__ >= 2
2934 __dpmi_yield ();
2935 #endif
2938 else
2940 EMACS_TIME clnow, cllast, cldiff;
2942 gettime (&t);
2943 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
2945 while (!check_input || !detect_input_pending ())
2947 gettime (&t);
2948 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
2949 EMACS_SUB_TIME (cldiff, clnow, cllast);
2951 /* When seconds wrap around, we assume that no more than
2952 1 minute passed since last `gettime'. */
2953 if (EMACS_TIME_NEG_P (cldiff))
2954 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
2955 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
2957 /* Stop when timeout value crosses zero. */
2958 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
2959 return 0;
2960 cllast = clnow;
2961 #if __DJGPP__ >= 2
2962 __dpmi_yield ();
2963 #endif
2967 FD_SET (0, rfds);
2968 return 1;
2970 #endif
2973 * Define overlaid functions:
2975 * chdir -> sys_chdir
2976 * tzset -> init_gettimeofday
2977 * abort -> dos_abort
2980 #ifdef chdir
2981 #undef chdir
2982 extern int chdir ();
2985 sys_chdir (path)
2986 const char* path;
2988 int len = strlen (path);
2989 char *tmp = (char *)path;
2991 if (*tmp && tmp[1] == ':')
2993 if (getdisk () != tolower (tmp[0]) - 'a')
2994 setdisk (tolower (tmp[0]) - 'a');
2995 tmp += 2; /* strip drive: KFS 1995-07-06 */
2996 len -= 2;
2999 if (len > 1 && (tmp[len - 1] == '/'))
3001 char *tmp1 = (char *) alloca (len + 1);
3002 strcpy (tmp1, tmp);
3003 tmp1[len - 1] = 0;
3004 tmp = tmp1;
3006 return chdir (tmp);
3008 #endif
3010 #ifdef tzset
3011 #undef tzset
3012 extern void tzset (void);
3014 void
3015 init_gettimeofday ()
3017 time_t ltm, gtm;
3018 struct tm *lstm;
3020 tzset ();
3021 ltm = gtm = time (NULL);
3022 ltm = mktime (lstm = localtime (&ltm));
3023 gtm = mktime (gmtime (&gtm));
3024 time_rec.tm_hour = 99; /* force gettimeofday to get date */
3025 time_rec.tm_isdst = lstm->tm_isdst;
3026 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
3028 #endif
3030 #ifdef abort
3031 #undef abort
3032 void
3033 dos_abort (file, line)
3034 char *file;
3035 int line;
3037 char buffer1[200], buffer2[400];
3038 int i, j;
3040 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
3041 for (i = j = 0; buffer1[i]; i++) {
3042 buffer2[j++] = buffer1[i];
3043 buffer2[j++] = 0x70;
3045 dosmemput (buffer2, j, (int)ScreenPrimary);
3046 ScreenSetCursor (2, 0);
3047 abort ();
3049 #else
3050 void
3051 abort ()
3053 dos_ttcooked ();
3054 ScreenSetCursor (10, 0);
3055 cputs ("\r\n\nEmacs aborted!\r\n");
3056 #if __DJGPP__ > 1
3057 /* Generate traceback, so we could tell whodunit. */
3058 signal (SIGINT, SIG_DFL);
3059 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
3060 #endif
3061 exit (2);
3063 #endif
3065 syms_of_msdos ()
3067 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
3068 staticpro (&recent_doskeys);
3070 defsubr (&Srecent_doskeys);
3071 defsubr (&Smsdos_long_file_names);
3072 defsubr (&Smsdos_downcase_filename);
3075 #endif /* MSDOS */