(viper-non-vi-major-modes): Fix customize type.
[emacs.git] / src / msdos.c
blob72b485869b8eb1b50cdc0292c8271d0bcd3ead93
1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
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 <string.h> /* for bzero and string functions */
37 #include <sys/stat.h> /* for _fixpath */
38 #include <unistd.h> /* for chdir, dup, dup2, etc. */
39 #if __DJGPP__ >= 2
40 #include <fcntl.h>
41 #include <io.h> /* for setmode */
42 #include <dpmi.h> /* for __dpmi_xxx stuff */
43 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
44 #include <libc/dosio.h> /* for _USE_LFN */
45 #include <conio.h> /* for cputs */
46 #endif
48 #include "dosfns.h"
49 #include "msdos.h"
50 #include "systime.h"
51 #include "termhooks.h"
52 #include "dispextern.h"
53 #include "termopts.h"
54 #include "frame.h"
55 #include "window.h"
56 #include "buffer.h"
57 #include "commands.h"
58 #include <go32.h>
59 #include <pc.h>
60 #include <ctype.h>
61 /* #include <process.h> */
62 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
63 #define P_WAIT 1
65 #ifndef _USE_LFN
66 #define _USE_LFN 0
67 #endif
69 #ifndef _dos_ds
70 #define _dos_ds _go32_info_block.selector_for_linear_memory
71 #endif
73 #if __DJGPP__ > 1
75 #include <signal.h>
76 #include "syssignal.h"
78 #ifndef SYSTEM_MALLOC
80 #ifdef GNU_MALLOC
82 /* If other `malloc' than ours is used, force our `sbrk' behave like
83 Unix programs expect (resize memory blocks to keep them contiguous).
84 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
85 because that's what `gmalloc' expects to get. */
86 #include <crt0.h>
88 #ifdef REL_ALLOC
89 int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
90 #else /* not REL_ALLOC */
91 int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
92 #endif /* not REL_ALLOC */
93 #endif /* GNU_MALLOC */
95 #endif /* not SYSTEM_MALLOC */
96 #endif /* __DJGPP__ > 1 */
98 static unsigned long
99 event_timestamp ()
101 struct time t;
102 unsigned long s;
104 gettime (&t);
105 s = t.ti_min;
106 s *= 60;
107 s += t.ti_sec;
108 s *= 1000;
109 s += t.ti_hund * 10;
111 return s;
115 /* ------------------------ Mouse control ---------------------------
117 * Coordinates are in screen positions and zero based.
118 * Mouse buttons are numbered from left to right and also zero based.
121 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
122 static int mouse_visible;
124 static int mouse_last_x;
125 static int mouse_last_y;
127 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
128 static int mouse_button_count;
130 void
131 mouse_on ()
133 union REGS regs;
135 if (have_mouse > 0 && !mouse_visible)
137 if (termscript)
138 fprintf (termscript, "<M_ON>");
139 regs.x.ax = 0x0001;
140 int86 (0x33, &regs, &regs);
141 mouse_visible = 1;
145 void
146 mouse_off ()
148 union REGS regs;
150 if (have_mouse > 0 && mouse_visible)
152 if (termscript)
153 fprintf (termscript, "<M_OFF>");
154 regs.x.ax = 0x0002;
155 int86 (0x33, &regs, &regs);
156 mouse_visible = 0;
160 void
161 mouse_moveto (x, y)
162 int x, y;
164 union REGS regs;
166 if (termscript)
167 fprintf (termscript, "<M_XY=%dx%d>", x, y);
168 regs.x.ax = 0x0004;
169 mouse_last_x = regs.x.cx = x * 8;
170 mouse_last_y = regs.x.dx = y * 8;
171 int86 (0x33, &regs, &regs);
174 static int
175 mouse_pressed (b, xp, yp)
176 int b, *xp, *yp;
178 union REGS regs;
180 if (b >= mouse_button_count)
181 return 0;
182 regs.x.ax = 0x0005;
183 regs.x.bx = mouse_button_translate[b];
184 int86 (0x33, &regs, &regs);
185 if (regs.x.bx)
186 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
187 return (regs.x.bx != 0);
190 static int
191 mouse_released (b, xp, yp)
192 int b, *xp, *yp;
194 union REGS regs;
196 if (b >= mouse_button_count)
197 return 0;
198 regs.x.ax = 0x0006;
199 regs.x.bx = mouse_button_translate[b];
200 int86 (0x33, &regs, &regs);
201 if (regs.x.bx)
202 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
203 return (regs.x.bx != 0);
206 static void
207 mouse_get_xy (int *x, int *y)
209 union REGS regs;
211 regs.x.ax = 0x0003;
212 int86 (0x33, &regs, &regs);
213 *x = regs.x.cx / 8;
214 *y = regs.x.dx / 8;
217 void
218 mouse_get_pos (f, insist, bar_window, part, x, y, time)
219 FRAME_PTR *f;
220 int insist;
221 Lisp_Object *bar_window, *x, *y;
222 enum scroll_bar_part *part;
223 unsigned long *time;
225 int ix, iy;
226 union REGS regs;
228 regs.x.ax = 0x0003;
229 int86 (0x33, &regs, &regs);
230 *f = selected_frame;
231 *bar_window = Qnil;
232 mouse_get_xy (&ix, &iy);
233 selected_frame->mouse_moved = 0;
234 *x = make_number (ix);
235 *y = make_number (iy);
236 *time = event_timestamp ();
239 static void
240 mouse_check_moved ()
242 int x, y;
244 mouse_get_xy (&x, &y);
245 selected_frame->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
246 mouse_last_x = x;
247 mouse_last_y = y;
250 void
251 mouse_init ()
253 union REGS regs;
255 if (termscript)
256 fprintf (termscript, "<M_INIT>");
258 regs.x.ax = 0x0021;
259 int86 (0x33, &regs, &regs);
261 regs.x.ax = 0x0007;
262 regs.x.cx = 0;
263 regs.x.dx = 8 * (ScreenCols () - 1);
264 int86 (0x33, &regs, &regs);
266 regs.x.ax = 0x0008;
267 regs.x.cx = 0;
268 regs.x.dx = 8 * (ScreenRows () - 1);
269 int86 (0x33, &regs, &regs);
271 mouse_moveto (0, 0);
272 mouse_visible = 0;
275 /* ------------------------- Screen control ----------------------
279 static int internal_terminal = 0;
281 #ifndef HAVE_X_WINDOWS
282 extern unsigned char ScreenAttrib;
283 static int screen_face;
284 static int highlight;
286 static int screen_size_X;
287 static int screen_size_Y;
288 static int screen_size;
290 static int current_pos_X;
291 static int current_pos_Y;
292 static int new_pos_X;
293 static int new_pos_Y;
295 static void *startup_screen_buffer;
296 static int startup_screen_size_X;
297 static int startup_screen_size_Y;
298 static int startup_pos_X;
299 static int startup_pos_Y;
300 static unsigned char startup_screen_attrib;
302 static int term_setup_done;
304 /* Similar to the_only_frame. */
305 struct x_output the_only_x_display;
307 /* This is never dereferenced. */
308 Display *x_current_display;
310 static
311 dos_direct_output (y, x, buf, len)
312 int y;
313 int x;
314 char *buf;
315 int len;
317 int t = (int) ScreenPrimary + 2 * (x + y * screen_size_X);
319 #if (__DJGPP__ < 2)
320 while (--len >= 0) {
321 dosmemput (buf++, 1, t);
322 t += 2;
324 #else
325 /* This is faster. */
326 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
327 _farnspokeb (t, *buf);
328 #endif
330 #endif
332 /* Flash the screen as a substitute for BEEPs. */
334 #if (__DJGPP__ < 2)
335 static void
336 do_visible_bell (xorattr)
337 unsigned char xorattr;
339 asm volatile
340 (" movb $1,%%dl
341 visible_bell_0:
342 movl _ScreenPrimary,%%eax
343 call dosmemsetup
344 movl %%eax,%%ebx
345 movl %1,%%ecx
346 movb %0,%%al
347 incl %%ebx
348 visible_bell_1:
349 xorb %%al,%%gs:(%%ebx)
350 addl $2,%%ebx
351 decl %%ecx
352 jne visible_bell_1
353 decb %%dl
354 jne visible_bell_3
355 visible_bell_2:
356 movzwl %%ax,%%eax
357 movzwl %%ax,%%eax
358 movzwl %%ax,%%eax
359 movzwl %%ax,%%eax
360 decw %%cx
361 jne visible_bell_2
362 jmp visible_bell_0
363 visible_bell_3:"
364 : /* no output */
365 : "m" (xorattr), "g" (screen_size)
366 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
369 static void
370 ScreenVisualBell (void)
372 /* This creates an xor-mask that will swap the default fore- and
373 background colors. */
374 do_visible_bell (((the_only_x_display.foreground_pixel
375 ^ the_only_x_display.background_pixel)
376 * 0x11) & 0x7f);
378 #endif
380 #ifndef HAVE_X_WINDOWS
382 static int blink_bit = -1; /* the state of the blink bit at startup */
384 /* Enable bright background colors. */
385 static void
386 bright_bg (void)
388 union REGS regs;
390 /* Remember the original state of the blink/bright-background bit.
391 It is stored at 0040:0065h in the BIOS data area. */
392 if (blink_bit == -1)
393 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
395 regs.h.bl = 0;
396 regs.x.ax = 0x1003;
397 int86 (0x10, &regs, &regs);
400 /* Disable bright background colors (and enable blinking) if we found
401 the video system in that state at startup. */
402 static void
403 maybe_enable_blinking (void)
405 if (blink_bit == 1)
407 union REGS regs;
409 regs.h.bl = 1;
410 regs.x.ax = 0x1003;
411 int86 (0x10, &regs, &regs);
415 /* Set the screen dimensions so that it can show no less than
416 ROWS x COLS frame. */
418 void
419 dos_set_window_size (rows, cols)
420 int *rows, *cols;
422 char video_name[30];
423 Lisp_Object video_mode;
424 int video_mode_value;
425 int have_vga = 0;
426 union REGS regs;
427 int current_rows = ScreenRows (), current_cols = ScreenCols ();
429 if (*rows == current_rows && *cols == current_cols)
430 return;
432 /* Do we have a VGA? */
433 regs.x.ax = 0x1a00;
434 int86 (0x10, &regs, &regs);
435 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
436 have_vga = 1;
438 mouse_off ();
440 /* If the user specified a special video mode for these dimensions,
441 use that mode. */
442 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
443 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
444 Qnil))-> value;
446 if (INTEGERP (video_mode)
447 && (video_mode_value = XINT (video_mode)) > 0)
449 regs.x.ax = video_mode_value;
450 int86 (0x10, &regs, &regs);
452 if (have_mouse)
454 /* Must hardware-reset the mouse, or else it won't update
455 its notion of screen dimensions for some non-standard
456 video modes. This is *painfully* slow... */
457 regs.x.ax = 0;
458 int86 (0x33, &regs, &regs);
462 /* Find one of the dimensions supported by standard EGA/VGA
463 which gives us at least the required dimensions. */
465 #if __DJGPP__ > 1
467 else
469 static struct {
470 int rows;
471 int need_vga;
472 } std_dimension[] = {
473 {25, 0},
474 {28, 1},
475 {35, 0},
476 {40, 1},
477 {43, 0},
478 {50, 1}
480 int i = 0;
482 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
484 if (std_dimension[i].need_vga <= have_vga
485 && std_dimension[i].rows >= *rows)
487 if (std_dimension[i].rows != current_rows
488 || *cols != current_cols)
489 _set_screen_lines (std_dimension[i].rows);
490 break;
492 i++;
496 #else /* not __DJGPP__ > 1 */
498 else if (*rows <= 25)
500 if (current_rows != 25 || current_cols != 80)
502 regs.x.ax = 3;
503 int86 (0x10, &regs, &regs);
504 regs.x.ax = 0x1101;
505 regs.h.bl = 0;
506 int86 (0x10, &regs, &regs);
507 regs.x.ax = 0x1200;
508 regs.h.bl = 32;
509 int86 (0x10, &regs, &regs);
510 regs.x.ax = 3;
511 int86 (0x10, &regs, &regs);
514 else if (*rows <= 50)
515 if (have_vga && (current_rows != 50 || current_cols != 80)
516 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
518 regs.x.ax = 3;
519 int86 (0x10, &regs, &regs);
520 regs.x.ax = 0x1112;
521 regs.h.bl = 0;
522 int86 (0x10, &regs, &regs);
523 regs.x.ax = 0x1200;
524 regs.h.bl = 32;
525 int86 (0x10, &regs, &regs);
526 regs.x.ax = 0x0100;
527 regs.x.cx = 7;
528 int86 (0x10, &regs, &regs);
530 #endif /* not __DJGPP__ > 1 */
532 if (have_mouse)
534 mouse_init ();
535 mouse_on ();
538 /* Tell the caller what dimensions have been REALLY set. */
539 *rows = ScreenRows ();
540 *cols = ScreenCols ();
542 /* Enable bright background colors. */
543 bright_bg ();
546 /* If we write a character in the position where the mouse is,
547 the mouse cursor may need to be refreshed. */
549 static void
550 mouse_off_maybe ()
552 int x, y;
554 if (!mouse_visible)
555 return;
557 mouse_get_xy (&x, &y);
558 if (y != new_pos_Y || x < new_pos_X)
559 return;
561 mouse_off ();
564 static
565 IT_ring_bell ()
567 if (visible_bell)
569 mouse_off ();
570 ScreenVisualBell ();
572 else
574 union REGS inregs, outregs;
575 inregs.h.ah = 2;
576 inregs.h.dl = 7;
577 intdos (&inregs, &outregs);
581 static void
582 IT_set_face (int face)
584 struct face *fp;
585 extern struct face *intern_face (/* FRAME_PTR, struct face * */);
587 if (face == 1 || (face == 0 && highlight))
588 fp = FRAME_MODE_LINE_FACE (foo);
589 else if (face <= 0 || face >= FRAME_N_COMPUTED_FACES (foo))
590 fp = FRAME_DEFAULT_FACE (foo);
591 else
592 fp = intern_face (selected_frame, FRAME_COMPUTED_FACES (foo)[face]);
593 if (termscript)
594 fprintf (termscript, "<FACE %d: %d/%d>",
595 face, FACE_FOREGROUND (fp), FACE_BACKGROUND (fp));
596 screen_face = face;
597 ScreenAttrib = (FACE_BACKGROUND (fp) << 4) | FACE_FOREGROUND (fp);
600 static
601 IT_write_glyphs (GLYPH *str, int len)
603 int newface;
604 int ch, l = len;
605 unsigned char *buf, *bp;
607 if (len == 0) return;
609 buf = bp = alloca (len * 2);
611 while (--l >= 0)
613 newface = FAST_GLYPH_FACE (*str);
614 if (newface != screen_face)
615 IT_set_face (newface);
616 ch = FAST_GLYPH_CHAR (*str);
617 *bp++ = (unsigned char)ch;
618 *bp++ = ScreenAttrib;
620 if (termscript)
621 fputc (ch, termscript);
622 str++;
625 mouse_off_maybe ();
626 dosmemput (buf, 2 * len,
627 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
628 new_pos_X += len;
631 static
632 IT_clear_end_of_line (first_unused)
634 char *spaces, *sp;
635 int i, j;
637 IT_set_face (0);
638 if (termscript)
639 fprintf (termscript, "<CLR:EOL>");
640 i = (j = screen_size_X - new_pos_X) * 2;
641 spaces = sp = alloca (i);
643 while (--j >= 0)
645 *sp++ = ' ';
646 *sp++ = ScreenAttrib;
649 mouse_off_maybe ();
650 dosmemput (spaces, i,
651 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
654 static
655 IT_clear_screen (void)
657 if (termscript)
658 fprintf (termscript, "<CLR:SCR>");
659 IT_set_face (0);
660 mouse_off ();
661 ScreenClear ();
662 new_pos_X = new_pos_Y = 0;
665 static
666 IT_clear_to_end (void)
668 if (termscript)
669 fprintf (termscript, "<CLR:EOS>");
671 while (new_pos_Y < screen_size_Y) {
672 new_pos_X = 0;
673 IT_clear_end_of_line (0);
674 new_pos_Y++;
678 static
679 IT_cursor_to (int y, int x)
681 if (termscript)
682 fprintf (termscript, "\n<XY=%dx%d>", x, y);
683 new_pos_X = x;
684 new_pos_Y = y;
687 static int cursor_cleared;
689 static
690 IT_display_cursor (int on)
692 if (on && cursor_cleared)
694 ScreenSetCursor (current_pos_Y, current_pos_X);
695 cursor_cleared = 0;
697 else if (!on && !cursor_cleared)
699 ScreenSetCursor (-1, -1);
700 cursor_cleared = 1;
704 /* Emacs calls cursor-movement functions a lot when it updates the
705 display (probably a legacy of old terminals where you cannot
706 update a screen line without first moving the cursor there).
707 However, cursor movement is expensive on MSDOS (it calls a slow
708 BIOS function and requires 2 mode switches), while actual screen
709 updates access the video memory directly and don't depend on
710 cursor position. To avoid slowing down the redisplay, we cheat:
711 all functions that move the cursor only set internal variables
712 which record the cursor position, whereas the cursor is only
713 moved to its final position whenever screen update is complete.
715 `IT_cmgoto' is called from the keyboard reading loop and when the
716 frame update is complete. This means that we are ready for user
717 input, so we update the cursor position to show where the point is,
718 and also make the mouse pointer visible.
720 Special treatment is required when the cursor is in the echo area,
721 to put the cursor at the end of the text displayed there. */
723 static
724 IT_cmgoto (f)
725 FRAME_PTR f;
727 /* Only set the cursor to where it should be if the display is
728 already in sync with the window contents. */
729 int update_cursor_pos = MODIFF == unchanged_modified;
731 /* If we are in the echo area, put the cursor at the end of text. */
732 if (!update_cursor_pos
733 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y)
735 new_pos_X = FRAME_DESIRED_GLYPHS (f)->used[new_pos_Y];
736 update_cursor_pos = 1;
739 if (update_cursor_pos
740 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
742 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
743 if (termscript)
744 fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
747 /* Maybe cursor is invisible, so make it visible. */
748 IT_display_cursor (1);
750 /* Mouse pointer should be always visible if we are waiting for
751 keyboard input. */
752 if (!mouse_visible)
753 mouse_on ();
756 static
757 IT_reassert_line_highlight (new, vpos)
758 int new, vpos;
760 highlight = new;
761 IT_set_face (0); /* To possibly clear the highlighting. */
764 static
765 IT_change_line_highlight (new_highlight, vpos, first_unused_hpos)
767 highlight = new_highlight;
768 IT_set_face (0); /* To possibly clear the highlighting. */
769 IT_cursor_to (vpos, 0);
770 IT_clear_end_of_line (first_unused_hpos);
773 static
774 IT_update_begin ()
776 highlight = 0;
777 IT_set_face (0); /* To possibly clear the highlighting. */
778 screen_face = -1;
781 static
782 IT_update_end ()
786 /* This was more or less copied from xterm.c
788 Nowadays, the corresponding function under X is `x_set_menu_bar_lines_1'
789 on xfns.c */
791 static void
792 IT_set_menu_bar_lines (window, n)
793 Lisp_Object window;
794 int n;
796 struct window *w = XWINDOW (window);
798 XSETFASTINT (w->last_modified, 0);
799 XSETFASTINT (w->last_overlay_modified, 0);
800 XSETFASTINT (w->top, XFASTINT (w->top) + n);
801 XSETFASTINT (w->height, XFASTINT (w->height) - n);
803 /* Handle just the top child in a vertical split. */
804 if (!NILP (w->vchild))
805 IT_set_menu_bar_lines (w->vchild, n);
807 /* Adjust all children in a horizontal split. */
808 for (window = w->hchild; !NILP (window); window = w->next)
810 w = XWINDOW (window);
811 IT_set_menu_bar_lines (window, n);
815 /* This was copied from xfns.c */
817 Lisp_Object Qbackground_color;
818 Lisp_Object Qforeground_color;
820 void
821 x_set_menu_bar_lines (f, value, oldval)
822 struct frame *f;
823 Lisp_Object value, oldval;
825 int nlines;
826 int olines = FRAME_MENU_BAR_LINES (f);
828 /* Right now, menu bars don't work properly in minibuf-only frames;
829 most of the commands try to apply themselves to the minibuffer
830 frame itslef, and get an error because you can't switch buffers
831 in or split the minibuffer window. */
832 if (FRAME_MINIBUF_ONLY_P (f))
833 return;
835 if (INTEGERP (value))
836 nlines = XINT (value);
837 else
838 nlines = 0;
840 FRAME_MENU_BAR_LINES (f) = nlines;
841 IT_set_menu_bar_lines (f->root_window, nlines - olines);
844 /* IT_set_terminal_modes is called when emacs is started,
845 resumed, and whenever the screen is redrawn! */
847 static
848 IT_set_terminal_modes (void)
850 if (termscript)
851 fprintf (termscript, "\n<SET_TERM>");
852 highlight = 0;
854 screen_size_X = ScreenCols ();
855 screen_size_Y = ScreenRows ();
856 screen_size = screen_size_X * screen_size_Y;
858 new_pos_X = new_pos_Y = 0;
859 current_pos_X = current_pos_Y = -1;
861 if (term_setup_done)
862 return;
863 term_setup_done = 1;
865 startup_screen_size_X = screen_size_X;
866 startup_screen_size_Y = screen_size_Y;
867 startup_screen_attrib = ScreenAttrib;
869 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
870 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
872 if (termscript)
873 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
874 screen_size_X, screen_size_Y);
876 bright_bg ();
879 /* IT_reset_terminal_modes is called when emacs is
880 suspended or killed. */
882 static
883 IT_reset_terminal_modes (void)
885 int display_row_start = (int) ScreenPrimary;
886 int saved_row_len = startup_screen_size_X * 2;
887 int update_row_len = ScreenCols () * 2;
888 int current_rows = ScreenRows ();
889 int to_next_row = update_row_len;
890 unsigned char *saved_row = startup_screen_buffer;
891 int cursor_pos_X = ScreenCols () - 1;
892 int cursor_pos_Y = ScreenRows () - 1;
894 if (termscript)
895 fprintf (termscript, "\n<RESET_TERM>");
897 highlight = 0;
899 if (!term_setup_done)
900 return;
902 mouse_off ();
904 /* Leave the video system in the same state as we found it,
905 as far as the blink/bright-background bit is concerned. */
906 maybe_enable_blinking ();
908 /* We have a situation here.
909 We cannot just do ScreenUpdate(startup_screen_buffer) because
910 the luser could have changed screen dimensions inside Emacs
911 and failed (or didn't want) to restore them before killing
912 Emacs. ScreenUpdate() uses the *current* screen dimensions and
913 thus will happily use memory outside what was allocated for
914 `startup_screen_buffer'.
915 Thus we only restore as much as the current screen dimensions
916 can hold, and clear the rest (if the saved screen is smaller than
917 the current) with the color attribute saved at startup. The cursor
918 is also restored within the visible dimensions. */
920 ScreenAttrib = startup_screen_attrib;
921 ScreenClear ();
923 if (update_row_len > saved_row_len)
924 update_row_len = saved_row_len;
925 if (current_rows > startup_screen_size_Y)
926 current_rows = startup_screen_size_Y;
928 if (termscript)
929 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
930 update_row_len / 2, current_rows);
932 while (current_rows--)
934 dosmemput (saved_row, update_row_len, display_row_start);
935 saved_row += saved_row_len;
936 display_row_start += to_next_row;
938 if (startup_pos_X < cursor_pos_X)
939 cursor_pos_X = startup_pos_X;
940 if (startup_pos_Y < cursor_pos_Y)
941 cursor_pos_Y = startup_pos_Y;
943 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
944 xfree (startup_screen_buffer);
946 term_setup_done = 0;
949 static
950 IT_set_terminal_window (void)
954 void
955 IT_set_frame_parameters (f, alist)
956 FRAME_PTR f;
957 Lisp_Object alist;
959 Lisp_Object tail;
960 int length = XINT (Flength (alist));
961 int i;
962 Lisp_Object *parms
963 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
964 Lisp_Object *values
965 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
966 int redraw;
967 extern unsigned long load_color ();
969 redraw = 0;
971 /* Extract parm names and values into those vectors. */
972 i = 0;
973 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
975 Lisp_Object elt;
977 elt = Fcar (tail);
978 parms[i] = Fcar (elt);
979 CHECK_SYMBOL (parms[i], 1);
980 values[i] = Fcdr (elt);
981 i++;
985 /* Now process them in reverse of specified order. */
986 for (i--; i >= 0; i--)
988 Lisp_Object prop = parms[i];
989 Lisp_Object val = values[i];
991 if (EQ (prop, Qforeground_color))
993 unsigned long new_color = load_color (f, val);
994 if (new_color != ~0)
996 FRAME_FOREGROUND_PIXEL (f) = new_color;
997 redraw = 1;
998 if (termscript)
999 fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
1002 else if (EQ (prop, Qbackground_color))
1004 unsigned long new_color = load_color (f, val);
1005 if (new_color != ~0)
1007 FRAME_BACKGROUND_PIXEL (f) = new_color;
1008 redraw = 1;
1009 if (termscript)
1010 fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
1013 else if (EQ (prop, intern ("menu-bar-lines")))
1014 x_set_menu_bar_lines (f, val, 0);
1016 store_frame_param (f, prop, val);
1020 if (redraw)
1022 extern void recompute_basic_faces (FRAME_PTR);
1023 extern void redraw_frame (FRAME_PTR);
1025 recompute_basic_faces (f);
1026 if (f == selected_frame)
1027 redraw_frame (f);
1031 extern void init_frame_faces (FRAME_PTR);
1033 #endif /* !HAVE_X_WINDOWS */
1036 /* Do we need the internal terminal? */
1038 void
1039 internal_terminal_init ()
1041 char *term = getenv ("TERM");
1042 char *colors;
1044 #ifdef HAVE_X_WINDOWS
1045 if (!inhibit_window_system)
1046 return;
1047 #endif
1049 internal_terminal
1050 = (!noninteractive) && term && !strcmp (term, "internal");
1052 if (getenv ("EMACSTEST"))
1053 termscript = fopen (getenv ("EMACSTEST"), "wt");
1055 #ifndef HAVE_X_WINDOWS
1056 if (!internal_terminal || inhibit_window_system)
1058 selected_frame->output_method = output_termcap;
1059 return;
1062 Vwindow_system = intern ("pc");
1063 Vwindow_system_version = make_number (1);
1065 bzero (&the_only_x_display, sizeof the_only_x_display);
1066 the_only_x_display.background_pixel = 7; /* White */
1067 the_only_x_display.foreground_pixel = 0; /* Black */
1068 bright_bg ();
1069 colors = getenv ("EMACSCOLORS");
1070 if (colors && strlen (colors) >= 2)
1072 /* The colors use 4 bits each (we enable bright background). */
1073 if (isdigit (colors[0]))
1074 colors[0] -= '0';
1075 else if (isxdigit (colors[0]))
1076 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1077 if (colors[0] >= 0 && colors[0] < 16)
1078 the_only_x_display.foreground_pixel = colors[0];
1079 if (isdigit (colors[1]))
1080 colors[1] -= '0';
1081 else if (isxdigit (colors[1]))
1082 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
1083 if (colors[1] >= 0 && colors[1] < 16)
1084 the_only_x_display.background_pixel = colors[1];
1086 the_only_x_display.line_height = 1;
1087 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
1089 init_frame_faces (selected_frame);
1091 ring_bell_hook = IT_ring_bell;
1092 write_glyphs_hook = IT_write_glyphs;
1093 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
1094 clear_to_end_hook = IT_clear_to_end;
1095 clear_end_of_line_hook = IT_clear_end_of_line;
1096 clear_frame_hook = IT_clear_screen;
1097 change_line_highlight_hook = IT_change_line_highlight;
1098 update_begin_hook = IT_update_begin;
1099 update_end_hook = IT_update_end;
1100 reassert_line_highlight_hook = IT_reassert_line_highlight;
1101 frame_up_to_date_hook = IT_cmgoto; /* position cursor when update is done */
1103 /* These hooks are called by term.c without being checked. */
1104 set_terminal_modes_hook = IT_set_terminal_modes;
1105 reset_terminal_modes_hook = IT_reset_terminal_modes;
1106 set_terminal_window_hook = IT_set_terminal_window;
1107 #endif
1110 dos_get_saved_screen (screen, rows, cols)
1111 char **screen;
1112 int *rows;
1113 int *cols;
1115 #ifndef HAVE_X_WINDOWS
1116 *screen = startup_screen_buffer;
1117 *cols = startup_screen_size_X;
1118 *rows = startup_screen_size_Y;
1119 return 1;
1120 #else
1121 return 0;
1122 #endif
1125 #ifndef HAVE_X_WINDOWS
1127 /* We are not X, but we can emulate it well enough for our needs... */
1128 void
1129 check_x (void)
1131 if (! FRAME_MSDOS_P (selected_frame))
1132 error ("Not running under a windows system");
1135 #endif
1138 /* ----------------------- Keyboard control ----------------------
1140 * Keymaps reflect the following keyboard layout:
1142 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1143 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1144 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1145 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1146 * SPACE
1149 static int extended_kbd; /* 101 (102) keyboard present. */
1151 struct dos_keyboard_map
1153 char *unshifted;
1154 char *shifted;
1155 char *alt_gr;
1159 static struct dos_keyboard_map us_keyboard = {
1160 /* 0 1 2 3 4 5 */
1161 /* 01234567890123456789012345678901234567890 12345678901234 */
1162 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1163 /* 0123456789012345678901234567890123456789 012345678901234 */
1164 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1165 0 /* no Alt-Gr key */
1168 static struct dos_keyboard_map fr_keyboard = {
1169 /* 0 1 2 3 4 5 */
1170 /* 012 3456789012345678901234567890123456789012345678901234 */
1171 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
1172 /* 0123456789012345678901234567890123456789012345678901234 */
1173 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
1174 /* 01234567 89012345678901234567890123456789012345678901234 */
1175 " ~#{[|`\\^@]} Ï "
1178 static struct dos_keyboard_map dk_keyboard = {
1179 /* 0 1 2 3 4 5 */
1180 /* 0123456789012345678901234567890123456789012345678901234 */
1181 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
1182 /* 01 23456789012345678901234567890123456789012345678901234 */
1183 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
1184 /* 0123456789012345678901234567890123456789012345678901234 */
1185 " @œ$ {[]} | "
1188 static struct keyboard_layout_list
1190 int country_code;
1191 struct dos_keyboard_map *keyboard_map;
1192 } keyboard_layout_list[] =
1194 1, &us_keyboard,
1195 33, &fr_keyboard,
1196 45, &dk_keyboard
1199 static struct dos_keyboard_map *keyboard;
1200 static int keyboard_map_all;
1201 static int international_keyboard;
1204 dos_set_keyboard (code, always)
1205 int code;
1206 int always;
1208 int i;
1209 union REGS regs;
1211 /* See if Keyb.Com is installed (for international keyboard support). */
1212 regs.x.ax = 0xad80;
1213 int86 (0x2f, &regs, &regs);
1214 if (regs.h.al == 0xff)
1215 international_keyboard = 1;
1217 /* Initialize to US settings, for countries that don't have their own. */
1218 keyboard = keyboard_layout_list[0].keyboard_map;
1219 keyboard_map_all = always;
1220 dos_keyboard_layout = 1;
1222 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
1223 if (code == keyboard_layout_list[i].country_code)
1225 keyboard = keyboard_layout_list[i].keyboard_map;
1226 keyboard_map_all = always;
1227 dos_keyboard_layout = code;
1228 return 1;
1230 return 0;
1233 #define Ignore 0x0000
1234 #define Normal 0x0000 /* normal key - alt changes scan-code */
1235 #define FctKey 0x1000 /* func key if c == 0, else c */
1236 #define Special 0x2000 /* func key even if c != 0 */
1237 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1238 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1239 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1240 #define Grey 0x6000 /* Grey keypad key */
1242 #define Alt 0x0100 /* alt scan-code */
1243 #define Ctrl 0x0200 /* ctrl scan-code */
1244 #define Shift 0x0400 /* shift scan-code */
1246 static struct
1248 unsigned char char_code; /* normal code */
1249 unsigned char meta_code; /* M- code */
1250 unsigned char keypad_code; /* keypad code */
1251 unsigned char editkey_code; /* edit key */
1252 } keypad_translate_map[] = {
1253 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1254 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1255 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1256 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1257 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1258 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1259 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1260 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1261 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1262 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1263 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1266 static struct
1268 unsigned char char_code; /* normal code */
1269 unsigned char keypad_code; /* keypad code */
1270 } grey_key_translate_map[] = {
1271 '/', 0xaf, /* kp-decimal */
1272 '*', 0xaa, /* kp-multiply */
1273 '-', 0xad, /* kp-subtract */
1274 '+', 0xab, /* kp-add */
1275 '\r', 0x8d /* kp-enter */
1278 static unsigned short
1279 ibmpc_translate_map[] =
1281 /* --------------- 00 to 0f --------------- */
1282 Normal | 0xff, /* Ctrl Break + Alt-NNN */
1283 Alt | ModFct | 0x1b, /* Escape */
1284 Normal | 1, /* '1' */
1285 Normal | 2, /* '2' */
1286 Normal | 3, /* '3' */
1287 Normal | 4, /* '4' */
1288 Normal | 5, /* '5' */
1289 Normal | 6, /* '6' */
1290 Normal | 7, /* '7' */
1291 Normal | 8, /* '8' */
1292 Normal | 9, /* '9' */
1293 Normal | 10, /* '0' */
1294 Normal | 11, /* '-' */
1295 Normal | 12, /* '=' */
1296 Special | 0x08, /* Backspace */
1297 ModFct | 0x74, /* Tab/Backtab */
1299 /* --------------- 10 to 1f --------------- */
1300 Map | 15, /* 'q' */
1301 Map | 16, /* 'w' */
1302 Map | 17, /* 'e' */
1303 Map | 18, /* 'r' */
1304 Map | 19, /* 't' */
1305 Map | 20, /* 'y' */
1306 Map | 21, /* 'u' */
1307 Map | 22, /* 'i' */
1308 Map | 23, /* 'o' */
1309 Map | 24, /* 'p' */
1310 Map | 25, /* '[' */
1311 Map | 26, /* ']' */
1312 ModFct | 0x0d, /* Return */
1313 Ignore, /* Ctrl */
1314 Map | 30, /* 'a' */
1315 Map | 31, /* 's' */
1317 /* --------------- 20 to 2f --------------- */
1318 Map | 32, /* 'd' */
1319 Map | 33, /* 'f' */
1320 Map | 34, /* 'g' */
1321 Map | 35, /* 'h' */
1322 Map | 36, /* 'j' */
1323 Map | 37, /* 'k' */
1324 Map | 38, /* 'l' */
1325 Map | 39, /* ';' */
1326 Map | 40, /* '\'' */
1327 Map | 0, /* '`' */
1328 Ignore, /* Left shift */
1329 Map | 41, /* '\\' */
1330 Map | 45, /* 'z' */
1331 Map | 46, /* 'x' */
1332 Map | 47, /* 'c' */
1333 Map | 48, /* 'v' */
1335 /* --------------- 30 to 3f --------------- */
1336 Map | 49, /* 'b' */
1337 Map | 50, /* 'n' */
1338 Map | 51, /* 'm' */
1339 Map | 52, /* ',' */
1340 Map | 53, /* '.' */
1341 Map | 54, /* '/' */
1342 Ignore, /* Right shift */
1343 Grey | 1, /* Grey * */
1344 Ignore, /* Alt */
1345 Normal | ' ', /* ' ' */
1346 Ignore, /* Caps Lock */
1347 FctKey | 0xbe, /* F1 */
1348 FctKey | 0xbf, /* F2 */
1349 FctKey | 0xc0, /* F3 */
1350 FctKey | 0xc1, /* F4 */
1351 FctKey | 0xc2, /* F5 */
1353 /* --------------- 40 to 4f --------------- */
1354 FctKey | 0xc3, /* F6 */
1355 FctKey | 0xc4, /* F7 */
1356 FctKey | 0xc5, /* F8 */
1357 FctKey | 0xc6, /* F9 */
1358 FctKey | 0xc7, /* F10 */
1359 Ignore, /* Num Lock */
1360 Ignore, /* Scroll Lock */
1361 KeyPad | 7, /* Home */
1362 KeyPad | 8, /* Up */
1363 KeyPad | 9, /* Page Up */
1364 Grey | 2, /* Grey - */
1365 KeyPad | 4, /* Left */
1366 KeyPad | 5, /* Keypad 5 */
1367 KeyPad | 6, /* Right */
1368 Grey | 3, /* Grey + */
1369 KeyPad | 1, /* End */
1371 /* --------------- 50 to 5f --------------- */
1372 KeyPad | 2, /* Down */
1373 KeyPad | 3, /* Page Down */
1374 KeyPad | 0, /* Insert */
1375 KeyPad | 10, /* Delete */
1376 Shift | FctKey | 0xbe, /* (Shift) F1 */
1377 Shift | FctKey | 0xbf, /* (Shift) F2 */
1378 Shift | FctKey | 0xc0, /* (Shift) F3 */
1379 Shift | FctKey | 0xc1, /* (Shift) F4 */
1380 Shift | FctKey | 0xc2, /* (Shift) F5 */
1381 Shift | FctKey | 0xc3, /* (Shift) F6 */
1382 Shift | FctKey | 0xc4, /* (Shift) F7 */
1383 Shift | FctKey | 0xc5, /* (Shift) F8 */
1384 Shift | FctKey | 0xc6, /* (Shift) F9 */
1385 Shift | FctKey | 0xc7, /* (Shift) F10 */
1386 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
1387 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
1389 /* --------------- 60 to 6f --------------- */
1390 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
1391 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
1392 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
1393 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
1394 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
1395 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
1396 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
1397 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
1398 Alt | FctKey | 0xbe, /* (Alt) F1 */
1399 Alt | FctKey | 0xbf, /* (Alt) F2 */
1400 Alt | FctKey | 0xc0, /* (Alt) F3 */
1401 Alt | FctKey | 0xc1, /* (Alt) F4 */
1402 Alt | FctKey | 0xc2, /* (Alt) F5 */
1403 Alt | FctKey | 0xc3, /* (Alt) F6 */
1404 Alt | FctKey | 0xc4, /* (Alt) F7 */
1405 Alt | FctKey | 0xc5, /* (Alt) F8 */
1407 /* --------------- 70 to 7f --------------- */
1408 Alt | FctKey | 0xc6, /* (Alt) F9 */
1409 Alt | FctKey | 0xc7, /* (Alt) F10 */
1410 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
1411 Ctrl | KeyPad | 4, /* (Ctrl) Left */
1412 Ctrl | KeyPad | 6, /* (Ctrl) Right */
1413 Ctrl | KeyPad | 1, /* (Ctrl) End */
1414 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
1415 Ctrl | KeyPad | 7, /* (Ctrl) Home */
1416 Alt | Map | 1, /* '1' */
1417 Alt | Map | 2, /* '2' */
1418 Alt | Map | 3, /* '3' */
1419 Alt | Map | 4, /* '4' */
1420 Alt | Map | 5, /* '5' */
1421 Alt | Map | 6, /* '6' */
1422 Alt | Map | 7, /* '7' */
1423 Alt | Map | 8, /* '8' */
1425 /* --------------- 80 to 8f --------------- */
1426 Alt | Map | 9, /* '9' */
1427 Alt | Map | 10, /* '0' */
1428 Alt | Map | 11, /* '-' */
1429 Alt | Map | 12, /* '=' */
1430 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
1431 FctKey | 0xc8, /* F11 */
1432 FctKey | 0xc9, /* F12 */
1433 Shift | FctKey | 0xc8, /* (Shift) F11 */
1434 Shift | FctKey | 0xc9, /* (Shift) F12 */
1435 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
1436 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
1437 Alt | FctKey | 0xc8, /* (Alt) F11 */
1438 Alt | FctKey | 0xc9, /* (Alt) F12 */
1439 Ctrl | KeyPad | 8, /* (Ctrl) Up */
1440 Ctrl | Grey | 2, /* (Ctrl) Grey - */
1441 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
1443 /* --------------- 90 to 9f --------------- */
1444 Ctrl | Grey | 3, /* (Ctrl) Grey + */
1445 Ctrl | KeyPad | 2, /* (Ctrl) Down */
1446 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
1447 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
1448 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
1449 Ctrl | Grey | 0, /* (Ctrl) Grey / */
1450 Ctrl | Grey | 1, /* (Ctrl) Grey * */
1451 Alt | FctKey | 0x50, /* (Alt) Home */
1452 Alt | FctKey | 0x52, /* (Alt) Up */
1453 Alt | FctKey | 0x55, /* (Alt) Page Up */
1454 Ignore, /* NO KEY */
1455 Alt | FctKey | 0x51, /* (Alt) Left */
1456 Ignore, /* NO KEY */
1457 Alt | FctKey | 0x53, /* (Alt) Right */
1458 Ignore, /* NO KEY */
1459 Alt | FctKey | 0x57, /* (Alt) End */
1461 /* --------------- a0 to af --------------- */
1462 Alt | KeyPad | 2, /* (Alt) Down */
1463 Alt | KeyPad | 3, /* (Alt) Page Down */
1464 Alt | KeyPad | 0, /* (Alt) Insert */
1465 Alt | KeyPad | 10, /* (Alt) Delete */
1466 Alt | Grey | 0, /* (Alt) Grey / */
1467 Alt | FctKey | 0x09, /* (Alt) Tab */
1468 Alt | Grey | 4 /* (Alt) Keypad Enter */
1471 /* These bit-positions corresponds to values returned by BIOS */
1472 #define SHIFT_P 0x0003 /* two bits! */
1473 #define CTRL_P 0x0004
1474 #define ALT_P 0x0008
1475 #define SCRLOCK_P 0x0010
1476 #define NUMLOCK_P 0x0020
1477 #define CAPSLOCK_P 0x0040
1478 #define ALT_GR_P 0x0800
1479 #define SUPER_P 0x4000 /* pseudo */
1480 #define HYPER_P 0x8000 /* pseudo */
1482 static int
1483 dos_get_modifiers (keymask)
1484 int *keymask;
1486 union REGS regs;
1487 int mask;
1488 int modifiers = 0;
1490 /* Calculate modifier bits */
1491 regs.h.ah = extended_kbd ? 0x12 : 0x02;
1492 int86 (0x16, &regs, &regs);
1494 if (!extended_kbd)
1496 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
1497 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1499 else
1501 mask = regs.h.al & (SHIFT_P |
1502 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1504 /* Do not break international keyboard support. */
1505 /* When Keyb.Com is loaded, the right Alt key is */
1506 /* used for accessing characters like { and } */
1507 if (regs.h.ah & 2) /* Left ALT pressed ? */
1508 mask |= ALT_P;
1510 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
1512 mask |= ALT_GR_P;
1513 if (dos_hyper_key == 1)
1515 mask |= HYPER_P;
1516 modifiers |= hyper_modifier;
1518 else if (dos_super_key == 1)
1520 mask |= SUPER_P;
1521 modifiers |= super_modifier;
1523 else if (!international_keyboard)
1525 /* If Keyb.Com is NOT installed, let Right Alt behave
1526 like the Left Alt. */
1527 mask &= ~ALT_GR_P;
1528 mask |= ALT_P;
1532 if (regs.h.ah & 1) /* Left CTRL pressed ? */
1533 mask |= CTRL_P;
1535 if (regs.h.ah & 4) /* Right CTRL pressed ? */
1537 if (dos_hyper_key == 2)
1539 mask |= HYPER_P;
1540 modifiers |= hyper_modifier;
1542 else if (dos_super_key == 2)
1544 mask |= SUPER_P;
1545 modifiers |= super_modifier;
1547 else
1548 mask |= CTRL_P;
1552 if (mask & SHIFT_P)
1553 modifiers |= shift_modifier;
1554 if (mask & CTRL_P)
1555 modifiers |= ctrl_modifier;
1556 if (mask & ALT_P)
1557 modifiers |= meta_modifier;
1559 if (keymask)
1560 *keymask = mask;
1561 return modifiers;
1564 #define NUM_RECENT_DOSKEYS (100)
1565 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
1566 int total_doskeys; /* Total number of elements stored into recent_doskeys */
1567 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
1569 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
1570 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1571 Each input key receives two values in this vector: first the ASCII code,\n\
1572 and then the scan code.")
1575 Lisp_Object *keys = XVECTOR (recent_doskeys)->contents;
1576 Lisp_Object val;
1578 if (total_doskeys < NUM_RECENT_DOSKEYS)
1579 return Fvector (total_doskeys, keys);
1580 else
1582 val = Fvector (NUM_RECENT_DOSKEYS, keys);
1583 bcopy (keys + recent_doskeys_index,
1584 XVECTOR (val)->contents,
1585 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
1586 bcopy (keys,
1587 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
1588 recent_doskeys_index * sizeof (Lisp_Object));
1589 return val;
1593 /* Get a char from keyboard. Function keys are put into the event queue. */
1595 extern void kbd_buffer_store_event (struct input_event *);
1597 static int
1598 dos_rawgetc ()
1600 struct input_event event;
1601 union REGS regs;
1603 #ifndef HAVE_X_WINDOWS
1604 /* Maybe put the cursor where it should be. */
1605 IT_cmgoto (selected_frame);
1606 #endif
1608 /* The following condition is equivalent to `kbhit ()', except that
1609 it uses the bios to do its job. This pleases DESQview/X. */
1610 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
1611 int86 (0x16, &regs, &regs),
1612 (regs.x.flags & 0x40) == 0)
1614 union REGS regs;
1615 register unsigned char c;
1616 int sc, code, mask, kp_mode;
1617 int modifiers;
1619 regs.h.ah = extended_kbd ? 0x10 : 0x00;
1620 int86 (0x16, &regs, &regs);
1621 c = regs.h.al;
1622 sc = regs.h.ah;
1624 total_doskeys += 2;
1625 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1626 = make_number (c);
1627 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1628 recent_doskeys_index = 0;
1629 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1630 = make_number (sc);
1631 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1632 recent_doskeys_index = 0;
1634 modifiers = dos_get_modifiers (&mask);
1636 #ifndef HAVE_X_WINDOWS
1637 if (!NILP (Vdos_display_scancodes))
1639 char buf[11];
1640 sprintf (buf, "%02x:%02x*%04x",
1641 (unsigned) (sc&0xff), (unsigned) c, mask);
1642 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
1644 #endif
1646 if (sc == 0xe0)
1648 switch (c)
1650 case 10: /* Ctrl Grey Enter */
1651 code = Ctrl | Grey | 4;
1652 break;
1653 case 13: /* Grey Enter */
1654 code = Grey | 4;
1655 break;
1656 case '/': /* Grey / */
1657 code = Grey | 0;
1658 break;
1659 default:
1660 continue;
1662 c = 0;
1664 else
1666 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
1667 continue;
1668 if ((code = ibmpc_translate_map[sc]) == Ignore)
1669 continue;
1672 if (c == 0)
1674 /* We only look at the keyboard Ctrl/Shift/Alt keys when
1675 Emacs is ready to read a key. Therefore, if they press
1676 `Alt-x' when Emacs is busy, by the time we get to
1677 `dos_get_modifiers', they might have already released the
1678 Alt key, and Emacs gets just `x', which is BAD.
1679 However, for keys with the `Map' property set, the ASCII
1680 code returns zero iff Alt is pressed. So, when we DON'T
1681 have to support international_keyboard, we don't have to
1682 distinguish between the left and right Alt keys, and we
1683 can set the META modifier for any keys with the `Map'
1684 property if they return zero ASCII code (c = 0). */
1685 if ( (code & Alt)
1686 || ( (code & 0xf000) == Map && !international_keyboard))
1687 modifiers |= meta_modifier;
1688 if (code & Ctrl)
1689 modifiers |= ctrl_modifier;
1690 if (code & Shift)
1691 modifiers |= shift_modifier;
1694 switch (code & 0xf000)
1696 case ModFct:
1697 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
1698 return c;
1699 c = 0; /* Special */
1701 case FctKey:
1702 if (c != 0)
1703 return c;
1705 case Special:
1706 code |= 0xff00;
1707 break;
1709 case Normal:
1710 if (sc == 0)
1712 if (c == 0) /* ctrl-break */
1713 continue;
1714 return c; /* ALT-nnn */
1716 if (!keyboard_map_all)
1718 if (c != ' ')
1719 return c;
1720 code = c;
1721 break;
1724 case Map:
1725 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
1726 if (!keyboard_map_all)
1727 return c;
1729 code &= 0xff;
1730 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
1731 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
1733 if (mask & SHIFT_P)
1735 code = keyboard->shifted[code];
1736 mask -= SHIFT_P;
1737 modifiers &= ~shift_modifier;
1739 else
1740 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
1741 code = keyboard->alt_gr[code];
1742 else
1743 code = keyboard->unshifted[code];
1744 break;
1746 case KeyPad:
1747 code &= 0xff;
1748 if (c == 0xe0) /* edit key */
1749 kp_mode = 3;
1750 else
1751 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
1752 kp_mode = dos_keypad_mode & 0x03;
1753 else
1754 kp_mode = (dos_keypad_mode >> 4) & 0x03;
1756 switch (kp_mode)
1758 case 0:
1759 if (code == 10 && dos_decimal_point)
1760 return dos_decimal_point;
1761 return keypad_translate_map[code].char_code;
1763 case 1:
1764 code = 0xff00 | keypad_translate_map[code].keypad_code;
1765 break;
1767 case 2:
1768 code = keypad_translate_map[code].meta_code;
1769 modifiers = meta_modifier;
1770 break;
1772 case 3:
1773 code = 0xff00 | keypad_translate_map[code].editkey_code;
1774 break;
1776 break;
1778 case Grey:
1779 code &= 0xff;
1780 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
1781 if (dos_keypad_mode & kp_mode)
1782 code = 0xff00 | grey_key_translate_map[code].keypad_code;
1783 else
1784 code = grey_key_translate_map[code].char_code;
1785 break;
1788 make_event:
1789 if (code == 0)
1790 continue;
1792 if (code >= 0x100)
1793 event.kind = non_ascii_keystroke;
1794 else
1795 event.kind = ascii_keystroke;
1796 event.code = code;
1797 event.modifiers = modifiers;
1798 XSETFRAME (event.frame_or_window, selected_frame);
1799 event.timestamp = event_timestamp ();
1800 kbd_buffer_store_event (&event);
1803 if (have_mouse > 0)
1805 int but, press, x, y, ok;
1807 /* Check for mouse movement *before* buttons. */
1808 mouse_check_moved ();
1810 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
1811 for (press = 0; press < 2; press++)
1813 int button_num = but;
1815 if (press)
1816 ok = mouse_pressed (but, &x, &y);
1817 else
1818 ok = mouse_released (but, &x, &y);
1819 if (ok)
1821 /* Allow a simultaneous press/release of Mouse-1 and
1822 Mouse-2 to simulate Mouse-3 on two-button mice. */
1823 if (mouse_button_count == 2 && but < 2)
1825 int x2, y2; /* don't clobber original coordinates */
1827 /* If only one button is pressed, wait 100 msec and
1828 check again. This way, Speedy Gonzales isn't
1829 punished, while the slow get their chance. */
1830 if (press && mouse_pressed (1-but, &x2, &y2)
1831 || !press && mouse_released (1-but, &x2, &y2))
1832 button_num = 2;
1833 else
1835 delay (100);
1836 if (press && mouse_pressed (1-but, &x2, &y2)
1837 || !press && mouse_released (1-but, &x2, &y2))
1838 button_num = 2;
1842 event.kind = mouse_click;
1843 event.code = button_num;
1844 event.modifiers = dos_get_modifiers (0)
1845 | (press ? down_modifier : up_modifier);
1846 event.x = x;
1847 event.y = y;
1848 XSETFRAME (event.frame_or_window, selected_frame);
1849 event.timestamp = event_timestamp ();
1850 kbd_buffer_store_event (&event);
1855 return -1;
1858 static int prev_get_char = -1;
1860 /* Return 1 if a key is ready to be read without suspending execution. */
1862 dos_keysns ()
1864 if (prev_get_char != -1)
1865 return 1;
1866 else
1867 return ((prev_get_char = dos_rawgetc ()) != -1);
1870 /* Read a key. Return -1 if no key is ready. */
1872 dos_keyread ()
1874 if (prev_get_char != -1)
1876 int c = prev_get_char;
1877 prev_get_char = -1;
1878 return c;
1880 else
1881 return dos_rawgetc ();
1884 #ifndef HAVE_X_WINDOWS
1885 /* See xterm.c for more info. */
1886 void
1887 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
1888 FRAME_PTR f;
1889 register int pix_x, pix_y;
1890 register int *x, *y;
1891 void /* XRectangle */ *bounds;
1892 int noclip;
1894 if (bounds) abort ();
1896 /* Ignore clipping. */
1898 *x = pix_x;
1899 *y = pix_y;
1902 void
1903 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1904 FRAME_PTR f;
1905 register int x, y;
1906 register int *pix_x, *pix_y;
1908 *pix_x = x;
1909 *pix_y = y;
1912 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1913 for now.
1915 Actually, I don't know the meaning of all the parameters of the functions
1916 here -- I only know how they are called by xmenu.c. I could of course
1917 grab the nearest Xlib manual (down the hall, second-to-last door on the
1918 left), but I don't think it's worth the effort. */
1920 static XMenu *
1921 IT_menu_create ()
1923 XMenu *menu;
1925 menu = (XMenu *) xmalloc (sizeof (XMenu));
1926 menu->allocated = menu->count = menu->panecount = menu->width = 0;
1927 return menu;
1930 /* Allocate some (more) memory for MENU ensuring that there is room for one
1931 for item. */
1933 static void
1934 IT_menu_make_room (XMenu *menu)
1936 if (menu->allocated == 0)
1938 int count = menu->allocated = 10;
1939 menu->text = (char **) xmalloc (count * sizeof (char *));
1940 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
1941 menu->panenumber = (int *) xmalloc (count * sizeof (int));
1943 else if (menu->allocated == menu->count)
1945 int count = menu->allocated = menu->allocated + 10;
1946 menu->text
1947 = (char **) xrealloc (menu->text, count * sizeof (char *));
1948 menu->submenu
1949 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
1950 menu->panenumber
1951 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
1955 /* Search the given menu structure for a given pane number. */
1957 static XMenu *
1958 IT_menu_search_pane (XMenu *menu, int pane)
1960 int i;
1961 XMenu *try;
1963 for (i = 0; i < menu->count; i++)
1964 if (menu->submenu[i])
1966 if (pane == menu->panenumber[i])
1967 return menu->submenu[i];
1968 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
1969 return try;
1971 return (XMenu *) 0;
1974 /* Determine how much screen space a given menu needs. */
1976 static void
1977 IT_menu_calc_size (XMenu *menu, int *width, int *height)
1979 int i, h2, w2, maxsubwidth, maxheight;
1981 maxsubwidth = 0;
1982 maxheight = menu->count;
1983 for (i = 0; i < menu->count; i++)
1985 if (menu->submenu[i])
1987 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
1988 if (w2 > maxsubwidth) maxsubwidth = w2;
1989 if (i + h2 > maxheight) maxheight = i + h2;
1992 *width = menu->width + maxsubwidth;
1993 *height = maxheight;
1996 /* Display MENU at (X,Y) using FACES. */
1998 static void
1999 IT_menu_display (XMenu *menu, int y, int x, int *faces)
2001 int i, j, face, width;
2002 GLYPH *text, *p;
2003 char *q;
2004 int mx, my;
2005 int enabled, mousehere;
2006 int row, col;
2008 width = menu->width;
2009 text = (GLYPH *) xmalloc ((width + 2) * sizeof (GLYPH));
2010 ScreenGetCursor (&row, &col);
2011 mouse_get_xy (&mx, &my);
2012 IT_update_begin ();
2013 for (i = 0; i < menu->count; i++)
2015 IT_cursor_to (y + i, x);
2016 enabled
2017 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
2018 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
2019 face = faces[enabled + mousehere * 2];
2020 p = text;
2021 *p++ = FAST_MAKE_GLYPH (' ', face);
2022 for (j = 0, q = menu->text[i]; *q; j++)
2024 if (*q > 26)
2025 *p++ = FAST_MAKE_GLYPH (*q++, face);
2026 else /* make '^x' */
2028 *p++ = FAST_MAKE_GLYPH ('^', face);
2029 j++;
2030 *p++ = FAST_MAKE_GLYPH (*q++ + 64, face);
2034 for (; j < width; j++)
2035 *p++ = FAST_MAKE_GLYPH (' ', face);
2036 *p++ = FAST_MAKE_GLYPH (menu->submenu[i] ? 16 : ' ', face);
2037 IT_write_glyphs (text, width + 2);
2039 IT_update_end ();
2040 IT_cursor_to (row, col);
2041 xfree (text);
2044 /* --------------------------- X Menu emulation ---------------------- */
2046 /* Report availability of menus. */
2049 have_menus_p ()
2051 return 1;
2054 /* Create a brand new menu structure. */
2056 XMenu *
2057 XMenuCreate (Display *foo1, Window foo2, char *foo3)
2059 return IT_menu_create ();
2062 /* Create a new pane and place it on the outer-most level. It is not
2063 clear that it should be placed out there, but I don't know what else
2064 to do. */
2067 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
2069 int len;
2070 char *p;
2072 if (!enable)
2073 abort ();
2075 IT_menu_make_room (menu);
2076 menu->submenu[menu->count] = IT_menu_create ();
2077 menu->text[menu->count] = txt;
2078 menu->panenumber[menu->count] = ++menu->panecount;
2079 menu->count++;
2081 /* Adjust length for possible control characters (which will
2082 be written as ^x). */
2083 for (len = strlen (txt), p = txt; *p; p++)
2084 if (*p < 27)
2085 len++;
2087 if (len > menu->width)
2088 menu->width = len;
2090 return menu->panecount;
2093 /* Create a new item in a menu pane. */
2096 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
2097 int foo, char *txt, int enable)
2099 int len;
2100 char *p;
2102 if (pane)
2103 if (!(menu = IT_menu_search_pane (menu, pane)))
2104 return XM_FAILURE;
2105 IT_menu_make_room (menu);
2106 menu->submenu[menu->count] = (XMenu *) 0;
2107 menu->text[menu->count] = txt;
2108 menu->panenumber[menu->count] = enable;
2109 menu->count++;
2111 /* Adjust length for possible control characters (which will
2112 be written as ^x). */
2113 for (len = strlen (txt), p = txt; *p; p++)
2114 if (*p < 27)
2115 len++;
2117 if (len > menu->width)
2118 menu->width = len;
2120 return XM_SUCCESS;
2123 /* Decide where the menu would be placed if requested at (X,Y). */
2125 void
2126 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
2127 int *ulx, int *uly, int *width, int *height)
2129 IT_menu_calc_size (menu, width, height);
2130 *ulx = x + 1;
2131 *uly = y;
2132 *width += 2;
2135 struct IT_menu_state
2137 void *screen_behind;
2138 XMenu *menu;
2139 int pane;
2140 int x, y;
2144 /* Display menu, wait for user's response, and return that response. */
2147 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
2148 int x0, int y0, unsigned ButtonMask, char **txt)
2150 struct IT_menu_state *state;
2151 int statecount;
2152 int x, y, i, b;
2153 int screensize;
2154 int faces[4], selectface;
2155 int leave, result, onepane;
2156 int title_faces[4]; /* face to display the menu title */
2157 int buffers_num_deleted = 0;
2159 /* Just in case we got here without a mouse present... */
2160 if (have_mouse <= 0)
2161 return XM_IA_SELECT;
2162 /* Don't allow non-positive x0 and y0, lest the menu will wrap
2163 around the display. */
2164 if (x0 <= 0)
2165 x0 = 1;
2166 if (y0 <= 0)
2167 y0 = 1;
2169 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
2170 screensize = screen_size * 2;
2171 faces[0]
2172 = compute_glyph_face (selected_frame,
2173 face_name_id_number
2174 (selected_frame,
2175 intern ("msdos-menu-passive-face")),
2177 faces[1]
2178 = compute_glyph_face (selected_frame,
2179 face_name_id_number
2180 (selected_frame,
2181 intern ("msdos-menu-active-face")),
2183 selectface
2184 = face_name_id_number (selected_frame, intern ("msdos-menu-select-face"));
2185 faces[2] = compute_glyph_face (selected_frame, selectface, faces[0]);
2186 faces[3] = compute_glyph_face (selected_frame, selectface, faces[1]);
2188 /* Make sure the menu title is always displayed with
2189 `msdos-menu-active-face', no matter where the mouse pointer is. */
2190 for (i = 0; i < 4; i++)
2191 title_faces[i] = faces[3];
2193 statecount = 1;
2195 /* Don't let the title for the "Buffers" popup menu include a
2196 digit (which is ugly).
2198 This is a terrible kludge, but I think the "Buffers" case is
2199 the only one where the title includes a number, so it doesn't
2200 seem to be necessary to make this more general. */
2201 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
2203 menu->text[0][7] = '\0';
2204 buffers_num_deleted = 1;
2206 state[0].menu = menu;
2207 mouse_off ();
2208 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
2210 /* Turn off the cursor. Otherwise it shows through the menu
2211 panes, which is ugly. */
2212 IT_display_cursor (0);
2214 IT_menu_display (menu, y0 - 1, x0 - 1, title_faces); /* display menu title */
2215 if (buffers_num_deleted)
2216 menu->text[0][7] = ' ';
2217 if ((onepane = menu->count == 1 && menu->submenu[0]))
2219 menu->width = menu->submenu[0]->width;
2220 state[0].menu = menu->submenu[0];
2222 else
2224 state[0].menu = menu;
2226 state[0].x = x0 - 1;
2227 state[0].y = y0;
2228 state[0].pane = onepane;
2230 mouse_last_x = -1; /* A hack that forces display. */
2231 leave = 0;
2232 while (!leave)
2234 if (!mouse_visible) mouse_on ();
2235 mouse_check_moved ();
2236 if (selected_frame->mouse_moved)
2238 selected_frame->mouse_moved = 0;
2239 result = XM_IA_SELECT;
2240 mouse_get_xy (&x, &y);
2241 for (i = 0; i < statecount; i++)
2242 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
2244 int dy = y - state[i].y;
2245 if (0 <= dy && dy < state[i].menu->count)
2247 if (!state[i].menu->submenu[dy])
2248 if (state[i].menu->panenumber[dy])
2249 result = XM_SUCCESS;
2250 else
2251 result = XM_IA_SELECT;
2252 *pane = state[i].pane - 1;
2253 *selidx = dy;
2254 /* We hit some part of a menu, so drop extra menus that
2255 have been opened. That does not include an open and
2256 active submenu. */
2257 if (i != statecount - 2
2258 || state[i].menu->submenu[dy] != state[i+1].menu)
2259 while (i != statecount - 1)
2261 statecount--;
2262 mouse_off ();
2263 ScreenUpdate (state[statecount].screen_behind);
2264 xfree (state[statecount].screen_behind);
2266 if (i == statecount - 1 && state[i].menu->submenu[dy])
2268 IT_menu_display (state[i].menu,
2269 state[i].y,
2270 state[i].x,
2271 faces);
2272 state[statecount].menu = state[i].menu->submenu[dy];
2273 state[statecount].pane = state[i].menu->panenumber[dy];
2274 mouse_off ();
2275 ScreenRetrieve (state[statecount].screen_behind
2276 = xmalloc (screensize));
2277 state[statecount].x
2278 = state[i].x + state[i].menu->width + 2;
2279 state[statecount].y = y;
2280 statecount++;
2284 IT_menu_display (state[statecount - 1].menu,
2285 state[statecount - 1].y,
2286 state[statecount - 1].x,
2287 faces);
2289 for (b = 0; b < mouse_button_count; b++)
2291 (void) mouse_pressed (b, &x, &y);
2292 if (mouse_released (b, &x, &y))
2293 leave = 1;
2297 mouse_off ();
2298 ScreenUpdate (state[0].screen_behind);
2299 while (statecount--)
2300 xfree (state[statecount].screen_behind);
2301 IT_display_cursor (1); /* turn cursor back on */
2302 return result;
2305 /* Dispose of a menu. */
2307 void
2308 XMenuDestroy (Display *foo, XMenu *menu)
2310 int i;
2311 if (menu->allocated)
2313 for (i = 0; i < menu->count; i++)
2314 if (menu->submenu[i])
2315 XMenuDestroy (foo, menu->submenu[i]);
2316 xfree (menu->text);
2317 xfree (menu->submenu);
2318 xfree (menu->panenumber);
2320 xfree (menu);
2324 x_pixel_width (struct frame *f)
2326 return FRAME_WIDTH (f);
2330 x_pixel_height (struct frame *f)
2332 return FRAME_HEIGHT (f);
2334 #endif /* !HAVE_X_WINDOWS */
2336 /* ----------------------- DOS / UNIX conversion --------------------- */
2338 void msdos_downcase_filename (unsigned char *);
2340 /* Destructively turn backslashes into slashes. */
2342 void
2343 dostounix_filename (p)
2344 register char *p;
2346 msdos_downcase_filename (p);
2348 while (*p)
2350 if (*p == '\\')
2351 *p = '/';
2352 p++;
2356 /* Destructively turn slashes into backslashes. */
2358 void
2359 unixtodos_filename (p)
2360 register char *p;
2362 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
2364 *p += 'a' - 'A';
2365 p += 2;
2368 while (*p)
2370 if (*p == '/')
2371 *p = '\\';
2372 p++;
2376 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2379 getdefdir (drive, dst)
2380 int drive;
2381 char *dst;
2383 char in_path[4], *p = in_path;
2384 int e = errno;
2386 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2387 if (drive != 0)
2389 *p++ = drive + 'A' - 1;
2390 *p++ = ':';
2393 *p++ = '.';
2394 *p = '\0';
2395 errno = 0;
2396 _fixpath (in_path, dst);
2397 if (errno)
2398 return 0;
2400 msdos_downcase_filename (dst);
2402 errno = e;
2403 return 1;
2406 /* Remove all CR's that are followed by a LF. */
2409 crlf_to_lf (n, buf)
2410 register int n;
2411 register unsigned char *buf;
2413 unsigned char *np = buf;
2414 unsigned char *startp = buf;
2415 unsigned char *endp = buf + n;
2417 if (n == 0)
2418 return n;
2419 while (buf < endp - 1)
2421 if (*buf == 0x0d)
2423 if (*(++buf) != 0x0a)
2424 *np++ = 0x0d;
2426 else
2427 *np++ = *buf++;
2429 if (buf < endp)
2430 *np++ = *buf++;
2431 return np - startp;
2434 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
2436 /* In DJGPP v2.0, library `write' can call `malloc', which might
2437 cause relocation of the buffer whose address we get in ADDR.
2438 Here is a version of `write' that avoids calling `malloc',
2439 to serve us until such time as the library is fixed.
2440 Actually, what we define here is called `__write', because
2441 `write' is a stub that just jmp's to `__write' (to be
2442 POSIXLY-correct with respect to the global name-space). */
2444 #include <io.h> /* for _write */
2445 #include <libc/dosio.h> /* for __file_handle_modes[] */
2447 static char xbuf[64 * 1024]; /* DOS cannot write more in one chunk */
2449 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
2452 __write (int handle, const void *buffer, size_t count)
2454 if (count == 0)
2455 return 0;
2457 if(__file_handle_modes[handle] & O_BINARY)
2458 return _write (handle, buffer, count);
2459 else
2461 char *xbp = xbuf;
2462 const char *bp = buffer;
2463 int total_written = 0;
2464 int nmoved = 0, ncr = 0;
2466 while (count)
2468 /* The next test makes sure there's space for at least 2 more
2469 characters in xbuf[], so both CR and LF can be put there. */
2470 if (xbp < XBUF_END)
2472 if (*bp == '\n')
2474 ncr++;
2475 *xbp++ = '\r';
2477 *xbp++ = *bp++;
2478 nmoved++;
2479 count--;
2481 if (xbp >= XBUF_END || !count)
2483 size_t to_write = nmoved + ncr;
2484 int written = _write (handle, xbuf, to_write);
2486 if (written == -1)
2487 return -1;
2488 else
2489 total_written += nmoved; /* CRs aren't counted in ret value */
2491 /* If some, but not all were written (disk full?), return
2492 an estimate of the total written bytes not counting CRs. */
2493 if (written < to_write)
2494 return total_written - (to_write - written) * nmoved/to_write;
2496 nmoved = 0;
2497 ncr = 0;
2498 xbp = xbuf;
2501 return total_written;
2505 /* A low-level file-renaming function which works around Windows 95 bug.
2506 This is pulled directly out of DJGPP v2.01 library sources, and only
2507 used when you compile with DJGPP v2.0. */
2509 #include <io.h>
2511 int _rename(const char *old, const char *new)
2513 __dpmi_regs r;
2514 int olen = strlen(old) + 1;
2515 int i;
2516 int use_lfn = _USE_LFN;
2517 char tempfile[FILENAME_MAX];
2518 const char *orig = old;
2519 int lfn_fd = -1;
2521 r.x.dx = __tb_offset;
2522 r.x.di = __tb_offset + olen;
2523 r.x.ds = r.x.es = __tb_segment;
2525 if (use_lfn)
2527 /* Windows 95 bug: for some filenames, when you rename
2528 file -> file~ (as in Emacs, to leave a backup), the
2529 short 8+3 alias doesn't change, which effectively
2530 makes OLD and NEW the same file. We must rename
2531 through a temporary file to work around this. */
2533 char *pbase = 0, *p;
2534 static char try_char[] = "abcdefghijklmnopqrstuvwxyz012345789";
2535 int idx = sizeof(try_char) - 1;
2537 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
2538 might point to another drive, which will fail the DOS call. */
2539 strcpy(tempfile, old);
2540 for (p = tempfile; *p; p++) /* ensure temporary is on the same drive */
2541 if (*p == '/' || *p == '\\' || *p == ':')
2542 pbase = p;
2543 if (pbase)
2544 pbase++;
2545 else
2546 pbase = tempfile;
2547 strcpy(pbase, "X$$djren$$.$$temp$$");
2551 if (idx <= 0)
2552 return -1;
2553 *pbase = try_char[--idx];
2554 } while (_chmod(tempfile, 0) != -1);
2556 r.x.ax = 0x7156;
2557 _put_path2(tempfile, olen);
2558 _put_path(old);
2559 __dpmi_int(0x21, &r);
2560 if (r.x.flags & 1)
2562 errno = __doserr_to_errno(r.x.ax);
2563 return -1;
2566 /* Now create a file with the original name. This will
2567 ensure that NEW will always have a 8+3 alias
2568 different from that of OLD. (Seems to be required
2569 when NameNumericTail in the Registry is set to 0.) */
2570 lfn_fd = _creat(old, 0);
2572 olen = strlen(tempfile) + 1;
2573 old = tempfile;
2574 r.x.di = __tb_offset + olen;
2577 for (i=0; i<2; i++)
2579 if(use_lfn)
2580 r.x.ax = 0x7156;
2581 else
2582 r.h.ah = 0x56;
2583 _put_path2(new, olen);
2584 _put_path(old);
2585 __dpmi_int(0x21, &r);
2586 if(r.x.flags & 1)
2588 if (r.x.ax == 5 && i == 0) /* access denied */
2589 remove(new); /* and try again */
2590 else
2592 errno = __doserr_to_errno(r.x.ax);
2594 /* Restore to original name if we renamed it to temporary. */
2595 if (use_lfn)
2597 if (lfn_fd != -1)
2599 _close (lfn_fd);
2600 remove (orig);
2602 _put_path2(orig, olen);
2603 _put_path(tempfile);
2604 r.x.ax = 0x7156;
2605 __dpmi_int(0x21, &r);
2607 return -1;
2610 else
2611 break;
2614 /* Success. Delete the file possibly created to work
2615 around the Windows 95 bug. */
2616 if (lfn_fd != -1)
2617 return (_close (lfn_fd) == 0) ? remove (orig) : -1;
2618 return 0;
2621 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
2623 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
2624 0, 0, 0,
2625 "Return non-nil if long file names are supported on MSDOS.")
2628 return (_USE_LFN ? Qt : Qnil);
2631 /* Convert alphabetic characters in a filename to lower-case. */
2633 void
2634 msdos_downcase_filename (p)
2635 register unsigned char *p;
2637 /* Always lower-case drive letters a-z, even if the filesystem
2638 preserves case in filenames.
2639 This is so MSDOS filenames could be compared by string comparison
2640 functions that are case-sensitive. Even case-preserving filesystems
2641 do not distinguish case in drive letters. */
2642 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
2644 *p += 'a' - 'A';
2645 p += 2;
2648 /* Under LFN we expect to get pathnames in their true case. */
2649 if (NILP (Fmsdos_long_file_names ()))
2650 for ( ; *p; p++)
2651 if (*p >= 'A' && *p <= 'Z')
2652 *p += 'a' - 'A';
2655 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
2656 1, 1, 0,
2657 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
2658 When long filenames are supported, doesn't change FILENAME.\n\
2659 If FILENAME is not a string, returns nil.\n\
2660 The argument object is never altered--the value is a copy.")
2661 (filename)
2662 Lisp_Object filename;
2664 Lisp_Object tem;
2666 if (! STRINGP (filename))
2667 return Qnil;
2669 tem = Fcopy_sequence (filename);
2670 msdos_downcase_filename (XSTRING (tem)->data);
2671 return tem;
2674 /* The Emacs root directory as determined by init_environment. */
2676 static char emacsroot[MAXPATHLEN];
2678 char *
2679 rootrelativepath (rel)
2680 char *rel;
2682 static char result[MAXPATHLEN + 10];
2684 strcpy (result, emacsroot);
2685 strcat (result, "/");
2686 strcat (result, rel);
2687 return result;
2690 /* Define a lot of environment variables if not already defined. Don't
2691 remove anything unless you know what you're doing -- lots of code will
2692 break if one or more of these are missing. */
2694 void
2695 init_environment (argc, argv, skip_args)
2696 int argc;
2697 char **argv;
2698 int skip_args;
2700 char *s, *t, *root;
2701 int len;
2703 /* Find our root from argv[0]. Assuming argv[0] is, say,
2704 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
2705 root = alloca (MAXPATHLEN + 20);
2706 _fixpath (argv[0], root);
2707 msdos_downcase_filename (root);
2708 len = strlen (root);
2709 while (len > 0 && root[len] != '/' && root[len] != ':')
2710 len--;
2711 root[len] = '\0';
2712 if (len > 4
2713 && (strcmp (root + len - 4, "/bin") == 0
2714 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
2715 root[len - 4] = '\0';
2716 else
2717 strcpy (root, "c:/emacs"); /* let's be defensive */
2718 len = strlen (root);
2719 strcpy (emacsroot, root);
2721 /* We default HOME to our root. */
2722 setenv ("HOME", root, 0);
2724 /* We default EMACSPATH to root + "/bin". */
2725 strcpy (root + len, "/bin");
2726 setenv ("EMACSPATH", root, 0);
2728 /* I don't expect anybody to ever use other terminals so the internal
2729 terminal is the default. */
2730 setenv ("TERM", "internal", 0);
2732 #ifdef HAVE_X_WINDOWS
2733 /* Emacs expects DISPLAY to be set. */
2734 setenv ("DISPLAY", "unix:0.0", 0);
2735 #endif
2737 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
2738 downcase it and mirror the backslashes. */
2739 s = getenv ("COMSPEC");
2740 if (!s) s = "c:/command.com";
2741 t = alloca (strlen (s) + 1);
2742 strcpy (t, s);
2743 dostounix_filename (t);
2744 setenv ("SHELL", t, 0);
2746 /* PATH is also downcased and backslashes mirrored. */
2747 s = getenv ("PATH");
2748 if (!s) s = "";
2749 t = alloca (strlen (s) + 3);
2750 /* Current directory is always considered part of MsDos's path but it is
2751 not normally mentioned. Now it is. */
2752 strcat (strcpy (t, ".;"), s);
2753 dostounix_filename (t); /* Not a single file name, but this should work. */
2754 setenv ("PATH", t, 1);
2756 /* In some sense all dos users have root privileges, so... */
2757 setenv ("USER", "root", 0);
2758 setenv ("NAME", getenv ("USER"), 0);
2760 /* Time zone determined from country code. To make this possible, the
2761 country code may not span more than one time zone. In other words,
2762 in the USA, you lose. */
2763 if (!getenv ("TZ"))
2764 switch (dos_country_code)
2766 case 31: /* Belgium */
2767 case 32: /* The Netherlands */
2768 case 33: /* France */
2769 case 34: /* Spain */
2770 case 36: /* Hungary */
2771 case 38: /* Yugoslavia (or what's left of it?) */
2772 case 39: /* Italy */
2773 case 41: /* Switzerland */
2774 case 42: /* Tjekia */
2775 case 45: /* Denmark */
2776 case 46: /* Sweden */
2777 case 47: /* Norway */
2778 case 48: /* Poland */
2779 case 49: /* Germany */
2780 /* Daylight saving from last Sunday in March to last Sunday in
2781 September, both at 2AM. */
2782 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2783 break;
2784 case 44: /* United Kingdom */
2785 case 351: /* Portugal */
2786 case 354: /* Iceland */
2787 setenv ("TZ", "GMT+00", 0);
2788 break;
2789 case 81: /* Japan */
2790 case 82: /* Korea */
2791 setenv ("TZ", "JST-09", 0);
2792 break;
2793 case 90: /* Turkey */
2794 case 358: /* Finland */
2795 setenv ("TZ", "EET-02", 0);
2796 break;
2797 case 972: /* Israel */
2798 /* This is an approximation. (For exact rules, use the
2799 `zoneinfo/israel' file which comes with DJGPP, but you need
2800 to install it in `/usr/share/zoneinfo/' directory first.) */
2801 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2802 break;
2804 tzset ();
2809 static int break_stat; /* BREAK check mode status. */
2810 static int stdin_stat; /* stdin IOCTL status. */
2812 #if __DJGPP__ < 2
2814 /* These must be global. */
2815 static _go32_dpmi_seginfo ctrl_break_vector;
2816 static _go32_dpmi_registers ctrl_break_regs;
2817 static int ctrlbreakinstalled = 0;
2819 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2821 void
2822 ctrl_break_func (regs)
2823 _go32_dpmi_registers *regs;
2825 Vquit_flag = Qt;
2828 void
2829 install_ctrl_break_check ()
2831 if (!ctrlbreakinstalled)
2833 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2834 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2835 ctrlbreakinstalled = 1;
2836 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
2837 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
2838 &ctrl_break_regs);
2839 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
2843 #endif /* __DJGPP__ < 2 */
2845 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
2846 control chars by DOS. Determine the keyboard type. */
2849 dos_ttraw ()
2851 union REGS inregs, outregs;
2852 static int first_time = 1;
2854 break_stat = getcbrk ();
2855 setcbrk (0);
2856 #if __DJGPP__ < 2
2857 install_ctrl_break_check ();
2858 #endif
2860 if (first_time)
2862 inregs.h.ah = 0xc0;
2863 int86 (0x15, &inregs, &outregs);
2864 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
2866 have_mouse = 0;
2868 if (internal_terminal
2869 #ifdef HAVE_X_WINDOWS
2870 && inhibit_window_system
2871 #endif
2874 inregs.x.ax = 0x0021;
2875 int86 (0x33, &inregs, &outregs);
2876 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2877 if (!have_mouse)
2879 /* Reportedly, the above doesn't work for some mouse drivers. There
2880 is an additional detection method that should work, but might be
2881 a little slower. Use that as an alternative. */
2882 inregs.x.ax = 0x0000;
2883 int86 (0x33, &inregs, &outregs);
2884 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2887 if (have_mouse)
2889 have_mouse = 1; /* enable mouse */
2890 mouse_visible = 0;
2892 if (outregs.x.bx == 3)
2894 mouse_button_count = 3;
2895 mouse_button_translate[0] = 0; /* Left */
2896 mouse_button_translate[1] = 2; /* Middle */
2897 mouse_button_translate[2] = 1; /* Right */
2899 else
2901 mouse_button_count = 2;
2902 mouse_button_translate[0] = 0;
2903 mouse_button_translate[1] = 1;
2905 mouse_position_hook = &mouse_get_pos;
2906 mouse_init ();
2910 first_time = 0;
2912 #if __DJGPP__ >= 2
2914 stdin_stat = setmode (fileno (stdin), O_BINARY);
2915 return (stdin_stat != -1);
2917 else
2918 return (setmode (fileno (stdin), O_BINARY) != -1);
2920 #else /* __DJGPP__ < 2 */
2924 /* I think it is wrong to overwrite `stdin_stat' every time
2925 but the first one this function is called, but I don't
2926 want to change the way it used to work in v1.x.--EZ */
2928 inregs.x.ax = 0x4400; /* Get IOCTL status. */
2929 inregs.x.bx = 0x00; /* 0 = stdin. */
2930 intdos (&inregs, &outregs);
2931 stdin_stat = outregs.h.dl;
2933 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
2934 inregs.x.ax = 0x4401; /* Set IOCTL status */
2935 intdos (&inregs, &outregs);
2936 return !outregs.x.cflag;
2938 #endif /* __DJGPP__ < 2 */
2941 /* Restore status of standard input and Ctrl-C checking. */
2944 dos_ttcooked ()
2946 union REGS inregs, outregs;
2948 setcbrk (break_stat);
2949 mouse_off ();
2951 #if __DJGPP__ >= 2
2953 return (setmode (fileno (stdin), stdin_stat) != -1);
2955 #else /* not __DJGPP__ >= 2 */
2957 inregs.x.ax = 0x4401; /* Set IOCTL status. */
2958 inregs.x.bx = 0x00; /* 0 = stdin. */
2959 inregs.x.dx = stdin_stat;
2960 intdos (&inregs, &outregs);
2961 return !outregs.x.cflag;
2963 #endif /* not __DJGPP__ >= 2 */
2967 /* Run command as specified by ARGV in directory DIR.
2968 The command is run with input from TEMPIN, output to
2969 file TEMPOUT and stderr to TEMPERR. */
2972 run_msdos_command (argv, dir, tempin, tempout, temperr)
2973 unsigned char **argv;
2974 Lisp_Object dir;
2975 int tempin, tempout, temperr;
2977 char *saveargv1, *saveargv2, **envv, *lowcase_argv0, *pa, *pl;
2978 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
2979 int msshell, result = -1;
2980 int inbak, outbak, errbak;
2981 int x, y;
2982 Lisp_Object cmd;
2984 /* Get current directory as MSDOS cwd is not per-process. */
2985 getwd (oldwd);
2987 /* If argv[0] is the shell, it might come in any lettercase.
2988 Since `Fmember' is case-sensitive, we need to downcase
2989 argv[0], even if we are on case-preserving filesystems. */
2990 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
2991 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
2993 *pl = *pa++;
2994 if (*pl >= 'A' && *pl <= 'Z')
2995 *pl += 'a' - 'A';
2997 *pl = '\0';
2999 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
3000 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
3001 && !strcmp ("-c", argv[1]);
3002 if (msshell)
3004 saveargv1 = argv[1];
3005 saveargv2 = argv[2];
3006 argv[1] = "/c";
3007 if (argv[2])
3009 char *p = alloca (strlen (argv[2]) + 1);
3011 strcpy (argv[2] = p, saveargv2);
3012 while (*p && isspace (*p))
3013 p++;
3014 while (*p && !isspace (*p))
3015 if (*p == '/')
3016 *p++ = '\\';
3017 else
3018 p++;
3022 /* Build the environment array. */
3024 extern Lisp_Object Vprocess_environment;
3025 Lisp_Object tmp, lst;
3026 int i, len;
3028 lst = Vprocess_environment;
3029 len = XFASTINT (Flength (lst));
3031 envv = alloca ((len + 1) * sizeof (char *));
3032 for (i = 0; i < len; i++)
3034 tmp = Fcar (lst);
3035 lst = Fcdr (lst);
3036 CHECK_STRING (tmp, 0);
3037 envv[i] = alloca (XSTRING (tmp)->size + 1);
3038 strcpy (envv[i], XSTRING (tmp)->data);
3040 envv[len] = (char *) 0;
3043 if (STRINGP (dir))
3044 chdir (XSTRING (dir)->data);
3045 inbak = dup (0);
3046 outbak = dup (1);
3047 errbak = dup (2);
3048 if (inbak < 0 || outbak < 0 || errbak < 0)
3049 goto done; /* Allocation might fail due to lack of descriptors. */
3051 if (have_mouse > 0)
3052 mouse_get_xy (&x, &y);
3054 dos_ttcooked (); /* do it here while 0 = stdin */
3056 dup2 (tempin, 0);
3057 dup2 (tempout, 1);
3058 dup2 (temperr, 2);
3060 #if __DJGPP__ > 1
3062 if (msshell && !argv[3])
3064 /* MS-DOS native shells are too restrictive. For starters, they
3065 cannot grok commands longer than 126 characters. In DJGPP v2
3066 and later, `system' is much smarter, so we'll call it instead. */
3068 extern char **environ;
3069 environ = envv;
3071 /* A shell gets a single argument--its full command
3072 line--whose original was saved in `saveargv2'. */
3073 result = system (saveargv2);
3075 else
3077 #endif /* __DJGPP__ > 1 */
3079 result = spawnve (P_WAIT, argv[0], argv, envv);
3081 dup2 (inbak, 0);
3082 dup2 (outbak, 1);
3083 dup2 (errbak, 2);
3084 close (inbak);
3085 close (outbak);
3086 close (errbak);
3088 dos_ttraw ();
3089 if (have_mouse > 0)
3091 mouse_init ();
3092 mouse_moveto (x, y);
3095 /* Some programs might change the meaning of the highest bit of the
3096 text attribute byte, so we get blinking characters instead of the
3097 bright background colors. Restore that. */
3098 bright_bg ();
3100 done:
3101 chdir (oldwd);
3102 if (msshell)
3104 argv[1] = saveargv1;
3105 argv[2] = saveargv2;
3107 return result;
3110 croak (badfunc)
3111 char *badfunc;
3113 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
3114 reset_sys_modes ();
3115 exit (1);
3118 #if __DJGPP__ < 2
3120 /* ------------------------- Compatibility functions -------------------
3121 * gethostname
3122 * gettimeofday
3125 /* Hostnames for a pc are not really funny,
3126 but they are used in change log so we emulate the best we can. */
3128 gethostname (p, size)
3129 char *p;
3130 int size;
3132 char *q = egetenv ("HOSTNAME");
3134 if (!q) q = "pc";
3135 strcpy (p, q);
3136 return 0;
3139 /* When time zones are set from Ms-Dos too many C-libraries are playing
3140 tricks with time values. We solve this by defining our own version
3141 of `gettimeofday' bypassing GO32. Our version needs to be initialized
3142 once and after each call to `tzset' with TZ changed. That is
3143 accomplished by aliasing tzset to init_gettimeofday. */
3145 static struct tm time_rec;
3148 gettimeofday (struct timeval *tp, struct timezone *tzp)
3150 if (tp)
3152 struct time t;
3153 struct tm tm;
3155 gettime (&t);
3156 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
3158 struct date d;
3159 getdate (&d);
3160 time_rec.tm_year = d.da_year - 1900;
3161 time_rec.tm_mon = d.da_mon - 1;
3162 time_rec.tm_mday = d.da_day;
3165 time_rec.tm_hour = t.ti_hour;
3166 time_rec.tm_min = t.ti_min;
3167 time_rec.tm_sec = t.ti_sec;
3169 tm = time_rec;
3170 tm.tm_gmtoff = dos_timezone_offset;
3172 tp->tv_sec = mktime (&tm); /* may modify tm */
3173 tp->tv_usec = t.ti_hund * (1000000 / 100);
3175 /* Ignore tzp; it's obsolescent. */
3176 return 0;
3179 #endif /* __DJGPP__ < 2 */
3182 * A list of unimplemented functions that we silently ignore.
3185 #if __DJGPP__ < 2
3186 unsigned alarm (s) unsigned s; {}
3187 fork () { return 0; }
3188 int kill (x, y) int x, y; { return -1; }
3189 nice (p) int p; {}
3190 void volatile pause () {}
3191 sigsetmask (x) int x; { return 0; }
3192 sigblock (mask) int mask; { return 0; }
3193 #endif
3195 request_sigio () {}
3196 setpgrp () {return 0; }
3197 setpriority (x,y,z) int x,y,z; { return 0; }
3198 unrequest_sigio () {}
3200 #if __DJGPP__ > 1
3202 #ifdef POSIX_SIGNALS
3204 /* Augment DJGPP library POSIX signal functions. This is needed
3205 as of DJGPP v2.01, but might be in the library in later releases. */
3207 #include <libc/bss.h>
3209 /* A counter to know when to re-initialize the static sets. */
3210 static int sigprocmask_count = -1;
3212 /* Which signals are currently blocked (initially none). */
3213 static sigset_t current_mask;
3215 /* Which signals are pending (initially none). */
3216 static sigset_t pending_signals;
3218 /* Previous handlers to restore when the blocked signals are unblocked. */
3219 typedef void (*sighandler_t)(int);
3220 static sighandler_t prev_handlers[320];
3222 /* A signal handler which just records that a signal occured
3223 (it will be raised later, if and when the signal is unblocked). */
3224 static void
3225 sig_suspender (signo)
3226 int signo;
3228 sigaddset (&pending_signals, signo);
3232 sigprocmask (how, new_set, old_set)
3233 int how;
3234 const sigset_t *new_set;
3235 sigset_t *old_set;
3237 int signo;
3238 sigset_t new_mask;
3240 /* If called for the first time, initialize. */
3241 if (sigprocmask_count != __bss_count)
3243 sigprocmask_count = __bss_count;
3244 sigemptyset (&pending_signals);
3245 sigemptyset (&current_mask);
3246 for (signo = 0; signo < 320; signo++)
3247 prev_handlers[signo] = SIG_ERR;
3250 if (old_set)
3251 *old_set = current_mask;
3253 if (new_set == 0)
3254 return 0;
3256 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
3258 errno = EINVAL;
3259 return -1;
3262 sigemptyset (&new_mask);
3264 /* DJGPP supports upto 320 signals. */
3265 for (signo = 0; signo < 320; signo++)
3267 if (sigismember (&current_mask, signo))
3268 sigaddset (&new_mask, signo);
3269 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
3271 sigaddset (&new_mask, signo);
3273 /* SIGKILL is silently ignored, as on other platforms. */
3274 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
3275 prev_handlers[signo] = signal (signo, sig_suspender);
3277 if (( how == SIG_UNBLOCK
3278 && sigismember (&new_mask, signo)
3279 && sigismember (new_set, signo))
3280 || (how == SIG_SETMASK
3281 && sigismember (&new_mask, signo)
3282 && !sigismember (new_set, signo)))
3284 sigdelset (&new_mask, signo);
3285 if (prev_handlers[signo] != SIG_ERR)
3287 signal (signo, prev_handlers[signo]);
3288 prev_handlers[signo] = SIG_ERR;
3290 if (sigismember (&pending_signals, signo))
3292 sigdelset (&pending_signals, signo);
3293 raise (signo);
3297 current_mask = new_mask;
3298 return 0;
3301 #else /* not POSIX_SIGNALS */
3303 sigsetmask (x) int x; { return 0; }
3304 sigblock (mask) int mask; { return 0; }
3306 #endif /* not POSIX_SIGNALS */
3307 #endif /* __DJGPP__ > 1 */
3309 #ifndef HAVE_SELECT
3310 #include "sysselect.h"
3312 #ifndef EMACS_TIME_ZERO_OR_NEG_P
3313 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
3314 ((long)(time).tv_sec < 0 \
3315 || ((time).tv_sec == 0 \
3316 && (long)(time).tv_usec <= 0))
3317 #endif
3320 /* Only event queue is checked. */
3321 /* We don't have to call timer_check here
3322 because wait_reading_process_input takes care of that. */
3324 sys_select (nfds, rfds, wfds, efds, timeout)
3325 int nfds;
3326 SELECT_TYPE *rfds, *wfds, *efds;
3327 EMACS_TIME *timeout;
3329 int check_input;
3330 struct time t;
3332 check_input = 0;
3333 if (rfds)
3335 check_input = FD_ISSET (0, rfds);
3336 FD_ZERO (rfds);
3338 if (wfds)
3339 FD_ZERO (wfds);
3340 if (efds)
3341 FD_ZERO (efds);
3343 if (nfds != 1)
3344 abort ();
3346 /* If we are looking only for the terminal, with no timeout,
3347 just read it and wait -- that's more efficient. */
3348 if (!timeout)
3350 while (!detect_input_pending ())
3352 #if __DJGPP__ >= 2
3353 __dpmi_yield ();
3354 #endif
3357 else
3359 EMACS_TIME clnow, cllast, cldiff;
3361 gettime (&t);
3362 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
3364 while (!check_input || !detect_input_pending ())
3366 gettime (&t);
3367 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
3368 EMACS_SUB_TIME (cldiff, clnow, cllast);
3370 /* When seconds wrap around, we assume that no more than
3371 1 minute passed since last `gettime'. */
3372 if (EMACS_TIME_NEG_P (cldiff))
3373 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
3374 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
3376 /* Stop when timeout value crosses zero. */
3377 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
3378 return 0;
3379 cllast = clnow;
3380 #if __DJGPP__ >= 2
3381 __dpmi_yield ();
3382 #endif
3386 FD_SET (0, rfds);
3387 return 1;
3389 #endif
3392 * Define overlaid functions:
3394 * chdir -> sys_chdir
3395 * tzset -> init_gettimeofday
3396 * abort -> dos_abort
3399 #ifdef chdir
3400 #undef chdir
3401 extern int chdir ();
3404 sys_chdir (path)
3405 const char* path;
3407 int len = strlen (path);
3408 char *tmp = (char *)path;
3410 if (*tmp && tmp[1] == ':')
3412 if (getdisk () != tolower (tmp[0]) - 'a')
3413 setdisk (tolower (tmp[0]) - 'a');
3414 tmp += 2; /* strip drive: KFS 1995-07-06 */
3415 len -= 2;
3418 if (len > 1 && (tmp[len - 1] == '/'))
3420 char *tmp1 = (char *) alloca (len + 1);
3421 strcpy (tmp1, tmp);
3422 tmp1[len - 1] = 0;
3423 tmp = tmp1;
3425 return chdir (tmp);
3427 #endif
3429 #ifdef tzset
3430 #undef tzset
3431 extern void tzset (void);
3433 void
3434 init_gettimeofday ()
3436 time_t ltm, gtm;
3437 struct tm *lstm;
3439 tzset ();
3440 ltm = gtm = time (NULL);
3441 ltm = mktime (lstm = localtime (&ltm));
3442 gtm = mktime (gmtime (&gtm));
3443 time_rec.tm_hour = 99; /* force gettimeofday to get date */
3444 time_rec.tm_isdst = lstm->tm_isdst;
3445 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
3447 #endif
3449 #ifdef abort
3450 #undef abort
3451 void
3452 dos_abort (file, line)
3453 char *file;
3454 int line;
3456 char buffer1[200], buffer2[400];
3457 int i, j;
3459 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
3460 for (i = j = 0; buffer1[i]; i++) {
3461 buffer2[j++] = buffer1[i];
3462 buffer2[j++] = 0x70;
3464 dosmemput (buffer2, j, (int)ScreenPrimary);
3465 ScreenSetCursor (2, 0);
3466 abort ();
3468 #else
3469 void
3470 abort ()
3472 dos_ttcooked ();
3473 ScreenSetCursor (10, 0);
3474 cputs ("\r\n\nEmacs aborted!\r\n");
3475 #if __DJGPP__ > 1
3476 /* Generate traceback, so we could tell whodunit. */
3477 signal (SIGINT, SIG_DFL);
3478 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
3479 #endif
3480 exit (2);
3482 #endif
3484 /* The following two are required so that customization feature
3485 won't complain about unbound variables. */
3486 #ifndef HAVE_X_WINDOWS
3487 /* Search path for bitmap files (xfns.c). */
3488 Lisp_Object Vx_bitmap_file_path;
3489 #endif
3490 #ifndef subprocesses
3491 /* Nonzero means delete a process right away if it exits (process.c). */
3492 static int delete_exited_processes;
3493 #endif
3495 syms_of_msdos ()
3497 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
3498 staticpro (&recent_doskeys);
3499 #ifndef HAVE_X_WINDOWS
3500 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
3501 "List of directories to search for bitmap files for X.");
3502 Vx_bitmap_file_path = decode_env_path ((char *) 0, ".");
3504 /* The following two are from xfns.c: */
3505 Qbackground_color = intern ("background-color");
3506 staticpro (&Qbackground_color);
3507 Qforeground_color = intern ("foreground-color");
3508 staticpro (&Qforeground_color);
3509 #endif
3510 #ifndef subprocesses
3511 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
3512 "*Non-nil means delete processes immediately when they exit.\n\
3513 nil means don't delete them until `list-processes' is run.");
3514 delete_exited_processes = 0;
3515 #endif
3517 defsubr (&Srecent_doskeys);
3518 defsubr (&Smsdos_long_file_names);
3519 defsubr (&Smsdos_downcase_filename);
3522 #endif /* MSDOS */