(array-mode): Add autoload cookie.
[emacs.git] / src / msdos.c
blobfcbb4128b81b14274f88382da2264fa8d238024f
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 static void
161 mouse_get_xy (int *x, int *y)
163 union REGS regs;
165 regs.x.ax = 0x0003;
166 int86 (0x33, &regs, &regs);
167 *x = regs.x.cx / 8;
168 *y = regs.x.dx / 8;
171 void
172 mouse_moveto (x, y)
173 int x, y;
175 union REGS regs;
177 if (termscript)
178 fprintf (termscript, "<M_XY=%dx%d>", x, y);
179 regs.x.ax = 0x0004;
180 mouse_last_x = regs.x.cx = x * 8;
181 mouse_last_y = regs.x.dx = y * 8;
182 int86 (0x33, &regs, &regs);
185 static int
186 mouse_pressed (b, xp, yp)
187 int b, *xp, *yp;
189 union REGS regs;
191 if (b >= mouse_button_count)
192 return 0;
193 regs.x.ax = 0x0005;
194 regs.x.bx = mouse_button_translate[b];
195 int86 (0x33, &regs, &regs);
196 if (regs.x.bx)
197 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
198 return (regs.x.bx != 0);
201 static int
202 mouse_released (b, xp, yp)
203 int b, *xp, *yp;
205 union REGS regs;
207 if (b >= mouse_button_count)
208 return 0;
209 regs.x.ax = 0x0006;
210 regs.x.bx = mouse_button_translate[b];
211 int86 (0x33, &regs, &regs);
212 if (regs.x.bx)
213 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
214 return (regs.x.bx != 0);
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 Lisp_Object frame, tail;
228 /* Clear the mouse-moved flag for every frame on this display. */
229 FOR_EACH_FRAME (tail, frame)
230 XFRAME (frame)->mouse_moved = 0;
232 *f = selected_frame;
233 *bar_window = Qnil;
234 mouse_get_xy (&ix, &iy);
235 *time = event_timestamp ();
236 *x = make_number (mouse_last_x = ix);
237 *y = make_number (mouse_last_y = iy);
240 static void
241 mouse_check_moved ()
243 int x, y;
245 mouse_get_xy (&x, &y);
246 selected_frame->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
247 mouse_last_x = x;
248 mouse_last_y = y;
251 void
252 mouse_init ()
254 union REGS regs;
256 if (termscript)
257 fprintf (termscript, "<M_INIT>");
259 regs.x.ax = 0x0021;
260 int86 (0x33, &regs, &regs);
262 regs.x.ax = 0x0007;
263 regs.x.cx = 0;
264 regs.x.dx = 8 * (ScreenCols () - 1);
265 int86 (0x33, &regs, &regs);
267 regs.x.ax = 0x0008;
268 regs.x.cx = 0;
269 regs.x.dx = 8 * (ScreenRows () - 1);
270 int86 (0x33, &regs, &regs);
272 mouse_moveto (0, 0);
273 mouse_visible = 0;
276 /* ------------------------- Screen control ----------------------
280 static int internal_terminal = 0;
282 #ifndef HAVE_X_WINDOWS
283 extern unsigned char ScreenAttrib;
284 static int screen_face;
285 static int highlight;
287 static int screen_size_X;
288 static int screen_size_Y;
289 static int screen_size;
291 static int current_pos_X;
292 static int current_pos_Y;
293 static int new_pos_X;
294 static int new_pos_Y;
296 static void *startup_screen_buffer;
297 static int startup_screen_size_X;
298 static int startup_screen_size_Y;
299 static int startup_pos_X;
300 static int startup_pos_Y;
301 static unsigned char startup_screen_attrib;
303 static int term_setup_done;
305 /* Similar to the_only_frame. */
306 struct x_output the_only_x_display;
308 /* This is never dereferenced. */
309 Display *x_current_display;
311 /* Support for DOS/V (allows Japanese characters to be displayed on
312 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
314 /* Holds the address of the text-mode screen buffer. */
315 static unsigned long screen_old_address = 0;
316 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
317 static unsigned short screen_virtual_segment = 0;
318 static unsigned short screen_virtual_offset = 0;
320 #if __DJGPP__ > 1
321 /* Update the screen from a part of relocated DOS/V screen buffer which
322 begins at OFFSET and includes COUNT characters. */
323 static void
324 dosv_refresh_virtual_screen (int offset, int count)
326 __dpmi_regs regs;
328 if (offset < 0 || count < 0) /* paranoia; illegal values crash DOS/V */
329 return;
331 regs.h.ah = 0xff; /* update relocated screen */
332 regs.x.es = screen_virtual_segment;
333 regs.x.di = screen_virtual_offset + offset;
334 regs.x.cx = count;
335 __dpmi_int (0x10, &regs);
337 #endif
339 static
340 dos_direct_output (y, x, buf, len)
341 int y;
342 int x;
343 char *buf;
344 int len;
346 int t0 = 2 * (x + y * screen_size_X);
347 int t = t0 + (int) ScreenPrimary;
348 int l0 = len;
350 #if (__DJGPP__ < 2)
351 while (--len >= 0) {
352 dosmemput (buf++, 1, t);
353 t += 2;
355 #else
356 /* This is faster. */
357 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
358 _farnspokeb (t, *buf);
360 if (screen_virtual_segment)
361 dosv_refresh_virtual_screen (t0, l0);
362 #endif
364 #endif
366 /* Flash the screen as a substitute for BEEPs. */
368 #if (__DJGPP__ < 2)
369 static void
370 do_visible_bell (xorattr)
371 unsigned char xorattr;
373 asm volatile
374 (" movb $1,%%dl
375 visible_bell_0:
376 movl _ScreenPrimary,%%eax
377 call dosmemsetup
378 movl %%eax,%%ebx
379 movl %1,%%ecx
380 movb %0,%%al
381 incl %%ebx
382 visible_bell_1:
383 xorb %%al,%%gs:(%%ebx)
384 addl $2,%%ebx
385 decl %%ecx
386 jne visible_bell_1
387 decb %%dl
388 jne visible_bell_3
389 visible_bell_2:
390 movzwl %%ax,%%eax
391 movzwl %%ax,%%eax
392 movzwl %%ax,%%eax
393 movzwl %%ax,%%eax
394 decw %%cx
395 jne visible_bell_2
396 jmp visible_bell_0
397 visible_bell_3:"
398 : /* no output */
399 : "m" (xorattr), "g" (screen_size)
400 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
403 static void
404 ScreenVisualBell (void)
406 /* This creates an xor-mask that will swap the default fore- and
407 background colors. */
408 do_visible_bell (((the_only_x_display.foreground_pixel
409 ^ the_only_x_display.background_pixel)
410 * 0x11) & 0x7f);
412 #endif
414 #ifndef HAVE_X_WINDOWS
416 static int blink_bit = -1; /* the state of the blink bit at startup */
418 /* Enable bright background colors. */
419 static void
420 bright_bg (void)
422 union REGS regs;
424 /* Remember the original state of the blink/bright-background bit.
425 It is stored at 0040:0065h in the BIOS data area. */
426 if (blink_bit == -1)
427 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
429 regs.h.bl = 0;
430 regs.x.ax = 0x1003;
431 int86 (0x10, &regs, &regs);
434 /* Disable bright background colors (and enable blinking) if we found
435 the video system in that state at startup. */
436 static void
437 maybe_enable_blinking (void)
439 if (blink_bit == 1)
441 union REGS regs;
443 regs.h.bl = 1;
444 regs.x.ax = 0x1003;
445 int86 (0x10, &regs, &regs);
449 /* Set the screen dimensions so that it can show no less than
450 ROWS x COLS frame. */
452 void
453 dos_set_window_size (rows, cols)
454 int *rows, *cols;
456 char video_name[30];
457 Lisp_Object video_mode;
458 int video_mode_value;
459 int have_vga = 0;
460 union REGS regs;
461 int current_rows = ScreenRows (), current_cols = ScreenCols ();
463 if (*rows == current_rows && *cols == current_cols)
464 return;
466 /* Do we have a VGA? */
467 regs.x.ax = 0x1a00;
468 int86 (0x10, &regs, &regs);
469 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
470 have_vga = 1;
472 mouse_off ();
474 /* If the user specified a special video mode for these dimensions,
475 use that mode. */
476 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
477 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
478 Qnil))-> value;
480 if (INTEGERP (video_mode)
481 && (video_mode_value = XINT (video_mode)) > 0)
483 regs.x.ax = video_mode_value;
484 int86 (0x10, &regs, &regs);
486 if (have_mouse)
488 /* Must hardware-reset the mouse, or else it won't update
489 its notion of screen dimensions for some non-standard
490 video modes. This is *painfully* slow... */
491 regs.x.ax = 0;
492 int86 (0x33, &regs, &regs);
496 /* Find one of the dimensions supported by standard EGA/VGA
497 which gives us at least the required dimensions. */
499 #if __DJGPP__ > 1
501 else
503 static struct {
504 int rows;
505 int need_vga;
506 } std_dimension[] = {
507 {25, 0},
508 {28, 1},
509 {35, 0},
510 {40, 1},
511 {43, 0},
512 {50, 1}
514 int i = 0;
516 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
518 if (std_dimension[i].need_vga <= have_vga
519 && std_dimension[i].rows >= *rows)
521 if (std_dimension[i].rows != current_rows
522 || *cols != current_cols)
523 _set_screen_lines (std_dimension[i].rows);
524 break;
526 i++;
530 #else /* not __DJGPP__ > 1 */
532 else if (*rows <= 25)
534 if (current_rows != 25 || current_cols != 80)
536 regs.x.ax = 3;
537 int86 (0x10, &regs, &regs);
538 regs.x.ax = 0x1101;
539 regs.h.bl = 0;
540 int86 (0x10, &regs, &regs);
541 regs.x.ax = 0x1200;
542 regs.h.bl = 32;
543 int86 (0x10, &regs, &regs);
544 regs.x.ax = 3;
545 int86 (0x10, &regs, &regs);
548 else if (*rows <= 50)
549 if (have_vga && (current_rows != 50 || current_cols != 80)
550 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
552 regs.x.ax = 3;
553 int86 (0x10, &regs, &regs);
554 regs.x.ax = 0x1112;
555 regs.h.bl = 0;
556 int86 (0x10, &regs, &regs);
557 regs.x.ax = 0x1200;
558 regs.h.bl = 32;
559 int86 (0x10, &regs, &regs);
560 regs.x.ax = 0x0100;
561 regs.x.cx = 7;
562 int86 (0x10, &regs, &regs);
564 #endif /* not __DJGPP__ > 1 */
566 if (have_mouse)
568 mouse_init ();
569 mouse_on ();
572 /* Tell the caller what dimensions have been REALLY set. */
573 *rows = ScreenRows ();
574 *cols = ScreenCols ();
576 /* Enable bright background colors. */
577 bright_bg ();
579 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
580 be defensive anyway. */
581 if (screen_virtual_segment)
582 dosv_refresh_virtual_screen (0, *cols * *rows);
585 /* If we write a character in the position where the mouse is,
586 the mouse cursor may need to be refreshed. */
588 static void
589 mouse_off_maybe ()
591 int x, y;
593 if (!mouse_visible)
594 return;
596 mouse_get_xy (&x, &y);
597 if (y != new_pos_Y || x < new_pos_X)
598 return;
600 mouse_off ();
603 static
604 IT_ring_bell ()
606 if (visible_bell)
608 mouse_off ();
609 ScreenVisualBell ();
611 else
613 union REGS inregs, outregs;
614 inregs.h.ah = 2;
615 inregs.h.dl = 7;
616 intdos (&inregs, &outregs);
620 static void
621 IT_set_face (int face)
623 struct face *fp;
624 extern struct face *intern_face (/* FRAME_PTR, struct face * */);
626 if (face == 1 || (face == 0 && highlight))
627 fp = FRAME_MODE_LINE_FACE (foo);
628 else if (face <= 0 || face >= FRAME_N_COMPUTED_FACES (foo))
629 fp = FRAME_DEFAULT_FACE (foo);
630 else
631 fp = intern_face (selected_frame, FRAME_COMPUTED_FACES (foo)[face]);
632 if (termscript)
633 fprintf (termscript, "<FACE %d: %d/%d>",
634 face, FACE_FOREGROUND (fp), FACE_BACKGROUND (fp));
635 screen_face = face;
636 ScreenAttrib = (FACE_BACKGROUND (fp) << 4) | FACE_FOREGROUND (fp);
639 static
640 IT_write_glyphs (GLYPH *str, int len)
642 int newface;
643 int ch, l = len;
644 unsigned char *buf, *bp;
645 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
647 if (len == 0) return;
649 buf = bp = alloca (len * 2);
651 while (--l >= 0)
653 newface = FAST_GLYPH_FACE (*str);
654 if (newface != screen_face)
655 IT_set_face (newface);
656 ch = FAST_GLYPH_CHAR (*str);
657 *bp++ = (unsigned char)ch;
658 *bp++ = ScreenAttrib;
660 if (termscript)
661 fputc (ch, termscript);
662 str++;
665 mouse_off_maybe ();
666 dosmemput (buf, 2 * len, (int)ScreenPrimary + offset);
667 if (screen_virtual_segment)
668 dosv_refresh_virtual_screen (offset, len);
669 new_pos_X += len;
672 static
673 IT_clear_end_of_line (first_unused)
675 char *spaces, *sp;
676 int i, j;
677 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
679 IT_set_face (0);
680 if (termscript)
681 fprintf (termscript, "<CLR:EOL>");
682 i = (j = screen_size_X - new_pos_X) * 2;
683 spaces = sp = alloca (i);
685 while (--j >= 0)
687 *sp++ = ' ';
688 *sp++ = ScreenAttrib;
691 mouse_off_maybe ();
692 dosmemput (spaces, i, (int)ScreenPrimary + offset);
693 if (screen_virtual_segment)
694 dosv_refresh_virtual_screen (offset, i / 2);
697 static
698 IT_clear_screen (void)
700 if (termscript)
701 fprintf (termscript, "<CLR:SCR>");
702 IT_set_face (0);
703 mouse_off ();
704 ScreenClear ();
705 if (screen_virtual_segment)
706 dosv_refresh_virtual_screen (0, screen_size);
707 new_pos_X = new_pos_Y = 0;
710 static
711 IT_clear_to_end (void)
713 if (termscript)
714 fprintf (termscript, "<CLR:EOS>");
716 while (new_pos_Y < screen_size_Y) {
717 new_pos_X = 0;
718 IT_clear_end_of_line (0);
719 new_pos_Y++;
723 static
724 IT_cursor_to (int y, int x)
726 if (termscript)
727 fprintf (termscript, "\n<XY=%dx%d>", x, y);
728 new_pos_X = x;
729 new_pos_Y = y;
732 static int cursor_cleared;
734 static
735 IT_display_cursor (int on)
737 if (on && cursor_cleared)
739 ScreenSetCursor (current_pos_Y, current_pos_X);
740 cursor_cleared = 0;
742 else if (!on && !cursor_cleared)
744 ScreenSetCursor (-1, -1);
745 cursor_cleared = 1;
749 /* Emacs calls cursor-movement functions a lot when it updates the
750 display (probably a legacy of old terminals where you cannot
751 update a screen line without first moving the cursor there).
752 However, cursor movement is expensive on MSDOS (it calls a slow
753 BIOS function and requires 2 mode switches), while actual screen
754 updates access the video memory directly and don't depend on
755 cursor position. To avoid slowing down the redisplay, we cheat:
756 all functions that move the cursor only set internal variables
757 which record the cursor position, whereas the cursor is only
758 moved to its final position whenever screen update is complete.
760 `IT_cmgoto' is called from the keyboard reading loop and when the
761 frame update is complete. This means that we are ready for user
762 input, so we update the cursor position to show where the point is,
763 and also make the mouse pointer visible.
765 Special treatment is required when the cursor is in the echo area,
766 to put the cursor at the end of the text displayed there. */
768 static
769 IT_cmgoto (f)
770 FRAME_PTR f;
772 /* Only set the cursor to where it should be if the display is
773 already in sync with the window contents. */
774 int update_cursor_pos = MODIFF == unchanged_modified;
776 /* If we are in the echo area, put the cursor at the end of text. */
777 if (!update_cursor_pos
778 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y)
780 new_pos_X = FRAME_DESIRED_GLYPHS (f)->used[new_pos_Y];
781 update_cursor_pos = 1;
784 if (update_cursor_pos
785 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
787 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
788 if (termscript)
789 fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
792 /* Maybe cursor is invisible, so make it visible. */
793 IT_display_cursor (1);
795 /* Mouse pointer should be always visible if we are waiting for
796 keyboard input. */
797 if (!mouse_visible)
798 mouse_on ();
801 static
802 IT_reassert_line_highlight (new, vpos)
803 int new, vpos;
805 highlight = new;
806 IT_set_face (0); /* To possibly clear the highlighting. */
809 static
810 IT_change_line_highlight (new_highlight, vpos, first_unused_hpos)
812 highlight = new_highlight;
813 IT_set_face (0); /* To possibly clear the highlighting. */
814 IT_cursor_to (vpos, 0);
815 IT_clear_end_of_line (first_unused_hpos);
818 static
819 IT_update_begin ()
821 highlight = 0;
822 IT_set_face (0); /* To possibly clear the highlighting. */
823 screen_face = -1;
826 static
827 IT_update_end ()
831 /* set-window-configuration on window.c needs this. */
832 void
833 x_set_menu_bar_lines (f, value, oldval)
834 struct frame *f;
835 Lisp_Object value, oldval;
837 set_menu_bar_lines (f, value, oldval);
840 /* This was copied from xfns.c */
842 Lisp_Object Qbackground_color;
843 Lisp_Object Qforeground_color;
844 extern Lisp_Object Qtitle;
846 /* IT_set_terminal_modes is called when emacs is started,
847 resumed, and whenever the screen is redrawn! */
849 static
850 IT_set_terminal_modes (void)
852 if (termscript)
853 fprintf (termscript, "\n<SET_TERM>");
854 highlight = 0;
856 screen_size_X = ScreenCols ();
857 screen_size_Y = ScreenRows ();
858 screen_size = screen_size_X * screen_size_Y;
860 new_pos_X = new_pos_Y = 0;
861 current_pos_X = current_pos_Y = -1;
863 if (term_setup_done)
864 return;
865 term_setup_done = 1;
867 startup_screen_size_X = screen_size_X;
868 startup_screen_size_Y = screen_size_Y;
869 startup_screen_attrib = ScreenAttrib;
871 #if __DJGPP__ > 1
872 /* Is DOS/V (or any other RSIS software which relocates
873 the screen) installed? */
875 unsigned short es_value;
876 __dpmi_regs regs;
878 regs.h.ah = 0xfe; /* get relocated screen address */
879 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
880 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
881 else if (screen_old_address) /* already switched to Japanese mode once */
882 regs.x.es = (screen_old_address >> 4) & 0xffff;
883 else
884 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
885 regs.x.di = 0;
886 es_value = regs.x.es;
887 __dpmi_int (0x10, &regs);
889 if (regs.x.es != es_value && regs.x.es != (ScreenPrimary >> 4) & 0xffff)
891 screen_old_address = ScreenPrimary;
892 screen_virtual_segment = regs.x.es;
893 screen_virtual_offset = regs.x.di;
894 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
897 #endif /* __DJGPP__ > 1 */
899 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
900 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
902 if (termscript)
903 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
904 screen_size_X, screen_size_Y);
906 bright_bg ();
909 /* IT_reset_terminal_modes is called when emacs is
910 suspended or killed. */
912 static
913 IT_reset_terminal_modes (void)
915 int display_row_start = (int) ScreenPrimary;
916 int saved_row_len = startup_screen_size_X * 2;
917 int update_row_len = ScreenCols () * 2;
918 int current_rows = ScreenRows ();
919 int to_next_row = update_row_len;
920 unsigned char *saved_row = startup_screen_buffer;
921 int cursor_pos_X = ScreenCols () - 1;
922 int cursor_pos_Y = ScreenRows () - 1;
924 if (termscript)
925 fprintf (termscript, "\n<RESET_TERM>");
927 highlight = 0;
929 if (!term_setup_done)
930 return;
932 mouse_off ();
934 /* Leave the video system in the same state as we found it,
935 as far as the blink/bright-background bit is concerned. */
936 maybe_enable_blinking ();
938 /* We have a situation here.
939 We cannot just do ScreenUpdate(startup_screen_buffer) because
940 the luser could have changed screen dimensions inside Emacs
941 and failed (or didn't want) to restore them before killing
942 Emacs. ScreenUpdate() uses the *current* screen dimensions and
943 thus will happily use memory outside what was allocated for
944 `startup_screen_buffer'.
945 Thus we only restore as much as the current screen dimensions
946 can hold, and clear the rest (if the saved screen is smaller than
947 the current) with the color attribute saved at startup. The cursor
948 is also restored within the visible dimensions. */
950 ScreenAttrib = startup_screen_attrib;
951 ScreenClear ();
952 if (screen_virtual_segment)
953 dosv_refresh_virtual_screen (0, screen_size);
955 if (update_row_len > saved_row_len)
956 update_row_len = saved_row_len;
957 if (current_rows > startup_screen_size_Y)
958 current_rows = startup_screen_size_Y;
960 if (termscript)
961 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
962 update_row_len / 2, current_rows);
964 while (current_rows--)
966 dosmemput (saved_row, update_row_len, display_row_start);
967 if (screen_virtual_segment)
968 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
969 update_row_len / 2);
970 saved_row += saved_row_len;
971 display_row_start += to_next_row;
973 if (startup_pos_X < cursor_pos_X)
974 cursor_pos_X = startup_pos_X;
975 if (startup_pos_Y < cursor_pos_Y)
976 cursor_pos_Y = startup_pos_Y;
978 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
979 xfree (startup_screen_buffer);
981 term_setup_done = 0;
984 static
985 IT_set_terminal_window (void)
989 void
990 IT_set_frame_parameters (f, alist)
991 FRAME_PTR f;
992 Lisp_Object alist;
994 Lisp_Object tail;
995 int length = XINT (Flength (alist));
996 int i;
997 Lisp_Object *parms
998 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
999 Lisp_Object *values
1000 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
1001 int redraw;
1002 extern unsigned long load_color ();
1004 redraw = 0;
1006 /* Extract parm names and values into those vectors. */
1007 i = 0;
1008 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
1010 Lisp_Object elt;
1012 elt = Fcar (tail);
1013 parms[i] = Fcar (elt);
1014 CHECK_SYMBOL (parms[i], 1);
1015 values[i] = Fcdr (elt);
1016 i++;
1020 /* Now process them in reverse of specified order. */
1021 for (i--; i >= 0; i--)
1023 Lisp_Object prop = parms[i];
1024 Lisp_Object val = values[i];
1026 if (EQ (prop, Qforeground_color))
1028 unsigned long new_color = load_color (f, val);
1029 if (new_color != ~0)
1031 FRAME_FOREGROUND_PIXEL (f) = new_color;
1032 redraw = 1;
1033 if (termscript)
1034 fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
1037 else if (EQ (prop, Qbackground_color))
1039 unsigned long new_color = load_color (f, val);
1040 if (new_color != ~0)
1042 FRAME_BACKGROUND_PIXEL (f) = new_color;
1043 redraw = 1;
1044 if (termscript)
1045 fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
1048 else if (EQ (prop, Qtitle))
1050 x_set_title (f, val);
1051 if (termscript)
1052 fprintf (termscript, "<TITLE: %s>\n", XSTRING (val)->data);
1054 else if (EQ (prop, intern ("reverse")) && EQ (val, Qt))
1056 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
1058 FRAME_FOREGROUND_PIXEL (f) = FRAME_BACKGROUND_PIXEL (f);
1059 FRAME_BACKGROUND_PIXEL (f) = fg;
1060 if (termscript)
1061 fprintf (termscript, "<INVERSE-VIDEO>\n");
1063 store_frame_param (f, prop, val);
1067 if (redraw)
1069 extern void recompute_basic_faces (FRAME_PTR);
1070 extern void redraw_frame (FRAME_PTR);
1072 recompute_basic_faces (f);
1073 if (f == selected_frame)
1074 redraw_frame (f);
1078 extern void init_frame_faces (FRAME_PTR);
1080 #endif /* !HAVE_X_WINDOWS */
1083 /* Do we need the internal terminal? */
1085 void
1086 internal_terminal_init ()
1088 char *term = getenv ("TERM");
1089 char *colors;
1091 #ifdef HAVE_X_WINDOWS
1092 if (!inhibit_window_system)
1093 return;
1094 #endif
1096 internal_terminal
1097 = (!noninteractive) && term && !strcmp (term, "internal");
1099 if (getenv ("EMACSTEST"))
1100 termscript = fopen (getenv ("EMACSTEST"), "wt");
1102 #ifndef HAVE_X_WINDOWS
1103 if (!internal_terminal || inhibit_window_system)
1105 selected_frame->output_method = output_termcap;
1106 return;
1109 Vwindow_system = intern ("pc");
1110 Vwindow_system_version = make_number (1);
1112 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
1113 screen_old_address = 0;
1115 bzero (&the_only_x_display, sizeof the_only_x_display);
1116 the_only_x_display.background_pixel = 7; /* White */
1117 the_only_x_display.foreground_pixel = 0; /* Black */
1118 bright_bg ();
1119 colors = getenv ("EMACSCOLORS");
1120 if (colors && strlen (colors) >= 2)
1122 /* The colors use 4 bits each (we enable bright background). */
1123 if (isdigit (colors[0]))
1124 colors[0] -= '0';
1125 else if (isxdigit (colors[0]))
1126 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1127 if (colors[0] >= 0 && colors[0] < 16)
1128 the_only_x_display.foreground_pixel = colors[0];
1129 if (isdigit (colors[1]))
1130 colors[1] -= '0';
1131 else if (isxdigit (colors[1]))
1132 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
1133 if (colors[1] >= 0 && colors[1] < 16)
1134 the_only_x_display.background_pixel = colors[1];
1136 the_only_x_display.line_height = 1;
1137 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
1139 init_frame_faces (selected_frame);
1141 ring_bell_hook = IT_ring_bell;
1142 write_glyphs_hook = IT_write_glyphs;
1143 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
1144 clear_to_end_hook = IT_clear_to_end;
1145 clear_end_of_line_hook = IT_clear_end_of_line;
1146 clear_frame_hook = IT_clear_screen;
1147 change_line_highlight_hook = IT_change_line_highlight;
1148 update_begin_hook = IT_update_begin;
1149 update_end_hook = IT_update_end;
1150 reassert_line_highlight_hook = IT_reassert_line_highlight;
1151 frame_up_to_date_hook = IT_cmgoto; /* position cursor when update is done */
1153 /* These hooks are called by term.c without being checked. */
1154 set_terminal_modes_hook = IT_set_terminal_modes;
1155 reset_terminal_modes_hook = IT_reset_terminal_modes;
1156 set_terminal_window_hook = IT_set_terminal_window;
1157 #endif
1160 dos_get_saved_screen (screen, rows, cols)
1161 char **screen;
1162 int *rows;
1163 int *cols;
1165 #ifndef HAVE_X_WINDOWS
1166 *screen = startup_screen_buffer;
1167 *cols = startup_screen_size_X;
1168 *rows = startup_screen_size_Y;
1169 return *screen != (char *)0;
1170 #else
1171 return 0;
1172 #endif
1175 #ifndef HAVE_X_WINDOWS
1177 /* We are not X, but we can emulate it well enough for our needs... */
1178 void
1179 check_x (void)
1181 if (! FRAME_MSDOS_P (selected_frame))
1182 error ("Not running under a windows system");
1185 #endif
1188 /* ----------------------- Keyboard control ----------------------
1190 * Keymaps reflect the following keyboard layout:
1192 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1193 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1194 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1195 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1196 * SPACE
1199 static int extended_kbd; /* 101 (102) keyboard present. */
1201 struct dos_keyboard_map
1203 char *unshifted;
1204 char *shifted;
1205 char *alt_gr;
1209 static struct dos_keyboard_map us_keyboard = {
1210 /* 0 1 2 3 4 5 */
1211 /* 01234567890123456789012345678901234567890 12345678901234 */
1212 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1213 /* 0123456789012345678901234567890123456789 012345678901234 */
1214 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1215 0 /* no Alt-Gr key */
1218 static struct dos_keyboard_map fr_keyboard = {
1219 /* 0 1 2 3 4 5 */
1220 /* 012 3456789012345678901234567890123456789012345678901234 */
1221 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
1222 /* 0123456789012345678901234567890123456789012345678901234 */
1223 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
1224 /* 01234567 89012345678901234567890123456789012345678901234 */
1225 " ~#{[|`\\^@]} Ï "
1229 * Italian keyboard support, country code 39.
1230 * '<' 56:3c*0000
1231 * '>' 56:3e*0000
1232 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
1233 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
1235 static struct dos_keyboard_map it_keyboard = {
1236 /* 0 1 2 3 4 5 */
1237 /* 0 123456789012345678901234567890123456789012345678901234 */
1238 "\\1234567890'� qwertyuiopŠ+ asdfghjkl•…— zxcvbnm,.- ",
1239 /* 01 23456789012345678901234567890123456789012345678901234 */
1240 "|!\"œ$%&/()=?^ QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
1241 /* 0123456789012345678901234567890123456789012345678901234 */
1242 " {}~` [] @# "
1245 static struct dos_keyboard_map dk_keyboard = {
1246 /* 0 1 2 3 4 5 */
1247 /* 0123456789012345678901234567890123456789012345678901234 */
1248 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
1249 /* 01 23456789012345678901234567890123456789012345678901234 */
1250 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
1251 /* 0123456789012345678901234567890123456789012345678901234 */
1252 " @œ$ {[]} | "
1255 static struct keyboard_layout_list
1257 int country_code;
1258 struct dos_keyboard_map *keyboard_map;
1259 } keyboard_layout_list[] =
1261 1, &us_keyboard,
1262 33, &fr_keyboard,
1263 39, &it_keyboard,
1264 45, &dk_keyboard
1267 static struct dos_keyboard_map *keyboard;
1268 static int keyboard_map_all;
1269 static int international_keyboard;
1272 dos_set_keyboard (code, always)
1273 int code;
1274 int always;
1276 int i;
1277 union REGS regs;
1279 /* See if Keyb.Com is installed (for international keyboard support). */
1280 regs.x.ax = 0xad80;
1281 int86 (0x2f, &regs, &regs);
1282 if (regs.h.al == 0xff)
1283 international_keyboard = 1;
1285 /* Initialize to US settings, for countries that don't have their own. */
1286 keyboard = keyboard_layout_list[0].keyboard_map;
1287 keyboard_map_all = always;
1288 dos_keyboard_layout = 1;
1290 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
1291 if (code == keyboard_layout_list[i].country_code)
1293 keyboard = keyboard_layout_list[i].keyboard_map;
1294 keyboard_map_all = always;
1295 dos_keyboard_layout = code;
1296 return 1;
1298 return 0;
1301 #define Ignore 0x0000
1302 #define Normal 0x0000 /* normal key - alt changes scan-code */
1303 #define FctKey 0x1000 /* func key if c == 0, else c */
1304 #define Special 0x2000 /* func key even if c != 0 */
1305 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1306 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1307 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1308 #define Grey 0x6000 /* Grey keypad key */
1310 #define Alt 0x0100 /* alt scan-code */
1311 #define Ctrl 0x0200 /* ctrl scan-code */
1312 #define Shift 0x0400 /* shift scan-code */
1314 static struct
1316 unsigned char char_code; /* normal code */
1317 unsigned char meta_code; /* M- code */
1318 unsigned char keypad_code; /* keypad code */
1319 unsigned char editkey_code; /* edit key */
1320 } keypad_translate_map[] = {
1321 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1322 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1323 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1324 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1325 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1326 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1327 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1328 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1329 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1330 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1331 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1334 static struct
1336 unsigned char char_code; /* normal code */
1337 unsigned char keypad_code; /* keypad code */
1338 } grey_key_translate_map[] = {
1339 '/', 0xaf, /* kp-decimal */
1340 '*', 0xaa, /* kp-multiply */
1341 '-', 0xad, /* kp-subtract */
1342 '+', 0xab, /* kp-add */
1343 '\r', 0x8d /* kp-enter */
1346 static unsigned short
1347 ibmpc_translate_map[] =
1349 /* --------------- 00 to 0f --------------- */
1350 Normal | 0xff, /* Ctrl Break + Alt-NNN */
1351 Alt | ModFct | 0x1b, /* Escape */
1352 Normal | 1, /* '1' */
1353 Normal | 2, /* '2' */
1354 Normal | 3, /* '3' */
1355 Normal | 4, /* '4' */
1356 Normal | 5, /* '5' */
1357 Normal | 6, /* '6' */
1358 Normal | 7, /* '7' */
1359 Normal | 8, /* '8' */
1360 Normal | 9, /* '9' */
1361 Normal | 10, /* '0' */
1362 Normal | 11, /* '-' */
1363 Normal | 12, /* '=' */
1364 Special | 0x08, /* Backspace */
1365 ModFct | 0x74, /* Tab/Backtab */
1367 /* --------------- 10 to 1f --------------- */
1368 Map | 15, /* 'q' */
1369 Map | 16, /* 'w' */
1370 Map | 17, /* 'e' */
1371 Map | 18, /* 'r' */
1372 Map | 19, /* 't' */
1373 Map | 20, /* 'y' */
1374 Map | 21, /* 'u' */
1375 Map | 22, /* 'i' */
1376 Map | 23, /* 'o' */
1377 Map | 24, /* 'p' */
1378 Map | 25, /* '[' */
1379 Map | 26, /* ']' */
1380 ModFct | 0x0d, /* Return */
1381 Ignore, /* Ctrl */
1382 Map | 30, /* 'a' */
1383 Map | 31, /* 's' */
1385 /* --------------- 20 to 2f --------------- */
1386 Map | 32, /* 'd' */
1387 Map | 33, /* 'f' */
1388 Map | 34, /* 'g' */
1389 Map | 35, /* 'h' */
1390 Map | 36, /* 'j' */
1391 Map | 37, /* 'k' */
1392 Map | 38, /* 'l' */
1393 Map | 39, /* ';' */
1394 Map | 40, /* '\'' */
1395 Map | 0, /* '`' */
1396 Ignore, /* Left shift */
1397 Map | 41, /* '\\' */
1398 Map | 45, /* 'z' */
1399 Map | 46, /* 'x' */
1400 Map | 47, /* 'c' */
1401 Map | 48, /* 'v' */
1403 /* --------------- 30 to 3f --------------- */
1404 Map | 49, /* 'b' */
1405 Map | 50, /* 'n' */
1406 Map | 51, /* 'm' */
1407 Map | 52, /* ',' */
1408 Map | 53, /* '.' */
1409 Map | 54, /* '/' */
1410 Ignore, /* Right shift */
1411 Grey | 1, /* Grey * */
1412 Ignore, /* Alt */
1413 Normal | ' ', /* ' ' */
1414 Ignore, /* Caps Lock */
1415 FctKey | 0xbe, /* F1 */
1416 FctKey | 0xbf, /* F2 */
1417 FctKey | 0xc0, /* F3 */
1418 FctKey | 0xc1, /* F4 */
1419 FctKey | 0xc2, /* F5 */
1421 /* --------------- 40 to 4f --------------- */
1422 FctKey | 0xc3, /* F6 */
1423 FctKey | 0xc4, /* F7 */
1424 FctKey | 0xc5, /* F8 */
1425 FctKey | 0xc6, /* F9 */
1426 FctKey | 0xc7, /* F10 */
1427 Ignore, /* Num Lock */
1428 Ignore, /* Scroll Lock */
1429 KeyPad | 7, /* Home */
1430 KeyPad | 8, /* Up */
1431 KeyPad | 9, /* Page Up */
1432 Grey | 2, /* Grey - */
1433 KeyPad | 4, /* Left */
1434 KeyPad | 5, /* Keypad 5 */
1435 KeyPad | 6, /* Right */
1436 Grey | 3, /* Grey + */
1437 KeyPad | 1, /* End */
1439 /* --------------- 50 to 5f --------------- */
1440 KeyPad | 2, /* Down */
1441 KeyPad | 3, /* Page Down */
1442 KeyPad | 0, /* Insert */
1443 KeyPad | 10, /* Delete */
1444 Shift | FctKey | 0xbe, /* (Shift) F1 */
1445 Shift | FctKey | 0xbf, /* (Shift) F2 */
1446 Shift | FctKey | 0xc0, /* (Shift) F3 */
1447 Shift | FctKey | 0xc1, /* (Shift) F4 */
1448 Shift | FctKey | 0xc2, /* (Shift) F5 */
1449 Shift | FctKey | 0xc3, /* (Shift) F6 */
1450 Shift | FctKey | 0xc4, /* (Shift) F7 */
1451 Shift | FctKey | 0xc5, /* (Shift) F8 */
1452 Shift | FctKey | 0xc6, /* (Shift) F9 */
1453 Shift | FctKey | 0xc7, /* (Shift) F10 */
1454 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
1455 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
1457 /* --------------- 60 to 6f --------------- */
1458 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
1459 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
1460 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
1461 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
1462 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
1463 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
1464 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
1465 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
1466 Alt | FctKey | 0xbe, /* (Alt) F1 */
1467 Alt | FctKey | 0xbf, /* (Alt) F2 */
1468 Alt | FctKey | 0xc0, /* (Alt) F3 */
1469 Alt | FctKey | 0xc1, /* (Alt) F4 */
1470 Alt | FctKey | 0xc2, /* (Alt) F5 */
1471 Alt | FctKey | 0xc3, /* (Alt) F6 */
1472 Alt | FctKey | 0xc4, /* (Alt) F7 */
1473 Alt | FctKey | 0xc5, /* (Alt) F8 */
1475 /* --------------- 70 to 7f --------------- */
1476 Alt | FctKey | 0xc6, /* (Alt) F9 */
1477 Alt | FctKey | 0xc7, /* (Alt) F10 */
1478 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
1479 Ctrl | KeyPad | 4, /* (Ctrl) Left */
1480 Ctrl | KeyPad | 6, /* (Ctrl) Right */
1481 Ctrl | KeyPad | 1, /* (Ctrl) End */
1482 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
1483 Ctrl | KeyPad | 7, /* (Ctrl) Home */
1484 Alt | Map | 1, /* '1' */
1485 Alt | Map | 2, /* '2' */
1486 Alt | Map | 3, /* '3' */
1487 Alt | Map | 4, /* '4' */
1488 Alt | Map | 5, /* '5' */
1489 Alt | Map | 6, /* '6' */
1490 Alt | Map | 7, /* '7' */
1491 Alt | Map | 8, /* '8' */
1493 /* --------------- 80 to 8f --------------- */
1494 Alt | Map | 9, /* '9' */
1495 Alt | Map | 10, /* '0' */
1496 Alt | Map | 11, /* '-' */
1497 Alt | Map | 12, /* '=' */
1498 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
1499 FctKey | 0xc8, /* F11 */
1500 FctKey | 0xc9, /* F12 */
1501 Shift | FctKey | 0xc8, /* (Shift) F11 */
1502 Shift | FctKey | 0xc9, /* (Shift) F12 */
1503 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
1504 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
1505 Alt | FctKey | 0xc8, /* (Alt) F11 */
1506 Alt | FctKey | 0xc9, /* (Alt) F12 */
1507 Ctrl | KeyPad | 8, /* (Ctrl) Up */
1508 Ctrl | Grey | 2, /* (Ctrl) Grey - */
1509 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
1511 /* --------------- 90 to 9f --------------- */
1512 Ctrl | Grey | 3, /* (Ctrl) Grey + */
1513 Ctrl | KeyPad | 2, /* (Ctrl) Down */
1514 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
1515 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
1516 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
1517 Ctrl | Grey | 0, /* (Ctrl) Grey / */
1518 Ctrl | Grey | 1, /* (Ctrl) Grey * */
1519 Alt | FctKey | 0x50, /* (Alt) Home */
1520 Alt | FctKey | 0x52, /* (Alt) Up */
1521 Alt | FctKey | 0x55, /* (Alt) Page Up */
1522 Ignore, /* NO KEY */
1523 Alt | FctKey | 0x51, /* (Alt) Left */
1524 Ignore, /* NO KEY */
1525 Alt | FctKey | 0x53, /* (Alt) Right */
1526 Ignore, /* NO KEY */
1527 Alt | FctKey | 0x57, /* (Alt) End */
1529 /* --------------- a0 to af --------------- */
1530 Alt | KeyPad | 2, /* (Alt) Down */
1531 Alt | KeyPad | 3, /* (Alt) Page Down */
1532 Alt | KeyPad | 0, /* (Alt) Insert */
1533 Alt | KeyPad | 10, /* (Alt) Delete */
1534 Alt | Grey | 0, /* (Alt) Grey / */
1535 Alt | FctKey | 0x09, /* (Alt) Tab */
1536 Alt | Grey | 4 /* (Alt) Keypad Enter */
1539 /* These bit-positions corresponds to values returned by BIOS */
1540 #define SHIFT_P 0x0003 /* two bits! */
1541 #define CTRL_P 0x0004
1542 #define ALT_P 0x0008
1543 #define SCRLOCK_P 0x0010
1544 #define NUMLOCK_P 0x0020
1545 #define CAPSLOCK_P 0x0040
1546 #define ALT_GR_P 0x0800
1547 #define SUPER_P 0x4000 /* pseudo */
1548 #define HYPER_P 0x8000 /* pseudo */
1550 static int
1551 dos_get_modifiers (keymask)
1552 int *keymask;
1554 union REGS regs;
1555 int mask;
1556 int modifiers = 0;
1558 /* Calculate modifier bits */
1559 regs.h.ah = extended_kbd ? 0x12 : 0x02;
1560 int86 (0x16, &regs, &regs);
1562 if (!extended_kbd)
1564 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
1565 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1567 else
1569 mask = regs.h.al & (SHIFT_P |
1570 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1572 /* Do not break international keyboard support. */
1573 /* When Keyb.Com is loaded, the right Alt key is */
1574 /* used for accessing characters like { and } */
1575 if (regs.h.ah & 2) /* Left ALT pressed ? */
1576 mask |= ALT_P;
1578 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
1580 mask |= ALT_GR_P;
1581 if (dos_hyper_key == 1)
1583 mask |= HYPER_P;
1584 modifiers |= hyper_modifier;
1586 else if (dos_super_key == 1)
1588 mask |= SUPER_P;
1589 modifiers |= super_modifier;
1591 else if (!international_keyboard)
1593 /* If Keyb.Com is NOT installed, let Right Alt behave
1594 like the Left Alt. */
1595 mask &= ~ALT_GR_P;
1596 mask |= ALT_P;
1600 if (regs.h.ah & 1) /* Left CTRL pressed ? */
1601 mask |= CTRL_P;
1603 if (regs.h.ah & 4) /* Right CTRL pressed ? */
1605 if (dos_hyper_key == 2)
1607 mask |= HYPER_P;
1608 modifiers |= hyper_modifier;
1610 else if (dos_super_key == 2)
1612 mask |= SUPER_P;
1613 modifiers |= super_modifier;
1615 else
1616 mask |= CTRL_P;
1620 if (mask & SHIFT_P)
1621 modifiers |= shift_modifier;
1622 if (mask & CTRL_P)
1623 modifiers |= ctrl_modifier;
1624 if (mask & ALT_P)
1625 modifiers |= meta_modifier;
1627 if (keymask)
1628 *keymask = mask;
1629 return modifiers;
1632 #define NUM_RECENT_DOSKEYS (100)
1633 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
1634 int total_doskeys; /* Total number of elements stored into recent_doskeys */
1635 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
1637 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
1638 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1639 Each input key receives two values in this vector: first the ASCII code,\n\
1640 and then the scan code.")
1643 Lisp_Object *keys = XVECTOR (recent_doskeys)->contents;
1644 Lisp_Object val;
1646 if (total_doskeys < NUM_RECENT_DOSKEYS)
1647 return Fvector (total_doskeys, keys);
1648 else
1650 val = Fvector (NUM_RECENT_DOSKEYS, keys);
1651 bcopy (keys + recent_doskeys_index,
1652 XVECTOR (val)->contents,
1653 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
1654 bcopy (keys,
1655 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
1656 recent_doskeys_index * sizeof (Lisp_Object));
1657 return val;
1661 /* Get a char from keyboard. Function keys are put into the event queue. */
1663 extern void kbd_buffer_store_event (struct input_event *);
1665 static int
1666 dos_rawgetc ()
1668 struct input_event event;
1669 union REGS regs;
1671 #ifndef HAVE_X_WINDOWS
1672 /* Maybe put the cursor where it should be. */
1673 IT_cmgoto (selected_frame);
1674 #endif
1676 /* The following condition is equivalent to `kbhit ()', except that
1677 it uses the bios to do its job. This pleases DESQview/X. */
1678 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
1679 int86 (0x16, &regs, &regs),
1680 (regs.x.flags & 0x40) == 0)
1682 union REGS regs;
1683 register unsigned char c;
1684 int sc, code, mask, kp_mode;
1685 int modifiers;
1687 regs.h.ah = extended_kbd ? 0x10 : 0x00;
1688 int86 (0x16, &regs, &regs);
1689 c = regs.h.al;
1690 sc = regs.h.ah;
1692 total_doskeys += 2;
1693 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1694 = make_number (c);
1695 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1696 recent_doskeys_index = 0;
1697 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1698 = make_number (sc);
1699 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1700 recent_doskeys_index = 0;
1702 modifiers = dos_get_modifiers (&mask);
1704 #ifndef HAVE_X_WINDOWS
1705 if (!NILP (Vdos_display_scancodes))
1707 char buf[11];
1708 sprintf (buf, "%02x:%02x*%04x",
1709 (unsigned) (sc&0xff), (unsigned) c, mask);
1710 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
1712 #endif
1714 if (sc == 0xe0)
1716 switch (c)
1718 case 10: /* Ctrl Grey Enter */
1719 code = Ctrl | Grey | 4;
1720 break;
1721 case 13: /* Grey Enter */
1722 code = Grey | 4;
1723 break;
1724 case '/': /* Grey / */
1725 code = Grey | 0;
1726 break;
1727 default:
1728 continue;
1730 c = 0;
1732 else
1734 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
1735 continue;
1736 if ((code = ibmpc_translate_map[sc]) == Ignore)
1737 continue;
1740 if (c == 0)
1742 /* We only look at the keyboard Ctrl/Shift/Alt keys when
1743 Emacs is ready to read a key. Therefore, if they press
1744 `Alt-x' when Emacs is busy, by the time we get to
1745 `dos_get_modifiers', they might have already released the
1746 Alt key, and Emacs gets just `x', which is BAD.
1747 However, for keys with the `Map' property set, the ASCII
1748 code returns zero iff Alt is pressed. So, when we DON'T
1749 have to support international_keyboard, we don't have to
1750 distinguish between the left and right Alt keys, and we
1751 can set the META modifier for any keys with the `Map'
1752 property if they return zero ASCII code (c = 0). */
1753 if ( (code & Alt)
1754 || ( (code & 0xf000) == Map && !international_keyboard))
1755 modifiers |= meta_modifier;
1756 if (code & Ctrl)
1757 modifiers |= ctrl_modifier;
1758 if (code & Shift)
1759 modifiers |= shift_modifier;
1762 switch (code & 0xf000)
1764 case ModFct:
1765 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
1766 return c;
1767 c = 0; /* Special */
1769 case FctKey:
1770 if (c != 0)
1771 return c;
1773 case Special:
1774 code |= 0xff00;
1775 break;
1777 case Normal:
1778 if (sc == 0)
1780 if (c == 0) /* ctrl-break */
1781 continue;
1782 return c; /* ALT-nnn */
1784 if (!keyboard_map_all)
1786 if (c != ' ')
1787 return c;
1788 code = c;
1789 break;
1792 case Map:
1793 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
1794 if (!keyboard_map_all)
1795 return c;
1797 code &= 0xff;
1798 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
1799 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
1801 if (mask & SHIFT_P)
1803 code = keyboard->shifted[code];
1804 mask -= SHIFT_P;
1805 modifiers &= ~shift_modifier;
1807 else
1808 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
1809 code = keyboard->alt_gr[code];
1810 else
1811 code = keyboard->unshifted[code];
1812 break;
1814 case KeyPad:
1815 code &= 0xff;
1816 if (c == 0xe0) /* edit key */
1817 kp_mode = 3;
1818 else
1819 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
1820 kp_mode = dos_keypad_mode & 0x03;
1821 else
1822 kp_mode = (dos_keypad_mode >> 4) & 0x03;
1824 switch (kp_mode)
1826 case 0:
1827 if (code == 10 && dos_decimal_point)
1828 return dos_decimal_point;
1829 return keypad_translate_map[code].char_code;
1831 case 1:
1832 code = 0xff00 | keypad_translate_map[code].keypad_code;
1833 break;
1835 case 2:
1836 code = keypad_translate_map[code].meta_code;
1837 modifiers = meta_modifier;
1838 break;
1840 case 3:
1841 code = 0xff00 | keypad_translate_map[code].editkey_code;
1842 break;
1844 break;
1846 case Grey:
1847 code &= 0xff;
1848 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
1849 if (dos_keypad_mode & kp_mode)
1850 code = 0xff00 | grey_key_translate_map[code].keypad_code;
1851 else
1852 code = grey_key_translate_map[code].char_code;
1853 break;
1856 make_event:
1857 if (code == 0)
1858 continue;
1860 if (code >= 0x100)
1861 event.kind = non_ascii_keystroke;
1862 else
1863 event.kind = ascii_keystroke;
1864 event.code = code;
1865 event.modifiers = modifiers;
1866 XSETFRAME (event.frame_or_window, selected_frame);
1867 event.timestamp = event_timestamp ();
1868 kbd_buffer_store_event (&event);
1871 if (have_mouse > 0)
1873 int but, press, x, y, ok;
1875 /* Check for mouse movement *before* buttons. */
1876 mouse_check_moved ();
1878 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
1879 for (press = 0; press < 2; press++)
1881 int button_num = but;
1883 if (press)
1884 ok = mouse_pressed (but, &x, &y);
1885 else
1886 ok = mouse_released (but, &x, &y);
1887 if (ok)
1889 /* Allow a simultaneous press/release of Mouse-1 and
1890 Mouse-2 to simulate Mouse-3 on two-button mice. */
1891 if (mouse_button_count == 2 && but < 2)
1893 int x2, y2; /* don't clobber original coordinates */
1895 /* If only one button is pressed, wait 100 msec and
1896 check again. This way, Speedy Gonzales isn't
1897 punished, while the slow get their chance. */
1898 if (press && mouse_pressed (1-but, &x2, &y2)
1899 || !press && mouse_released (1-but, &x2, &y2))
1900 button_num = 2;
1901 else
1903 delay (100);
1904 if (press && mouse_pressed (1-but, &x2, &y2)
1905 || !press && mouse_released (1-but, &x2, &y2))
1906 button_num = 2;
1910 event.kind = mouse_click;
1911 event.code = button_num;
1912 event.modifiers = dos_get_modifiers (0)
1913 | (press ? down_modifier : up_modifier);
1914 event.x = x;
1915 event.y = y;
1916 XSETFRAME (event.frame_or_window, selected_frame);
1917 event.timestamp = event_timestamp ();
1918 kbd_buffer_store_event (&event);
1923 return -1;
1926 static int prev_get_char = -1;
1928 /* Return 1 if a key is ready to be read without suspending execution. */
1930 dos_keysns ()
1932 if (prev_get_char != -1)
1933 return 1;
1934 else
1935 return ((prev_get_char = dos_rawgetc ()) != -1);
1938 /* Read a key. Return -1 if no key is ready. */
1940 dos_keyread ()
1942 if (prev_get_char != -1)
1944 int c = prev_get_char;
1945 prev_get_char = -1;
1946 return c;
1948 else
1949 return dos_rawgetc ();
1952 #ifndef HAVE_X_WINDOWS
1953 /* See xterm.c for more info. */
1954 void
1955 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
1956 FRAME_PTR f;
1957 register int pix_x, pix_y;
1958 register int *x, *y;
1959 void /* XRectangle */ *bounds;
1960 int noclip;
1962 if (bounds) abort ();
1964 /* Ignore clipping. */
1966 *x = pix_x;
1967 *y = pix_y;
1970 void
1971 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1972 FRAME_PTR f;
1973 register int x, y;
1974 register int *pix_x, *pix_y;
1976 *pix_x = x;
1977 *pix_y = y;
1980 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1981 for now.
1983 Actually, I don't know the meaning of all the parameters of the functions
1984 here -- I only know how they are called by xmenu.c. I could of course
1985 grab the nearest Xlib manual (down the hall, second-to-last door on the
1986 left), but I don't think it's worth the effort. */
1988 static XMenu *
1989 IT_menu_create ()
1991 XMenu *menu;
1993 menu = (XMenu *) xmalloc (sizeof (XMenu));
1994 menu->allocated = menu->count = menu->panecount = menu->width = 0;
1995 return menu;
1998 /* Allocate some (more) memory for MENU ensuring that there is room for one
1999 for item. */
2001 static void
2002 IT_menu_make_room (XMenu *menu)
2004 if (menu->allocated == 0)
2006 int count = menu->allocated = 10;
2007 menu->text = (char **) xmalloc (count * sizeof (char *));
2008 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
2009 menu->panenumber = (int *) xmalloc (count * sizeof (int));
2011 else if (menu->allocated == menu->count)
2013 int count = menu->allocated = menu->allocated + 10;
2014 menu->text
2015 = (char **) xrealloc (menu->text, count * sizeof (char *));
2016 menu->submenu
2017 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
2018 menu->panenumber
2019 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
2023 /* Search the given menu structure for a given pane number. */
2025 static XMenu *
2026 IT_menu_search_pane (XMenu *menu, int pane)
2028 int i;
2029 XMenu *try;
2031 for (i = 0; i < menu->count; i++)
2032 if (menu->submenu[i])
2034 if (pane == menu->panenumber[i])
2035 return menu->submenu[i];
2036 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
2037 return try;
2039 return (XMenu *) 0;
2042 /* Determine how much screen space a given menu needs. */
2044 static void
2045 IT_menu_calc_size (XMenu *menu, int *width, int *height)
2047 int i, h2, w2, maxsubwidth, maxheight;
2049 maxsubwidth = 0;
2050 maxheight = menu->count;
2051 for (i = 0; i < menu->count; i++)
2053 if (menu->submenu[i])
2055 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
2056 if (w2 > maxsubwidth) maxsubwidth = w2;
2057 if (i + h2 > maxheight) maxheight = i + h2;
2060 *width = menu->width + maxsubwidth;
2061 *height = maxheight;
2064 /* Display MENU at (X,Y) using FACES. */
2066 static void
2067 IT_menu_display (XMenu *menu, int y, int x, int *faces)
2069 int i, j, face, width;
2070 GLYPH *text, *p;
2071 char *q;
2072 int mx, my;
2073 int enabled, mousehere;
2074 int row, col;
2076 width = menu->width;
2077 text = (GLYPH *) xmalloc ((width + 2) * sizeof (GLYPH));
2078 ScreenGetCursor (&row, &col);
2079 mouse_get_xy (&mx, &my);
2080 IT_update_begin ();
2081 for (i = 0; i < menu->count; i++)
2083 IT_cursor_to (y + i, x);
2084 enabled
2085 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
2086 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
2087 face = faces[enabled + mousehere * 2];
2088 p = text;
2089 *p++ = FAST_MAKE_GLYPH (' ', face);
2090 for (j = 0, q = menu->text[i]; *q; j++)
2092 if (*q > 26)
2093 *p++ = FAST_MAKE_GLYPH (*q++, face);
2094 else /* make '^x' */
2096 *p++ = FAST_MAKE_GLYPH ('^', face);
2097 j++;
2098 *p++ = FAST_MAKE_GLYPH (*q++ + 64, face);
2102 for (; j < width; j++)
2103 *p++ = FAST_MAKE_GLYPH (' ', face);
2104 *p++ = FAST_MAKE_GLYPH (menu->submenu[i] ? 16 : ' ', face);
2105 IT_write_glyphs (text, width + 2);
2107 IT_update_end ();
2108 IT_cursor_to (row, col);
2109 xfree (text);
2112 /* --------------------------- X Menu emulation ---------------------- */
2114 /* Report availability of menus. */
2117 have_menus_p ()
2119 return 1;
2122 /* Create a brand new menu structure. */
2124 XMenu *
2125 XMenuCreate (Display *foo1, Window foo2, char *foo3)
2127 return IT_menu_create ();
2130 /* Create a new pane and place it on the outer-most level. It is not
2131 clear that it should be placed out there, but I don't know what else
2132 to do. */
2135 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
2137 int len;
2138 char *p;
2140 if (!enable)
2141 abort ();
2143 IT_menu_make_room (menu);
2144 menu->submenu[menu->count] = IT_menu_create ();
2145 menu->text[menu->count] = txt;
2146 menu->panenumber[menu->count] = ++menu->panecount;
2147 menu->count++;
2149 /* Adjust length for possible control characters (which will
2150 be written as ^x). */
2151 for (len = strlen (txt), p = txt; *p; p++)
2152 if (*p < 27)
2153 len++;
2155 if (len > menu->width)
2156 menu->width = len;
2158 return menu->panecount;
2161 /* Create a new item in a menu pane. */
2164 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
2165 int foo, char *txt, int enable)
2167 int len;
2168 char *p;
2170 if (pane)
2171 if (!(menu = IT_menu_search_pane (menu, pane)))
2172 return XM_FAILURE;
2173 IT_menu_make_room (menu);
2174 menu->submenu[menu->count] = (XMenu *) 0;
2175 menu->text[menu->count] = txt;
2176 menu->panenumber[menu->count] = enable;
2177 menu->count++;
2179 /* Adjust length for possible control characters (which will
2180 be written as ^x). */
2181 for (len = strlen (txt), p = txt; *p; p++)
2182 if (*p < 27)
2183 len++;
2185 if (len > menu->width)
2186 menu->width = len;
2188 return XM_SUCCESS;
2191 /* Decide where the menu would be placed if requested at (X,Y). */
2193 void
2194 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
2195 int *ulx, int *uly, int *width, int *height)
2197 IT_menu_calc_size (menu, width, height);
2198 *ulx = x + 1;
2199 *uly = y;
2200 *width += 2;
2203 struct IT_menu_state
2205 void *screen_behind;
2206 XMenu *menu;
2207 int pane;
2208 int x, y;
2212 /* Display menu, wait for user's response, and return that response. */
2215 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
2216 int x0, int y0, unsigned ButtonMask, char **txt)
2218 struct IT_menu_state *state;
2219 int statecount;
2220 int x, y, i, b;
2221 int screensize;
2222 int faces[4], selectface;
2223 int leave, result, onepane;
2224 int title_faces[4]; /* face to display the menu title */
2225 int buffers_num_deleted = 0;
2227 /* Just in case we got here without a mouse present... */
2228 if (have_mouse <= 0)
2229 return XM_IA_SELECT;
2230 /* Don't allow non-positive x0 and y0, lest the menu will wrap
2231 around the display. */
2232 if (x0 <= 0)
2233 x0 = 1;
2234 if (y0 <= 0)
2235 y0 = 1;
2237 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
2238 screensize = screen_size * 2;
2239 faces[0]
2240 = compute_glyph_face (selected_frame,
2241 face_name_id_number
2242 (selected_frame,
2243 intern ("msdos-menu-passive-face")),
2245 faces[1]
2246 = compute_glyph_face (selected_frame,
2247 face_name_id_number
2248 (selected_frame,
2249 intern ("msdos-menu-active-face")),
2251 selectface
2252 = face_name_id_number (selected_frame, intern ("msdos-menu-select-face"));
2253 faces[2] = compute_glyph_face (selected_frame, selectface, faces[0]);
2254 faces[3] = compute_glyph_face (selected_frame, selectface, faces[1]);
2256 /* Make sure the menu title is always displayed with
2257 `msdos-menu-active-face', no matter where the mouse pointer is. */
2258 for (i = 0; i < 4; i++)
2259 title_faces[i] = faces[3];
2261 statecount = 1;
2263 /* Don't let the title for the "Buffers" popup menu include a
2264 digit (which is ugly).
2266 This is a terrible kludge, but I think the "Buffers" case is
2267 the only one where the title includes a number, so it doesn't
2268 seem to be necessary to make this more general. */
2269 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
2271 menu->text[0][7] = '\0';
2272 buffers_num_deleted = 1;
2274 state[0].menu = menu;
2275 mouse_off ();
2276 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
2278 /* Turn off the cursor. Otherwise it shows through the menu
2279 panes, which is ugly. */
2280 IT_display_cursor (0);
2282 IT_menu_display (menu, y0 - 1, x0 - 1, title_faces); /* display menu title */
2283 if (buffers_num_deleted)
2284 menu->text[0][7] = ' ';
2285 if ((onepane = menu->count == 1 && menu->submenu[0]))
2287 menu->width = menu->submenu[0]->width;
2288 state[0].menu = menu->submenu[0];
2290 else
2292 state[0].menu = menu;
2294 state[0].x = x0 - 1;
2295 state[0].y = y0;
2296 state[0].pane = onepane;
2298 mouse_last_x = -1; /* A hack that forces display. */
2299 leave = 0;
2300 while (!leave)
2302 if (!mouse_visible) mouse_on ();
2303 mouse_check_moved ();
2304 if (selected_frame->mouse_moved)
2306 selected_frame->mouse_moved = 0;
2307 result = XM_IA_SELECT;
2308 mouse_get_xy (&x, &y);
2309 for (i = 0; i < statecount; i++)
2310 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
2312 int dy = y - state[i].y;
2313 if (0 <= dy && dy < state[i].menu->count)
2315 if (!state[i].menu->submenu[dy])
2316 if (state[i].menu->panenumber[dy])
2317 result = XM_SUCCESS;
2318 else
2319 result = XM_IA_SELECT;
2320 *pane = state[i].pane - 1;
2321 *selidx = dy;
2322 /* We hit some part of a menu, so drop extra menus that
2323 have been opened. That does not include an open and
2324 active submenu. */
2325 if (i != statecount - 2
2326 || state[i].menu->submenu[dy] != state[i+1].menu)
2327 while (i != statecount - 1)
2329 statecount--;
2330 mouse_off ();
2331 ScreenUpdate (state[statecount].screen_behind);
2332 if (screen_virtual_segment)
2333 dosv_refresh_virtual_screen (0, screen_size);
2334 xfree (state[statecount].screen_behind);
2336 if (i == statecount - 1 && state[i].menu->submenu[dy])
2338 IT_menu_display (state[i].menu,
2339 state[i].y,
2340 state[i].x,
2341 faces);
2342 state[statecount].menu = state[i].menu->submenu[dy];
2343 state[statecount].pane = state[i].menu->panenumber[dy];
2344 mouse_off ();
2345 ScreenRetrieve (state[statecount].screen_behind
2346 = xmalloc (screensize));
2347 state[statecount].x
2348 = state[i].x + state[i].menu->width + 2;
2349 state[statecount].y = y;
2350 statecount++;
2354 IT_menu_display (state[statecount - 1].menu,
2355 state[statecount - 1].y,
2356 state[statecount - 1].x,
2357 faces);
2359 for (b = 0; b < mouse_button_count; b++)
2361 (void) mouse_pressed (b, &x, &y);
2362 if (mouse_released (b, &x, &y))
2363 leave = 1;
2367 mouse_off ();
2368 ScreenUpdate (state[0].screen_behind);
2369 if (screen_virtual_segment)
2370 dosv_refresh_virtual_screen (0, screen_size);
2371 while (statecount--)
2372 xfree (state[statecount].screen_behind);
2373 IT_display_cursor (1); /* turn cursor back on */
2374 return result;
2377 /* Dispose of a menu. */
2379 void
2380 XMenuDestroy (Display *foo, XMenu *menu)
2382 int i;
2383 if (menu->allocated)
2385 for (i = 0; i < menu->count; i++)
2386 if (menu->submenu[i])
2387 XMenuDestroy (foo, menu->submenu[i]);
2388 xfree (menu->text);
2389 xfree (menu->submenu);
2390 xfree (menu->panenumber);
2392 xfree (menu);
2396 x_pixel_width (struct frame *f)
2398 return FRAME_WIDTH (f);
2402 x_pixel_height (struct frame *f)
2404 return FRAME_HEIGHT (f);
2406 #endif /* !HAVE_X_WINDOWS */
2408 /* ----------------------- DOS / UNIX conversion --------------------- */
2410 void msdos_downcase_filename (unsigned char *);
2412 /* Destructively turn backslashes into slashes. */
2414 void
2415 dostounix_filename (p)
2416 register char *p;
2418 msdos_downcase_filename (p);
2420 while (*p)
2422 if (*p == '\\')
2423 *p = '/';
2424 p++;
2428 /* Destructively turn slashes into backslashes. */
2430 void
2431 unixtodos_filename (p)
2432 register char *p;
2434 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
2436 *p += 'a' - 'A';
2437 p += 2;
2440 while (*p)
2442 if (*p == '/')
2443 *p = '\\';
2444 p++;
2448 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2451 getdefdir (drive, dst)
2452 int drive;
2453 char *dst;
2455 char in_path[4], *p = in_path;
2456 int e = errno;
2458 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2459 if (drive != 0)
2461 *p++ = drive + 'A' - 1;
2462 *p++ = ':';
2465 *p++ = '.';
2466 *p = '\0';
2467 errno = 0;
2468 _fixpath (in_path, dst);
2469 if (errno)
2470 return 0;
2472 msdos_downcase_filename (dst);
2474 errno = e;
2475 return 1;
2478 /* Remove all CR's that are followed by a LF. */
2481 crlf_to_lf (n, buf)
2482 register int n;
2483 register unsigned char *buf;
2485 unsigned char *np = buf;
2486 unsigned char *startp = buf;
2487 unsigned char *endp = buf + n;
2489 if (n == 0)
2490 return n;
2491 while (buf < endp - 1)
2493 if (*buf == 0x0d)
2495 if (*(++buf) != 0x0a)
2496 *np++ = 0x0d;
2498 else
2499 *np++ = *buf++;
2501 if (buf < endp)
2502 *np++ = *buf++;
2503 return np - startp;
2506 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
2508 /* In DJGPP v2.0, library `write' can call `malloc', which might
2509 cause relocation of the buffer whose address we get in ADDR.
2510 Here is a version of `write' that avoids calling `malloc',
2511 to serve us until such time as the library is fixed.
2512 Actually, what we define here is called `__write', because
2513 `write' is a stub that just jmp's to `__write' (to be
2514 POSIXLY-correct with respect to the global name-space). */
2516 #include <io.h> /* for _write */
2517 #include <libc/dosio.h> /* for __file_handle_modes[] */
2519 static char xbuf[64 * 1024]; /* DOS cannot write more in one chunk */
2521 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
2524 __write (int handle, const void *buffer, size_t count)
2526 if (count == 0)
2527 return 0;
2529 if(__file_handle_modes[handle] & O_BINARY)
2530 return _write (handle, buffer, count);
2531 else
2533 char *xbp = xbuf;
2534 const char *bp = buffer;
2535 int total_written = 0;
2536 int nmoved = 0, ncr = 0;
2538 while (count)
2540 /* The next test makes sure there's space for at least 2 more
2541 characters in xbuf[], so both CR and LF can be put there. */
2542 if (xbp < XBUF_END)
2544 if (*bp == '\n')
2546 ncr++;
2547 *xbp++ = '\r';
2549 *xbp++ = *bp++;
2550 nmoved++;
2551 count--;
2553 if (xbp >= XBUF_END || !count)
2555 size_t to_write = nmoved + ncr;
2556 int written = _write (handle, xbuf, to_write);
2558 if (written == -1)
2559 return -1;
2560 else
2561 total_written += nmoved; /* CRs aren't counted in ret value */
2563 /* If some, but not all were written (disk full?), return
2564 an estimate of the total written bytes not counting CRs. */
2565 if (written < to_write)
2566 return total_written - (to_write - written) * nmoved/to_write;
2568 nmoved = 0;
2569 ncr = 0;
2570 xbp = xbuf;
2573 return total_written;
2577 /* A low-level file-renaming function which works around Windows 95 bug.
2578 This is pulled directly out of DJGPP v2.01 library sources, and only
2579 used when you compile with DJGPP v2.0. */
2581 #include <io.h>
2583 int _rename(const char *old, const char *new)
2585 __dpmi_regs r;
2586 int olen = strlen(old) + 1;
2587 int i;
2588 int use_lfn = _USE_LFN;
2589 char tempfile[FILENAME_MAX];
2590 const char *orig = old;
2591 int lfn_fd = -1;
2593 r.x.dx = __tb_offset;
2594 r.x.di = __tb_offset + olen;
2595 r.x.ds = r.x.es = __tb_segment;
2597 if (use_lfn)
2599 /* Windows 95 bug: for some filenames, when you rename
2600 file -> file~ (as in Emacs, to leave a backup), the
2601 short 8+3 alias doesn't change, which effectively
2602 makes OLD and NEW the same file. We must rename
2603 through a temporary file to work around this. */
2605 char *pbase = 0, *p;
2606 static char try_char[] = "abcdefghijklmnopqrstuvwxyz012345789";
2607 int idx = sizeof(try_char) - 1;
2609 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
2610 might point to another drive, which will fail the DOS call. */
2611 strcpy(tempfile, old);
2612 for (p = tempfile; *p; p++) /* ensure temporary is on the same drive */
2613 if (*p == '/' || *p == '\\' || *p == ':')
2614 pbase = p;
2615 if (pbase)
2616 pbase++;
2617 else
2618 pbase = tempfile;
2619 strcpy(pbase, "X$$djren$$.$$temp$$");
2623 if (idx <= 0)
2624 return -1;
2625 *pbase = try_char[--idx];
2626 } while (_chmod(tempfile, 0) != -1);
2628 r.x.ax = 0x7156;
2629 _put_path2(tempfile, olen);
2630 _put_path(old);
2631 __dpmi_int(0x21, &r);
2632 if (r.x.flags & 1)
2634 errno = __doserr_to_errno(r.x.ax);
2635 return -1;
2638 /* Now create a file with the original name. This will
2639 ensure that NEW will always have a 8+3 alias
2640 different from that of OLD. (Seems to be required
2641 when NameNumericTail in the Registry is set to 0.) */
2642 lfn_fd = _creat(old, 0);
2644 olen = strlen(tempfile) + 1;
2645 old = tempfile;
2646 r.x.di = __tb_offset + olen;
2649 for (i=0; i<2; i++)
2651 if(use_lfn)
2652 r.x.ax = 0x7156;
2653 else
2654 r.h.ah = 0x56;
2655 _put_path2(new, olen);
2656 _put_path(old);
2657 __dpmi_int(0x21, &r);
2658 if(r.x.flags & 1)
2660 if (r.x.ax == 5 && i == 0) /* access denied */
2661 remove(new); /* and try again */
2662 else
2664 errno = __doserr_to_errno(r.x.ax);
2666 /* Restore to original name if we renamed it to temporary. */
2667 if (use_lfn)
2669 if (lfn_fd != -1)
2671 _close (lfn_fd);
2672 remove (orig);
2674 _put_path2(orig, olen);
2675 _put_path(tempfile);
2676 r.x.ax = 0x7156;
2677 __dpmi_int(0x21, &r);
2679 return -1;
2682 else
2683 break;
2686 /* Success. Delete the file possibly created to work
2687 around the Windows 95 bug. */
2688 if (lfn_fd != -1)
2689 return (_close (lfn_fd) == 0) ? remove (orig) : -1;
2690 return 0;
2693 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
2695 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
2696 0, 0, 0,
2697 "Return non-nil if long file names are supported on MSDOS.")
2700 return (_USE_LFN ? Qt : Qnil);
2703 /* Convert alphabetic characters in a filename to lower-case. */
2705 void
2706 msdos_downcase_filename (p)
2707 register unsigned char *p;
2709 /* Always lower-case drive letters a-z, even if the filesystem
2710 preserves case in filenames.
2711 This is so MSDOS filenames could be compared by string comparison
2712 functions that are case-sensitive. Even case-preserving filesystems
2713 do not distinguish case in drive letters. */
2714 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
2716 *p += 'a' - 'A';
2717 p += 2;
2720 /* Under LFN we expect to get pathnames in their true case. */
2721 if (NILP (Fmsdos_long_file_names ()))
2722 for ( ; *p; p++)
2723 if (*p >= 'A' && *p <= 'Z')
2724 *p += 'a' - 'A';
2727 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
2728 1, 1, 0,
2729 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
2730 When long filenames are supported, doesn't change FILENAME.\n\
2731 If FILENAME is not a string, returns nil.\n\
2732 The argument object is never altered--the value is a copy.")
2733 (filename)
2734 Lisp_Object filename;
2736 Lisp_Object tem;
2738 if (! STRINGP (filename))
2739 return Qnil;
2741 tem = Fcopy_sequence (filename);
2742 msdos_downcase_filename (XSTRING (tem)->data);
2743 return tem;
2746 /* The Emacs root directory as determined by init_environment. */
2748 static char emacsroot[MAXPATHLEN];
2750 char *
2751 rootrelativepath (rel)
2752 char *rel;
2754 static char result[MAXPATHLEN + 10];
2756 strcpy (result, emacsroot);
2757 strcat (result, "/");
2758 strcat (result, rel);
2759 return result;
2762 /* Define a lot of environment variables if not already defined. Don't
2763 remove anything unless you know what you're doing -- lots of code will
2764 break if one or more of these are missing. */
2766 void
2767 init_environment (argc, argv, skip_args)
2768 int argc;
2769 char **argv;
2770 int skip_args;
2772 char *s, *t, *root;
2773 int len;
2775 /* Find our root from argv[0]. Assuming argv[0] is, say,
2776 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
2777 root = alloca (MAXPATHLEN + 20);
2778 _fixpath (argv[0], root);
2779 msdos_downcase_filename (root);
2780 len = strlen (root);
2781 while (len > 0 && root[len] != '/' && root[len] != ':')
2782 len--;
2783 root[len] = '\0';
2784 if (len > 4
2785 && (strcmp (root + len - 4, "/bin") == 0
2786 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
2787 root[len - 4] = '\0';
2788 else
2789 strcpy (root, "c:/emacs"); /* let's be defensive */
2790 len = strlen (root);
2791 strcpy (emacsroot, root);
2793 /* We default HOME to our root. */
2794 setenv ("HOME", root, 0);
2796 /* We default EMACSPATH to root + "/bin". */
2797 strcpy (root + len, "/bin");
2798 setenv ("EMACSPATH", root, 0);
2800 /* I don't expect anybody to ever use other terminals so the internal
2801 terminal is the default. */
2802 setenv ("TERM", "internal", 0);
2804 #ifdef HAVE_X_WINDOWS
2805 /* Emacs expects DISPLAY to be set. */
2806 setenv ("DISPLAY", "unix:0.0", 0);
2807 #endif
2809 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
2810 downcase it and mirror the backslashes. */
2811 s = getenv ("COMSPEC");
2812 if (!s) s = "c:/command.com";
2813 t = alloca (strlen (s) + 1);
2814 strcpy (t, s);
2815 dostounix_filename (t);
2816 setenv ("SHELL", t, 0);
2818 /* PATH is also downcased and backslashes mirrored. */
2819 s = getenv ("PATH");
2820 if (!s) s = "";
2821 t = alloca (strlen (s) + 3);
2822 /* Current directory is always considered part of MsDos's path but it is
2823 not normally mentioned. Now it is. */
2824 strcat (strcpy (t, ".;"), s);
2825 dostounix_filename (t); /* Not a single file name, but this should work. */
2826 setenv ("PATH", t, 1);
2828 /* In some sense all dos users have root privileges, so... */
2829 setenv ("USER", "root", 0);
2830 setenv ("NAME", getenv ("USER"), 0);
2832 /* Time zone determined from country code. To make this possible, the
2833 country code may not span more than one time zone. In other words,
2834 in the USA, you lose. */
2835 if (!getenv ("TZ"))
2836 switch (dos_country_code)
2838 case 31: /* Belgium */
2839 case 32: /* The Netherlands */
2840 case 33: /* France */
2841 case 34: /* Spain */
2842 case 36: /* Hungary */
2843 case 38: /* Yugoslavia (or what's left of it?) */
2844 case 39: /* Italy */
2845 case 41: /* Switzerland */
2846 case 42: /* Tjekia */
2847 case 45: /* Denmark */
2848 case 46: /* Sweden */
2849 case 47: /* Norway */
2850 case 48: /* Poland */
2851 case 49: /* Germany */
2852 /* Daylight saving from last Sunday in March to last Sunday in
2853 September, both at 2AM. */
2854 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2855 break;
2856 case 44: /* United Kingdom */
2857 case 351: /* Portugal */
2858 case 354: /* Iceland */
2859 setenv ("TZ", "GMT+00", 0);
2860 break;
2861 case 81: /* Japan */
2862 case 82: /* Korea */
2863 setenv ("TZ", "JST-09", 0);
2864 break;
2865 case 90: /* Turkey */
2866 case 358: /* Finland */
2867 setenv ("TZ", "EET-02", 0);
2868 break;
2869 case 972: /* Israel */
2870 /* This is an approximation. (For exact rules, use the
2871 `zoneinfo/israel' file which comes with DJGPP, but you need
2872 to install it in `/usr/share/zoneinfo/' directory first.) */
2873 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2874 break;
2876 tzset ();
2881 static int break_stat; /* BREAK check mode status. */
2882 static int stdin_stat; /* stdin IOCTL status. */
2884 #if __DJGPP__ < 2
2886 /* These must be global. */
2887 static _go32_dpmi_seginfo ctrl_break_vector;
2888 static _go32_dpmi_registers ctrl_break_regs;
2889 static int ctrlbreakinstalled = 0;
2891 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2893 void
2894 ctrl_break_func (regs)
2895 _go32_dpmi_registers *regs;
2897 Vquit_flag = Qt;
2900 void
2901 install_ctrl_break_check ()
2903 if (!ctrlbreakinstalled)
2905 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2906 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2907 ctrlbreakinstalled = 1;
2908 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
2909 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
2910 &ctrl_break_regs);
2911 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
2915 #endif /* __DJGPP__ < 2 */
2917 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
2918 control chars by DOS. Determine the keyboard type. */
2921 dos_ttraw ()
2923 union REGS inregs, outregs;
2924 static int first_time = 1;
2926 break_stat = getcbrk ();
2927 setcbrk (0);
2928 #if __DJGPP__ < 2
2929 install_ctrl_break_check ();
2930 #endif
2932 if (first_time)
2934 inregs.h.ah = 0xc0;
2935 int86 (0x15, &inregs, &outregs);
2936 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
2938 have_mouse = 0;
2940 if (internal_terminal
2941 #ifdef HAVE_X_WINDOWS
2942 && inhibit_window_system
2943 #endif
2946 inregs.x.ax = 0x0021;
2947 int86 (0x33, &inregs, &outregs);
2948 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2949 if (!have_mouse)
2951 /* Reportedly, the above doesn't work for some mouse drivers. There
2952 is an additional detection method that should work, but might be
2953 a little slower. Use that as an alternative. */
2954 inregs.x.ax = 0x0000;
2955 int86 (0x33, &inregs, &outregs);
2956 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2959 if (have_mouse)
2961 have_mouse = 1; /* enable mouse */
2962 mouse_visible = 0;
2964 if (outregs.x.bx == 3)
2966 mouse_button_count = 3;
2967 mouse_button_translate[0] = 0; /* Left */
2968 mouse_button_translate[1] = 2; /* Middle */
2969 mouse_button_translate[2] = 1; /* Right */
2971 else
2973 mouse_button_count = 2;
2974 mouse_button_translate[0] = 0;
2975 mouse_button_translate[1] = 1;
2977 mouse_position_hook = &mouse_get_pos;
2978 mouse_init ();
2982 first_time = 0;
2984 #if __DJGPP__ >= 2
2986 stdin_stat = setmode (fileno (stdin), O_BINARY);
2987 return (stdin_stat != -1);
2989 else
2990 return (setmode (fileno (stdin), O_BINARY) != -1);
2992 #else /* __DJGPP__ < 2 */
2996 /* I think it is wrong to overwrite `stdin_stat' every time
2997 but the first one this function is called, but I don't
2998 want to change the way it used to work in v1.x.--EZ */
3000 inregs.x.ax = 0x4400; /* Get IOCTL status. */
3001 inregs.x.bx = 0x00; /* 0 = stdin. */
3002 intdos (&inregs, &outregs);
3003 stdin_stat = outregs.h.dl;
3005 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
3006 inregs.x.ax = 0x4401; /* Set IOCTL status */
3007 intdos (&inregs, &outregs);
3008 return !outregs.x.cflag;
3010 #endif /* __DJGPP__ < 2 */
3013 /* Restore status of standard input and Ctrl-C checking. */
3016 dos_ttcooked ()
3018 union REGS inregs, outregs;
3020 setcbrk (break_stat);
3021 mouse_off ();
3023 #if __DJGPP__ >= 2
3025 return (setmode (fileno (stdin), stdin_stat) != -1);
3027 #else /* not __DJGPP__ >= 2 */
3029 inregs.x.ax = 0x4401; /* Set IOCTL status. */
3030 inregs.x.bx = 0x00; /* 0 = stdin. */
3031 inregs.x.dx = stdin_stat;
3032 intdos (&inregs, &outregs);
3033 return !outregs.x.cflag;
3035 #endif /* not __DJGPP__ >= 2 */
3039 /* Run command as specified by ARGV in directory DIR.
3040 The command is run with input from TEMPIN, output to
3041 file TEMPOUT and stderr to TEMPERR. */
3044 run_msdos_command (argv, dir, tempin, tempout, temperr)
3045 unsigned char **argv;
3046 Lisp_Object dir;
3047 int tempin, tempout, temperr;
3049 char *saveargv1, *saveargv2, **envv, *lowcase_argv0, *pa, *pl;
3050 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
3051 int msshell, result = -1;
3052 int inbak, outbak, errbak;
3053 int x, y;
3054 Lisp_Object cmd;
3056 /* Get current directory as MSDOS cwd is not per-process. */
3057 getwd (oldwd);
3059 /* If argv[0] is the shell, it might come in any lettercase.
3060 Since `Fmember' is case-sensitive, we need to downcase
3061 argv[0], even if we are on case-preserving filesystems. */
3062 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
3063 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
3065 *pl = *pa++;
3066 if (*pl >= 'A' && *pl <= 'Z')
3067 *pl += 'a' - 'A';
3069 *pl = '\0';
3071 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
3072 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
3073 && !strcmp ("-c", argv[1]);
3074 if (msshell)
3076 saveargv1 = argv[1];
3077 saveargv2 = argv[2];
3078 argv[1] = "/c";
3079 if (argv[2])
3081 char *p = alloca (strlen (argv[2]) + 1);
3083 strcpy (argv[2] = p, saveargv2);
3084 while (*p && isspace (*p))
3085 p++;
3086 while (*p && !isspace (*p))
3087 if (*p == '/')
3088 *p++ = '\\';
3089 else
3090 p++;
3094 /* Build the environment array. */
3096 extern Lisp_Object Vprocess_environment;
3097 Lisp_Object tmp, lst;
3098 int i, len;
3100 lst = Vprocess_environment;
3101 len = XFASTINT (Flength (lst));
3103 envv = alloca ((len + 1) * sizeof (char *));
3104 for (i = 0; i < len; i++)
3106 tmp = Fcar (lst);
3107 lst = Fcdr (lst);
3108 CHECK_STRING (tmp, 0);
3109 envv[i] = alloca (XSTRING (tmp)->size + 1);
3110 strcpy (envv[i], XSTRING (tmp)->data);
3112 envv[len] = (char *) 0;
3115 if (STRINGP (dir))
3116 chdir (XSTRING (dir)->data);
3117 inbak = dup (0);
3118 outbak = dup (1);
3119 errbak = dup (2);
3120 if (inbak < 0 || outbak < 0 || errbak < 0)
3121 goto done; /* Allocation might fail due to lack of descriptors. */
3123 if (have_mouse > 0)
3124 mouse_get_xy (&x, &y);
3126 dos_ttcooked (); /* do it here while 0 = stdin */
3128 dup2 (tempin, 0);
3129 dup2 (tempout, 1);
3130 dup2 (temperr, 2);
3132 #if __DJGPP__ > 1
3134 if (msshell && !argv[3])
3136 /* MS-DOS native shells are too restrictive. For starters, they
3137 cannot grok commands longer than 126 characters. In DJGPP v2
3138 and later, `system' is much smarter, so we'll call it instead. */
3140 extern char **environ;
3141 environ = envv;
3143 /* A shell gets a single argument--its full command
3144 line--whose original was saved in `saveargv2'. */
3145 result = system (saveargv2);
3147 else
3149 #endif /* __DJGPP__ > 1 */
3151 result = spawnve (P_WAIT, argv[0], argv, envv);
3153 dup2 (inbak, 0);
3154 dup2 (outbak, 1);
3155 dup2 (errbak, 2);
3156 close (inbak);
3157 close (outbak);
3158 close (errbak);
3160 dos_ttraw ();
3161 if (have_mouse > 0)
3163 mouse_init ();
3164 mouse_moveto (x, y);
3167 /* Some programs might change the meaning of the highest bit of the
3168 text attribute byte, so we get blinking characters instead of the
3169 bright background colors. Restore that. */
3170 bright_bg ();
3172 done:
3173 chdir (oldwd);
3174 if (msshell)
3176 argv[1] = saveargv1;
3177 argv[2] = saveargv2;
3179 return result;
3182 croak (badfunc)
3183 char *badfunc;
3185 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
3186 reset_sys_modes ();
3187 exit (1);
3190 #if __DJGPP__ < 2
3192 /* ------------------------- Compatibility functions -------------------
3193 * gethostname
3194 * gettimeofday
3197 /* Hostnames for a pc are not really funny,
3198 but they are used in change log so we emulate the best we can. */
3200 gethostname (p, size)
3201 char *p;
3202 int size;
3204 char *q = egetenv ("HOSTNAME");
3206 if (!q) q = "pc";
3207 strcpy (p, q);
3208 return 0;
3211 /* When time zones are set from Ms-Dos too many C-libraries are playing
3212 tricks with time values. We solve this by defining our own version
3213 of `gettimeofday' bypassing GO32. Our version needs to be initialized
3214 once and after each call to `tzset' with TZ changed. That is
3215 accomplished by aliasing tzset to init_gettimeofday. */
3217 static struct tm time_rec;
3220 gettimeofday (struct timeval *tp, struct timezone *tzp)
3222 if (tp)
3224 struct time t;
3225 struct tm tm;
3227 gettime (&t);
3228 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
3230 struct date d;
3231 getdate (&d);
3232 time_rec.tm_year = d.da_year - 1900;
3233 time_rec.tm_mon = d.da_mon - 1;
3234 time_rec.tm_mday = d.da_day;
3237 time_rec.tm_hour = t.ti_hour;
3238 time_rec.tm_min = t.ti_min;
3239 time_rec.tm_sec = t.ti_sec;
3241 tm = time_rec;
3242 tm.tm_gmtoff = dos_timezone_offset;
3244 tp->tv_sec = mktime (&tm); /* may modify tm */
3245 tp->tv_usec = t.ti_hund * (1000000 / 100);
3247 /* Ignore tzp; it's obsolescent. */
3248 return 0;
3251 #endif /* __DJGPP__ < 2 */
3254 * A list of unimplemented functions that we silently ignore.
3257 #if __DJGPP__ < 2
3258 unsigned alarm (s) unsigned s; {}
3259 fork () { return 0; }
3260 int kill (x, y) int x, y; { return -1; }
3261 nice (p) int p; {}
3262 void volatile pause () {}
3263 sigsetmask (x) int x; { return 0; }
3264 sigblock (mask) int mask; { return 0; }
3265 #endif
3267 void request_sigio (void) {}
3268 setpgrp () {return 0; }
3269 setpriority (x,y,z) int x,y,z; { return 0; }
3270 void unrequest_sigio (void) {}
3272 #if __DJGPP__ > 1
3274 #ifdef POSIX_SIGNALS
3276 /* Augment DJGPP library POSIX signal functions. This is needed
3277 as of DJGPP v2.01, but might be in the library in later releases. */
3279 #include <libc/bss.h>
3281 /* A counter to know when to re-initialize the static sets. */
3282 static int sigprocmask_count = -1;
3284 /* Which signals are currently blocked (initially none). */
3285 static sigset_t current_mask;
3287 /* Which signals are pending (initially none). */
3288 static sigset_t pending_signals;
3290 /* Previous handlers to restore when the blocked signals are unblocked. */
3291 typedef void (*sighandler_t)(int);
3292 static sighandler_t prev_handlers[320];
3294 /* A signal handler which just records that a signal occured
3295 (it will be raised later, if and when the signal is unblocked). */
3296 static void
3297 sig_suspender (signo)
3298 int signo;
3300 sigaddset (&pending_signals, signo);
3304 sigprocmask (how, new_set, old_set)
3305 int how;
3306 const sigset_t *new_set;
3307 sigset_t *old_set;
3309 int signo;
3310 sigset_t new_mask;
3312 /* If called for the first time, initialize. */
3313 if (sigprocmask_count != __bss_count)
3315 sigprocmask_count = __bss_count;
3316 sigemptyset (&pending_signals);
3317 sigemptyset (&current_mask);
3318 for (signo = 0; signo < 320; signo++)
3319 prev_handlers[signo] = SIG_ERR;
3322 if (old_set)
3323 *old_set = current_mask;
3325 if (new_set == 0)
3326 return 0;
3328 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
3330 errno = EINVAL;
3331 return -1;
3334 sigemptyset (&new_mask);
3336 /* DJGPP supports upto 320 signals. */
3337 for (signo = 0; signo < 320; signo++)
3339 if (sigismember (&current_mask, signo))
3340 sigaddset (&new_mask, signo);
3341 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
3343 sigaddset (&new_mask, signo);
3345 /* SIGKILL is silently ignored, as on other platforms. */
3346 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
3347 prev_handlers[signo] = signal (signo, sig_suspender);
3349 if (( how == SIG_UNBLOCK
3350 && sigismember (&new_mask, signo)
3351 && sigismember (new_set, signo))
3352 || (how == SIG_SETMASK
3353 && sigismember (&new_mask, signo)
3354 && !sigismember (new_set, signo)))
3356 sigdelset (&new_mask, signo);
3357 if (prev_handlers[signo] != SIG_ERR)
3359 signal (signo, prev_handlers[signo]);
3360 prev_handlers[signo] = SIG_ERR;
3362 if (sigismember (&pending_signals, signo))
3364 sigdelset (&pending_signals, signo);
3365 raise (signo);
3369 current_mask = new_mask;
3370 return 0;
3373 #else /* not POSIX_SIGNALS */
3375 sigsetmask (x) int x; { return 0; }
3376 sigblock (mask) int mask; { return 0; }
3378 #endif /* not POSIX_SIGNALS */
3379 #endif /* __DJGPP__ > 1 */
3381 #ifndef HAVE_SELECT
3382 #include "sysselect.h"
3384 #ifndef EMACS_TIME_ZERO_OR_NEG_P
3385 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
3386 ((long)(time).tv_sec < 0 \
3387 || ((time).tv_sec == 0 \
3388 && (long)(time).tv_usec <= 0))
3389 #endif
3392 /* Only event queue is checked. */
3393 /* We don't have to call timer_check here
3394 because wait_reading_process_input takes care of that. */
3396 sys_select (nfds, rfds, wfds, efds, timeout)
3397 int nfds;
3398 SELECT_TYPE *rfds, *wfds, *efds;
3399 EMACS_TIME *timeout;
3401 int check_input;
3402 struct time t;
3404 check_input = 0;
3405 if (rfds)
3407 check_input = FD_ISSET (0, rfds);
3408 FD_ZERO (rfds);
3410 if (wfds)
3411 FD_ZERO (wfds);
3412 if (efds)
3413 FD_ZERO (efds);
3415 if (nfds != 1)
3416 abort ();
3418 /* If we are looking only for the terminal, with no timeout,
3419 just read it and wait -- that's more efficient. */
3420 if (!timeout)
3422 while (!detect_input_pending ())
3424 #if __DJGPP__ >= 2
3425 __dpmi_yield ();
3426 #endif
3429 else
3431 EMACS_TIME clnow, cllast, cldiff;
3433 gettime (&t);
3434 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
3436 while (!check_input || !detect_input_pending ())
3438 gettime (&t);
3439 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
3440 EMACS_SUB_TIME (cldiff, clnow, cllast);
3442 /* When seconds wrap around, we assume that no more than
3443 1 minute passed since last `gettime'. */
3444 if (EMACS_TIME_NEG_P (cldiff))
3445 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
3446 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
3448 /* Stop when timeout value crosses zero. */
3449 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
3450 return 0;
3451 cllast = clnow;
3452 #if __DJGPP__ >= 2
3453 __dpmi_yield ();
3454 #endif
3458 FD_SET (0, rfds);
3459 return 1;
3461 #endif
3464 * Define overlaid functions:
3466 * chdir -> sys_chdir
3467 * tzset -> init_gettimeofday
3468 * abort -> dos_abort
3471 #ifdef chdir
3472 #undef chdir
3473 extern int chdir ();
3476 sys_chdir (path)
3477 const char* path;
3479 int len = strlen (path);
3480 char *tmp = (char *)path;
3482 if (*tmp && tmp[1] == ':')
3484 if (getdisk () != tolower (tmp[0]) - 'a')
3485 setdisk (tolower (tmp[0]) - 'a');
3486 tmp += 2; /* strip drive: KFS 1995-07-06 */
3487 len -= 2;
3490 if (len > 1 && (tmp[len - 1] == '/'))
3492 char *tmp1 = (char *) alloca (len + 1);
3493 strcpy (tmp1, tmp);
3494 tmp1[len - 1] = 0;
3495 tmp = tmp1;
3497 return chdir (tmp);
3499 #endif
3501 #ifdef tzset
3502 #undef tzset
3503 extern void tzset (void);
3505 void
3506 init_gettimeofday ()
3508 time_t ltm, gtm;
3509 struct tm *lstm;
3511 tzset ();
3512 ltm = gtm = time (NULL);
3513 ltm = mktime (lstm = localtime (&ltm));
3514 gtm = mktime (gmtime (&gtm));
3515 time_rec.tm_hour = 99; /* force gettimeofday to get date */
3516 time_rec.tm_isdst = lstm->tm_isdst;
3517 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
3519 #endif
3521 #ifdef abort
3522 #undef abort
3523 void
3524 dos_abort (file, line)
3525 char *file;
3526 int line;
3528 char buffer1[200], buffer2[400];
3529 int i, j;
3531 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
3532 for (i = j = 0; buffer1[i]; i++) {
3533 buffer2[j++] = buffer1[i];
3534 buffer2[j++] = 0x70;
3536 dosmemput (buffer2, j, (int)ScreenPrimary);
3537 ScreenSetCursor (2, 0);
3538 abort ();
3540 #else
3541 void
3542 abort ()
3544 dos_ttcooked ();
3545 ScreenSetCursor (10, 0);
3546 cputs ("\r\n\nEmacs aborted!\r\n");
3547 #if __DJGPP__ > 1
3548 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
3549 if (screen_virtual_segment)
3550 dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
3551 #endif /* __DJGPP_MINOR__ < 2 */
3552 /* Generate traceback, so we could tell whodunit. */
3553 signal (SIGINT, SIG_DFL);
3554 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
3555 #endif
3556 exit (2);
3558 #endif
3560 /* The following two are required so that customization feature
3561 won't complain about unbound variables. */
3562 #ifndef HAVE_X_WINDOWS
3563 /* Search path for bitmap files (xfns.c). */
3564 Lisp_Object Vx_bitmap_file_path;
3565 #endif
3566 #ifndef subprocesses
3567 /* Nonzero means delete a process right away if it exits (process.c). */
3568 static int delete_exited_processes;
3569 #endif
3571 syms_of_msdos ()
3573 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
3574 staticpro (&recent_doskeys);
3575 #ifndef HAVE_X_WINDOWS
3576 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
3577 "List of directories to search for bitmap files for X.");
3578 Vx_bitmap_file_path = decode_env_path ((char *) 0, ".");
3580 /* The following two are from xfns.c: */
3581 Qbackground_color = intern ("background-color");
3582 staticpro (&Qbackground_color);
3583 Qforeground_color = intern ("foreground-color");
3584 staticpro (&Qforeground_color);
3585 #endif
3586 #ifndef subprocesses
3587 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
3588 "*Non-nil means delete processes immediately when they exit.\n\
3589 nil means don't delete them until `list-processes' is run.");
3590 delete_exited_processes = 0;
3591 #endif
3593 defsubr (&Srecent_doskeys);
3594 defsubr (&Smsdos_long_file_names);
3595 defsubr (&Smsdos_downcase_filename);
3598 #endif /* MSDOS */