(internal_flush): Removed
[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
edfc0d45 8the Free Software Foundation; either version 2, or (at your option)
1b94449f
RS
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"
87485d6f
MW
37#include "dispextern.h"
38#include "termopts.h"
1b94449f 39#include "frame.h"
87485d6f 40#include "window.h"
1b94449f
RS
41#include <go32.h>
42#include <pc.h>
43#include <ctype.h>
44/* #include <process.h> */
45/* Damn that local process.h! Instead we can define P_WAIT ourselves. */
46#define P_WAIT 1
47
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
aee81730
RS
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
1b94449f
RS
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;
aee81730
RS
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
1b94449f
RS
83 break_stat = getcbrk ();
84 setcbrk (0);
85 install_ctrl_break_check ();
1b94449f 86
aee81730
RS
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. */
1b94449f
RS
92 intdos (&inregs, &outregs);
93 stdin_stat = outregs.h.dl;
94
aee81730
RS
95 only_once = 0;
96
97 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
98 inregs.x.ax = 0x4401; /* Set IOCTL status */
1b94449f
RS
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);
aee81730 110 mouse_off ();
1b94449f
RS
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
aee81730
RS
119/* generate a reliable event timestamp, KFS 1995-07-06 */
120
121static unsigned long
122event_timestamp ()
123{
124 struct time t;
125 unsigned long s;
126
127 gettime (&t);
128 s = t.ti_min;
129 s *= 60;
130 s += t.ti_sec;
131 s *= 1000;
132 s += t.ti_hund * 10;
133
134 return s;
135}
136
1b94449f
RS
137static unsigned short
138ibmpc_translate_map[] =
139{
140 /* --------------- 00 to 0f --------------- */
141 0, /* Ctrl Break */
142 0xff1b, /* Escape */
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
236 /* --------------- 70 to 7f --------------- */
237 0xffc6, /* (Alt) F9 */
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
247 /* --------------- 80 to 8f --------------- */
248 '9', '0', '-', '=', /* (Alt) */
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
280 /* --------------- a0 to af --------------- */
281 0xff54, /* (Alt) Down */
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
290/* Get a char from keyboard. Function keys are put into the event queue. */
291static int
292dos_rawgetc ()
293{
294 struct input_event event;
1b94449f
RS
295 union REGS regs;
296 int ctrl_p, alt_p, shift_p;
aee81730 297
1b94449f
RS
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);
9da6e765
RS
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. */
1b94449f
RS
306 alt_p = ((extended_kbd ? (regs.h.ah & 2) : (regs.h.al & 8)) != 0);
307
3ec5651b
RS
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)
1b94449f
RS
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;
9da6e765
RS
326 else if (sc == 0x53 && c != 0xe0)
327 {
aee81730 328 code = 0xffae; /* Keypad decimal point/comma. */
9da6e765
RS
329 goto nonascii;
330 }
1b94449f
RS
331 else if (sc == 0xe0)
332 {
333 switch (c)
334 {
aee81730 335 case 10: /* Ctrl Enter */
1b94449f
RS
336 case 13:
337 sc = 0x1c;
338 break;
1b94449f
RS
339 case '/':
340 sc = 0x35;
341 break;
342 default:
343 sc = 0;
344 };
345 c = 0;
346 }
347
348 if (c == 0
349 || c == ' '
350 || alt_p
351 || (ctrl_p && shift_p)
aee81730
RS
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;
1b94449f
RS
404 }
405
aee81730 406 if (have_mouse > 0)
1b94449f
RS
407 {
408 int but, press, x, y, ok;
409
410 /* Check for mouse movement *before* buttons. */
49a09c76 411 mouse_check_moved ();
1b94449f
RS
412
413 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
414 for (press = 0; press < 2; press++)
415 {
416 if (press)
49a09c76 417 ok = mouse_pressed (but, &x, &y);
1b94449f 418 else
49a09c76 419 ok = mouse_released (but, &x, &y);
1b94449f
RS
420 if (ok)
421 {
422 event.kind = mouse_click;
423 event.code = but;
424 event.modifiers
9da6e765
RS
425 = (shift_p ? shift_modifier : 0)
426 + (ctrl_p ? ctrl_modifier : 0)
427 + (alt_p ? meta_modifier : 0)
428 + (press ? down_modifier : up_modifier);
1b94449f
RS
429 event.x = x;
430 event.y = y;
87485d6f 431 XSETFRAME (event.frame_or_window, selected_frame);
aee81730 432 event.timestamp = event_timestamp ();
1b94449f
RS
433 kbd_buffer_store_event (&event);
434 }
435 }
436 }
437
438 return -1;
439}
440
441static int prev_get_char = -1;
442
443/* Return 1 if a key is ready to be read without suspending execution. */
444dos_keysns ()
445{
446 if (prev_get_char != -1)
447 return 1;
448 else
449 return ((prev_get_char = dos_rawgetc ()) != -1);
450}
451
452/* Read a key. Return -1 if no key is ready. */
453dos_keyread ()
454{
455 if (prev_get_char != -1)
456 {
457 int c = prev_get_char;
458 prev_get_char = -1;
459 return c;
460 }
461 else
462 return dos_rawgetc ();
463}
464
465/* Hostnames for a pc are not really funny, but they are used in change log
466 so we emulate the best we can. */
467gethostname (p, size)
468 char *p;
469 int size;
470{
471 char *q = egetenv ("HOSTNAME");
472
473 if (!q) q = "pc";
474 strcpy (p, q);
475 return 0;
476}
477
478/* Destructively turn backslashes into slashes. */
479void
480dostounix_filename (p)
481 register char *p;
482{
483 while (*p)
484 {
485 if (*p == '\\')
486 *p = '/';
487 p++;
488 }
489}
490
491/* Destructively turn slashes into backslashes. */
492void
493unixtodos_filename (p)
494 register char *p;
495{
496 while (*p)
497 {
498 if (*p == '/')
499 *p = '\\';
500 p++;
501 }
502}
503
504/* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
505int
506getdefdir (drive, dst)
507 int drive;
508 char *dst;
509{
510 union REGS regs;
511
512 *dst++ = '/';
513 regs.h.dl = drive;
514 regs.x.si = (int) dst;
515 regs.h.ah = 0x47;
516 intdos (&regs, &regs);
517 return !regs.x.cflag;
518}
519
520/* Remove all CR's that are followed by a LF. */
521int
522crlf_to_lf (n, buf)
523 register int n;
524 register unsigned char *buf;
525{
526 unsigned char *np = buf;
527 unsigned char *startp = buf;
528 unsigned char *endp = buf + n;
529 unsigned char c;
530
531 if (n == 0)
532 return n;
3d4ad6e0 533 while (buf < endp - 1)
1b94449f
RS
534 {
535 if (*buf == 0x0d)
536 {
537 if (*(++buf) != 0x0a)
538 *np++ = 0x0d;
539 }
540 else
541 *np++ = *buf++;
542 }
3d4ad6e0
RS
543 if (buf < endp)
544 *np++ = *buf++;
1b94449f
RS
545 return np - startp;
546}
547
548
549/* Run command as specified by ARGV in directory DIR.
550 The command is run with input from TEMPIN and output to file TEMPOUT. */
551int
552run_msdos_command (argv, dir, tempin, tempout)
553 unsigned char **argv;
554 Lisp_Object dir;
555 int tempin, tempout;
556{
557 char *saveargv1, *saveargv2, **envv;
558 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
559 int msshell, result = -1;
560 int in, out, inbak, outbak, errbak;
aee81730 561 int x, y;
1b94449f
RS
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];
647c32eb 573 saveargv2 = argv[2];
1b94449f
RS
574 argv[1] = "/c";
575 if (argv[2])
576 {
647c32eb
KH
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++;
1b94449f
RS
587 }
588 }
589
590 /* Build the environment array. */
591 {
592 extern Lisp_Object Vprocess_environment;
091d0bdf
KH
593 Lisp_Object tmp, lst;
594 int i, len;
595
596 lst = Vprocess_environment;
597 len = XFASTINT (Flength (lst));
1b94449f
RS
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
30d0f552 611 if (STRINGP (dir))
1b94449f
RS
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. */
aee81730
RS
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
1b94449f
RS
626 dup2 (tempin, 0);
627 dup2 (tempout, 1);
628 dup2 (tempout, 2);
aee81730 629
1b94449f 630 result = spawnve (P_WAIT, argv[0], argv, envv);
aee81730 631
1b94449f
RS
632 dup2 (inbak, 0);
633 dup2 (outbak, 1);
634 dup2 (errbak, 2);
aee81730
RS
635 close (inbak);
636 close (outbak);
637 close (errbak);
638
639 dos_ttraw();
640 if (have_mouse > 0) {
641 mouse_init ();
642 mouse_moveto (x, y);
643 }
644
1b94449f
RS
645 done:
646 chdir (oldwd);
647 if (msshell)
648 {
649 argv[1] = saveargv1;
647c32eb 650 argv[2] = saveargv2;
1b94449f
RS
651 }
652 return result;
653}
654
655
656croak (badfunc)
657 char *badfunc;
658{
659 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
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
676#ifdef chdir
677#undef chdir
678#endif
679
680int
681sys_chdir (path)
682 const char* path;
683{
684 int len = strlen (path);
aee81730 685 char *tmp = (char *)path;
1b94449f
RS
686 /* Gotta do this extern here due to the corresponding #define: */
687 extern int chdir ();
688
aee81730
RS
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 }
1b94449f
RS
704 return chdir (tmp);
705}
706
aee81730
RS
707#ifndef HAVE_SELECT
708#include "sysselect.h"
709
710/* Only event queue is checked. */
711int
712sys_select (nfds, rfds, wfds, efds, timeout)
713 int nfds;
714 SELECT_TYPE *rfds, *wfds, *efds;
715 EMACS_TIME *timeout;
1b94449f 716{
aee81730
RS
717 SELECT_TYPE orfds;
718 long timeoutval, clnow, cllast;
719 struct time t;
1b94449f 720
aee81730
RS
721 FD_ZERO (&orfds);
722 if (rfds)
723 {
724 orfds = *rfds;
725 FD_ZERO (rfds);
726 }
727 if (wfds)
728 FD_ZERO (wfds);
729 if (efds)
730 FD_ZERO (efds);
1b94449f 731
aee81730
RS
732 if (nfds != 1 || !FD_ISSET (0, &orfds))
733 abort ();
734
735 /* If we are looking only for the terminal, with no timeout,
736 just read it and wait -- that's more efficient. */
737 if (!timeout)
1b94449f 738 {
aee81730 739 while (! detect_input_pending ());
1b94449f 740 }
aee81730
RS
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
747 while (!detect_input_pending ())
748 {
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;
1b94449f 763}
aee81730 764#endif
1b94449f 765
88b28483
RS
766/* The Emacs root directory as determined by init_environment. */
767static char emacsroot[MAXPATHLEN];
768
769char *
770rootrelativepath (rel)
771 char *rel;
772{
773 static char result[MAXPATHLEN + 10];
774
775 strcpy (result, emacsroot);
776 strcat (result, "/");
777 strcat (result, rel);
778 return result;
779}
780
1b94449f
RS
781/* Define a lot of environment variables if not already defined. Don't
782 remove anything unless you know what you're doing -- lots of code will
783 break if one or more of these are missing. */
784void
785init_environment (argc, argv, skip_args)
786 int argc;
787 char **argv;
788 int skip_args;
789{
88b28483
RS
790 char *s, *t, *root;
791 int len;
792
793 /* Find our root from argv[0]. Assuming argv[0] is, say,
794 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
872e2c82
RS
795 root = alloca (MAXPATHLEN + 20);
796 _fixpath (argv[0], root);
87485d6f
MW
797 strlwr (root);
798 len = strlen (root);
88b28483
RS
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';
1b94449f 804 else
88b28483
RS
805 strcpy (root, "c:/emacs"); /* Only under debuggers, I think. */
806 len = strlen (root);
807 strcpy (emacsroot, root);
808
809 /* We default HOME to our root. */
810 setenv ("HOME", root, 0);
811
812 /* We default EMACSPATH to root + "/bin". */
813 strcpy (root + len, "/bin");
814 setenv ("EMACSPATH", root, 0);
1b94449f
RS
815
816 /* I don't expect anybody to ever use other terminals so the internal
817 terminal is the default. */
818 setenv ("TERM", "internal", 0);
819
87485d6f
MW
820#ifdef HAVE_X_WINDOWS
821 /* Emacs expects DISPLAY to be set. */
822 setenv ("DISPLAY", "unix:0.0", 0);
823#endif
824
1b94449f
RS
825 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
826 downcase it and mirror the backslashes. */
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
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
846 /* In some sense all dos users have root privileges, so... */
847 setenv ("USER", "root", 0);
848 setenv ("NAME", getenv ("USER"), 0);
849
850 /* Time zone determined from country code. To make this possible, the
851 country code may not span more than one time zone. In other words,
852 in the USA, you lose. */
853 switch (dos_country_code)
854 {
855 case 31: /* Belgium */
856 case 32: /* The Netherlands */
857 case 33: /* France */
858 case 34: /* Spain */
859 case 36: /* Hungary */
860 case 38: /* Yugoslavia (or what's left of it?) */
861 case 39: /* Italy */
862 case 41: /* Switzerland */
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 }
1b94449f
RS
888}
889
890/* Flash the screen as a substitute for BEEPs. */
891
49a09c76 892static void
fcea9cd4 893do_visible_bell (xorattr)
1b94449f
RS
894 unsigned char xorattr;
895{
49a09c76 896 asm volatile
ca986694 897 (" movb $1,%%dl
1b94449f 898visible_bell_0:
ca986694 899 movl _ScreenPrimary,%%eax
49a09c76 900 call dosmemsetup
ca986694
RS
901 movl %%eax,%%ebx
902 movl %1,%%ecx
903 movb %0,%%al
904 incl %%ebx
1b94449f 905visible_bell_1:
ca986694
RS
906 xorb %%al,%%gs:(%%ebx)
907 addl $2,%%ebx
908 decl %%ecx
49a09c76 909 jne visible_bell_1
ca986694 910 decb %%dl
49a09c76 911 jne visible_bell_3
1b94449f 912visible_bell_2:
ca986694
RS
913 movzwl %%ax,%%eax
914 movzwl %%ax,%%eax
915 movzwl %%ax,%%eax
916 movzwl %%ax,%%eax
917 decw %%cx
49a09c76
RS
918 jne visible_bell_2
919 jmp visible_bell_0
ca986694
RS
920visible_bell_3:"
921 : /* no output */
922 : "m" (xorattr), "g" (ScreenCols () * ScreenRows ())
923 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
1b94449f
RS
924}
925
09e2ac30
RS
926/* At screen position (X,Y), output C characters from string S with
927 attribute A. Do it fast! */
928
929static void
930output_string (x, y, s, c, a)
931 int x, y, c;
932 unsigned char *s;
933 unsigned char a;
934{
935 char *t = (char *)ScreenPrimary + 2 * (x + ScreenCols () * y);
aee81730
RS
936#ifdef DO_TERMSCRIPT
937 if (termscript)
938 {
939 fprintf (termscript, "<%d@%dx%d>", c, x, y);
940 fwrite (s, sizeof (unsigned char), c, termscript);
941 }
942#endif
09e2ac30
RS
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"
aee81730 957 : /* no output */
09e2ac30 958 : "m" (a), "g" (t), "g" (c), "g" (s)
aee81730 959 : "%eax", "%ecx", /* "%gs",*/ "%esi", "%edi");
09e2ac30
RS
960}
961
1b94449f 962static int internal_terminal = 0;
87485d6f
MW
963static int highlight;
964
1b94449f
RS
965#undef fflush
966
aee81730
RS
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
1062 esc_count = 0;
1063 return used;
1064}
1065
1b94449f
RS
1066int
1067internal_flush (f)
1068 FILE *f;
1069{
1070 static int x;
1071 static int y;
aee81730 1072 static int resume_esc = 0;
09e2ac30 1073 unsigned char *cp, *cp0;
aee81730 1074 int count, i;
1b94449f 1075
aee81730 1076 if (!internal_terminal || f != stdout)
1b94449f 1077 {
aee81730
RS
1078 /* This is a call to the original fflush. */
1079 fflush (f);
1080 return;
1081 }
1082
1083 mouse_off ();
1084 cp = stdout->_base;
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
1092 if (resume_esc)
1093 {
1094 i = flush_escape (1, cp, count, &x, &y);
1095 if (i < 0)
1096 count = 0;
1097 else
1b94449f 1098 {
aee81730
RS
1099 resume_esc = 0;
1100 count -= i;
1101 cp += i;
1102 }
1103 }
1104
1105 while (count > 0)
1106 {
1107 switch (*cp++)
1108 {
1109 case 27:
1110 i = flush_escape (0, cp, count, &x, &y);
1111 if (i < 0)
1b94449f 1112 {
aee81730
RS
1113 resume_esc = 1;
1114 count = 0;
1b94449f 1115 }
aee81730
RS
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);
1b94449f 1145 }
1b94449f 1146 }
aee81730
RS
1147 fpurge (stdout);
1148 ScreenSetCursor (y, x);
1149 mouse_on ();
1b94449f
RS
1150}
1151
87485d6f
MW
1152#ifndef HAVE_X_WINDOWS
1153static void
1154rien_du_tout ()
1155{
1156 /* Rien du tout, cela va sans dire! */
1157}
1158
1159static
1160IT_ring_bell ()
1161{
1162 if (visible_bell)
1163 {
1164 /* This creates an xor-mask that will swap the default fore- and
1165 background colors. */
aee81730 1166 mouse_off ();
87485d6f
MW
1167 do_visible_bell (((the_only_x_display.foreground_pixel
1168 ^ the_only_x_display.background_pixel)
1169 * 0x11) & 0x7f);
aee81730 1170 mouse_on ();
87485d6f
MW
1171 }
1172 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);
1176}
1177
1178static void
1179IT_set_face (int face)
1180{
1181 struct face *fp;
1182 extern struct face *intern_face (/* FRAME_PTR, struct face * */);
1183
1184 if (face == 1 || (face == 0 && highlight))
1185 fp = FRAME_MODE_LINE_FACE (foo);
1186 else if (face <= 0 || face >= FRAME_N_COMPUTED_FACES (foo))
1187 fp = FRAME_DEFAULT_FACE (foo);
1188 else
1189 fp = intern_face (selected_frame, FRAME_COMPUTED_FACES (foo)[face]);
aee81730
RS
1190#ifdef DO_TERMSCRIPT
1191 if (termscript)
1192 fprintf (termscript, "<FACE:%d:%d>", FACE_FOREGROUND (fp), FACE_BACKGROUND (fp));
1193#endif
87485d6f
MW
1194 putchar ('\e');
1195 putchar ('A');
1196 putchar ((FACE_BACKGROUND (fp) << 4) | FACE_FOREGROUND (fp));
1197}
1198
1199static
1200IT_write_glyphs (GLYPH *str, int len)
1201{
1202 int face = -1;
1203 int newface;
aee81730
RS
1204 int ch;
1205
87485d6f
MW
1206 while (len > 0)
1207 {
1208 newface = FAST_GLYPH_FACE (*str);
1209 if (newface != face)
1210 IT_set_face ((face = newface));
aee81730
RS
1211 ch = FAST_GLYPH_CHAR (*str);
1212#ifdef DO_TERMSCRIPT
1213 if (termscript)
1214 fputc (ch, termscript);
1215#endif
1216 if (ch == '\e') putchar (ch); /* allow esc to be printed */
1217 putchar (ch);
87485d6f
MW
1218 str++, len--;
1219 }
1220}
1221
1222static
1223IT_clear_end_of_line (first_unused)
1224{
aee81730
RS
1225 IT_set_face (0);
1226#ifdef DO_TERMSCRIPT
1227 if (termscript)
1228 fprintf (termscript, "<CLR:EOL>");
1229#endif
87485d6f
MW
1230 putchar ('\e');
1231 putchar ('E');
1232}
1233
1234static
1235IT_cursor_to (int y, int x)
1236{
aee81730
RS
1237#ifdef DO_TERMSCRIPT
1238 if (termscript)
1239 fprintf (termscript, "\n<XY=%dx%d>", x, y);
1240#endif
87485d6f
MW
1241 putchar ('\e');
1242 putchar ('@');
1243 putchar (y);
1244 putchar (x);
1245}
1246
1247IT_reassert_line_highlight (new, vpos)
1248 int new, vpos;
1249{
1250 highlight = new;
1251 IT_set_face (0); /* To possibly clear the highlighting. */
1252}
1253
1254static
1255IT_change_line_highlight (new_highlight, vpos, first_unused_hpos)
1256{
1257 highlight = new_highlight;
1258 IT_set_face (0); /* To possibly clear the highlighting. */
1259 IT_cursor_to (vpos, 0);
1260 IT_clear_end_of_line (first_unused_hpos);
1261}
1262
1263static
1264IT_update_begin ()
1265{
1266 highlight = 0;
1267 IT_set_face (0); /* To possibly clear the highlighting. */
1268}
1269
1270/* This was more or less copied from xterm.c */
1271static void
1272IT_set_menu_bar_lines (window, n)
1273 Lisp_Object window;
1274 int n;
1275{
1276 struct window *w = XWINDOW (window);
1277
1278 XSETFASTINT (w->top, XFASTINT (w->top) + n);
1279 XSETFASTINT (w->height, XFASTINT (w->height) - n);
1280
1281 /* Handle just the top child in a vertical split. */
1282 if (!NILP (w->vchild))
1283 IT_set_menu_bar_lines (w->vchild, n);
1284
1285 /* Adjust all children in a horizontal split. */
1286 for (window = w->hchild; !NILP (window); window = w->next)
1287 {
1288 w = XWINDOW (window);
1289 IT_set_menu_bar_lines (window, n);
1290 }
1291}
1292
1293void
1294IT_set_frame_parameters (frame, alist)
1295 FRAME_PTR frame;
1296 Lisp_Object alist;
1297{
1298 Lisp_Object tail;
1299 int redraw;
1300 extern unsigned long load_color ();
1301 FRAME_PTR f = (FRAME_PTR) &the_only_frame;
1302
1303 redraw = 0;
1304 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
1305 {
1306 Lisp_Object elt, prop, val;
1307
1308 elt = Fcar (tail);
1309 prop = Fcar (elt);
1310 val = Fcdr (elt);
1311 CHECK_SYMBOL (prop, 1);
1312
1313 if (EQ (prop, intern ("foreground-color")))
1314 {
1315 unsigned long new_color = load_color (f, val);
1316 if (new_color != ~0)
1317 {
1318 FRAME_FOREGROUND_PIXEL (f) = new_color;
1319 redraw = 1;
1320 }
1321 }
1322 else if (EQ (prop, intern ("background-color")))
1323 {
1324 unsigned long new_color = load_color (f, val);
1325 if (new_color != ~0)
1326 {
1327 FRAME_BACKGROUND_PIXEL (f) = new_color & ~8;
1328 redraw = 1;
1329 }
1330 }
1331 else if (EQ (prop, intern ("menu-bar-lines")))
1332 {
1333 int new;
1334 int old = FRAME_MENU_BAR_LINES (the_only_frame);
1335
1336 if (INTEGERP (val))
1337 new = XINT (val);
1338 else
1339 new = 0;
1340 FRAME_MENU_BAR_LINES (f) = new;
1341 IT_set_menu_bar_lines (the_only_frame.root_window, new - old);
1342 }
1343 }
1344
1345 if (redraw)
1346 {
1347 recompute_basic_faces (f);
1348 Fredraw_frame (Fselected_frame ());
1349 }
1350}
1351
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 */
1359
1b94449f
RS
1360/* Do we need the internal terminal? */
1361void
1362internal_terminal_init ()
1363{
1364 char *term = getenv ("TERM");
aee81730
RS
1365 char *colors;
1366
87485d6f
MW
1367#ifdef HAVE_X_WINDOWS
1368 if (!inhibit_window_system)
1369 return;
1370#endif
1371
1b94449f
RS
1372 internal_terminal
1373 = (!noninteractive) && term && !strcmp (term, "internal");
87485d6f
MW
1374
1375#ifndef HAVE_X_WINDOWS
1376 if (internal_terminal && !inhibit_window_system)
1377 {
1378 Vwindow_system = intern ("pc");
1379 Vwindow_system_version = make_number (1);
1380
1381 bzero (&the_only_x_display, sizeof the_only_x_display);
1382 the_only_x_display.background_pixel = 7; /* White */
1383 the_only_x_display.foreground_pixel = 0; /* Black */
aee81730
RS
1384 colors = getenv ("EMACSCOLORS");
1385 if (colors && strlen (colors) >=2)
1386 {
1387 the_only_x_display.foreground_pixel = colors[0] & 0x07;
1388 the_only_x_display.background_pixel = colors[1] & 0x07;
1389 }
87485d6f
MW
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 }
1411 else
1412 the_only_frame.output_method = output_termcap;
1413#endif
1b94449f 1414}
b278e52a
RS
1415\f
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
70b13a6c
PE
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;
b278e52a
RS
1422
1423int
1424gettimeofday (struct timeval *tp, struct timezone *tzp)
1425{
1426 if (tp)
1427 {
1428 struct time t;
70b13a6c
PE
1429 struct date d;
1430 struct tm tmrec;
b278e52a
RS
1431
1432 gettime (&t);
70b13a6c
PE
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);
b278e52a 1445 }
ccc4fdaa 1446 /* Ignore tzp; it's obsolescent. */
b278e52a
RS
1447 return 0;
1448}
70b13a6c
PE
1449
1450void
1451init_gettimeofday ()
1452{
1453 time_t ltm, gtm;
1454 struct tm *lstm;
1455#undef tzset
1456 extern void tzset (void);
1457
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}
b278e52a 1467\f
1b94449f
RS
1468/* These must be global. */
1469static _go32_dpmi_seginfo ctrl_break_vector;
1470static _go32_dpmi_registers ctrl_break_regs;
1471static int ctrlbreakinstalled = 0;
1472
1473/* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
1474void
1475ctrl_break_func (regs)
1476 _go32_dpmi_registers *regs;
1477{
1478 Vquit_flag = Qt;
1479}
1480
1481void
1482install_ctrl_break_check ()
1483{
1484 if (!ctrlbreakinstalled)
1485 {
1486 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
ca986694 1487 was compiler with Djgpp 1.11 maintenance level 5 or later! */
1b94449f
RS
1488 ctrlbreakinstalled = 1;
1489 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
1490 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
1491 &ctrl_break_regs);
1492 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
1493 }
1494}
1495\f
87485d6f
MW
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. */
1b94449f
RS
1499
1500static int mouse_button_translate[NUM_MOUSE_BUTTONS];
1501static int mouse_button_count;
1502
1503void
1504mouse_init ()
1505{
1506 union REGS regs;
1507
1508 regs.x.ax = 0x0007;
1509 regs.x.cx = 0;
1510 regs.x.dx = 8 * (ScreenCols () - 1);
1511 int86 (0x33, &regs, &regs);
1512
1513 regs.x.ax = 0x0008;
1514 regs.x.cx = 0;
1515 regs.x.dx = 8 * (ScreenRows () - 1);
1516 int86 (0x33, &regs, &regs);
1517
1518 mouse_moveto (ScreenCols () - 1, ScreenRows () - 1);
1519 mouse_on ();
1520}
1521
1522void
1523mouse_on ()
1524{
1525 union REGS regs;
1526
aee81730
RS
1527 if (have_mouse > 0)
1528 {
1529 regs.x.ax = 0x0001;
1530 int86 (0x33, &regs, &regs);
1531 }
1b94449f
RS
1532}
1533
1534void
1535mouse_off ()
1536{
1537 union REGS regs;
1538
aee81730
RS
1539 if (have_mouse > 0)
1540 {
1541 regs.x.ax = 0x0002;
1542 int86 (0x33, &regs, &regs);
1543 }
1b94449f
RS
1544}
1545
1546void
1547mouse_moveto (x, y)
1548 int x, y;
1549{
1550 union REGS regs;
1551
1552 regs.x.ax = 0x0004;
1553 mouse_last_x = regs.x.cx = x * 8;
1554 mouse_last_y = regs.x.dx = y * 8;
1555 int86 (0x33, &regs, &regs);
1556}
1557
1558int
1559mouse_pressed (b, xp, yp)
1560 int b, *xp, *yp;
1561{
1562 union REGS regs;
1563
1564 if (b >= mouse_button_count)
1565 return 0;
1566 regs.x.ax = 0x0005;
1567 regs.x.bx = mouse_button_translate[b];
1568 int86 (0x33, &regs, &regs);
1569 if (regs.x.bx)
ca986694 1570 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
1b94449f
RS
1571 return (regs.x.bx != 0);
1572}
1573
1574int
1575mouse_released (b, xp, yp)
1576 int b, *xp, *yp;
1577{
1578 union REGS regs;
1579
1580 if (b >= mouse_button_count)
1581 return 0;
1582 regs.x.ax = 0x0006;
1583 regs.x.bx = mouse_button_translate[b];
1584 int86 (0x33, &regs, &regs);
aee81730
RS
1585#if 0
1586 if (regs.x.ax & (1 << mouse_button_translate[b]))
1587 regs.x.bx = 0; /* if mouse is still pressed, ignore release */
1588#endif
1b94449f
RS
1589 if (regs.x.bx)
1590 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
1591 return (regs.x.bx != 0);
1592}
1593
87485d6f
MW
1594static void
1595mouse_get_xy (int *x, int *y)
1596{
1597 union REGS regs;
1598
1599 regs.x.ax = 0x0003;
1600 int86 (0x33, &regs, &regs);
1601 *x = regs.x.cx / 8;
1602 *y = regs.x.dx / 8;
1603}
1604
1b94449f 1605void
fadfaf55 1606mouse_get_pos (f, insist, bar_window, part, x, y, time)
1b94449f 1607 FRAME_PTR *f;
fadfaf55 1608 int insist;
1b94449f
RS
1609 Lisp_Object *bar_window, *x, *y;
1610 enum scroll_bar_part *part;
1611 unsigned long *time;
1612{
87485d6f 1613 int ix, iy;
1b94449f 1614 union REGS regs;
1b94449f
RS
1615
1616 regs.x.ax = 0x0003;
1617 int86 (0x33, &regs, &regs);
1618 *f = selected_frame;
1619 *bar_window = Qnil;
87485d6f 1620 mouse_get_xy (&ix, &iy);
f2f23562 1621 selected_frame->mouse_moved = 0;
87485d6f
MW
1622 *x = make_number (ix);
1623 *y = make_number (iy);
aee81730 1624 *time = event_timestamp ();
1b94449f
RS
1625}
1626
1627void
1628mouse_check_moved ()
1629{
87485d6f 1630 int x, y;
1b94449f 1631
87485d6f 1632 mouse_get_xy (&x, &y);
f2f23562 1633 selected_frame->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
87485d6f
MW
1634 mouse_last_x = x;
1635 mouse_last_y = y;
1b94449f
RS
1636}
1637
1638int
1639mouse_init1 ()
1640{
1641 union REGS regs;
1642 int present;
1643
87485d6f
MW
1644#ifdef HAVE_X_WINDOWS
1645 if (!inhibit_window_system)
1646 return 0;
1647#endif
e118d5ef
RS
1648 if (!internal_terminal)
1649 return 0;
1650
1b94449f
RS
1651 regs.x.ax = 0x0021;
1652 int86 (0x33, &regs, &regs);
e118d5ef
RS
1653 present = (regs.x.ax & 0xffff) == 0xffff;
1654 if (!present)
1655 {
1656 /* Reportedly, the above doesn't work for some mouse drivers. There
1657 is an additional detection method that should work, but might be
1658 a little slower. Use that as an alternative. */
1659 regs.x.ax = 0x0000;
1660 int86 (0x33, &regs, &regs);
1661 present = (regs.x.ax & 0xffff) == 0xffff;
1662 }
1663
1b94449f
RS
1664 if (present)
1665 {
1666 if (regs.x.bx == 3)
1667 {
1668 mouse_button_count = 3;
1669 mouse_button_translate[0] = 0; /* Left */
1670 mouse_button_translate[1] = 2; /* Middle */
1671 mouse_button_translate[2] = 1; /* Right */
1672 }
1673 else
1674 {
1675 mouse_button_count = 2;
1676 mouse_button_translate[0] = 0;
1677 mouse_button_translate[1] = 1;
1678 }
1679 mouse_position_hook = &mouse_get_pos;
1680 mouse_init ();
aee81730 1681 }
1b94449f
RS
1682 return present;
1683}
1684
87485d6f 1685#ifndef HAVE_X_WINDOWS
49a09c76
RS
1686/* See xterm.c for more info. */
1687void
1688pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
1689 FRAME_PTR f;
1690 register int pix_x, pix_y;
1691 register int *x, *y;
1692 void /* XRectangle */ *bounds;
1693 int noclip;
1694{
1695 if (bounds) abort ();
1696
1697 /* Ignore clipping. */
1698
1699 *x = pix_x;
1700 *y = pix_y;
1701}
1702
1703void
1704glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1705 FRAME_PTR f;
1706 register int x, y;
1707 register int *pix_x, *pix_y;
1708{
1709 *pix_x = x;
1710 *pix_y = y;
1711}
87485d6f
MW
1712\f
1713/* Simulation of X's menus. Nothing too fancy here -- just make it work
1714 for now.
1715
1716 Actually, I don't know the meaning of all the parameters of the functions
1717 here -- I only know how they are called by xmenu.c. I could of course
1718 grab the nearest Xlib manual (down the hall, second-to-last door on the
1719 left), but I don't think it's worth the effort. */
1720
1721static XMenu *
1722IT_menu_create ()
1723{
1724 XMenu *menu;
1725
1726 menu = (XMenu *) xmalloc (sizeof (XMenu));
1727 menu->allocated = menu->count = menu->panecount = menu->width = 0;
1728 return menu;
1729}
1730
1731/* Allocate some (more) memory for MENU ensuring that there is room for one
1732 for item. */
aee81730 1733
87485d6f
MW
1734static void
1735IT_menu_make_room (XMenu *menu)
1736{
1737 if (menu->allocated == 0)
1738 {
1739 int count = menu->allocated = 10;
1740 menu->text = (char **) xmalloc (count * sizeof (char *));
1741 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
1742 menu->panenumber = (int *) xmalloc (count * sizeof (int));
1743 }
1744 else if (menu->allocated == menu->count)
1745 {
1746 int count = menu->allocated = menu->allocated + 10;
1747 menu->text
1748 = (char **) xrealloc (menu->text, count * sizeof (char *));
1749 menu->submenu
1750 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
1751 menu->panenumber
1752 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
1753 }
1754}
1755
1756/* Search the given menu structure for a given pane number. */
aee81730 1757
87485d6f
MW
1758static XMenu *
1759IT_menu_search_pane (XMenu *menu, int pane)
1760{
1761 int i;
1762 XMenu *try;
1763
1764 for (i = 0; i < menu->count; i++)
1765 if (menu->submenu[i])
aee81730
RS
1766 {
1767 if (pane == menu->panenumber[i])
1768 return menu->submenu[i];
1769 else if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
87485d6f 1770 return try;
aee81730 1771 }
87485d6f
MW
1772 return (XMenu *) 0;
1773}
1774
1775/* Determine how much screen space a given menu needs. */
aee81730 1776
87485d6f
MW
1777static void
1778IT_menu_calc_size (XMenu *menu, int *width, int *height)
1779{
1780 int i, h2, w2, maxsubwidth, maxheight;
1781
1782 maxsubwidth = 0;
1783 maxheight = menu->count;
1784 for (i = 0; i < menu->count; i++)
1785 {
1786 if (menu->submenu[i])
1787 {
1788 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
1789 if (w2 > maxsubwidth) maxsubwidth = w2;
1790 if (i + h2 > maxheight) maxheight = i + h2;
1791 }
1792 }
1793 *width = menu->width + maxsubwidth;
1794 *height = maxheight;
1795}
1796
1797/* Display MENU at (X,Y) using FACES. */
aee81730 1798
87485d6f
MW
1799static void
1800IT_menu_display (XMenu *menu, int y, int x, int *faces)
1801{
1802 int i, j, face, width;
1803 GLYPH *text, *p;
1804 char *q;
1805 int mx, my;
1806 int enabled, mousehere;
1807 int row, col;
1808
1809 width = menu->width;
1810 text = (GLYPH *) xmalloc ((width + 2) * sizeof (GLYPH));
1811 ScreenGetCursor (&row, &col);
1812 mouse_get_xy (&mx, &my);
1813 mouse_off ();
1814 (*update_begin_hook) ();
1815 for (i = 0; i < menu->count; i++)
1816 {
1817 (*cursor_to_hook) (y + i, x);
1818 enabled
1819 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
1820 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
1821 face = faces[enabled + mousehere * 2];
1822 p = text;
1823 *p++ = FAST_MAKE_GLYPH (' ', face);
1824 for (j = 0, q = menu->text[i]; *q; j++)
1825 *p++ = FAST_MAKE_GLYPH (*q++, face);
1826 for (; j < width; j++)
1827 *p++ = FAST_MAKE_GLYPH (' ', face);
1828 *p++ = FAST_MAKE_GLYPH (menu->submenu[i] ? 16 : ' ', face);
1829 (*write_glyphs_hook) (text, width + 2);
1830 }
1831 internal_flush (stdout);
1832 (*update_end_hook) ();
1833 mouse_on ();
1834 ScreenSetCursor (row, col);
1835 xfree (text);
1836}
1837
1838/* Create a brand new menu structure. */
aee81730 1839
87485d6f 1840XMenu *
1189e5a2 1841XMenuCreate (Display *foo1, Window foo2, char *foo3)
87485d6f
MW
1842{
1843 return IT_menu_create ();
1844}
1845
1846/* Create a new pane and place it on the outer-most level. It is not
1847 clear that it should be placed out there, but I don't know what else
1848 to do. */
aee81730 1849
87485d6f 1850int
1189e5a2 1851XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
87485d6f
MW
1852{
1853 int len;
1854
1855 if (!enable)
1856 abort ();
1857
1858 IT_menu_make_room (menu);
1859 menu->submenu[menu->count] = IT_menu_create ();
1860 menu->text[menu->count] = txt;
1861 menu->panenumber[menu->count] = ++menu->panecount;
1862 menu->count++;
aee81730
RS
1863 if ((len = strlen (txt)) > menu->width)
1864 menu->width = len;
87485d6f
MW
1865 return menu->panecount;
1866}
1867
1868/* Create a new item in a menu pane. */
aee81730 1869
87485d6f 1870int
1189e5a2
RS
1871XMenuAddSelection (Display *bar, XMenu *menu, int pane,
1872 int foo, char *txt, int enable)
87485d6f
MW
1873{
1874 int len;
1875
1876 if (pane)
1877 if (!(menu = IT_menu_search_pane (menu, pane)))
1878 return XM_FAILURE;
1879 IT_menu_make_room (menu);
1880 menu->submenu[menu->count] = (XMenu *) 0;
1881 menu->text[menu->count] = txt;
1882 menu->panenumber[menu->count] = enable;
1883 menu->count++;
aee81730
RS
1884 if ((len = strlen (txt)) > menu->width)
1885 menu->width = len;
87485d6f
MW
1886 return XM_SUCCESS;
1887}
1888
1889/* Decide where the menu would be placed if requested at (X,Y). */
aee81730 1890
1189e5a2
RS
1891void
1892XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
87485d6f
MW
1893 int *ulx, int *uly, int *width, int *height)
1894{
1895 if (menu->count == 1 && menu->submenu[0])
1896 /* Special case: the menu consists of only one pane. */
1897 IT_menu_calc_size (menu->submenu[0], width, height);
1898 else
1899 IT_menu_calc_size (menu, width, height);
1900 *ulx = x + 1;
1901 *uly = y;
1902 *width += 2;
1903}
1904
aee81730 1905struct IT_menu_state
87485d6f
MW
1906{
1907 void *screen_behind;
1908 XMenu *menu;
1909 int pane;
1910 int x, y;
aee81730 1911};
87485d6f
MW
1912
1913
1914/* Display menu, wait for user's response, and return that response. */
aee81730 1915
87485d6f 1916int
1189e5a2 1917XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
87485d6f
MW
1918 int x0, int y0, unsigned ButtonMask, char **txt)
1919{
aee81730 1920 struct IT_menu_state *state;
87485d6f
MW
1921 int statecount;
1922 int x, y, i, b;
1923 int screensize;
1924 int faces[4], selectface;
1925 int leave, result, onepane;
1926
1927 /* Just in case we got here without a mouse present... */
aee81730 1928 if (have_mouse <= 0)
87485d6f
MW
1929 return XM_IA_SELECT;
1930
aee81730 1931 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
87485d6f
MW
1932 screensize = ScreenRows () * ScreenCols () * 2;
1933 faces[0]
1934 = compute_glyph_face (&the_only_frame,
1935 face_name_id_number
1936 (&the_only_frame,
1937 intern ("msdos-menu-passive-face")),
1938 0);
1939 faces[1]
1940 = compute_glyph_face (&the_only_frame,
1941 face_name_id_number
1942 (&the_only_frame,
1943 intern ("msdos-menu-active-face")),
1944 0);
1945 selectface
1946 = face_name_id_number (&the_only_frame, intern ("msdos-menu-select-face"));
1947 faces[2] = compute_glyph_face (&the_only_frame, selectface, faces[0]);
1948 faces[3] = compute_glyph_face (&the_only_frame, selectface, faces[1]);
1949
1950 statecount = 1;
1951 state[0].menu = menu;
1952 mouse_off ();
1953 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
1954 mouse_on ();
1955 if ((onepane = menu->count == 1 && menu->submenu[0]))
1956 {
1957 menu->width = menu->submenu[0]->width;
1958 state[0].menu = menu->submenu[0];
1959 }
1960 else
1961 {
1962 state[0].menu = menu;
1963 }
1964 state[0].x = x0 - 1;
1965 state[0].y = y0;
1966 state[0].pane = onepane;
1967
1968 mouse_last_x = -1; /* A hack that forces display. */
1969 leave = 0;
1970 while (!leave)
1971 {
1972 mouse_check_moved ();
f2f23562 1973 if (selected_frame->mouse_moved)
87485d6f 1974 {
f2f23562 1975 selected_frame->mouse_moved = 0;
87485d6f
MW
1976 result = XM_IA_SELECT;
1977 mouse_get_xy (&x, &y);
1978 for (i = 0; i < statecount; i++)
1979 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
1980 {
1981 int dy = y - state[i].y;
1982 if (0 <= dy && dy < state[i].menu->count)
1983 {
1984 if (!state[i].menu->submenu[dy])
1985 if (state[i].menu->panenumber[dy])
1986 result = XM_SUCCESS;
1987 else
1988 result = XM_IA_SELECT;
1989 *pane = state[i].pane - 1;
1990 *selidx = dy;
1991 /* We hit some part of a menu, so drop extra menues that
1992 have been opened. That does not include an open and
1993 active submenu. */
1994 if (i != statecount - 2
1995 || state[i].menu->submenu[dy] != state[i+1].menu)
1996 while (i != statecount - 1)
1997 {
1998 statecount--;
1999 mouse_off ();
2000 ScreenUpdate (state[statecount].screen_behind);
2001 mouse_on ();
2002 xfree (state[statecount].screen_behind);
2003 }
2004 if (i == statecount - 1 && state[i].menu->submenu[dy])
2005 {
2006 IT_menu_display (state[i].menu,
2007 state[i].y,
2008 state[i].x,
2009 faces);
2010 state[statecount].menu = state[i].menu->submenu[dy];
2011 state[statecount].pane = state[i].menu->panenumber[dy];
2012 mouse_off ();
2013 ScreenRetrieve (state[statecount].screen_behind
2014 = xmalloc (screensize));
2015 mouse_on ();
2016 state[statecount].x
2017 = state[i].x + state[i].menu->width + 2;
2018 state[statecount].y = y;
2019 statecount++;
2020 }
2021 }
2022 }
2023 IT_menu_display (state[statecount - 1].menu,
2024 state[statecount - 1].y,
2025 state[statecount - 1].x,
2026 faces);
2027 }
2028 for (b = 0; b < mouse_button_count; b++)
2029 {
2030 (void) mouse_pressed (b, &x, &y);
2031 if (mouse_released (b, &x, &y))
2032 leave = 1;
2033 }
2034 }
2035
2036 mouse_off ();
2037 ScreenUpdate (state[0].screen_behind);
2038 mouse_on ();
2039 while (statecount--)
2040 xfree (state[statecount].screen_behind);
2041 return result;
2042}
2043
2044/* Dispose of a menu. */
aee81730 2045
1189e5a2
RS
2046void
2047XMenuDestroy (Display *foo, XMenu *menu)
87485d6f
MW
2048{
2049 int i;
2050 if (menu->allocated)
2051 {
2052 for (i = 0; i < menu->count; i++)
2053 if (menu->submenu[i])
1189e5a2 2054 XMenuDestroy (foo, menu->submenu[i]);
87485d6f
MW
2055 xfree (menu->text);
2056 xfree (menu->submenu);
2057 xfree (menu->panenumber);
2058 }
2059 xfree (menu);
2060}
2061
aee81730
RS
2062int
2063x_pixel_width (struct frame *f)
87485d6f 2064{
aee81730 2065 return FRAME_WIDTH (f);
87485d6f
MW
2066}
2067
aee81730
RS
2068int
2069x_pixel_height (struct frame *f)
87485d6f 2070{
aee81730 2071 return FRAME_HEIGHT (f);
87485d6f
MW
2072}
2073#endif /* !HAVE_X_WINDOWS */
49a09c76 2074
1b94449f 2075#endif /* MSDOS */