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