(Fselect_window): Fix bug checking new_point is in range.
[bpt/emacs.git] / src / msdos.c
CommitLineData
9da6e765
RS
1/* MS-DOS specific C utilities.
2 Copyright (C) 1993, 1994 Free Software Foundation, Inc.
1b94449f
RS
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
9da6e765
RS
20/* Contributed by Morten Welinder */
21
1b94449f
RS
22/* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
23
48984716 24#include <config.h>
1b94449f
RS
25
26#ifdef MSDOS
27#include "lisp.h"
28#include <stdio.h>
29#include <stdlib.h>
30#include <sys/param.h>
31#include <sys/time.h>
32#include <dos.h>
33#include "dosfns.h"
34#include "msdos.h"
35#include "systime.h"
36#include "termhooks.h"
37#include "frame.h"
38#include <go32.h>
39#include <pc.h>
40#include <ctype.h>
41/* #include <process.h> */
42/* Damn that local process.h! Instead we can define P_WAIT ourselves. */
43#define P_WAIT 1
44
45static int break_stat; /* BREAK check mode status. */
46static int stdin_stat; /* stdin IOCTL status. */
47static int extended_kbd; /* 101 (102) keyboard present. */
48
49int have_mouse; /* Mouse present? */
50static int mouse_last_x;
51static int mouse_last_y;
52
53/* Turn off Dos' Ctrl-C checking and inhibit interpretation of control chars
54 by Dos. Determine the keyboard type. */
55int
56dos_ttraw ()
57{
58 union REGS inregs, outregs;
59
60 inregs.h.ah = 0xc0;
61 int86 (0x15, &inregs, &outregs);
62 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
63
64 break_stat = getcbrk ();
65 setcbrk (0);
66 install_ctrl_break_check ();
49a09c76 67 have_mouse = mouse_init1 ();
1b94449f
RS
68
69 inregs.x.ax = 0x4400; /* Get IOCTL status. */
70 inregs.x.bx = 0x00; /* 0 = stdin. */
71 intdos (&inregs, &outregs);
72 stdin_stat = outregs.h.dl;
73
74 inregs.x.dx = (outregs.x.dx | 0x0020) & 0x0027; /* raw mode */
75 inregs.h.al = 0x01;
76 intdos (&inregs, &outregs);
77 return !outregs.x.cflag;
78}
79
80/* Restore status of standard input and Ctrl-C checking. */
81int
82dos_ttcooked ()
83{
84 union REGS inregs, outregs;
85
86 setcbrk (break_stat);
49a09c76 87 if (have_mouse) mouse_off ();
1b94449f
RS
88
89 inregs.x.ax = 0x4401; /* Set IOCTL status. */
90 inregs.x.bx = 0x00; /* 0 = stdin. */
91 inregs.x.dx = stdin_stat;
92 intdos (&inregs, &outregs);
93 return !outregs.x.cflag;
94}
95
96static unsigned short
97ibmpc_translate_map[] =
98{
99 /* --------------- 00 to 0f --------------- */
100 0, /* Ctrl Break */
101 0xff1b, /* Escape */
102 0xffb1, /* Keypad 1 */
103 0xffb2, /* Keypad 2 */
104 0xffb3, /* Keypad 3 */
105 0xffb4, /* Keypad 4 */
106 0xffb5, /* Keypad 5 */
107 0xffb6, /* Keypad 6 */
108 0xffb7, /* Keypad 7 */
109 0xffb8, /* Keypad 8 */
110 0xffb9, /* Keypad 9 */
111 0xffb0, /* Keypad 0 */
112 '-', '=',
113 0xff08, /* Backspace */
114 0xff74, /* (Shift) Tab [Tab doesn't use this table] */
115
116 /* --------------- 10 to 1f --------------- */
117 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']',
118 0xff8d, /* Keypad Enter */
119 0, /* Ctrl */
120 'a', 's',
121
122 /* --------------- 20 to 2f --------------- */
123 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
124 0, /* Left shift */
125 '\\', 'z', 'x', 'c', 'v',
126
127 /* --------------- 30 to 3f --------------- */
128 'b', 'n', 'm', ',', '.',
129 0xffaf, /* Grey / */
130 0, /* Right shift */
131 0xffaa, /* Grey * */
132 0, /* Alt */
133 ' ',
134 0, /* Caps Lock */
135 0xffbe, /* F1 */
136 0xffbf, /* F2 */
137 0xffc0, /* F3 */
138 0xffc1, /* F4 */
139 0xffc2, /* F5 */
140
141 /* --------------- 40 to 4f --------------- */
142 0xffc3, /* F6 */
143 0xffc4, /* F7 */
144 0xffc5, /* F8 */
145 0xffc6, /* F9 */
146 0xffc7, /* F10 */
147 0, /* Num Lock */
148 0, /* Scroll Lock */
149 0xff50, /* Home */
150 0xff52, /* Up */
151 0xff55, /* Page Up */
152 0xffad, /* Grey - */
153 0xff51, /* Left */
154 0xffb5, /* Keypad 5 */
155 0xff53, /* Right */
156 0xffab, /* Grey + */
157 0xff57, /* End */
158
159 /* --------------- 50 to 5f --------------- */
160 0xff54, /* Down */
161 0xff56, /* Page Down */
162 0xff63, /* Insert */
163 0xffff, /* Delete */
164 0xffbe, /* (Shift) F1 */
165 0xffbf, /* (Shift) F2 */
166 0xffc0, /* (Shift) F3 */
167 0xffc1, /* (Shift) F4 */
168 0xffc2, /* (Shift) F5 */
169 0xffc3, /* (Shift) F6 */
170 0xffc4, /* (Shift) F7 */
171 0xffc5, /* (Shift) F8 */
172 0xffc6, /* (Shift) F9 */
173 0xffc7, /* (Shift) F10 */
174 0xffbe, /* (Ctrl) F1 */
175 0xffbf, /* (Ctrl) F2 */
176
177 /* --------------- 60 to 6f --------------- */
178 0xffc0, /* (Ctrl) F3 */
179 0xffc1, /* (Ctrl) F4 */
180 0xffc2, /* (Ctrl) F5 */
181 0xffc3, /* (Ctrl) F6 */
182 0xffc4, /* (Ctrl) F7 */
183 0xffc5, /* (Ctrl) F8 */
184 0xffc6, /* (Ctrl) F9 */
185 0xffc7, /* (Ctrl) F10 */
186 0xffbe, /* (Alt) F1 */
187 0xffbf, /* (Alt) F2 */
188 0xffc0, /* (Alt) F3 */
189 0xffc1, /* (Alt) F4 */
190 0xffc2, /* (Alt) F5 */
191 0xffc3, /* (Alt) F6 */
192 0xffc4, /* (Alt) F7 */
193 0xffc5, /* (Alt) F8 */
194
195 /* --------------- 70 to 7f --------------- */
196 0xffc6, /* (Alt) F9 */
197 0xffc7, /* (Alt) F10 */
198 0xff6d, /* (Ctrl) Sys Rq */
199 0xff51, /* (Ctrl) Left */
200 0xff53, /* (Ctrl) Right */
201 0xff57, /* (Ctrl) End */
202 0xff56, /* (Ctrl) Page Down */
203 0xff50, /* (Ctrl) Home */
204 '1', '2', '3', '4', '5', '6', '7', '8', /* (Alt) */
205
206 /* --------------- 80 to 8f --------------- */
207 '9', '0', '-', '=', /* (Alt) */
208 0xff55, /* (Ctrl) Page Up */
209 0xffc8, /* F11 */
210 0xffc9, /* F12 */
211 0xffc8, /* (Shift) F11 */
212 0xffc9, /* (Shift) F12 */
213 0xffc8, /* (Ctrl) F11 */
214 0xffc9, /* (Ctrl) F12 */
215 0xffc8, /* (Alt) F11 */
216 0xffc9, /* (Alt) F12 */
217 0xff52, /* (Ctrl) Up */
218 0xffae, /* (Ctrl) Grey - */
219 0xffb5, /* (Ctrl) Keypad 5 */
220
221 /* --------------- 90 to 9f --------------- */
222 0xffab, /* (Ctrl) Grey + */
223 0xff54, /* (Ctrl) Down */
224 0xff63, /* (Ctrl) Insert */
225 0xffff, /* (Ctrl) Delete */
226 0xff09, /* (Ctrl) Tab */
227 0xffaf, /* (Ctrl) Grey / */
228 0xffaa, /* (Ctrl) Grey * */
229 0xff50, /* (Alt) Home */
230 0xff52, /* (Alt) Up */
231 0xff55, /* (Alt) Page Up */
232 0, /* NO KEY */
233 0xff51, /* (Alt) Left */
234 0, /* NO KEY */
235 0xff53, /* (Alt) Right */
236 0, /* NO KEY */
237 0xff57, /* (Alt) End */
238
239 /* --------------- a0 to af --------------- */
240 0xff54, /* (Alt) Down */
241 0xff56, /* (Alt) Page Down */
242 0xff63, /* (Alt) Insert */
243 0xffff, /* (Alt) Delete */
244 0xffaf, /* (Alt) Grey / */
245 0xff09, /* (Alt) Tab */
246 0xff0d /* (Alt) Enter */
247};
248
249/* Get a char from keyboard. Function keys are put into the event queue. */
250static int
251dos_rawgetc ()
252{
253 struct input_event event;
254 struct timeval tv;
255 union REGS regs;
256 int ctrl_p, alt_p, shift_p;
257
258 /* Calculate modifier bits */
259 regs.h.ah = extended_kbd ? 0x12 : 0x02;
260 int86 (0x16, &regs, &regs);
261 ctrl_p = ((regs.h.al & 4) != 0);
262 shift_p = ((regs.h.al & 3) != 0);
9da6e765
RS
263 /* Please be very careful here not to break international keyboard support.
264 When Keyb.Com is loaded, the key marked `Alt Gr' is used for accessing
265 characters like { and } if their positions are overlaid. */
1b94449f
RS
266 alt_p = ((extended_kbd ? (regs.h.ah & 2) : (regs.h.al & 8)) != 0);
267
3ec5651b
RS
268 /* The following condition is equivalent to `kbhit ()', except that
269 it uses the bios to do its job. This pleases DESQview/X. */
270 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
271 int86 (0x16, &regs, &regs),
272 (regs.x.flags & 0x40) == 0)
1b94449f
RS
273 {
274 union REGS regs;
275 register unsigned char c;
276 int sc, code;
277
278 regs.h.ah = extended_kbd ? 0x10 : 0x00;
279 int86 (0x16, &regs, &regs);
280 c = regs.h.al;
281 sc = regs.h.ah;
282
283 /* Determine from the scan code if a keypad key was pressed. */
284 if (c >= '0' && c <= '9' && sc > 0xb)
285 sc = (c == '0') ? 0xb : (c - '0' + 1), c = 0;
9da6e765
RS
286 else if (sc == 0x53 && c != 0xe0)
287 {
288 code = 0xffae; /* Keypad decimal point/comma. */
289 goto nonascii;
290 }
1b94449f
RS
291 else if (sc == 0xe0)
292 {
293 switch (c)
294 {
295 case 10: /* Ctrl Enter */
296 case 13:
297 sc = 0x1c;
298 break;
1b94449f
RS
299 case '/':
300 sc = 0x35;
301 break;
302 default:
303 sc = 0;
304 };
305 c = 0;
306 }
307
308 if (c == 0
309 || c == ' '
310 || alt_p
311 || (ctrl_p && shift_p)
312 || (c == 0xe0 && sc != 0) /* Pseudo-key */
313 || sc == 0x37 /* Grey * */
314 || sc == 0x4a /* Grey - */
315 || sc == 0x4e /* Grey + */
316 || sc == 0x0e) /* Back space *key*, not Ctrl-h */
317 {
318 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
319 code = 0;
320 else
321 code = ibmpc_translate_map[sc];
322 if (code != 0)
323 {
324 if (code >= 0x100)
325 {
9da6e765 326 nonascii:
1b94449f 327 event.kind = non_ascii_keystroke;
49a09c76 328 event.code = (code & 0xff) + 0xff00;
1b94449f
RS
329 }
330 else
331 {
9da6e765
RS
332 /* Don't return S- if we don't have to. `shifted' is
333 supposed to be the shifted versions of the characters
334 in `unshifted'. Unfortunately, this is only true for
335 US keyboard layout. If anyone knows how to do this
336 right, please tell us. */
337 static char *unshifted
338 = "abcdefghijklmnopqrstuvwxyz,./=;[\\]'-`0123456789";
339 static char *shifted
340 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ<>?+:{|}\"_~)!@#$%^&*(";
341 char *pos;
342
343 if (shift_p && (pos = strchr (unshifted, code)))
1b94449f 344 {
9da6e765 345 c = shifted[pos - unshifted];
1b94449f
RS
346 shift_p = 0;
347 }
348 else
349 if (c == 0) c = code;
350 event.kind = ascii_keystroke;
351 event.code = c;
352 }
353 event.modifiers
9da6e765
RS
354 = (shift_p ? shift_modifier : 0)
355 + (ctrl_p ? ctrl_modifier : 0)
356 + (alt_p ? meta_modifier : 0);
1b94449f
RS
357 /* EMACS == Enter Meta Alt Control Shift */
358 event.frame_or_window = selected_frame;
359 gettimeofday (&tv, NULL);
360 event.timestamp = tv.tv_usec;
361 kbd_buffer_store_event (&event);
362 }
363 } else
364 return c;
365 }
366
367 if (have_mouse)
368 {
369 int but, press, x, y, ok;
370
371 /* Check for mouse movement *before* buttons. */
49a09c76 372 mouse_check_moved ();
1b94449f
RS
373
374 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
375 for (press = 0; press < 2; press++)
376 {
377 if (press)
49a09c76 378 ok = mouse_pressed (but, &x, &y);
1b94449f 379 else
49a09c76 380 ok = mouse_released (but, &x, &y);
1b94449f
RS
381 if (ok)
382 {
383 event.kind = mouse_click;
384 event.code = but;
385 event.modifiers
9da6e765
RS
386 = (shift_p ? shift_modifier : 0)
387 + (ctrl_p ? ctrl_modifier : 0)
388 + (alt_p ? meta_modifier : 0)
389 + (press ? down_modifier : up_modifier);
1b94449f
RS
390 event.x = x;
391 event.y = y;
392 event.frame_or_window = selected_frame;
393 gettimeofday (&tv, NULL);
394 event.timestamp = tv.tv_usec;
395 kbd_buffer_store_event (&event);
396 }
397 }
398 }
399
400 return -1;
401}
402
403static int prev_get_char = -1;
404
405/* Return 1 if a key is ready to be read without suspending execution. */
406dos_keysns ()
407{
408 if (prev_get_char != -1)
409 return 1;
410 else
411 return ((prev_get_char = dos_rawgetc ()) != -1);
412}
413
414/* Read a key. Return -1 if no key is ready. */
415dos_keyread ()
416{
417 if (prev_get_char != -1)
418 {
419 int c = prev_get_char;
420 prev_get_char = -1;
421 return c;
422 }
423 else
424 return dos_rawgetc ();
425}
426
427/* Hostnames for a pc are not really funny, but they are used in change log
428 so we emulate the best we can. */
429gethostname (p, size)
430 char *p;
431 int size;
432{
433 char *q = egetenv ("HOSTNAME");
434
435 if (!q) q = "pc";
436 strcpy (p, q);
437 return 0;
438}
439
440/* Destructively turn backslashes into slashes. */
441void
442dostounix_filename (p)
443 register char *p;
444{
445 while (*p)
446 {
447 if (*p == '\\')
448 *p = '/';
449 p++;
450 }
451}
452
453/* Destructively turn slashes into backslashes. */
454void
455unixtodos_filename (p)
456 register char *p;
457{
458 while (*p)
459 {
460 if (*p == '/')
461 *p = '\\';
462 p++;
463 }
464}
465
466/* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
467int
468getdefdir (drive, dst)
469 int drive;
470 char *dst;
471{
472 union REGS regs;
473
474 *dst++ = '/';
475 regs.h.dl = drive;
476 regs.x.si = (int) dst;
477 regs.h.ah = 0x47;
478 intdos (&regs, &regs);
479 return !regs.x.cflag;
480}
481
482/* Remove all CR's that are followed by a LF. */
483int
484crlf_to_lf (n, buf)
485 register int n;
486 register unsigned char *buf;
487{
488 unsigned char *np = buf;
489 unsigned char *startp = buf;
490 unsigned char *endp = buf + n;
491 unsigned char c;
492
493 if (n == 0)
494 return n;
3d4ad6e0 495 while (buf < endp - 1)
1b94449f
RS
496 {
497 if (*buf == 0x0d)
498 {
499 if (*(++buf) != 0x0a)
500 *np++ = 0x0d;
501 }
502 else
503 *np++ = *buf++;
504 }
3d4ad6e0
RS
505 if (buf < endp)
506 *np++ = *buf++;
1b94449f
RS
507 return np - startp;
508}
509
510
511/* Run command as specified by ARGV in directory DIR.
512 The command is run with input from TEMPIN and output to file TEMPOUT. */
513int
514run_msdos_command (argv, dir, tempin, tempout)
515 unsigned char **argv;
516 Lisp_Object dir;
517 int tempin, tempout;
518{
519 char *saveargv1, *saveargv2, **envv;
520 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
521 int msshell, result = -1;
522 int in, out, inbak, outbak, errbak;
523 Lisp_Object cmd;
524
525 /* Get current directory as MSDOS cwd is not per-process. */
526 getwd (oldwd);
527
528 cmd = Ffile_name_nondirectory (build_string (argv[0]));
529 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
530 && !strcmp ("-c", argv[1]);
531 if (msshell)
532 {
533 saveargv1 = argv[1];
647c32eb 534 saveargv2 = argv[2];
1b94449f
RS
535 argv[1] = "/c";
536 if (argv[2])
537 {
647c32eb
KH
538 char *p = alloca (strlen (argv[2]) + 1);
539
540 strcpy (argv[2] = p, saveargv2);
541 while (*p && isspace (*p))
542 p++;
543 while (*p && !isspace (*p))
544 if (*p == '/')
545 *p++ = '\\';
546 else
547 p++;
1b94449f
RS
548 }
549 }
550
551 /* Build the environment array. */
552 {
553 extern Lisp_Object Vprocess_environment;
091d0bdf
KH
554 Lisp_Object tmp, lst;
555 int i, len;
556
557 lst = Vprocess_environment;
558 len = XFASTINT (Flength (lst));
1b94449f
RS
559
560 envv = alloca ((len + 1) * sizeof (char *));
561 for (i = 0; i < len; i++)
562 {
563 tmp = Fcar (lst);
564 lst = Fcdr (lst);
565 CHECK_STRING (tmp, 0);
566 envv[i] = alloca (XSTRING (tmp)->size + 1);
567 strcpy (envv[i], XSTRING (tmp)->data);
568 }
569 envv[len] = (char *) 0;
570 }
571
572 if (XTYPE (dir) == Lisp_String)
573 chdir (XSTRING (dir)->data);
574 inbak = dup (0);
575 outbak = dup (1);
576 errbak = dup (2);
577 if (inbak < 0 || outbak < 0 || errbak < 0)
578 goto done; /* Allocation might fail due to lack of descriptors. */
579 dup2 (tempin, 0);
580 dup2 (tempout, 1);
581 dup2 (tempout, 2);
582 dos_ttcooked ();
583 result = spawnve (P_WAIT, argv[0], argv, envv);
584 dos_ttraw ();
585 dup2 (inbak, 0);
586 dup2 (outbak, 1);
587 dup2 (errbak, 2);
588
589 done:
590 chdir (oldwd);
591 if (msshell)
592 {
593 argv[1] = saveargv1;
647c32eb 594 argv[2] = saveargv2;
1b94449f
RS
595 }
596 return result;
597}
598
599
600croak (badfunc)
601 char *badfunc;
602{
603 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
604 reset_sys_modes ();
605 exit (1);
606}
607
608/* A list of unimplemented functions that we silently ignore. */
609unsigned alarm (s) unsigned s; {}
610fork () { return 0; }
611int kill (x, y) int x, y; { return -1; }
612nice (p) int p; {}
613void volatile pause () {}
614request_sigio () {}
615setpgrp () {return 0; }
616setpriority (x,y,z) int x,y,z; { return 0; }
617sigsetmask (x) int x; { return 0; }
618unrequest_sigio () {}
619
620#ifdef chdir
621#undef chdir
622#endif
623
624int
625sys_chdir (path)
626 const char* path;
627{
628 int len = strlen (path);
629 char *tmp = (char *) alloca (len + 1);
630 /* Gotta do this extern here due to the corresponding #define: */
631 extern int chdir ();
632
633 if (*path && path[1] == ':' && (getdisk () != tolower (path[0]) - 'a'))
634 setdisk (tolower (path[0]) - 'a');
635
636 strcpy (tmp, path);
637 if (strcmp (path, "/") && strcmp (path + 1, ":/") && (path[len - 1] == '/'))
638 tmp[len - 1] = 0;
639 return chdir (tmp);
640}
641
642/* Sleep SECS. If KBDOK also return immediately if a key is pressed. */
643void
644sleep_or_kbd_hit (secs, kbdok)
645 int secs, kbdok;
646{
647 long clnow, clthen;
648 struct timeval t;
649
650 gettimeofday (&t, NULL);
651 clnow = t.tv_sec * 100 + t.tv_usec / 10000;
652 clthen = clnow + (100 * secs);
653
654 do
655 {
656 gettimeofday (&t, NULL);
657 clnow = t.tv_sec * 100 + t.tv_usec / 10000;
658 if (kbdok && detect_input_pending ())
659 return;
660 }
661 while (clnow < clthen);
662}
663
88b28483
RS
664/* The Emacs root directory as determined by init_environment. */
665static char emacsroot[MAXPATHLEN];
666
667char *
668rootrelativepath (rel)
669 char *rel;
670{
671 static char result[MAXPATHLEN + 10];
672
673 strcpy (result, emacsroot);
674 strcat (result, "/");
675 strcat (result, rel);
676 return result;
677}
678
1b94449f
RS
679/* Define a lot of environment variables if not already defined. Don't
680 remove anything unless you know what you're doing -- lots of code will
681 break if one or more of these are missing. */
682void
683init_environment (argc, argv, skip_args)
684 int argc;
685 char **argv;
686 int skip_args;
687{
88b28483
RS
688 char *s, *t, *root;
689 int len;
690
691 /* Find our root from argv[0]. Assuming argv[0] is, say,
692 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
693 len = strlen (argv[0]);
694 root = alloca (len + 10); /* A little extra space for the stuff below. */
695 strcpy (root, argv[0]);
696 while (len > 0 && root[len] != '/' && root[len] != ':')
697 len--;
698 root[len] = '\0';
699 if (len > 4 && strcmp (root + len - 4, "/bin") == 0)
700 root[len - 4] = '\0';
1b94449f 701 else
88b28483
RS
702 strcpy (root, "c:/emacs"); /* Only under debuggers, I think. */
703 len = strlen (root);
704 strcpy (emacsroot, root);
705
706 /* We default HOME to our root. */
707 setenv ("HOME", root, 0);
708
709 /* We default EMACSPATH to root + "/bin". */
710 strcpy (root + len, "/bin");
711 setenv ("EMACSPATH", root, 0);
1b94449f
RS
712
713 /* I don't expect anybody to ever use other terminals so the internal
714 terminal is the default. */
715 setenv ("TERM", "internal", 0);
716
717 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
718 downcase it and mirror the backslashes. */
719 s = getenv ("COMSPEC");
720 if (!s) s = "c:/command.com";
721 t = alloca (strlen (s) + 1);
722 strcpy (t, s);
723 strlwr (t);
724 dostounix_filename (t);
725 setenv ("SHELL", t, 0);
726
727 /* PATH is also downcased and backslashes mirrored. */
728 s = getenv ("PATH");
729 if (!s) s = "";
730 t = alloca (strlen (s) + 3);
731 /* Current directory is always considered part of MsDos's path but it is
732 not normally mentioned. Now it is. */
733 strcat (strcpy (t, ".;"), s);
734 strlwr (t);
735 dostounix_filename (t); /* Not a single file name, but this should work. */
736 setenv ("PATH", t, 1);
737
738 /* In some sense all dos users have root privileges, so... */
739 setenv ("USER", "root", 0);
740 setenv ("NAME", getenv ("USER"), 0);
741
742 /* Time zone determined from country code. To make this possible, the
743 country code may not span more than one time zone. In other words,
744 in the USA, you lose. */
745 switch (dos_country_code)
746 {
747 case 31: /* Belgium */
748 case 32: /* The Netherlands */
749 case 33: /* France */
750 case 34: /* Spain */
751 case 36: /* Hungary */
752 case 38: /* Yugoslavia (or what's left of it?) */
753 case 39: /* Italy */
754 case 41: /* Switzerland */
755 case 42: /* Tjekia */
756 case 45: /* Denmark */
757 case 46: /* Sweden */
758 case 47: /* Norway */
759 case 48: /* Poland */
760 case 49: /* Germany */
761 /* Daylight saving from last Sunday in March to last Sunday in
762 September, both at 2AM. */
763 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
764 break;
765 case 44: /* United Kingdom */
766 case 351: /* Portugal */
767 case 354: /* Iceland */
768 setenv ("TZ", "GMT+00", 0);
769 break;
770 case 81: /* Japan */
771 case 82: /* Korea */
772 setenv ("TZ", "???-09", 0);
773 break;
774 case 90: /* Turkey */
775 case 358: /* Finland */
776 case 972: /* Israel */
777 setenv ("TZ", "EET-02", 0);
778 break;
779 }
780 tzset ();
b278e52a 781 init_gettimeofday ();
1b94449f
RS
782}
783
784/* Flash the screen as a substitute for BEEPs. */
785
49a09c76 786static void
fcea9cd4 787do_visible_bell (xorattr)
1b94449f
RS
788 unsigned char xorattr;
789{
49a09c76 790 asm volatile
ca986694 791 (" movb $1,%%dl
1b94449f 792visible_bell_0:
ca986694 793 movl _ScreenPrimary,%%eax
49a09c76 794 call dosmemsetup
ca986694
RS
795 movl %%eax,%%ebx
796 movl %1,%%ecx
797 movb %0,%%al
798 incl %%ebx
1b94449f 799visible_bell_1:
ca986694
RS
800 xorb %%al,%%gs:(%%ebx)
801 addl $2,%%ebx
802 decl %%ecx
49a09c76 803 jne visible_bell_1
ca986694 804 decb %%dl
49a09c76 805 jne visible_bell_3
1b94449f 806visible_bell_2:
ca986694
RS
807 movzwl %%ax,%%eax
808 movzwl %%ax,%%eax
809 movzwl %%ax,%%eax
810 movzwl %%ax,%%eax
811 decw %%cx
49a09c76
RS
812 jne visible_bell_2
813 jmp visible_bell_0
ca986694
RS
814visible_bell_3:"
815 : /* no output */
816 : "m" (xorattr), "g" (ScreenCols () * ScreenRows ())
817 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
1b94449f
RS
818}
819
09e2ac30
RS
820/* At screen position (X,Y), output C characters from string S with
821 attribute A. Do it fast! */
822
823static void
824output_string (x, y, s, c, a)
825 int x, y, c;
826 unsigned char *s;
827 unsigned char a;
828{
829 char *t = (char *)ScreenPrimary + 2 * (x + ScreenCols () * y);
830 asm volatile
831 (" movl %1,%%eax
832 call dosmemsetup
833 movl %%eax,%%edi
834 movb %0,%%ah
835 movl %2,%%ecx
836 movl %3,%%esi
837output_string1:
838 movb (%%esi),%%al
839 movw %%ax,%%gs:(%%edi)
840 addl $2,%%edi
841 incl %%esi
842 decl %%ecx
843 jne output_string1"
844 : /* no output */
845 : "m" (a), "g" (t), "g" (c), "g" (s)
846 : "%eax", "%ecx", /* "%gs",*/ "%esi", "%edi");
847}
848
1b94449f
RS
849static int internal_terminal = 0;
850#undef fflush
851
852int
853internal_flush (f)
854 FILE *f;
855{
09e2ac30 856 static char spaces[] = " ";
1b94449f
RS
857 static int x;
858 static int y;
09e2ac30
RS
859 unsigned char *cp, *cp0;
860 int count, i, j;
1b94449f
RS
861
862 if (internal_terminal && f == stdout)
863 {
49a09c76 864 if (have_mouse) mouse_off ();
1b94449f
RS
865 cp = stdout->_base;
866 count = stdout->_ptr - stdout->_base;
867 while (count > 0)
868 {
09e2ac30 869 switch (*cp++)
1b94449f
RS
870 {
871 case 27:
872 switch (*cp++)
873 {
874 case '@':
875 y = *cp++;
876 x = *cp++;
877 count -= 4;
878 break;
879 case 'A':
880 ScreenAttrib = *cp++;
881 count -= 3;
882 break;
883 case 'B':
fcea9cd4 884 do_visible_bell (*cp++);
1b94449f
RS
885 count -= 3;
886 break;
887 case 'C':
888 ScreenClear ();
889 x = y = 0;
890 count -= 2;
891 break;
892 case 'E':
09e2ac30
RS
893 i = ScreenCols () - x;
894 j = x;
895 while (i >= sizeof spaces)
896 {
897 output_string (j, y, spaces, sizeof spaces,
898 ScreenAttrib);
899 j += sizeof spaces;
900 i -= sizeof spaces;
901 }
902 if (i > 0)
903 output_string (j, y, spaces, i, ScreenAttrib);
1b94449f
RS
904 count -= 2;
905 break;
906 case 'R':
907 x++;
908 count -= 2;
909 break;
910 case 'U':
911 y--;
912 count -= 2;
913 break;
914 case 'X':
915 ScreenAttrib ^= *cp++;
916 count -= 3;
917 break;
918 default:
919 count -= 2;
920 }
921 break;
fcea9cd4
RS
922 case 7:
923 write (1, "\007", 1);
924 count--;
925 break;
1b94449f
RS
926 case 8:
927 x--;
928 count--;
929 break;
930 case 13:
931 x = 0;
932 count--;
933 break;
934 case 10:
935 y++;
936 count--;
937 break;
938 default:
09e2ac30 939 cp0 = cp - 1;
1b94449f 940 count--;
09e2ac30
RS
941 while (count > 0 && *cp >= ' ')
942 cp++, count--;
943 output_string (x, y, cp0, cp - cp0, ScreenAttrib);
944 x += (cp - cp0);
1b94449f
RS
945 }
946 }
947 fpurge (stdout);
948 ScreenSetCursor (y, x);
49a09c76 949 if (have_mouse) mouse_on ();
1b94449f
RS
950 }
951 else
952 /* This is a call to the original fflush. */
953 fflush (f);
954}
955
956/* Do we need the internal terminal? */
957void
958internal_terminal_init ()
959{
960 char *term = getenv ("TERM");
961
962 internal_terminal
963 = (!noninteractive) && term && !strcmp (term, "internal");
964}
b278e52a
RS
965\f
966/* When time zones are set from Ms-Dos too may C-libraries are playing
967 tricks with time values. We solve this by defining our own version
968 of `gettimeofday' bypassing GO32. Our version needs to be initialized
969 once and after each call to `tzset' with TZ changed. */
1b94449f 970
b278e52a
RS
971static int daylight, gmtoffset;
972
973int
974gettimeofday (struct timeval *tp, struct timezone *tzp)
975{
976 if (tp)
977 {
978 struct time t;
979 struct date d;
980 struct tm tmrec;
981
982 gettime (&t);
983 getdate (&d);
984 tmrec.tm_year = d.da_year - 1900;
985 tmrec.tm_mon = d.da_mon - 1;
986 tmrec.tm_mday = d.da_day;
987 tmrec.tm_hour = t.ti_hour;
988 tmrec.tm_min = t.ti_min;
989 tmrec.tm_sec = t.ti_sec;
990 tmrec.tm_gmtoff = gmtoffset;
991 tmrec.tm_isdst = daylight;
992 tp->tv_sec = mktime (&tmrec);
993 tp->tv_usec = t.ti_hund * (1000000 / 100);
994 }
995 if (tzp)
996 {
997 tzp->tz_minuteswest = gmtoffset;
998 tzp->tz_dsttime = daylight;
999 }
1000 return 0;
1001}
1002
1003void
1004init_gettimeofday ()
1005{
1006 time_t ltm, gtm;
1007 struct tm *lstm;
1008
1009 daylight = 0;
1010 gmtoffset = 0;
1011 ltm = gtm = time (NULL);
1012 ltm = mktime (lstm = localtime (&ltm));
1013 gtm = mktime (gmtime (&gtm));
1014 daylight = lstm->tm_isdst;
1015 gmtoffset = (int)(gtm - ltm) / 60;
1016}
1017\f
1b94449f
RS
1018/* These must be global. */
1019static _go32_dpmi_seginfo ctrl_break_vector;
1020static _go32_dpmi_registers ctrl_break_regs;
1021static int ctrlbreakinstalled = 0;
1022
1023/* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
1024void
1025ctrl_break_func (regs)
1026 _go32_dpmi_registers *regs;
1027{
1028 Vquit_flag = Qt;
1029}
1030
1031void
1032install_ctrl_break_check ()
1033{
1034 if (!ctrlbreakinstalled)
1035 {
1036 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
ca986694 1037 was compiler with Djgpp 1.11 maintenance level 5 or later! */
1b94449f
RS
1038 ctrlbreakinstalled = 1;
1039 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
1040 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
1041 &ctrl_break_regs);
1042 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
1043 }
1044}
1045\f
1046
1047/* Mouse routines under devellopment follow. Coordinates are in screen
1048 positions and zero based. Mouse buttons are numbered from left to
1049 right and also zero based. */
1050
1051static int mouse_button_translate[NUM_MOUSE_BUTTONS];
1052static int mouse_button_count;
1053
1054void
1055mouse_init ()
1056{
1057 union REGS regs;
1058
1059 regs.x.ax = 0x0007;
1060 regs.x.cx = 0;
1061 regs.x.dx = 8 * (ScreenCols () - 1);
1062 int86 (0x33, &regs, &regs);
1063
1064 regs.x.ax = 0x0008;
1065 regs.x.cx = 0;
1066 regs.x.dx = 8 * (ScreenRows () - 1);
1067 int86 (0x33, &regs, &regs);
1068
1069 mouse_moveto (ScreenCols () - 1, ScreenRows () - 1);
1070 mouse_on ();
1071}
1072
1073void
1074mouse_on ()
1075{
1076 union REGS regs;
1077
1078 regs.x.ax = 0x0001;
1079 int86 (0x33, &regs, &regs);
1080}
1081
1082void
1083mouse_off ()
1084{
1085 union REGS regs;
1086
1087 regs.x.ax = 0x0002;
1088 int86 (0x33, &regs, &regs);
1089}
1090
1091void
1092mouse_moveto (x, y)
1093 int x, y;
1094{
1095 union REGS regs;
1096
1097 regs.x.ax = 0x0004;
1098 mouse_last_x = regs.x.cx = x * 8;
1099 mouse_last_y = regs.x.dx = y * 8;
1100 int86 (0x33, &regs, &regs);
1101}
1102
1103int
1104mouse_pressed (b, xp, yp)
1105 int b, *xp, *yp;
1106{
1107 union REGS regs;
1108
1109 if (b >= mouse_button_count)
1110 return 0;
1111 regs.x.ax = 0x0005;
1112 regs.x.bx = mouse_button_translate[b];
1113 int86 (0x33, &regs, &regs);
1114 if (regs.x.bx)
ca986694 1115 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
1b94449f
RS
1116 return (regs.x.bx != 0);
1117}
1118
1119int
1120mouse_released (b, xp, yp)
1121 int b, *xp, *yp;
1122{
1123 union REGS regs;
1124
1125 if (b >= mouse_button_count)
1126 return 0;
1127 regs.x.ax = 0x0006;
1128 regs.x.bx = mouse_button_translate[b];
1129 int86 (0x33, &regs, &regs);
1130 if (regs.x.bx)
1131 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
1132 return (regs.x.bx != 0);
1133}
1134
1135void
1136mouse_get_pos (f, bar_window, part, x, y, time)
1137 FRAME_PTR *f;
1138 Lisp_Object *bar_window, *x, *y;
1139 enum scroll_bar_part *part;
1140 unsigned long *time;
1141{
1142 union REGS regs;
1143 struct timeval tv;
1144
1145 regs.x.ax = 0x0003;
1146 int86 (0x33, &regs, &regs);
1147 *f = selected_frame;
1148 *bar_window = Qnil;
1149 gettimeofday (&tv, NULL);
411acee3
RS
1150 *x = make_number (regs.x.cx);
1151 *y = make_number (regs.x.dx);
1b94449f
RS
1152 *time = tv.tv_usec;
1153 mouse_moved = 0;
1154}
1155
1156void
1157mouse_check_moved ()
1158{
1159 union REGS regs;
1160
1161 regs.x.ax = 0x0003;
1162 int86 (0x33, &regs, &regs);
1163 if (regs.x.cx != mouse_last_x || regs.x.dx != mouse_last_y)
1164 {
1165 mouse_moved = 1;
1166 mouse_last_x = regs.x.cx;
1167 mouse_last_y = regs.x.dx;
1168 }
1169}
1170
1171int
1172mouse_init1 ()
1173{
1174 union REGS regs;
1175 int present;
1176
1177 regs.x.ax = 0x0021;
1178 int86 (0x33, &regs, &regs);
1179 present = internal_terminal && (regs.x.ax & 0xffff) == 0xffff;
1180 if (present)
1181 {
1182 if (regs.x.bx == 3)
1183 {
1184 mouse_button_count = 3;
1185 mouse_button_translate[0] = 0; /* Left */
1186 mouse_button_translate[1] = 2; /* Middle */
1187 mouse_button_translate[2] = 1; /* Right */
1188 }
1189 else
1190 {
1191 mouse_button_count = 2;
1192 mouse_button_translate[0] = 0;
1193 mouse_button_translate[1] = 1;
1194 }
1195 mouse_position_hook = &mouse_get_pos;
1196 mouse_init ();
1197 }
1198 return present;
1199}
1200
49a09c76
RS
1201/* See xterm.c for more info. */
1202void
1203pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
1204 FRAME_PTR f;
1205 register int pix_x, pix_y;
1206 register int *x, *y;
1207 void /* XRectangle */ *bounds;
1208 int noclip;
1209{
1210 if (bounds) abort ();
1211
1212 /* Ignore clipping. */
1213
1214 *x = pix_x;
1215 *y = pix_y;
1216}
1217
1218void
1219glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1220 FRAME_PTR f;
1221 register int x, y;
1222 register int *pix_x, *pix_y;
1223{
1224 *pix_x = x;
1225 *pix_y = y;
1226}
1227
1b94449f 1228#endif /* MSDOS */