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