Use <...> for config.h.
[bpt/emacs.git] / src / msdos.c
1 /* MS-DOS specific C utilities. Coded by Morten Welinder 1993
2 Copyright (C) 1993 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
21
22 #include <config.h>
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
43 static int break_stat; /* BREAK check mode status. */
44 static int stdin_stat; /* stdin IOCTL status. */
45 static int extended_kbd; /* 101 (102) keyboard present. */
46
47 int have_mouse; /* Mouse present? */
48 static int mouse_last_x;
49 static 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. */
53 int
54 dos_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 ();
65 have_mouse = Mouse_init1 ();
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. */
79 int
80 dos_ttcooked ()
81 {
82 union REGS inregs, outregs;
83
84 setcbrk (break_stat);
85 if (have_mouse) Mouse_off ();
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
94 static unsigned short
95 ibmpc_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. */
248 static int
249 dos_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;
317 event.code = code & 0xff;
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
333 = (shift_p ? shift_modifier : 0)
334 + (ctrl_p ? ctrl_modifier : 0)
335 + (alt_p ? meta_modifier : 0);
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. */
351 Mouse_check_moved ();
352
353 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
354 for (press = 0; press < 2; press++)
355 {
356 if (press)
357 ok = Mouse_pressed (but, &x, &y);
358 else
359 ok = Mouse_released (but, &x, &y);
360 if (ok)
361 {
362 event.kind = mouse_click;
363 event.code = but;
364 event.modifiers
365 = (shift_p ? shift_modifier : 0)
366 + (ctrl_p ? ctrl_modifier : 0)
367 + (alt_p ? meta_modifier : 0)
368 + (press ? down_modifier : up_modifier);
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
382 static int prev_get_char = -1;
383
384 /* Return 1 if a key is ready to be read without suspending execution. */
385 dos_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. */
394 dos_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. */
408 gethostname (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. */
420 void
421 dostounix_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. */
433 void
434 unixtodos_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, ... */
446 int
447 getdefdir (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. */
462 int
463 crlf_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;
474 while (buf < endp)
475 {
476 if (*buf == 0x0d)
477 {
478 if (*(++buf) != 0x0a)
479 *np++ = 0x0d;
480 }
481 else
482 *np++ = *buf++;
483 }
484 return np - startp;
485 }
486
487
488 /* Run command as specified by ARGV in directory DIR.
489 The command is run with input from TEMPIN and output to file TEMPOUT. */
490 int
491 run_msdos_command (argv, dir, tempin, tempout)
492 unsigned char **argv;
493 Lisp_Object dir;
494 int tempin, tempout;
495 {
496 char *saveargv1, *saveargv2, **envv;
497 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
498 int msshell, result = -1;
499 int in, out, inbak, outbak, errbak;
500 Lisp_Object cmd;
501
502 /* Get current directory as MSDOS cwd is not per-process. */
503 getwd (oldwd);
504
505 cmd = Ffile_name_nondirectory (build_string (argv[0]));
506 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
507 && !strcmp ("-c", argv[1]);
508 if (msshell)
509 {
510 saveargv1 = argv[1];
511 argv[1] = "/c";
512 if (argv[2])
513 {
514 saveargv2 = argv[2];
515 unixtodos_filename (argv[2] = strdup (argv[2]));
516 }
517 }
518
519 /* Build the environment array. */
520 {
521 extern Lisp_Object Vprocess_environment;
522 Lisp_Object tmp, lst = Vprocess_environment;
523 int i, len = XFASTINT (Flength (lst));
524
525 envv = alloca ((len + 1) * sizeof (char *));
526 for (i = 0; i < len; i++)
527 {
528 tmp = Fcar (lst);
529 lst = Fcdr (lst);
530 CHECK_STRING (tmp, 0);
531 envv[i] = alloca (XSTRING (tmp)->size + 1);
532 strcpy (envv[i], XSTRING (tmp)->data);
533 }
534 envv[len] = (char *) 0;
535 }
536
537 if (XTYPE (dir) == Lisp_String)
538 chdir (XSTRING (dir)->data);
539 inbak = dup (0);
540 outbak = dup (1);
541 errbak = dup (2);
542 if (inbak < 0 || outbak < 0 || errbak < 0)
543 goto done; /* Allocation might fail due to lack of descriptors. */
544 dup2 (tempin, 0);
545 dup2 (tempout, 1);
546 dup2 (tempout, 2);
547 dos_ttcooked ();
548 result = spawnve (P_WAIT, argv[0], argv, envv);
549 dos_ttraw ();
550 dup2 (inbak, 0);
551 dup2 (outbak, 1);
552 dup2 (errbak, 2);
553
554 done:
555 chdir (oldwd);
556 if (msshell)
557 {
558 argv[1] = saveargv1;
559 if (argv[2])
560 {
561 free (argv[2]);
562 argv[2] = saveargv2;
563 }
564 }
565 return result;
566 }
567
568
569 croak (badfunc)
570 char *badfunc;
571 {
572 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
573 reset_sys_modes ();
574 exit (1);
575 }
576
577 /* A list of unimplemented functions that we silently ignore. */
578 unsigned alarm (s) unsigned s; {}
579 fork () { return 0; }
580 int kill (x, y) int x, y; { return -1; }
581 nice (p) int p; {}
582 void volatile pause () {}
583 request_sigio () {}
584 setpgrp () {return 0; }
585 setpriority (x,y,z) int x,y,z; { return 0; }
586 sigsetmask (x) int x; { return 0; }
587 unrequest_sigio () {}
588
589 #ifdef chdir
590 #undef chdir
591 #endif
592
593 int
594 sys_chdir (path)
595 const char* path;
596 {
597 int len = strlen (path);
598 char *tmp = (char *) alloca (len + 1);
599 /* Gotta do this extern here due to the corresponding #define: */
600 extern int chdir ();
601
602 if (*path && path[1] == ':' && (getdisk () != tolower (path[0]) - 'a'))
603 setdisk (tolower (path[0]) - 'a');
604
605 strcpy (tmp, path);
606 if (strcmp (path, "/") && strcmp (path + 1, ":/") && (path[len - 1] == '/'))
607 tmp[len - 1] = 0;
608 return chdir (tmp);
609 }
610
611 /* Sleep SECS. If KBDOK also return immediately if a key is pressed. */
612 void
613 sleep_or_kbd_hit (secs, kbdok)
614 int secs, kbdok;
615 {
616 long clnow, clthen;
617 struct timeval t;
618
619 gettimeofday (&t, NULL);
620 clnow = t.tv_sec * 100 + t.tv_usec / 10000;
621 clthen = clnow + (100 * secs);
622
623 do
624 {
625 gettimeofday (&t, NULL);
626 clnow = t.tv_sec * 100 + t.tv_usec / 10000;
627 if (kbdok && detect_input_pending ())
628 return;
629 }
630 while (clnow < clthen);
631 }
632
633 /* Define a lot of environment variables if not already defined. Don't
634 remove anything unless you know what you're doing -- lots of code will
635 break if one or more of these are missing. */
636 void
637 init_environment (argc, argv, skip_args)
638 int argc;
639 char **argv;
640 int skip_args;
641 {
642 char *s, *t;
643
644 /* We default HOME to the directory from which Emacs was started, but with
645 a "/bin" suffix removed. */
646 s = argv[0];
647 t = alloca (strlen (s) + 1);
648 strcpy (t, s);
649 s = t + strlen (t);
650 while (s != t && *s != '/' && *s != ':') s--;
651 if (s == t)
652 t = "c:/emacs"; /* When run under debug32. */
653 else
654 {
655 if (*s == ':') s++;
656 *s = 0;
657 if (s - 4 >= t && strcmp (s - 4, "/bin") == 0)
658 s[strlen (s) - 4] = 0;
659 }
660 setenv ("HOME", t, 0);
661
662 /* We set EMACSPATH to ~/bin (expanded) */
663 s = getenv ("HOME");
664 t = strcpy (alloca (strlen (s) + 6), s);
665 if (s[strlen (s) - 1] != '/') strcat (t, "/");
666 strcat (t, "bin");
667 setenv ("EMACSPATH", t, 0);
668
669 /* I don't expect anybody to ever use other terminals so the internal
670 terminal is the default. */
671 setenv ("TERM", "internal", 0);
672
673 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
674 downcase it and mirror the backslashes. */
675 s = getenv ("COMSPEC");
676 if (!s) s = "c:/command.com";
677 t = alloca (strlen (s) + 1);
678 strcpy (t, s);
679 strlwr (t);
680 dostounix_filename (t);
681 setenv ("SHELL", t, 0);
682
683 /* PATH is also downcased and backslashes mirrored. */
684 s = getenv ("PATH");
685 if (!s) s = "";
686 t = alloca (strlen (s) + 3);
687 /* Current directory is always considered part of MsDos's path but it is
688 not normally mentioned. Now it is. */
689 strcat (strcpy (t, ".;"), s);
690 strlwr (t);
691 dostounix_filename (t); /* Not a single file name, but this should work. */
692 setenv ("PATH", t, 1);
693
694 /* In some sense all dos users have root privileges, so... */
695 setenv ("USER", "root", 0);
696 setenv ("NAME", getenv ("USER"), 0);
697
698 /* Time zone determined from country code. To make this possible, the
699 country code may not span more than one time zone. In other words,
700 in the USA, you lose. */
701 switch (dos_country_code)
702 {
703 case 31: /* Belgium */
704 case 32: /* The Netherlands */
705 case 33: /* France */
706 case 34: /* Spain */
707 case 36: /* Hungary */
708 case 38: /* Yugoslavia (or what's left of it?) */
709 case 39: /* Italy */
710 case 41: /* Switzerland */
711 case 42: /* Tjekia */
712 case 45: /* Denmark */
713 case 46: /* Sweden */
714 case 47: /* Norway */
715 case 48: /* Poland */
716 case 49: /* Germany */
717 /* Daylight saving from last Sunday in March to last Sunday in
718 September, both at 2AM. */
719 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
720 break;
721 case 44: /* United Kingdom */
722 case 351: /* Portugal */
723 case 354: /* Iceland */
724 setenv ("TZ", "GMT+00", 0);
725 break;
726 case 81: /* Japan */
727 case 82: /* Korea */
728 setenv ("TZ", "???-09", 0);
729 break;
730 case 90: /* Turkey */
731 case 358: /* Finland */
732 case 972: /* Israel */
733 setenv ("TZ", "EET-02", 0);
734 break;
735 }
736 tzset ();
737 }
738
739 /* Flash the screen as a substitute for BEEPs. */
740
741 static unsigned char _xorattr;
742
743 void
744 visible_bell (xorattr)
745 unsigned char xorattr;
746 {
747 _xorattr = xorattr;
748 asm (" pushl %eax
749 pushl %ebx
750 pushl %ecx
751 pushl %edx
752 movl $1,%edx
753 visible_bell_0:
754 movl _ScreenPrimary,%eax
755 call dosmemsetup
756 movl %eax,%ebx
757 call _ScreenRows
758 movl %eax,%ecx
759 call _ScreenCols
760 imull %eax,%ecx
761 movb (__xorattr),%al
762 incl %ebx
763 visible_bell_1:
764 xorb %al,%gs:(%ebx)
765 addl $2,%ebx
766 decl %ecx
767 jne visible_bell_1
768 decl %edx
769 jne visible_bell_3
770 visible_bell_2:
771 movzwl %ax,%eax
772 movzwl %ax,%eax
773 movzwl %ax,%eax
774 movzwl %ax,%eax
775 decw %cx
776 jne visible_bell_2
777 jmp visible_bell_0
778 visible_bell_3:
779 popl %edx
780 popl %ecx
781 popl %ebx
782 popl %eax");
783 }
784
785 static int internal_terminal = 0;
786 #undef fflush
787
788 int
789 internal_flush (f)
790 FILE *f;
791 {
792 static int x;
793 static int y;
794 char c, *cp;
795 int count, i;
796
797 if (internal_terminal && f == stdout)
798 {
799 if (have_mouse) Mouse_off ();
800 cp = stdout->_base;
801 count = stdout->_ptr - stdout->_base;
802 while (count > 0)
803 {
804 switch (c = *cp++)
805 {
806 case 27:
807 switch (*cp++)
808 {
809 case '@':
810 y = *cp++;
811 x = *cp++;
812 count -= 4;
813 break;
814 case 'A':
815 ScreenAttrib = *cp++;
816 count -= 3;
817 break;
818 case 'B':
819 visible_bell (*cp++);
820 count -= 3;
821 break;
822 case 'C':
823 ScreenClear ();
824 x = y = 0;
825 count -= 2;
826 break;
827 case 'E':
828 for (i = ScreenCols () - 1; i >= x; i--)
829 ScreenPutChar (' ', ScreenAttrib, i, y);
830 count -= 2;
831 break;
832 case 'R':
833 x++;
834 count -= 2;
835 break;
836 case 'U':
837 y--;
838 count -= 2;
839 break;
840 case 'X':
841 ScreenAttrib ^= *cp++;
842 count -= 3;
843 break;
844 default:
845 count -= 2;
846 }
847 break;
848 case 8:
849 x--;
850 count--;
851 break;
852 case 13:
853 x = 0;
854 count--;
855 break;
856 case 10:
857 y++;
858 count--;
859 break;
860 default:
861 ScreenPutChar (c, ScreenAttrib, x++, y);
862 count--;
863 }
864 }
865 fpurge (stdout);
866 ScreenSetCursor (y, x);
867 if (have_mouse) Mouse_on ();
868 }
869 else
870 /* This is a call to the original fflush. */
871 fflush (f);
872 }
873
874 /* Do we need the internal terminal? */
875 void
876 internal_terminal_init ()
877 {
878 char *term = getenv ("TERM");
879
880 internal_terminal
881 = (!noninteractive) && term && !strcmp (term, "internal");
882 }
883
884 /* These must be global. */
885 static _go32_dpmi_seginfo ctrl_break_vector;
886 static _go32_dpmi_registers ctrl_break_regs;
887 static int ctrlbreakinstalled = 0;
888
889 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
890 void
891 ctrl_break_func (regs)
892 _go32_dpmi_registers *regs;
893 {
894 Vquit_flag = Qt;
895 }
896
897 void
898 install_ctrl_break_check ()
899 {
900 if (!ctrlbreakinstalled)
901 {
902 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
903 was compiler with Djgpp 1.11 maintenance level 2 or later! */
904 ctrlbreakinstalled = 1;
905 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
906 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
907 &ctrl_break_regs);
908 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
909 }
910 }
911 \f
912
913 /* Mouse routines under devellopment follow. Coordinates are in screen
914 positions and zero based. Mouse buttons are numbered from left to
915 right and also zero based. */
916
917 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
918 static int mouse_button_count;
919
920 void
921 mouse_init ()
922 {
923 union REGS regs;
924
925 regs.x.ax = 0x0007;
926 regs.x.cx = 0;
927 regs.x.dx = 8 * (ScreenCols () - 1);
928 int86 (0x33, &regs, &regs);
929
930 regs.x.ax = 0x0008;
931 regs.x.cx = 0;
932 regs.x.dx = 8 * (ScreenRows () - 1);
933 int86 (0x33, &regs, &regs);
934
935 mouse_moveto (ScreenCols () - 1, ScreenRows () - 1);
936 mouse_on ();
937 }
938
939 void
940 mouse_on ()
941 {
942 union REGS regs;
943
944 regs.x.ax = 0x0001;
945 int86 (0x33, &regs, &regs);
946 }
947
948 void
949 mouse_off ()
950 {
951 union REGS regs;
952
953 regs.x.ax = 0x0002;
954 int86 (0x33, &regs, &regs);
955 }
956
957 void
958 mouse_moveto (x, y)
959 int x, y;
960 {
961 union REGS regs;
962
963 regs.x.ax = 0x0004;
964 mouse_last_x = regs.x.cx = x * 8;
965 mouse_last_y = regs.x.dx = y * 8;
966 int86 (0x33, &regs, &regs);
967 }
968
969 int
970 mouse_pressed (b, xp, yp)
971 int b, *xp, *yp;
972 {
973 union REGS regs;
974
975 if (b >= mouse_button_count)
976 return 0;
977 regs.x.ax = 0x0005;
978 regs.x.bx = mouse_button_translate[b];
979 int86 (0x33, &regs, &regs);
980 if (regs.x.bx)
981 *xp = regs.x.cx / 8, *yp = regs.x.dx /8;
982 return (regs.x.bx != 0);
983 }
984
985 int
986 mouse_released (b, xp, yp)
987 int b, *xp, *yp;
988 {
989 union REGS regs;
990
991 if (b >= mouse_button_count)
992 return 0;
993 regs.x.ax = 0x0006;
994 regs.x.bx = mouse_button_translate[b];
995 int86 (0x33, &regs, &regs);
996 if (regs.x.bx)
997 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
998 return (regs.x.bx != 0);
999 }
1000
1001 void
1002 mouse_get_pos (f, bar_window, part, x, y, time)
1003 FRAME_PTR *f;
1004 Lisp_Object *bar_window, *x, *y;
1005 enum scroll_bar_part *part;
1006 unsigned long *time;
1007 {
1008 union REGS regs;
1009 struct timeval tv;
1010
1011 regs.x.ax = 0x0003;
1012 int86 (0x33, &regs, &regs);
1013 *f = selected_frame;
1014 *bar_window = Qnil;
1015 gettimeofday (&tv, NULL);
1016 *x = make_number (regs.x.cx / 8);
1017 *y = make_number (regs.x.dx / 8);
1018 *time = tv.tv_usec;
1019 mouse_moved = 0;
1020 }
1021
1022 void
1023 mouse_check_moved ()
1024 {
1025 union REGS regs;
1026
1027 regs.x.ax = 0x0003;
1028 int86 (0x33, &regs, &regs);
1029 if (regs.x.cx != mouse_last_x || regs.x.dx != mouse_last_y)
1030 {
1031 mouse_moved = 1;
1032 mouse_last_x = regs.x.cx;
1033 mouse_last_y = regs.x.dx;
1034 }
1035 }
1036
1037 int
1038 mouse_init1 ()
1039 {
1040 union REGS regs;
1041 int present;
1042
1043 regs.x.ax = 0x0021;
1044 int86 (0x33, &regs, &regs);
1045 present = internal_terminal && (regs.x.ax & 0xffff) == 0xffff;
1046 if (present)
1047 {
1048 if (regs.x.bx == 3)
1049 {
1050 mouse_button_count = 3;
1051 mouse_button_translate[0] = 0; /* Left */
1052 mouse_button_translate[1] = 2; /* Middle */
1053 mouse_button_translate[2] = 1; /* Right */
1054 }
1055 else
1056 {
1057 mouse_button_count = 2;
1058 mouse_button_translate[0] = 0;
1059 mouse_button_translate[1] = 1;
1060 }
1061 mouse_position_hook = &mouse_get_pos;
1062 mouse_init ();
1063 }
1064 return present;
1065 }
1066
1067 #endif /* MSDOS */