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