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