comparison src/msdos.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children 0293115a14e9
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 /* MS-DOS specific C utilities.
2 Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
3
4 This file is part of XEmacs.
5
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; 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. */
20
21 /* Synched up with: FSF 19.30. */
22
23 /* Contributed by Morten Welinder */
24 /* New display, keyboard, and mouse control by Kim F. Storm */
25
26 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
27
28 #define DONT_ENCAPSULATE
29
30 #include <config.h>
31
32 #ifdef MSDOS
33 #include <sys/param.h>
34 #include <sys/time.h>
35 #include <dos.h>
36 #include "lisp.h"
37 #include "dosfns.h"
38 #include "msdos.h"
39 #include "redisplay.h"
40 #include "systime.h"
41 #include "termhooks.h"
42 #include "frame.h"
43 #include "window.h"
44 #include <go32.h>
45 #include <pc.h>
46
47 static unsigned long
48 event_timestamp (void)
49 {
50 struct time t;
51 unsigned long s;
52
53 gettime (&t);
54 s = t.ti_min;
55 s *= 60;
56 s += t.ti_sec;
57 s *= 1000;
58 s += t.ti_hund * 10;
59
60 return s;
61 }
62
63
64 /* ------------------------ Mouse control ---------------------------
65 *
66 * Coordinates are in screen positions and zero based.
67 * Mouse buttons are numbered from left to right and also zero based.
68 */
69
70 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
71 static int mouse_visible;
72
73 static int mouse_last_x;
74 static int mouse_last_y;
75
76 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
77 static int mouse_button_count;
78
79 void
80 mouse_on (void)
81 {
82 union REGS regs;
83
84 if (have_mouse > 0 && !mouse_visible)
85 {
86 if (termscript)
87 fprintf (termscript, "<M_ON>");
88 regs.x.ax = 0x0001;
89 int86 (0x33, &regs, &regs);
90 mouse_visible = 1;
91 }
92 }
93
94 void
95 mouse_off (void)
96 {
97 union REGS regs;
98
99 if (have_mouse > 0 && mouse_visible)
100 {
101 if (termscript)
102 fprintf (termscript, "<M_OFF>");
103 regs.x.ax = 0x0002;
104 int86 (0x33, &regs, &regs);
105 mouse_visible = 0;
106 }
107 }
108
109 void
110 mouse_moveto (int x, int y)
111 {
112 union REGS regs;
113
114 if (termscript)
115 fprintf (termscript, "<M_XY=%dx%d>", x, y);
116 regs.x.ax = 0x0004;
117 mouse_last_x = regs.x.cx = x * 8;
118 mouse_last_y = regs.x.dx = y * 8;
119 int86 (0x33, &regs, &regs);
120 }
121
122 static int
123 mouse_pressed (int b, int *xp, int *yp)
124 {
125 union REGS regs;
126
127 if (b >= mouse_button_count)
128 return 0;
129 regs.x.ax = 0x0005;
130 regs.x.bx = mouse_button_translate[b];
131 int86 (0x33, &regs, &regs);
132 if (regs.x.bx)
133 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
134 return (regs.x.bx != 0);
135 }
136
137 static int
138 mouse_released (int b, int *xp, int *yp)
139 {
140 union REGS regs;
141
142 if (b >= mouse_button_count)
143 return 0;
144 regs.x.ax = 0x0006;
145 regs.x.bx = mouse_button_translate[b];
146 int86 (0x33, &regs, &regs);
147 if (regs.x.bx)
148 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
149 return (regs.x.bx != 0);
150 }
151
152 static void
153 mouse_get_xy (int *x, int *y)
154 {
155 union REGS regs;
156
157 regs.x.ax = 0x0003;
158 int86 (0x33, &regs, &regs);
159 *x = regs.x.cx / 8;
160 *y = regs.x.dx / 8;
161 }
162
163 void
164 mouse_get_pos (FRAME_PTR *f, int insist, Lisp_Object *bar_window,
165 Lisp_Object *x, Lisp_Object *y, enum scroll_bar_part *part,
166 unsigned long *time)
167 {
168 int ix, iy;
169 union REGS regs;
170
171 regs.x.ax = 0x0003;
172 int86 (0x33, &regs, &regs);
173 *f = selected_frame;
174 *bar_window = Qnil;
175 mouse_get_xy (&ix, &iy);
176 selected_frame->mouse_moved = 0;
177 *x = make_int (ix);
178 *y = make_int (iy);
179 *time = event_timestamp ();
180 }
181
182 static void
183 mouse_check_moved (void)
184 {
185 int x, y;
186
187 mouse_get_xy (&x, &y);
188 selected_frame->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
189 mouse_last_x = x;
190 mouse_last_y = y;
191 }
192
193 void
194 mouse_init (void)
195 {
196 union REGS regs;
197
198 if (termscript)
199 fprintf (termscript, "<M_INIT>");
200
201 regs.x.ax = 0x0021;
202 int86 (0x33, &regs, &regs);
203
204 regs.x.ax = 0x0007;
205 regs.x.cx = 0;
206 regs.x.dx = 8 * (ScreenCols () - 1);
207 int86 (0x33, &regs, &regs);
208
209 regs.x.ax = 0x0008;
210 regs.x.cx = 0;
211 regs.x.dx = 8 * (ScreenRows () - 1);
212 int86 (0x33, &regs, &regs);
213
214 mouse_moveto (0, 0);
215 mouse_visible = 0;
216 }
217
218 /* ------------------------- Screen control ----------------------
219 *
220 */
221
222 static int internal_terminal = 0;
223
224 #ifndef HAVE_X_WINDOWS
225 extern unsigned char ScreenAttrib;
226 static int screen_face;
227 static int highlight;
228
229 static int screen_size_X;
230 static int screen_size_Y;
231 static int screen_size;
232
233 static int current_pos_X;
234 static int current_pos_Y;
235 static int new_pos_X;
236 static int new_pos_Y;
237
238 static void *startup_screen_buffer;
239 static int startup_screen_size_X;
240 static int startup_screen_size_Y;
241 static int startup_pos_X;
242 static int startup_pos_Y;
243
244 static int term_setup_done;
245
246 /* Similar to the_only_frame. */
247 struct x_output the_only_x_display;
248
249 /* This is never dereferenced. */
250 Display *x_current_display;
251
252
253 #define SCREEN_SET_CURSOR() \
254 if (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y) \
255 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X)
256
257 static
258 dos_direct_output (int y, int x, char *buf, int len)
259 {
260 int t = (int) ScreenPrimary + 2 * (x + y * screen_size_X);
261
262 while (--len >= 0) {
263 dosmemput (buf++, 1, t);
264 t += 2;
265 }
266 }
267 #endif
268
269 /* Flash the screen as a substitute for BEEPs. */
270
271 #if (__DJGPP__ < 2)
272 static void
273 do_visible_bell (unsigned char xorattr)
274 {
275 asm volatile
276 (" movb $1,%%dl
277 visible_bell_0:
278 movl _ScreenPrimary,%%eax
279 call dosmemsetup
280 movl %%eax,%%ebx
281 movl %1,%%ecx
282 movb %0,%%al
283 incl %%ebx
284 visible_bell_1:
285 xorb %%al,%%gs:(%%ebx)
286 addl $2,%%ebx
287 decl %%ecx
288 jne visible_bell_1
289 decb %%dl
290 jne visible_bell_3
291 visible_bell_2:
292 movzwl %%ax,%%eax
293 movzwl %%ax,%%eax
294 movzwl %%ax,%%eax
295 movzwl %%ax,%%eax
296 decw %%cx
297 jne visible_bell_2
298 jmp visible_bell_0
299 visible_bell_3:"
300 : /* no output */
301 : "m" (xorattr), "g" (screen_size)
302 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
303 }
304
305 static void
306 ScreenVisualBell (void)
307 {
308 /* This creates an xor-mask that will swap the default fore- and
309 background colors. */
310 do_visible_bell (((the_only_x_display.foreground_pixel
311 ^ the_only_x_display.background_pixel)
312 * 0x11) & 0x7f);
313 }
314 #endif
315
316 #ifndef HAVE_X_WINDOWS
317
318 /*
319 * If we write a character in the position where the mouse is,
320 * the mouse cursor may need to be refreshed.
321 */
322
323 static void
324 mouse_off_maybe (void)
325 {
326 int x, y;
327
328 if (!mouse_visible)
329 return;
330
331 mouse_get_xy (&x, &y);
332 if (y != new_pos_Y || x < new_pos_X)
333 return;
334
335 mouse_off ();
336 }
337
338 static
339 IT_ring_bell (void)
340 {
341 if (visible_bell)
342 {
343 mouse_off ();
344 ScreenVisualBell ();
345 }
346 else
347 {
348 union REGS inregs, outregs;
349 inregs.h.ah = 2;
350 inregs.h.dl = 7;
351 intdos (&inregs, &outregs);
352 }
353 }
354
355 static void
356 IT_set_face (int face)
357 {
358 struct face *fp;
359 extern struct face *intern_face (/* FRAME_PTR, struct face * */);
360
361 if (face == 1 || (face == 0 && highlight))
362 fp = FRAME_MODE_LINE_FACE (foo);
363 else if (face <= 0 || face >= FRAME_N_COMPUTED_FACES (foo))
364 fp = FRAME_DEFAULT_FACE (foo);
365 else
366 fp = intern_face (selected_frame, FRAME_COMPUTED_FACES (foo)[face]);
367 if (termscript)
368 fprintf (termscript, "<FACE:%d:%d>", FACE_FOREGROUND (fp), FACE_BACKGROUND (fp));
369 screen_face = face;
370 ScreenAttrib = (FACE_BACKGROUND (fp) << 4) | FACE_FOREGROUND (fp);
371 }
372
373 static
374 IT_write_glyphs (GLYPH *str, int len)
375 {
376 int newface;
377 int ch, l = len;
378 unsigned char *buf, *bp;
379
380 if (len == 0) return;
381
382 buf = bp = alloca (len * 2);
383
384 while (--l >= 0)
385 {
386 newface = FAST_GLYPH_FACE (*str);
387 if (newface != screen_face)
388 IT_set_face (newface);
389 ch = FAST_GLYPH_CHAR (*str);
390 *bp++ = (unsigned char)ch;
391 *bp++ = ScreenAttrib;
392
393 if (termscript)
394 fputc (ch, termscript);
395 str++;
396 }
397
398 mouse_off_maybe ();
399 dosmemput (buf, 2 * len,
400 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
401 new_pos_X += len;
402 }
403
404 static
405 IT_clear_end_of_line (int first_unused)
406 {
407 char *spaces, *sp;
408 int i, j;
409
410 IT_set_face (0);
411 if (termscript)
412 fprintf (termscript, "<CLR:EOL>");
413 i = (j = screen_size_X - new_pos_X) * 2;
414 spaces = sp = alloca (i);
415
416 while (--j >= 0)
417 {
418 *sp++ = ' ';
419 *sp++ = ScreenAttrib;
420 }
421
422 mouse_off_maybe ();
423 dosmemput (spaces, i,
424 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
425 }
426
427 static
428 IT_clear_screen (void)
429 {
430 if (termscript)
431 fprintf (termscript, "<CLR:SCR>");
432 IT_set_face (0);
433 mouse_off ();
434 ScreenClear ();
435 new_pos_X = new_pos_Y = 0;
436 }
437
438 static
439 IT_clear_to_end (void)
440 {
441 if (termscript)
442 fprintf (termscript, "<CLR:EOS>");
443
444 while (new_pos_Y < screen_size_Y) {
445 new_pos_X = 0;
446 IT_clear_end_of_line (0);
447 new_pos_Y++;
448 }
449 }
450
451 static
452 IT_cursor_to (int y, int x)
453 {
454 if (termscript)
455 fprintf (termscript, "\n<XY=%dx%d>", x, y);
456 new_pos_X = x;
457 new_pos_Y = y;
458 }
459
460 static
461 IT_reassert_line_highlight (int new, int vpos)
462 {
463 highlight = new;
464 IT_set_face (0); /* To possibly clear the highlighting. */
465 }
466
467 static
468 IT_change_line_highlight (int new_highlight, int vpos, int first_unused_hpos)
469 {
470 highlight = new_highlight;
471 IT_set_face (0); /* To possibly clear the highlighting. */
472 IT_cursor_to (vpos, 0);
473 IT_clear_end_of_line (first_unused_hpos);
474 }
475
476 static
477 IT_update_begin (void)
478 {
479 highlight = 0;
480 IT_set_face (0); /* To possibly clear the highlighting. */
481 screen_face = -1;
482 }
483
484 static
485 IT_update_end (void)
486 {
487 }
488
489 /* This was more or less copied from xterm.c */
490 static void
491 IT_set_menu_bar_lines (Lisp_Object window, int n)
492 {
493 struct window *w = XWINDOW (window);
494
495 XSETINT (w->last_modified, 0);
496 XSETINT (w->top, XINT (w->top) + n);
497 XSETINT (w->height, XINT (w->height) - n);
498
499 /* Handle just the top child in a vertical split. */
500 if (!NILP (w->vchild))
501 IT_set_menu_bar_lines (w->vchild, n);
502
503 /* Adjust all children in a horizontal split. */
504 for (window = w->hchild; !NILP (window); window = w->next)
505 {
506 w = XWINDOW (window);
507 IT_set_menu_bar_lines (window, n);
508 }
509 }
510
511 /*
512 * IT_set_terminal_modes is called when emacs is started,
513 * resumed, and whenever the screen is redrawn!
514 */
515
516 static
517 IT_set_terminal_modes (void)
518 {
519 char *colors;
520 FRAME_PTR f;
521 struct face *fp;
522
523 if (termscript)
524 fprintf (termscript, "\n<SET_TERM>");
525 highlight = 0;
526
527 screen_size_X = ScreenCols ();
528 screen_size_Y = ScreenRows ();
529 screen_size = screen_size_X * screen_size_Y;
530
531 new_pos_X = new_pos_Y = 0;
532 current_pos_X = current_pos_Y = -1;
533
534 if (term_setup_done)
535 return;
536 term_setup_done = 1;
537
538 startup_screen_size_X = screen_size_X;
539 startup_screen_size_Y = screen_size_Y;
540
541 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
542 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
543
544 if (termscript)
545 fprintf (termscript, "<SCREEN SAVED>\n");
546 }
547
548 /*
549 * IT_reset_terminal_modes is called when emacs is
550 * suspended or killed.
551 */
552
553 static
554 IT_reset_terminal_modes (void)
555 {
556 if (termscript)
557 fprintf (termscript, "\n<RESET_TERM>");
558
559 highlight = 0;
560
561 if (!term_setup_done)
562 return;
563
564 ScreenUpdate (startup_screen_buffer);
565 ScreenSetCursor (startup_pos_Y, startup_pos_X);
566 xfree (startup_screen_buffer);
567
568 if (termscript)
569 fprintf (termscript, "<SCREEN RESTORED>\n");
570
571 term_setup_done = 0;
572 }
573
574 static
575 IT_set_terminal_window (void)
576 {
577 }
578
579 void
580 IT_set_frame_parameters (FRAME_PTR frame, Lisp_Object alist)
581 {
582 Lisp_Object tail;
583 int redraw;
584 extern unsigned long load_color ();
585 FRAME_PTR f = (FRAME_PTR) &the_only_frame;
586
587 redraw = 0;
588 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
589 {
590 Lisp_Object elt, prop, val;
591
592 elt = Fcar (tail);
593 prop = Fcar (elt);
594 val = Fcdr (elt);
595 CHECK_SYMBOL (prop);
596
597 if (EQ (prop, intern ("foreground-color")))
598 {
599 unsigned long new_color = load_color (f, val);
600 if (new_color != ~0)
601 {
602 FRAME_FOREGROUND_PIXEL (f) = new_color;
603 redraw = 1;
604 }
605 }
606 else if (EQ (prop, intern ("background-color")))
607 {
608 unsigned long new_color = load_color (f, val);
609 if (new_color != ~0)
610 {
611 FRAME_BACKGROUND_PIXEL (f) = new_color & ~8;
612 redraw = 1;
613 }
614 }
615 else if (EQ (prop, intern ("menu-bar-lines")))
616 {
617 int new;
618 int old = FRAME_MENU_BAR_LINES (the_only_frame);
619
620 if (INTEGERP (val))
621 new = XINT (val);
622 else
623 new = 0;
624 FRAME_MENU_BAR_LINES (f) = new;
625 IT_set_menu_bar_lines (the_only_frame.root_window, new - old);
626 }
627 }
628
629 if (redraw)
630 {
631 recompute_basic_faces (f);
632 Fredraw_frame (Fselected_frame (Qnil), Qnil);
633 }
634 }
635
636 #endif /* !HAVE_X_WINDOWS */
637
638
639 /* Do we need the internal terminal? */
640 void
641 internal_terminal_init (void)
642 {
643 char *term = getenv ("TERM");
644 char *colors;
645
646 #ifdef HAVE_X_WINDOWS
647 if (!inhibit_window_system)
648 return;
649 #endif
650
651 internal_terminal
652 = (!noninteractive) && term && !strcmp (term, "internal");
653
654 if (getenv ("EMACSTEST"))
655 termscript = fopen (getenv ("EMACSTEST"), "wt");
656
657 #ifndef HAVE_X_WINDOWS
658 if (!internal_terminal || inhibit_window_system)
659 {
660 the_only_frame.output_method = output_termcap;
661 return;
662 }
663
664 Vwindow_system = intern ("pc");
665
666 bzero (&the_only_x_display, sizeof the_only_x_display);
667 the_only_x_display.background_pixel = 7; /* White */
668 the_only_x_display.foreground_pixel = 0; /* Black */
669 colors = getenv ("EMACSCOLORS");
670 if (colors && strlen (colors) >= 2)
671 {
672 the_only_x_display.foreground_pixel = colors[0] & 0x07;
673 the_only_x_display.background_pixel = colors[1] & 0x07;
674 }
675 the_only_x_display.line_height = 1;
676 the_only_frame.output_data.x = &the_only_x_display;
677 the_only_frame.output_method = output_msdos_raw;
678 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
679
680 init_frame_faces ((FRAME_PTR) &the_only_frame);
681
682 ring_bell_hook = IT_ring_bell;
683 write_glyphs_hook = IT_write_glyphs;
684 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
685 clear_to_end_hook = IT_clear_to_end;
686 clear_end_of_line_hook = IT_clear_end_of_line;
687 clear_frame_hook = IT_clear_screen;
688 change_line_highlight_hook = IT_change_line_highlight;
689 update_begin_hook = IT_update_begin;
690 update_end_hook = IT_update_end;
691 reassert_line_highlight_hook = IT_reassert_line_highlight;
692
693 /* These hooks are called by term.c without being checked. */
694 set_terminal_modes_hook = IT_set_terminal_modes;
695 reset_terminal_modes_hook = IT_reset_terminal_modes;
696 set_terminal_window_hook = IT_set_terminal_window;
697 #endif
698 }
699
700 dos_get_saved_screen (char **screen, int *rows, int *cols)
701 {
702 #ifndef HAVE_X_WINDOWS
703 *screen = startup_screen_buffer;
704 *cols = startup_screen_size_X;
705 *rows = startup_screen_size_Y;
706 return 1;
707 #else
708 return 0;
709 #endif
710 }
711
712
713
714 /* ----------------------- Keyboard control ----------------------
715 *
716 * Keymaps reflect the following keyboard layout:
717 *
718 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
719 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
720 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
721 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
722 * SPACE
723 */
724
725 static int extended_kbd; /* 101 (102) keyboard present. */
726
727 struct dos_keyboard_map
728 {
729 char *unshifted;
730 char *shifted;
731 char *alt_gr;
732 };
733
734
735 static struct dos_keyboard_map us_keyboard = {
736 /* 0 1 2 3 4 5 */
737 /* 01234567890123456789012345678901234567890 12345678901234 */
738 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
739 /* 0123456789012345678901234567890123456789 012345678901234 */
740 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
741 0 /* no Alt-Gr key */
742 };
743
744 static struct dos_keyboard_map fr_keyboard = {
745 /* 0 1 2 3 4 5 */
746 /* 012 3456789012345678901234567890123456789012345678901234 */
747 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
748 /* 0123456789012345678901234567890123456789012345678901234 */
749 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
750 /* 01234567 89012345678901234567890123456789012345678901234 */
751 " ~#{[|`\\^@]} Ï "
752 };
753
754 static struct dos_keyboard_map dk_keyboard = {
755 /* 0 1 2 3 4 5 */
756 /* 0123456789012345678901234567890123456789012345678901234 */
757 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
758 /* 01 23456789012345678901234567890123456789012345678901234 */
759 "õ!\"#$%&/()=?` QWERTYUIOP^ ASDFGHJKL’* ZXCVBNM;:_ ",
760 /* 0123456789012345678901234567890123456789012345678901234 */
761 " @œ$ {[]} | "
762 };
763
764 static struct keyboard_layout_list
765 {
766 int country_code;
767 struct dos_keyboard_map *keyboard_map;
768 } keyboard_layout_list[] =
769 {
770 1, &us_keyboard,
771 33, &fr_keyboard,
772 45, &dk_keyboard
773 };
774
775 static struct dos_keyboard_map *keyboard;
776 static int keyboard_map_all;
777
778 int
779 dos_set_keyboard (int code, int always)
780 {
781 int i;
782
783 /* Initialize to US settings, for countries that don't have their own. */
784 keyboard = keyboard_layout_list[0].keyboard_map;
785 keyboard_map_all = always;
786 dos_keyboard_layout = 1;
787
788 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
789 if (code == keyboard_layout_list[i].country_code)
790 {
791 keyboard = keyboard_layout_list[i].keyboard_map;
792 keyboard_map_all = always;
793 dos_keyboard_layout = code;
794 return 1;
795 }
796 return 0;
797 }
798
799 #define Ignore 0x0000
800 #define Normal 0x0000 /* normal key - alt changes scan-code */
801 #define FctKey 0x1000 /* func key if c == 0, else c */
802 #define Special 0x2000 /* func key even if c != 0 */
803 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
804 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
805 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
806 #define Grey 0x6000 /* Grey keypad key */
807
808 #define Alt 0x0100 /* alt scan-code */
809 #define Ctrl 0x0200 /* ctrl scan-code */
810 #define Shift 0x0400 /* shift scan-code */
811
812 static struct
813 {
814 unsigned char char_code; /* normal code */
815 unsigned char meta_code; /* M- code */
816 unsigned char keypad_code; /* keypad code */
817 unsigned char editkey_code; /* edit key */
818 } keypad_translate_map[] = {
819 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
820 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
821 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
822 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
823 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
824 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
825 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
826 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
827 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
828 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
829 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
830 };
831
832 static struct
833 {
834 unsigned char char_code; /* normal code */
835 unsigned char keypad_code; /* keypad code */
836 } grey_key_translate_map[] = {
837 '/', 0xaf, /* kp-decimal */
838 '*', 0xaa, /* kp-multiply */
839 '-', 0xad, /* kp-subtract */
840 '+', 0xab, /* kp-add */
841 '\r', 0x8d /* kp-enter */
842 };
843
844 static unsigned short
845 ibmpc_translate_map[] =
846 {
847 /* --------------- 00 to 0f --------------- */
848 Normal | 0xff, /* Ctrl Break + Alt-NNN */
849 Alt | ModFct | 0x1b, /* Escape */
850 Normal | 1, /* '1' */
851 Normal | 2, /* '2' */
852 Normal | 3, /* '3' */
853 Normal | 4, /* '4' */
854 Normal | 5, /* '5' */
855 Normal | 6, /* '6' */
856 Normal | 7, /* '7' */
857 Normal | 8, /* '8' */
858 Normal | 9, /* '9' */
859 Normal | 10, /* '0' */
860 Normal | 11, /* '-' */
861 Normal | 12, /* '=' */
862 Special | 0x08, /* Backspace */
863 ModFct | 0x74, /* Tab/Backtab */
864
865 /* --------------- 10 to 1f --------------- */
866 Map | 15, /* 'q' */
867 Map | 16, /* 'w' */
868 Map | 17, /* 'e' */
869 Map | 18, /* 'r' */
870 Map | 19, /* 't' */
871 Map | 20, /* 'y' */
872 Map | 21, /* 'u' */
873 Map | 22, /* 'i' */
874 Map | 23, /* 'o' */
875 Map | 24, /* 'p' */
876 Map | 25, /* '[' */
877 Map | 26, /* ']' */
878 ModFct | 0x0d, /* Return */
879 Ignore, /* Ctrl */
880 Map | 30, /* 'a' */
881 Map | 31, /* 's' */
882
883 /* --------------- 20 to 2f --------------- */
884 Map | 32, /* 'd' */
885 Map | 33, /* 'f' */
886 Map | 34, /* 'g' */
887 Map | 35, /* 'h' */
888 Map | 36, /* 'j' */
889 Map | 37, /* 'k' */
890 Map | 38, /* 'l' */
891 Map | 39, /* ';' */
892 Map | 40, /* '\'' */
893 Map | 0, /* '`' */
894 Ignore, /* Left shift */
895 Map | 41, /* '\\' */
896 Map | 45, /* 'z' */
897 Map | 46, /* 'x' */
898 Map | 47, /* 'c' */
899 Map | 48, /* 'v' */
900
901 /* --------------- 30 to 3f --------------- */
902 Map | 49, /* 'b' */
903 Map | 50, /* 'n' */
904 Map | 51, /* 'm' */
905 Map | 52, /* ',' */
906 Map | 53, /* '.' */
907 Map | 54, /* '/' */
908 Ignore, /* Right shift */
909 Grey | 1, /* Grey * */
910 Ignore, /* Alt */
911 Normal | ' ', /* ' ' */
912 Ignore, /* Caps Lock */
913 FctKey | 0xbe, /* F1 */
914 FctKey | 0xbf, /* F2 */
915 FctKey | 0xc0, /* F3 */
916 FctKey | 0xc1, /* F4 */
917 FctKey | 0xc2, /* F5 */
918
919 /* --------------- 40 to 4f --------------- */
920 FctKey | 0xc3, /* F6 */
921 FctKey | 0xc4, /* F7 */
922 FctKey | 0xc5, /* F8 */
923 FctKey | 0xc6, /* F9 */
924 FctKey | 0xc7, /* F10 */
925 Ignore, /* Num Lock */
926 Ignore, /* Scroll Lock */
927 KeyPad | 7, /* Home */
928 KeyPad | 8, /* Up */
929 KeyPad | 9, /* Page Up */
930 Grey | 2, /* Grey - */
931 KeyPad | 4, /* Left */
932 KeyPad | 5, /* Keypad 5 */
933 KeyPad | 6, /* Right */
934 Grey | 3, /* Grey + */
935 KeyPad | 1, /* End */
936
937 /* --------------- 50 to 5f --------------- */
938 KeyPad | 2, /* Down */
939 KeyPad | 3, /* Page Down */
940 KeyPad | 0, /* Insert */
941 KeyPad | 10, /* Delete */
942 Shift | FctKey | 0xbe, /* (Shift) F1 */
943 Shift | FctKey | 0xbf, /* (Shift) F2 */
944 Shift | FctKey | 0xc0, /* (Shift) F3 */
945 Shift | FctKey | 0xc1, /* (Shift) F4 */
946 Shift | FctKey | 0xc2, /* (Shift) F5 */
947 Shift | FctKey | 0xc3, /* (Shift) F6 */
948 Shift | FctKey | 0xc4, /* (Shift) F7 */
949 Shift | FctKey | 0xc5, /* (Shift) F8 */
950 Shift | FctKey | 0xc6, /* (Shift) F9 */
951 Shift | FctKey | 0xc7, /* (Shift) F10 */
952 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
953 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
954
955 /* --------------- 60 to 6f --------------- */
956 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
957 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
958 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
959 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
960 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
961 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
962 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
963 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
964 Alt | FctKey | 0xbe, /* (Alt) F1 */
965 Alt | FctKey | 0xbf, /* (Alt) F2 */
966 Alt | FctKey | 0xc0, /* (Alt) F3 */
967 Alt | FctKey | 0xc1, /* (Alt) F4 */
968 Alt | FctKey | 0xc2, /* (Alt) F5 */
969 Alt | FctKey | 0xc3, /* (Alt) F6 */
970 Alt | FctKey | 0xc4, /* (Alt) F7 */
971 Alt | FctKey | 0xc5, /* (Alt) F8 */
972
973 /* --------------- 70 to 7f --------------- */
974 Alt | FctKey | 0xc6, /* (Alt) F9 */
975 Alt | FctKey | 0xc7, /* (Alt) F10 */
976 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
977 Ctrl | KeyPad | 4, /* (Ctrl) Left */
978 Ctrl | KeyPad | 6, /* (Ctrl) Right */
979 Ctrl | KeyPad | 1, /* (Ctrl) End */
980 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
981 Ctrl | KeyPad | 7, /* (Ctrl) Home */
982 Alt | Map | 1, /* '1' */
983 Alt | Map | 2, /* '2' */
984 Alt | Map | 3, /* '3' */
985 Alt | Map | 4, /* '4' */
986 Alt | Map | 5, /* '5' */
987 Alt | Map | 6, /* '6' */
988 Alt | Map | 7, /* '7' */
989 Alt | Map | 8, /* '8' */
990
991 /* --------------- 80 to 8f --------------- */
992 Alt | Map | 9, /* '9' */
993 Alt | Map | 10, /* '0' */
994 Alt | Map | 11, /* '-' */
995 Alt | Map | 12, /* '=' */
996 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
997 FctKey | 0xc8, /* F11 */
998 FctKey | 0xc9, /* F12 */
999 Shift | FctKey | 0xc8, /* (Shift) F11 */
1000 Shift | FctKey | 0xc9, /* (Shift) F12 */
1001 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
1002 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
1003 Alt | FctKey | 0xc8, /* (Alt) F11 */
1004 Alt | FctKey | 0xc9, /* (Alt) F12 */
1005 Ctrl | KeyPad | 8, /* (Ctrl) Up */
1006 Ctrl | Grey | 2, /* (Ctrl) Grey - */
1007 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
1008
1009 /* --------------- 90 to 9f --------------- */
1010 Ctrl | Grey | 3, /* (Ctrl) Grey + */
1011 Ctrl | KeyPad | 2, /* (Ctrl) Down */
1012 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
1013 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
1014 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
1015 Ctrl | Grey | 0, /* (Ctrl) Grey / */
1016 Ctrl | Grey | 1, /* (Ctrl) Grey * */
1017 Alt | FctKey | 0x50, /* (Alt) Home */
1018 Alt | FctKey | 0x52, /* (Alt) Up */
1019 Alt | FctKey | 0x55, /* (Alt) Page Up */
1020 Ignore, /* NO KEY */
1021 Alt | FctKey | 0x51, /* (Alt) Left */
1022 Ignore, /* NO KEY */
1023 Alt | FctKey | 0x53, /* (Alt) Right */
1024 Ignore, /* NO KEY */
1025 Alt | FctKey | 0x57, /* (Alt) End */
1026
1027 /* --------------- a0 to af --------------- */
1028 Alt | KeyPad | 2, /* (Alt) Down */
1029 Alt | KeyPad | 3, /* (Alt) Page Down */
1030 Alt | KeyPad | 0, /* (Alt) Insert */
1031 Alt | KeyPad | 10, /* (Alt) Delete */
1032 Alt | Grey | 0, /* (Alt) Grey / */
1033 Alt | FctKey | 0x09, /* (Alt) Tab */
1034 Alt | Grey | 4 /* (Alt) Keypad Enter */
1035 };
1036
1037 /* These bit-positions corresponds to values returned by BIOS */
1038 #define SHIFT_P 0x0003 /* two bits! */
1039 #define CTRL_P 0x0004
1040 #define ALT_P 0x0008
1041 #define SCRLOCK_P 0x0010
1042 #define NUMLOCK_P 0x0020
1043 #define CAPSLOCK_P 0x0040
1044 #define ALT_GR_P 0x0800
1045 #define SUPER_P 0x4000 /* pseudo */
1046 #define HYPER_P 0x8000 /* pseudo */
1047
1048 static int
1049 dos_get_modifiers (int *keymask)
1050 {
1051 union REGS regs;
1052 int mask;
1053 int modifiers = 0;
1054
1055 /* Calculate modifier bits */
1056 regs.h.ah = extended_kbd ? 0x12 : 0x02;
1057 int86 (0x16, &regs, &regs);
1058
1059 if (!extended_kbd)
1060 {
1061 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
1062 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1063 }
1064 else
1065 {
1066 mask = regs.h.al & (SHIFT_P |
1067 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1068
1069 /* Do not break international keyboard support. */
1070 /* When Keyb.Com is loaded, the right Alt key is */
1071 /* used for accessing characters like { and } */
1072 if (regs.h.ah & 2) /* Left ALT pressed ? */
1073 mask |= ALT_P;
1074
1075 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
1076 {
1077 mask |= ALT_GR_P;
1078 if (dos_hyper_key == 1)
1079 {
1080 mask |= HYPER_P;
1081 modifiers |= hyper_modifier;
1082 }
1083 else if (dos_super_key == 1)
1084 {
1085 mask |= SUPER_P;
1086 modifiers |= super_modifier;
1087 }
1088 }
1089
1090 if (regs.h.ah & 1) /* Left CTRL pressed
1091 mask |= CTRL_P;
1092
1093 if (regs.h.ah & 4) /* Right CTRL pressed ? */
1094 {
1095 if (dos_hyper_key == 2)
1096 {
1097 mask |= HYPER_P;
1098 modifiers |= hyper_modifier;
1099 }
1100 else if (dos_super_key == 2)
1101 {
1102 mask |= SUPER_P;
1103 modifiers |= super_modifier;
1104 }
1105 else
1106 mask |= CTRL_P;
1107 }
1108 }
1109
1110 if (mask & SHIFT_P)
1111 modifiers |= shift_modifier;
1112 if (mask & CTRL_P)
1113 modifiers |= ctrl_modifier;
1114 if (mask & ALT_P)
1115 modifiers |= meta_modifier;
1116
1117 if (keymask)
1118 *keymask = mask;
1119 return modifiers;
1120 }
1121
1122 #define NUM_RECENT_DOSKEYS (100)
1123 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
1124 int total_doskeys; /* Total number of elements stored into recent_doskeys */
1125 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
1126
1127 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
1128 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1129 Each input key receives two values in this vector: first the ASCII code,\n\
1130 and then the scan code.")
1131 ()
1132 {
1133 Lisp_Object *keys = XVECTOR (recent_doskeys)->contents;
1134 Lisp_Object val;
1135
1136 if (total_doskeys < NUM_RECENT_DOSKEYS)
1137 return Fvector (total_doskeys, keys);
1138 else
1139 {
1140 val = Fvector (NUM_RECENT_DOSKEYS, keys);
1141 bcopy (keys + recent_doskeys_index,
1142 XVECTOR (val)->contents,
1143 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
1144 bcopy (keys,
1145 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
1146 recent_doskeys_index * sizeof (Lisp_Object));
1147 return val;
1148 }
1149 }
1150
1151 /* Get a char from keyboard. Function keys are put into the event queue. */
1152 static int
1153 dos_rawgetc (void)
1154 {
1155 struct input_event event;
1156 union REGS regs;
1157
1158 #ifndef HAVE_X_WINDOWS
1159 SCREEN_SET_CURSOR ();
1160 if (!mouse_visible) mouse_on ();
1161 #endif
1162
1163 /* The following condition is equivalent to `kbhit ()', except that
1164 it uses the bios to do its job. This pleases DESQview/X. */
1165 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
1166 int86 (0x16, &regs, &regs),
1167 (regs.x.flags & 0x40) == 0)
1168 {
1169 union REGS regs;
1170 REGISTER unsigned char c;
1171 int sc, code, mask, kp_mode;
1172 int modifiers;
1173
1174 regs.h.ah = extended_kbd ? 0x10 : 0x00;
1175 int86 (0x16, &regs, &regs);
1176 c = regs.h.al;
1177 sc = regs.h.ah;
1178
1179 total_doskeys += 2;
1180 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1181 = make_int (c);
1182 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1183 recent_doskeys_index = 0;
1184 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1185 = make_int (sc);
1186 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1187 recent_doskeys_index = 0;
1188
1189 modifiers = dos_get_modifiers (&mask);
1190
1191 #ifndef HAVE_X_WINDOWS
1192 if (!NILP (Vdos_display_scancodes))
1193 {
1194 char buf[10];
1195 sprintf (buf, "%02x:%02x*%04x",
1196 (unsigned) (sc&0xff), (unsigned) c, mask);
1197 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
1198 }
1199 #endif
1200
1201 if (sc == 0xe0)
1202 {
1203 switch (c)
1204 {
1205 case 10: /* Ctrl Grey Enter */
1206 code = Ctrl | Grey | 4;
1207 break;
1208 case 13: /* Grey Enter */
1209 code = Grey | 4;
1210 break;
1211 case '/': /* Grey / */
1212 code = Grey | 0;
1213 break;
1214 default:
1215 continue;
1216 };
1217 c = 0;
1218 }
1219 else
1220 {
1221 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
1222 continue;
1223 if ((code = ibmpc_translate_map[sc]) == Ignore)
1224 continue;
1225 }
1226
1227 if (c == 0)
1228 {
1229 if (code & Alt)
1230 modifiers |= meta_modifier;
1231 if (code & Ctrl)
1232 modifiers |= ctrl_modifier;
1233 if (code & Shift)
1234 modifiers |= shift_modifier;
1235 }
1236
1237 switch (code & 0xf000)
1238 {
1239 case ModFct:
1240 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
1241 return c;
1242 c = 0; /* Special */
1243
1244 case FctKey:
1245 if (c != 0)
1246 return c;
1247
1248 case Special:
1249 code |= 0xff00;
1250 break;
1251
1252 case Normal:
1253 if (sc == 0)
1254 {
1255 if (c == 0) /* ctrl-break */
1256 continue;
1257 return c; /* ALT-nnn */
1258 }
1259 if (!keyboard_map_all)
1260 {
1261 if (c != ' ')
1262 return c;
1263 code = c;
1264 break;
1265 }
1266
1267 case Map:
1268 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
1269 if (!keyboard_map_all)
1270 return c;
1271
1272 code &= 0xff;
1273 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
1274 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
1275
1276 if (mask & SHIFT_P)
1277 {
1278 code = keyboard->shifted[code];
1279 mask -= SHIFT_P;
1280 modifiers &= ~shift_modifier;
1281 }
1282 else
1283 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
1284 code = keyboard->alt_gr[code];
1285 else
1286 code = keyboard->unshifted[code];
1287 break;
1288
1289 case KeyPad:
1290 code &= 0xff;
1291 if (c == 0xe0) /* edit key */
1292 kp_mode = 3;
1293 else
1294 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
1295 kp_mode = dos_keypad_mode & 0x03;
1296 else
1297 kp_mode = (dos_keypad_mode >> 4) & 0x03;
1298
1299 switch (kp_mode)
1300 {
1301 case 0:
1302 if (code == 10 && dos_decimal_point)
1303 return dos_decimal_point;
1304 return keypad_translate_map[code].char_code;
1305
1306 case 1:
1307 code = 0xff00 | keypad_translate_map[code].keypad_code;
1308 break;
1309
1310 case 2:
1311 code = keypad_translate_map[code].meta_code;
1312 modifiers = meta_modifier;
1313 break;
1314
1315 case 3:
1316 code = 0xff00 | keypad_translate_map[code].editkey_code;
1317 break;
1318 }
1319 break;
1320
1321 case Grey:
1322 code &= 0xff;
1323 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
1324 if (dos_keypad_mode & kp_mode)
1325 code = 0xff00 | grey_key_translate_map[code].keypad_code;
1326 else
1327 code = grey_key_translate_map[code].char_code;
1328 break;
1329 }
1330
1331 make_event:
1332 if (code == 0)
1333 continue;
1334
1335 if (code >= 0x100)
1336 event.kind = non_ascii_keystroke;
1337 else
1338 event.kind = ascii_keystroke;
1339 event.code = code;
1340 event.modifiers = modifiers;
1341 XSETFRAME (event.frame_or_window, selected_frame);
1342 event.timestamp = event_timestamp ();
1343 kbd_buffer_store_event (&event);
1344 }
1345
1346 if (have_mouse > 0)
1347 {
1348 int but, press, x, y, ok;
1349
1350 /* Check for mouse movement *before* buttons. */
1351 mouse_check_moved ();
1352
1353 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
1354 for (press = 0; press < 2; press++)
1355 {
1356 if (press)
1357 ok = mouse_pressed (but, &x, &y);
1358 else
1359 ok = mouse_released (but, &x, &y);
1360 if (ok)
1361 {
1362 event.kind = mouse_click;
1363 event.code = but;
1364 event.modifiers = dos_get_modifiers (0)
1365 | (press ? down_modifier : up_modifier);
1366 event.x = x;
1367 event.y = y;
1368 XSETFRAME (event.frame_or_window, selected_frame);
1369 event.timestamp = event_timestamp ();
1370 kbd_buffer_store_event (&event);
1371 }
1372 }
1373 }
1374
1375 return -1;
1376 }
1377
1378 static int prev_get_char = -1;
1379
1380 /* Return 1 if a key is ready to be read without suspending execution. */
1381 dos_keysns (void)
1382 {
1383 if (prev_get_char != -1)
1384 return 1;
1385 else
1386 return ((prev_get_char = dos_rawgetc ()) != -1);
1387 }
1388
1389 /* Read a key. Return -1 if no key is ready. */
1390 dos_keyread (void)
1391 {
1392 if (prev_get_char != -1)
1393 {
1394 int c = prev_get_char;
1395 prev_get_char = -1;
1396 return c;
1397 }
1398 else
1399 return dos_rawgetc ();
1400 }
1401
1402 #ifndef HAVE_X_WINDOWS
1403 /* See xterm.c for more info. */
1404 void
1405 pixel_to_glyph_coords (FRAME_PTR f, REGISTER int pix_x, REGISTER int pix_y,
1406 REGISTER int *x, REGISTER int *y,
1407 void /* XRectangle */ *bounds,
1408 int noclip)
1409 {
1410 if (bounds) abort ();
1411
1412 /* Ignore clipping. */
1413
1414 *x = pix_x;
1415 *y = pix_y;
1416 }
1417
1418 void
1419 glyph_to_pixel_coords (FRAME_PTR f, REGISTER int x, REGISTER int y,
1420 REGISTER int *pix_x, REGISTER int *pix_y)
1421 {
1422 *pix_x = x;
1423 *pix_y = y;
1424 }
1425
1426 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1427 for now.
1428
1429 Actually, I don't know the meaning of all the parameters of the functions
1430 here -- I only know how they are called by xmenu.c. I could of course
1431 grab the nearest Xlib manual (down the hall, second-to-last door on the
1432 left), but I don't think it's worth the effort. */
1433
1434 static XMenu *
1435 IT_menu_create (void)
1436 {
1437 XMenu *menu;
1438
1439 menu = (XMenu *) xmalloc (sizeof (XMenu));
1440 menu->allocated = menu->count = menu->panecount = menu->width = 0;
1441 return menu;
1442 }
1443
1444 /* Allocate some (more) memory for MENU ensuring that there is room for one
1445 for item. */
1446
1447 static void
1448 IT_menu_make_room (XMenu *menu)
1449 {
1450 if (menu->allocated == 0)
1451 {
1452 int count = menu->allocated = 10;
1453 menu->text = (char **) xmalloc (count * sizeof (char *));
1454 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
1455 menu->panenumber = (int *) xmalloc (count * sizeof (int));
1456 }
1457 else if (menu->allocated == menu->count)
1458 {
1459 int count = menu->allocated = menu->allocated + 10;
1460 menu->text
1461 = (char **) xrealloc (menu->text, count * sizeof (char *));
1462 menu->submenu
1463 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
1464 menu->panenumber
1465 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
1466 }
1467 }
1468
1469 /* Search the given menu structure for a given pane number. */
1470
1471 static XMenu *
1472 IT_menu_search_pane (XMenu *menu, int pane)
1473 {
1474 int i;
1475 XMenu *try;
1476
1477 for (i = 0; i < menu->count; i++)
1478 if (menu->submenu[i])
1479 {
1480 if (pane == menu->panenumber[i])
1481 return menu->submenu[i];
1482 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
1483 return try;
1484 }
1485 return (XMenu *) 0;
1486 }
1487
1488 /* Determine how much screen space a given menu needs. */
1489
1490 static void
1491 IT_menu_calc_size (XMenu *menu, int *width, int *height)
1492 {
1493 int i, h2, w2, maxsubwidth, maxheight;
1494
1495 maxsubwidth = 0;
1496 maxheight = menu->count;
1497 for (i = 0; i < menu->count; i++)
1498 {
1499 if (menu->submenu[i])
1500 {
1501 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
1502 if (w2 > maxsubwidth) maxsubwidth = w2;
1503 if (i + h2 > maxheight) maxheight = i + h2;
1504 }
1505 }
1506 *width = menu->width + maxsubwidth;
1507 *height = maxheight;
1508 }
1509
1510 /* Display MENU at (X,Y) using FACES. */
1511
1512 static void
1513 IT_menu_display (XMenu *menu, int y, int x, int *faces)
1514 {
1515 int i, j, face, width;
1516 GLYPH *text, *p;
1517 char *q;
1518 int mx, my;
1519 int enabled, mousehere;
1520 int row, col;
1521
1522 width = menu->width;
1523 text = (GLYPH *) xmalloc ((width + 2) * sizeof (GLYPH));
1524 ScreenGetCursor (&row, &col);
1525 mouse_get_xy (&mx, &my);
1526 IT_update_begin ();
1527 for (i = 0; i < menu->count; i++)
1528 {
1529 IT_cursor_to (y + i, x);
1530 enabled
1531 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
1532 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
1533 face = faces[enabled + mousehere * 2];
1534 p = text;
1535 *p++ = FAST_MAKE_GLYPH (' ', face);
1536 for (j = 0, q = menu->text[i]; *q; j++)
1537 *p++ = FAST_MAKE_GLYPH (*q++, face);
1538 for (; j < width; j++)
1539 *p++ = FAST_MAKE_GLYPH (' ', face);
1540 *p++ = FAST_MAKE_GLYPH (menu->submenu[i] ? 16 : ' ', face);
1541 IT_write_glyphs (text, width + 2);
1542 }
1543 IT_update_end ();
1544 IT_cursor_to (row, col);
1545 xfree (text);
1546 }
1547
1548 /* --------------------------- X Menu emulation ---------------------- */
1549
1550 /* Create a brand new menu structure. */
1551
1552 XMenu *
1553 XMenuCreate (Display *foo1, Window foo2, char *foo3)
1554 {
1555 return IT_menu_create ();
1556 }
1557
1558 /* Create a new pane and place it on the outer-most level. It is not
1559 clear that it should be placed out there, but I don't know what else
1560 to do. */
1561
1562 int
1563 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
1564 {
1565 int len;
1566
1567 if (!enable)
1568 abort ();
1569
1570 IT_menu_make_room (menu);
1571 menu->submenu[menu->count] = IT_menu_create ();
1572 menu->text[menu->count] = txt;
1573 menu->panenumber[menu->count] = ++menu->panecount;
1574 menu->count++;
1575 if ((len = strlen (txt)) > menu->width)
1576 menu->width = len;
1577 return menu->panecount;
1578 }
1579
1580 /* Create a new item in a menu pane. */
1581
1582 int
1583 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
1584 int foo, char *txt, int enable)
1585 {
1586 int len;
1587
1588 if (pane)
1589 if (!(menu = IT_menu_search_pane (menu, pane)))
1590 return XM_FAILURE;
1591 IT_menu_make_room (menu);
1592 menu->submenu[menu->count] = (XMenu *) 0;
1593 menu->text[menu->count] = txt;
1594 menu->panenumber[menu->count] = enable;
1595 menu->count++;
1596 if ((len = strlen (txt)) > menu->width)
1597 menu->width = len;
1598 return XM_SUCCESS;
1599 }
1600
1601 /* Decide where the menu would be placed if requested at (X,Y). */
1602
1603 void
1604 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
1605 int *ulx, int *uly, int *width, int *height)
1606 {
1607 if (menu->count == 1 && menu->submenu[0])
1608 /* Special case: the menu consists of only one pane. */
1609 IT_menu_calc_size (menu->submenu[0], width, height);
1610 else
1611 IT_menu_calc_size (menu, width, height);
1612 *ulx = x + 1;
1613 *uly = y;
1614 *width += 2;
1615 }
1616
1617 struct IT_menu_state
1618 {
1619 void *screen_behind;
1620 XMenu *menu;
1621 int pane;
1622 int x, y;
1623 };
1624
1625
1626 /* Display menu, wait for user's response, and return that response. */
1627
1628 int
1629 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
1630 int x0, int y0, unsigned ButtonMask, char **txt)
1631 {
1632 struct IT_menu_state *state;
1633 int statecount;
1634 int x, y, i, b;
1635 int screensize;
1636 int faces[4], selectface;
1637 int leave, result, onepane;
1638
1639 /* Just in case we got here without a mouse present... */
1640 if (have_mouse <= 0)
1641 return XM_IA_SELECT;
1642
1643 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
1644 screensize = screen_size * 2;
1645 faces[0]
1646 = compute_glyph_face (&the_only_frame,
1647 face_name_id_number
1648 (&the_only_frame,
1649 intern ("msdos-menu-passive-face")),
1650 0);
1651 faces[1]
1652 = compute_glyph_face (&the_only_frame,
1653 face_name_id_number
1654 (&the_only_frame,
1655 intern ("msdos-menu-active-face")),
1656 0);
1657 selectface
1658 = face_name_id_number (&the_only_frame, intern ("msdos-menu-select-face"));
1659 faces[2] = compute_glyph_face (&the_only_frame, selectface, faces[0]);
1660 faces[3] = compute_glyph_face (&the_only_frame, selectface, faces[1]);
1661
1662 statecount = 1;
1663 state[0].menu = menu;
1664 mouse_off ();
1665 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
1666 if ((onepane = menu->count == 1 && menu->submenu[0]))
1667 {
1668 menu->width = menu->submenu[0]->width;
1669 state[0].menu = menu->submenu[0];
1670 }
1671 else
1672 {
1673 state[0].menu = menu;
1674 }
1675 state[0].x = x0 - 1;
1676 state[0].y = y0;
1677 state[0].pane = onepane;
1678
1679 mouse_last_x = -1; /* A hack that forces display. */
1680 leave = 0;
1681 while (!leave)
1682 {
1683 if (!mouse_visible) mouse_on ();
1684 mouse_check_moved ();
1685 if (selected_frame->mouse_moved)
1686 {
1687 selected_frame->mouse_moved = 0;
1688 result = XM_IA_SELECT;
1689 mouse_get_xy (&x, &y);
1690 for (i = 0; i < statecount; i++)
1691 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
1692 {
1693 int dy = y - state[i].y;
1694 if (0 <= dy && dy < state[i].menu->count)
1695 {
1696 if (!state[i].menu->submenu[dy])
1697 if (state[i].menu->panenumber[dy])
1698 result = XM_SUCCESS;
1699 else
1700 result = XM_IA_SELECT;
1701 *pane = state[i].pane - 1;
1702 *selidx = dy;
1703 /* We hit some part of a menu, so drop extra menues that
1704 have been opened. That does not include an open and
1705 active submenu. */
1706 if (i != statecount - 2
1707 || state[i].menu->submenu[dy] != state[i+1].menu)
1708 while (i != statecount - 1)
1709 {
1710 statecount--;
1711 mouse_off ();
1712 ScreenUpdate (state[statecount].screen_behind);
1713 xfree (state[statecount].screen_behind);
1714 }
1715 if (i == statecount - 1 && state[i].menu->submenu[dy])
1716 {
1717 IT_menu_display (state[i].menu,
1718 state[i].y,
1719 state[i].x,
1720 faces);
1721 state[statecount].menu = state[i].menu->submenu[dy];
1722 state[statecount].pane = state[i].menu->panenumber[dy];
1723 mouse_off ();
1724 ScreenRetrieve (state[statecount].screen_behind
1725 = xmalloc (screensize));
1726 state[statecount].x
1727 = state[i].x + state[i].menu->width + 2;
1728 state[statecount].y = y;
1729 statecount++;
1730 }
1731 }
1732 }
1733 IT_menu_display (state[statecount - 1].menu,
1734 state[statecount - 1].y,
1735 state[statecount - 1].x,
1736 faces);
1737 }
1738 for (b = 0; b < mouse_button_count; b++)
1739 {
1740 (void) mouse_pressed (b, &x, &y);
1741 if (mouse_released (b, &x, &y))
1742 leave = 1;
1743 }
1744 }
1745
1746 mouse_off ();
1747 ScreenUpdate (state[0].screen_behind);
1748 while (statecount--)
1749 xfree (state[statecount].screen_behind);
1750 return result;
1751 }
1752
1753 /* Dispose of a menu. */
1754
1755 void
1756 XMenuDestroy (Display *foo, XMenu *menu)
1757 {
1758 int i;
1759 if (menu->allocated)
1760 {
1761 for (i = 0; i < menu->count; i++)
1762 if (menu->submenu[i])
1763 XMenuDestroy (foo, menu->submenu[i]);
1764 xfree (menu->text);
1765 xfree (menu->submenu);
1766 xfree (menu->panenumber);
1767 }
1768 xfree (menu);
1769 }
1770
1771 int
1772 x_pixel_width (struct frame *f)
1773 {
1774 return FRAME_WIDTH (f);
1775 }
1776
1777 int
1778 x_pixel_height (struct frame *f)
1779 {
1780 return FRAME_HEIGHT (f);
1781 }
1782 #endif /* !HAVE_X_WINDOWS */
1783
1784
1785 /* ----------------------- DOS / UNIX conversion --------------------- */
1786
1787 /* Destructively turn backslashes into slashes. */
1788
1789 void
1790 dostounix_filename (REGISTER char *p)
1791 {
1792 while (*p)
1793 {
1794 if (*p == '\\')
1795 *p = '/';
1796 p++;
1797 }
1798 }
1799
1800 /* Destructively turn slashes into backslashes. */
1801
1802 void
1803 unixtodos_filename (REGISTER char *p)
1804 {
1805 while (*p)
1806 {
1807 if (*p == '/')
1808 *p = '\\';
1809 p++;
1810 }
1811 }
1812
1813 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
1814
1815 int
1816 getdefdir (int drive, char *dst)
1817 {
1818 union REGS regs;
1819
1820 *dst++ = '/';
1821 regs.h.dl = drive;
1822 regs.x.si = (int) dst;
1823 regs.h.ah = 0x47;
1824 intdos (&regs, &regs);
1825 return !regs.x.cflag;
1826 }
1827
1828 /* Remove all CR's that are followed by a LF. */
1829
1830 int
1831 crlf_to_lf (REGISTER int n, REGISTER unsigned char *buf)
1832 {
1833 unsigned char *np = buf;
1834 unsigned char *startp = buf;
1835 unsigned char *endp = buf + n;
1836 unsigned char c;
1837
1838 if (n == 0)
1839 return n;
1840 while (buf < endp - 1)
1841 {
1842 if (*buf == 0x0d)
1843 {
1844 if (*(++buf) != 0x0a)
1845 *np++ = 0x0d;
1846 }
1847 else
1848 *np++ = *buf++;
1849 }
1850 if (buf < endp)
1851 *np++ = *buf++;
1852 return np - startp;
1853 }
1854
1855 /* The Emacs root directory as determined by init_environment. */
1856
1857 static char emacsroot[MAXPATHLEN];
1858
1859 char *
1860 rootrelativepath (char *rel)
1861 {
1862 static char result[MAXPATHLEN + 10];
1863
1864 strcpy (result, emacsroot);
1865 strcat (result, "/");
1866 strcat (result, rel);
1867 return result;
1868 }
1869
1870 /* Define a lot of environment variables if not already defined. Don't
1871 remove anything unless you know what you're doing -- lots of code will
1872 break if one or more of these are missing. */
1873
1874 void
1875 init_environment (int argc, char **argv, int skip_args)
1876 {
1877 char *s, *t, *root;
1878 int len;
1879
1880 if (!initialized)
1881 return;
1882
1883 /* Find our root from argv[0]. Assuming argv[0] is, say,
1884 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
1885 root = alloca (MAXPATHLEN + 20);
1886 _fixpath (argv[0], root);
1887 strlwr (root);
1888 len = strlen (root);
1889 while (len > 0 && root[len] != '/' && root[len] != ':')
1890 len--;
1891 root[len] = '\0';
1892 if (len > 4 && strcmp (root + len - 4, "/bin") == 0)
1893 root[len - 4] = '\0';
1894 else
1895 strcpy (root, "c:/emacs"); /* Only under debuggers, I think. */
1896 len = strlen (root);
1897 strcpy (emacsroot, root);
1898
1899 /* We default HOME to our root. */
1900 setenv ("HOME", root, 0);
1901
1902 /* We default EMACSPATH to root + "/bin". */
1903 strcpy (root + len, "/bin");
1904 setenv ("EMACSPATH", root, 0);
1905
1906 /* I don't expect anybody to ever use other terminals so the internal
1907 terminal is the default. */
1908 setenv ("TERM", "internal", 0);
1909
1910 #ifdef HAVE_X_WINDOWS
1911 /* Emacs expects DISPLAY to be set. */
1912 setenv ("DISPLAY", "unix:0.0", 0);
1913 #endif
1914
1915 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
1916 downcase it and mirror the backslashes. */
1917 s = getenv ("COMSPEC");
1918 if (!s) s = "c:/command.com";
1919 t = alloca (strlen (s) + 1);
1920 strcpy (t, s);
1921 strlwr (t);
1922 dostounix_filename (t);
1923 setenv ("SHELL", t, 0);
1924
1925 /* PATH is also downcased and backslashes mirrored. */
1926 s = getenv ("PATH");
1927 if (!s) s = "";
1928 t = alloca (strlen (s) + 3);
1929 /* Current directory is always considered part of MsDos's path but it is
1930 not normally mentioned. Now it is. */
1931 strcat (strcpy (t, ".;"), s);
1932 strlwr (t);
1933 dostounix_filename (t); /* Not a single file name, but this should work. */
1934 setenv ("PATH", t, 1);
1935
1936 /* In some sense all dos users have root privileges, so... */
1937 setenv ("USER", "root", 0);
1938 setenv ("NAME", getenv ("USER"), 0);
1939
1940 /* Time zone determined from country code. To make this possible, the
1941 country code may not span more than one time zone. In other words,
1942 in the USA, you lose. */
1943 if (!getenv ("TZ"))
1944 switch (dos_country_code)
1945 {
1946 case 31: /* Belgium */
1947 case 32: /* The Netherlands */
1948 case 33: /* France */
1949 case 34: /* Spain */
1950 case 36: /* Hungary */
1951 case 38: /* Yugoslavia (or what's left of it?) */
1952 case 39: /* Italy */
1953 case 41: /* Switzerland */
1954 case 42: /* Tjekia */
1955 case 45: /* Denmark */
1956 case 46: /* Sweden */
1957 case 47: /* Norway */
1958 case 48: /* Poland */
1959 case 49: /* Germany */
1960 /* Daylight saving from last Sunday in March to last Sunday in
1961 September, both at 2AM. */
1962 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
1963 break;
1964 case 44: /* United Kingdom */
1965 case 351: /* Portugal */
1966 case 354: /* Iceland */
1967 setenv ("TZ", "GMT+00", 0);
1968 break;
1969 case 81: /* Japan */
1970 case 82: /* Korea */
1971 setenv ("TZ", "JST-09", 0);
1972 break;
1973 case 90: /* Turkey */
1974 case 358: /* Finland */
1975 setenv ("TZ", "EET-02", 0);
1976 break;
1977 case 972: /* Israel */
1978 /* This is an approximation. (For exact rules, use the
1979 `zoneinfo/israel' file which comes with DJGPP, but you need
1980 to install it in `/usr/share/zoneinfo/' directory first.) */
1981 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
1982 break;
1983 }
1984 init_gettimeofday ();
1985 }
1986
1987
1988
1989 static int break_stat; /* BREAK check mode status. */
1990 static int stdin_stat; /* stdin IOCTL status. */
1991
1992 /* These must be global. */
1993 static _go32_dpmi_seginfo ctrl_break_vector;
1994 static _go32_dpmi_registers ctrl_break_regs;
1995 static int ctrlbreakinstalled = 0;
1996
1997 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
1998
1999 void
2000 ctrl_break_func (_go32_dpmi_registers *regs)
2001 {
2002 Vquit_flag = Qt;
2003 }
2004
2005 void
2006 install_ctrl_break_check (void)
2007 {
2008 if (!ctrlbreakinstalled)
2009 {
2010 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2011 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2012 ctrlbreakinstalled = 1;
2013 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
2014 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
2015 &ctrl_break_regs);
2016 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
2017 }
2018 }
2019
2020 /*
2021 * Turn off Dos' Ctrl-C checking and inhibit interpretation of
2022 * control chars by Dos.
2023 * Determine the keyboard type.
2024 */
2025
2026 int
2027 dos_ttraw (void)
2028 {
2029 union REGS inregs, outregs;
2030 static int first_time = 1;
2031
2032 break_stat = getcbrk ();
2033 setcbrk (0);
2034 install_ctrl_break_check ();
2035
2036 if (first_time)
2037 {
2038 inregs.h.ah = 0xc0;
2039 int86 (0x15, &inregs, &outregs);
2040 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
2041
2042 have_mouse = 0;
2043
2044 if (internal_terminal
2045 #ifdef HAVE_X_WINDOWS
2046 && inhibit_window_system
2047 #endif
2048 )
2049 {
2050 inregs.x.ax = 0x0021;
2051 int86 (0x33, &inregs, &outregs);
2052 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2053 if (!have_mouse)
2054 {
2055 /* Reportedly, the above doesn't work for some mouse drivers. There
2056 is an additional detection method that should work, but might be
2057 a little slower. Use that as an alternative. */
2058 inregs.x.ax = 0x0000;
2059 int86 (0x33, &inregs, &outregs);
2060 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2061 }
2062
2063 if (have_mouse)
2064 {
2065 have_mouse = 1; /* enable mouse */
2066 mouse_visible = 0;
2067
2068 if (outregs.x.bx == 3)
2069 {
2070 mouse_button_count = 3;
2071 mouse_button_translate[0] = 0; /* Left */
2072 mouse_button_translate[1] = 2; /* Middle */
2073 mouse_button_translate[2] = 1; /* Right */
2074 }
2075 else
2076 {
2077 mouse_button_count = 2;
2078 mouse_button_translate[0] = 0;
2079 mouse_button_translate[1] = 1;
2080 }
2081 mouse_position_hook = &mouse_get_pos;
2082 mouse_init ();
2083 }
2084 }
2085
2086 first_time = 0;
2087 }
2088
2089 inregs.x.ax = 0x4400; /* Get IOCTL status. */
2090 inregs.x.bx = 0x00; /* 0 = stdin. */
2091 intdos (&inregs, &outregs);
2092 stdin_stat = outregs.h.dl;
2093
2094 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
2095 inregs.x.ax = 0x4401; /* Set IOCTL status */
2096 intdos (&inregs, &outregs);
2097 return !outregs.x.cflag;
2098 }
2099
2100 /* Restore status of standard input and Ctrl-C checking. */
2101 int
2102 dos_ttcooked (void)
2103 {
2104 union REGS inregs, outregs;
2105
2106 setcbrk (break_stat);
2107 mouse_off ();
2108
2109 inregs.x.ax = 0x4401; /* Set IOCTL status. */
2110 inregs.x.bx = 0x00; /* 0 = stdin. */
2111 inregs.x.dx = stdin_stat;
2112 intdos (&inregs, &outregs);
2113 return !outregs.x.cflag;
2114 }
2115
2116
2117 /* Run command as specified by ARGV in directory DIR.
2118 The command is run with input from TEMPIN and output to file TEMPOUT. */
2119 int
2120 run_msdos_command (unsigned char **argv, Lisp_Object dir,
2121 int tempin, int tempout)
2122 {
2123 char *saveargv1, *saveargv2, **envv;
2124 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
2125 int msshell, result = -1;
2126 int in, out, inbak, outbak, errbak;
2127 int x, y;
2128 Lisp_Object cmd;
2129
2130 /* Get current directory as MSDOS cwd is not per-process. */
2131 getwd (oldwd);
2132
2133 cmd = Ffile_name_nondirectory (build_string (argv[0]));
2134 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
2135 && !strcmp ("-c", argv[1]);
2136 if (msshell)
2137 {
2138 saveargv1 = argv[1];
2139 saveargv2 = argv[2];
2140 argv[1] = "/c";
2141 if (argv[2])
2142 {
2143 char *p = alloca (strlen (argv[2]) + 1);
2144
2145 strcpy (argv[2] = p, saveargv2);
2146 while (*p && isspace ((unsigned char) *p))
2147 p++;
2148 while (*p && !isspace ((unsigned char) *p))
2149 if (*p == '/')
2150 *p++ = '\\';
2151 else
2152 p++;
2153 }
2154 }
2155
2156 /* Build the environment array. */
2157 {
2158 extern Lisp_Object Vprocess_environment;
2159 Lisp_Object tmp, lst;
2160 int i, len;
2161
2162 lst = Vprocess_environment;
2163 len = XINT (Flength (lst));
2164
2165 envv = alloca ((len + 1) * sizeof (char *));
2166 for (i = 0; i < len; i++)
2167 {
2168 tmp = Fcar (lst);
2169 lst = Fcdr (lst);
2170 CHECK_STRING (tmp);
2171 envv[i] = alloca (string_length (XSTRING (tmp)) + 1);
2172 strcpy (envv[i], string_data (XSTRING (tmp)));
2173 }
2174 envv[len] = (char *) 0;
2175 }
2176
2177 if (STRINGP (dir))
2178 chdir (string_data (XSTRING (dir)));
2179 inbak = dup (0);
2180 outbak = dup (1);
2181 errbak = dup (2);
2182 if (inbak < 0 || outbak < 0 || errbak < 0)
2183 goto done; /* Allocation might fail due to lack of descriptors. */
2184
2185 if (have_mouse > 0)
2186 mouse_get_xy (&x, &y);
2187
2188 dos_ttcooked (); /* do it here while 0 = stdin */
2189
2190 dup2 (tempin, 0);
2191 dup2 (tempout, 1);
2192 dup2 (tempout, 2);
2193
2194 result = spawnve (P_WAIT, argv[0], argv, envv);
2195
2196 dup2 (inbak, 0);
2197 dup2 (outbak, 1);
2198 dup2 (errbak, 2);
2199 close (inbak);
2200 close (outbak);
2201 close (errbak);
2202
2203 dos_ttraw ();
2204 if (have_mouse > 0)
2205 {
2206 mouse_init ();
2207 mouse_moveto (x, y);
2208 }
2209
2210 done:
2211 chdir (oldwd);
2212 if (msshell)
2213 {
2214 argv[1] = saveargv1;
2215 argv[2] = saveargv2;
2216 }
2217 return result;
2218 }
2219
2220 croak (char *badfunc)
2221 {
2222 stderr_out ("%s not yet implemented\r\n", badfunc);
2223 reset_sys_modes ();
2224 exit (1);
2225 }
2226
2227
2228 /* ------------------------- Compatibility functions -------------------
2229 * gethostname
2230 * gettimeofday
2231 */
2232
2233 /*
2234 * Hostnames for a pc are not really funny,
2235 * but they are used in change log so we emulate the best we can.
2236 */
2237
2238 gethostname (char *p, int size)
2239 {
2240 char *q = egetenv ("HOSTNAME");
2241
2242 if (!q) q = "pc";
2243 strcpy (p, q);
2244 return 0;
2245 }
2246
2247 /* When time zones are set from Ms-Dos too many C-libraries are playing
2248 tricks with time values. We solve this by defining our own version
2249 of `gettimeofday' bypassing GO32. Our version needs to be initialized
2250 once and after each call to `tzset' with TZ changed. That is
2251 accomplished by aliasing tzset to init_gettimeofday. */
2252
2253 static struct tm time_rec;
2254
2255 int
2256 gettimeofday (struct timeval *tp, struct timezone *tzp)
2257 {
2258 if (tp)
2259 {
2260 struct time t;
2261 struct tm tm;
2262
2263 gettime (&t);
2264 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
2265 {
2266 struct date d;
2267 getdate (&d);
2268 time_rec.tm_year = d.da_year - 1900;
2269 time_rec.tm_mon = d.da_mon - 1;
2270 time_rec.tm_mday = d.da_day;
2271 }
2272
2273 time_rec.tm_hour = t.ti_hour;
2274 time_rec.tm_min = t.ti_min;
2275 time_rec.tm_sec = t.ti_sec;
2276
2277 tm = time_rec;
2278 tm.tm_gmtoff = dos_timezone_offset;
2279
2280 tp->tv_sec = mktime (&tm); /* may modify tm */
2281 tp->tv_usec = t.ti_hund * (1000000 / 100);
2282 }
2283 /* Ignore tzp; it's obsolescent. */
2284 return 0;
2285 }
2286
2287
2288 /*
2289 * A list of unimplemented functions that we silently ignore.
2290 */
2291
2292 unsigned alarm (unsigned int s) {}
2293 fork (void) { return 0; }
2294 int kill (int x, int y) { return -1; }
2295 nice (int p) {}
2296 void volatile pause (void) {}
2297 request_sigio (void) {}
2298 setpgrp (void) {return 0; }
2299 setpriority (int x, int y, int z) { return 0; }
2300 sigsetmask (int x) { return 0; }
2301 unrequest_sigio (void) {}
2302
2303 int run_dos_timer_hooks = 0;
2304
2305 #ifndef HAVE_SELECT
2306 #include "sysselect.h"
2307
2308 static int last_ti_sec = -1;
2309 static int dos_menubar_clock_displayed = 0;
2310
2311 static void
2312 check_timer (struct time *t)
2313 {
2314 gettime (t);
2315
2316 if (t->ti_sec == last_ti_sec)
2317 return;
2318 last_ti_sec = t->ti_sec;
2319
2320 if (!NILP (Vdos_menubar_clock))
2321 {
2322 char clock_str[16];
2323 int len;
2324 int min = t->ti_min;
2325 int hour = t->ti_hour;
2326
2327 if (dos_timezone_offset)
2328 {
2329 int tz = dos_timezone_offset;
2330 min -= tz % 60;
2331 if (min < 0)
2332 min += 60, hour--;
2333 else
2334 if (min >= 60)
2335 min -= 60, hour++;
2336
2337 if ((hour -= (tz / 60)) < 0)
2338 hour += 24;
2339 else
2340 hour %= 24;
2341 }
2342
2343 if ((dos_country_info[0x11] & 0x01) == 0) /* 12 hour clock */
2344 {
2345 hour %= 12;
2346 if (hour == 0) hour = 12;
2347 }
2348
2349 len = sprintf (clock_str, "%2d.%02d.%02d", hour, min, t->ti_sec);
2350 dos_direct_output (0, screen_size_X - len - 1, clock_str, len);
2351 dos_menubar_clock_displayed = 1;
2352 }
2353 else if (dos_menubar_clock_displayed)
2354 {
2355 /* Erase last displayed time. */
2356 dos_direct_output (0, screen_size_X - 9, " ", 8);
2357 dos_menubar_clock_displayed = 0;
2358 }
2359
2360 if (!NILP (Vdos_timer_hooks))
2361 run_dos_timer_hooks++;
2362 }
2363
2364 /* Only event queue is checked. */
2365 int
2366 sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds,
2367 EMACS_TIME *timeout)
2368 {
2369 int check_input;
2370 long timeoutval, clnow, cllast;
2371 struct time t;
2372
2373 check_input = 0;
2374 if (rfds)
2375 {
2376 check_input = FD_ISSET (0, rfds);
2377 FD_ZERO (rfds);
2378 }
2379 if (wfds)
2380 FD_ZERO (wfds);
2381 if (efds)
2382 FD_ZERO (efds);
2383
2384 if (nfds != 1)
2385 abort ();
2386
2387 /* If we are looking only for the terminal, with no timeout,
2388 just read it and wait -- that's more efficient. */
2389 if (!timeout)
2390 {
2391 while (! detect_input_pending ())
2392 check_timer (&t);
2393 }
2394 else
2395 {
2396 timeoutval = EMACS_SECS (*timeout) * 100 + EMACS_USECS (*timeout) / 10000;
2397 check_timer (&t);
2398 cllast = t.ti_sec * 100 + t.ti_hund;
2399
2400 while (!check_input || !detect_input_pending ())
2401 {
2402 check_timer (&t);
2403 clnow = t.ti_sec * 100 + t.ti_hund;
2404 if (clnow < cllast) /* time wrap */
2405 timeoutval -= clnow + 6000 - cllast;
2406 else
2407 timeoutval -= clnow - cllast;
2408 if (timeoutval <= 0) /* Stop on timer being cleared */
2409 return 0;
2410 cllast = clnow;
2411 }
2412 }
2413
2414 FD_SET (0, rfds);
2415 return 1;
2416 }
2417 #endif
2418
2419 /*
2420 * Define overlayed functions:
2421 *
2422 * chdir -> sys_chdir
2423 * tzset -> init_gettimeofday
2424 * abort -> dos_abort
2425 */
2426
2427 #ifdef chdir
2428 #undef chdir
2429 extern int chdir (CONST char *);
2430
2431 int
2432 sys_chdir (CONST char* path)
2433 {
2434 int len = strlen (path);
2435 char *tmp = (char *)path;
2436
2437 if (*tmp && tmp[1] == ':')
2438 {
2439 if (getdisk () != tolower (tmp[0]) - 'a')
2440 setdisk (tolower (tmp[0]) - 'a');
2441 tmp += 2; /* strip drive: KFS 1995-07-06 */
2442 len -= 2;
2443 }
2444
2445 if (len > 1 && (tmp[len - 1] == '/'))
2446 {
2447 char *tmp1 = (char *) alloca (len + 1);
2448 strcpy (tmp1, tmp);
2449 tmp1[len - 1] = 0;
2450 tmp = tmp1;
2451 }
2452 return chdir (tmp);
2453 }
2454 #endif
2455
2456 #ifdef tzset
2457 #undef tzset
2458 extern void tzset (void);
2459
2460 void
2461 init_gettimeofday (void)
2462 {
2463 time_t ltm, gtm;
2464 struct tm *lstm;
2465
2466 tzset ();
2467 ltm = gtm = time (NULL);
2468 ltm = mktime (lstm = localtime (&ltm));
2469 gtm = mktime (gmtime (&gtm));
2470 time_rec.tm_hour = 99; /* force gettimeofday to get date */
2471 time_rec.tm_isdst = lstm->tm_isdst;
2472 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
2473 }
2474 #endif
2475
2476 #ifdef abort
2477 #undef abort
2478 void
2479 dos_abort (char *file, int line)
2480 {
2481 char buffer1[200], buffer2[400];
2482 int i, j;
2483
2484 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
2485 for (i = j = 0; buffer1[i]; i++) {
2486 buffer2[j++] = buffer1[i];
2487 buffer2[j++] = 0x70;
2488 }
2489 dosmemput (buffer2, j, (int)ScreenPrimary);
2490 ScreenSetCursor (2, 0);
2491 abort ();
2492 }
2493 #endif
2494
2495 void
2496 syms_of_msdos (void)
2497 {
2498 defsubr (&Srecent_doskeys);
2499 }
2500
2501 void
2502 vars_of_msdos (void)
2503 {
2504 recent_doskeys = Fmake_vector (make_int (NUM_RECENT_DOSKEYS), Qnil);
2505 staticpro (&recent_doskeys);
2506
2507 }
2508
2509 #endif /* MSDOS */