(function-form): Fix spec for
[bpt/emacs.git] / src / msdos.c
1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 1994, 1995, 1996, 1997 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 2, 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, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 /* Contributed by Morten Welinder */
22 /* New display, keyboard, and mouse control by Kim F. Storm */
23
24 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
25
26 #include <config.h>
27
28 #ifdef MSDOS
29 #include "lisp.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/param.h>
33 #include <sys/time.h>
34 #include <dos.h>
35 #include <errno.h>
36 #include <string.h> /* for bzero and string functions */
37 #include <sys/stat.h> /* for _fixpath */
38 #include <unistd.h> /* for chdir, dup, dup2, etc. */
39 #if __DJGPP__ >= 2
40 #include <fcntl.h>
41 #include <io.h> /* for setmode */
42 #include <dpmi.h> /* for __dpmi_xxx stuff */
43 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
44 #include <libc/dosio.h> /* for _USE_LFN */
45 #include <conio.h> /* for cputs */
46 #endif
47
48 #include "dosfns.h"
49 #include "msdos.h"
50 #include "systime.h"
51 #include "termhooks.h"
52 #include "dispextern.h"
53 #include "termopts.h"
54 #include "frame.h"
55 #include "window.h"
56 #include "buffer.h"
57 #include "commands.h"
58 #include <go32.h>
59 #include <pc.h>
60 #include <ctype.h>
61 /* #include <process.h> */
62 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
63 #define P_WAIT 1
64
65 #ifndef _USE_LFN
66 #define _USE_LFN 0
67 #endif
68
69 #ifndef _dos_ds
70 #define _dos_ds _go32_info_block.selector_for_linear_memory
71 #endif
72
73 #if __DJGPP__ > 1
74
75 #include <signal.h>
76 #include "syssignal.h"
77
78 #ifndef SYSTEM_MALLOC
79
80 #ifdef GNU_MALLOC
81
82 /* If other `malloc' than ours is used, force our `sbrk' behave like
83 Unix programs expect (resize memory blocks to keep them contiguous).
84 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
85 because that's what `gmalloc' expects to get. */
86 #include <crt0.h>
87
88 #ifdef REL_ALLOC
89 int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
90 #else /* not REL_ALLOC */
91 int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
92 #endif /* not REL_ALLOC */
93 #endif /* GNU_MALLOC */
94
95 #endif /* not SYSTEM_MALLOC */
96 #endif /* __DJGPP__ > 1 */
97
98 static unsigned long
99 event_timestamp ()
100 {
101 struct time t;
102 unsigned long s;
103
104 gettime (&t);
105 s = t.ti_min;
106 s *= 60;
107 s += t.ti_sec;
108 s *= 1000;
109 s += t.ti_hund * 10;
110
111 return s;
112 }
113
114 \f
115 /* ------------------------ Mouse control ---------------------------
116 *
117 * Coordinates are in screen positions and zero based.
118 * Mouse buttons are numbered from left to right and also zero based.
119 */
120
121 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
122 static int mouse_visible;
123
124 static int mouse_last_x;
125 static int mouse_last_y;
126
127 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
128 static int mouse_button_count;
129
130 void
131 mouse_on ()
132 {
133 union REGS regs;
134
135 if (have_mouse > 0 && !mouse_visible)
136 {
137 if (termscript)
138 fprintf (termscript, "<M_ON>");
139 regs.x.ax = 0x0001;
140 int86 (0x33, &regs, &regs);
141 mouse_visible = 1;
142 }
143 }
144
145 void
146 mouse_off ()
147 {
148 union REGS regs;
149
150 if (have_mouse > 0 && mouse_visible)
151 {
152 if (termscript)
153 fprintf (termscript, "<M_OFF>");
154 regs.x.ax = 0x0002;
155 int86 (0x33, &regs, &regs);
156 mouse_visible = 0;
157 }
158 }
159
160 static void
161 mouse_get_xy (int *x, int *y)
162 {
163 union REGS regs;
164
165 regs.x.ax = 0x0003;
166 int86 (0x33, &regs, &regs);
167 *x = regs.x.cx / 8;
168 *y = regs.x.dx / 8;
169 }
170
171 void
172 mouse_moveto (x, y)
173 int x, y;
174 {
175 union REGS regs;
176
177 if (termscript)
178 fprintf (termscript, "<M_XY=%dx%d>", x, y);
179 regs.x.ax = 0x0004;
180 mouse_last_x = regs.x.cx = x * 8;
181 mouse_last_y = regs.x.dx = y * 8;
182 int86 (0x33, &regs, &regs);
183 }
184
185 static int
186 mouse_pressed (b, xp, yp)
187 int b, *xp, *yp;
188 {
189 union REGS regs;
190
191 if (b >= mouse_button_count)
192 return 0;
193 regs.x.ax = 0x0005;
194 regs.x.bx = mouse_button_translate[b];
195 int86 (0x33, &regs, &regs);
196 if (regs.x.bx)
197 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
198 return (regs.x.bx != 0);
199 }
200
201 static int
202 mouse_released (b, xp, yp)
203 int b, *xp, *yp;
204 {
205 union REGS regs;
206
207 if (b >= mouse_button_count)
208 return 0;
209 regs.x.ax = 0x0006;
210 regs.x.bx = mouse_button_translate[b];
211 int86 (0x33, &regs, &regs);
212 if (regs.x.bx)
213 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
214 return (regs.x.bx != 0);
215 }
216
217 static int
218 mouse_button_depressed (b, xp, yp)
219 int b, *xp, *yp;
220 {
221 union REGS regs;
222
223 if (b >= mouse_button_count)
224 return 0;
225 regs.x.ax = 0x0003;
226 int86 (0x33, &regs, &regs);
227 if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
228 {
229 *xp = regs.x.cx / 8;
230 *yp = regs.x.dx / 8;
231 return 1;
232 }
233 return 0;
234 }
235
236 void
237 mouse_get_pos (f, insist, bar_window, part, x, y, time)
238 FRAME_PTR *f;
239 int insist;
240 Lisp_Object *bar_window, *x, *y;
241 enum scroll_bar_part *part;
242 unsigned long *time;
243 {
244 int ix, iy;
245 Lisp_Object frame, tail;
246
247 /* Clear the mouse-moved flag for every frame on this display. */
248 FOR_EACH_FRAME (tail, frame)
249 XFRAME (frame)->mouse_moved = 0;
250
251 *f = selected_frame;
252 *bar_window = Qnil;
253 mouse_get_xy (&ix, &iy);
254 *time = event_timestamp ();
255 *x = make_number (mouse_last_x = ix);
256 *y = make_number (mouse_last_y = iy);
257 }
258
259 static void
260 mouse_check_moved ()
261 {
262 int x, y;
263
264 mouse_get_xy (&x, &y);
265 selected_frame->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
266 mouse_last_x = x;
267 mouse_last_y = y;
268 }
269
270 void
271 mouse_init ()
272 {
273 union REGS regs;
274 int b;
275
276 if (termscript)
277 fprintf (termscript, "<M_INIT>");
278
279 regs.x.ax = 0x0021;
280 int86 (0x33, &regs, &regs);
281
282 /* Reset the mouse last press/release info. It seems that Windows
283 doesn't do that automatically when function 21h is called, which
284 causes Emacs to ``remember'' the click that switched focus to the
285 window just before Emacs was started from that window. */
286 for (b = 0; b < mouse_button_count; b++)
287 {
288 int dummy_x, dummy_y;
289
290 (void) mouse_pressed (b, &dummy_x, &dummy_y);
291 (void) mouse_released (b, &dummy_x, &dummy_y);
292 }
293
294 regs.x.ax = 0x0007;
295 regs.x.cx = 0;
296 regs.x.dx = 8 * (ScreenCols () - 1);
297 int86 (0x33, &regs, &regs);
298
299 regs.x.ax = 0x0008;
300 regs.x.cx = 0;
301 regs.x.dx = 8 * (ScreenRows () - 1);
302 int86 (0x33, &regs, &regs);
303
304 mouse_moveto (0, 0);
305 mouse_visible = 0;
306 }
307 \f
308 /* ------------------------- Screen control ----------------------
309 *
310 */
311
312 static int internal_terminal = 0;
313
314 #ifndef HAVE_X_WINDOWS
315 extern unsigned char ScreenAttrib;
316 static int screen_face;
317 static int highlight;
318
319 static int screen_size_X;
320 static int screen_size_Y;
321 static int screen_size;
322
323 static int current_pos_X;
324 static int current_pos_Y;
325 static int new_pos_X;
326 static int new_pos_Y;
327
328 static void *startup_screen_buffer;
329 static int startup_screen_size_X;
330 static int startup_screen_size_Y;
331 static int startup_pos_X;
332 static int startup_pos_Y;
333 static unsigned char startup_screen_attrib;
334
335 static int term_setup_done;
336
337 /* Similar to the_only_frame. */
338 struct x_output the_only_x_display;
339
340 /* This is never dereferenced. */
341 Display *x_current_display;
342
343 /* Support for DOS/V (allows Japanese characters to be displayed on
344 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
345
346 /* Holds the address of the text-mode screen buffer. */
347 static unsigned long screen_old_address = 0;
348 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
349 static unsigned short screen_virtual_segment = 0;
350 static unsigned short screen_virtual_offset = 0;
351
352 #if __DJGPP__ > 1
353 /* Update the screen from a part of relocated DOS/V screen buffer which
354 begins at OFFSET and includes COUNT characters. */
355 static void
356 dosv_refresh_virtual_screen (int offset, int count)
357 {
358 __dpmi_regs regs;
359
360 if (offset < 0 || count < 0) /* paranoia; illegal values crash DOS/V */
361 return;
362
363 regs.h.ah = 0xff; /* update relocated screen */
364 regs.x.es = screen_virtual_segment;
365 regs.x.di = screen_virtual_offset + offset;
366 regs.x.cx = count;
367 __dpmi_int (0x10, &regs);
368 }
369 #endif
370
371 static
372 dos_direct_output (y, x, buf, len)
373 int y;
374 int x;
375 char *buf;
376 int len;
377 {
378 int t0 = 2 * (x + y * screen_size_X);
379 int t = t0 + (int) ScreenPrimary;
380 int l0 = len;
381
382 #if (__DJGPP__ < 2)
383 while (--len >= 0) {
384 dosmemput (buf++, 1, t);
385 t += 2;
386 }
387 #else
388 /* This is faster. */
389 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
390 _farnspokeb (t, *buf);
391
392 if (screen_virtual_segment)
393 dosv_refresh_virtual_screen (t0, l0);
394 #endif
395 }
396 #endif
397
398 /* Flash the screen as a substitute for BEEPs. */
399
400 #if (__DJGPP__ < 2)
401 static void
402 do_visible_bell (xorattr)
403 unsigned char xorattr;
404 {
405 asm volatile
406 (" movb $1,%%dl
407 visible_bell_0:
408 movl _ScreenPrimary,%%eax
409 call dosmemsetup
410 movl %%eax,%%ebx
411 movl %1,%%ecx
412 movb %0,%%al
413 incl %%ebx
414 visible_bell_1:
415 xorb %%al,%%gs:(%%ebx)
416 addl $2,%%ebx
417 decl %%ecx
418 jne visible_bell_1
419 decb %%dl
420 jne visible_bell_3
421 visible_bell_2:
422 movzwl %%ax,%%eax
423 movzwl %%ax,%%eax
424 movzwl %%ax,%%eax
425 movzwl %%ax,%%eax
426 decw %%cx
427 jne visible_bell_2
428 jmp visible_bell_0
429 visible_bell_3:"
430 : /* no output */
431 : "m" (xorattr), "g" (screen_size)
432 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
433 }
434
435 static void
436 ScreenVisualBell (void)
437 {
438 /* This creates an xor-mask that will swap the default fore- and
439 background colors. */
440 do_visible_bell (((the_only_x_display.foreground_pixel
441 ^ the_only_x_display.background_pixel)
442 * 0x11) & 0x7f);
443 }
444 #endif
445
446 #ifndef HAVE_X_WINDOWS
447
448 static int blink_bit = -1; /* the state of the blink bit at startup */
449
450 /* Enable bright background colors. */
451 static void
452 bright_bg (void)
453 {
454 union REGS regs;
455
456 /* Remember the original state of the blink/bright-background bit.
457 It is stored at 0040:0065h in the BIOS data area. */
458 if (blink_bit == -1)
459 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
460
461 regs.h.bl = 0;
462 regs.x.ax = 0x1003;
463 int86 (0x10, &regs, &regs);
464 }
465
466 /* Disable bright background colors (and enable blinking) if we found
467 the video system in that state at startup. */
468 static void
469 maybe_enable_blinking (void)
470 {
471 if (blink_bit == 1)
472 {
473 union REGS regs;
474
475 regs.h.bl = 1;
476 regs.x.ax = 0x1003;
477 int86 (0x10, &regs, &regs);
478 }
479 }
480
481 /* Set the screen dimensions so that it can show no less than
482 ROWS x COLS frame. */
483
484 void
485 dos_set_window_size (rows, cols)
486 int *rows, *cols;
487 {
488 char video_name[30];
489 Lisp_Object video_mode;
490 int video_mode_value;
491 int have_vga = 0;
492 union REGS regs;
493 int current_rows = ScreenRows (), current_cols = ScreenCols ();
494
495 if (*rows == current_rows && *cols == current_cols)
496 return;
497
498 /* Do we have a VGA? */
499 regs.x.ax = 0x1a00;
500 int86 (0x10, &regs, &regs);
501 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
502 have_vga = 1;
503
504 mouse_off ();
505
506 /* If the user specified a special video mode for these dimensions,
507 use that mode. */
508 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
509 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
510 Qnil))-> value;
511
512 if (INTEGERP (video_mode)
513 && (video_mode_value = XINT (video_mode)) > 0)
514 {
515 regs.x.ax = video_mode_value;
516 int86 (0x10, &regs, &regs);
517
518 if (have_mouse)
519 {
520 /* Must hardware-reset the mouse, or else it won't update
521 its notion of screen dimensions for some non-standard
522 video modes. This is *painfully* slow... */
523 regs.x.ax = 0;
524 int86 (0x33, &regs, &regs);
525 }
526 }
527
528 /* Find one of the dimensions supported by standard EGA/VGA
529 which gives us at least the required dimensions. */
530
531 #if __DJGPP__ > 1
532
533 else
534 {
535 static struct {
536 int rows;
537 int need_vga;
538 } std_dimension[] = {
539 {25, 0},
540 {28, 1},
541 {35, 0},
542 {40, 1},
543 {43, 0},
544 {50, 1}
545 };
546 int i = 0;
547
548 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
549 {
550 if (std_dimension[i].need_vga <= have_vga
551 && std_dimension[i].rows >= *rows)
552 {
553 if (std_dimension[i].rows != current_rows
554 || *cols != current_cols)
555 _set_screen_lines (std_dimension[i].rows);
556 break;
557 }
558 i++;
559 }
560 }
561
562 #else /* not __DJGPP__ > 1 */
563
564 else if (*rows <= 25)
565 {
566 if (current_rows != 25 || current_cols != 80)
567 {
568 regs.x.ax = 3;
569 int86 (0x10, &regs, &regs);
570 regs.x.ax = 0x1101;
571 regs.h.bl = 0;
572 int86 (0x10, &regs, &regs);
573 regs.x.ax = 0x1200;
574 regs.h.bl = 32;
575 int86 (0x10, &regs, &regs);
576 regs.x.ax = 3;
577 int86 (0x10, &regs, &regs);
578 }
579 }
580 else if (*rows <= 50)
581 if (have_vga && (current_rows != 50 || current_cols != 80)
582 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
583 {
584 regs.x.ax = 3;
585 int86 (0x10, &regs, &regs);
586 regs.x.ax = 0x1112;
587 regs.h.bl = 0;
588 int86 (0x10, &regs, &regs);
589 regs.x.ax = 0x1200;
590 regs.h.bl = 32;
591 int86 (0x10, &regs, &regs);
592 regs.x.ax = 0x0100;
593 regs.x.cx = 7;
594 int86 (0x10, &regs, &regs);
595 }
596 #endif /* not __DJGPP__ > 1 */
597
598 if (have_mouse)
599 {
600 mouse_init ();
601 mouse_on ();
602 }
603
604 /* Tell the caller what dimensions have been REALLY set. */
605 *rows = ScreenRows ();
606 *cols = ScreenCols ();
607
608 /* Enable bright background colors. */
609 bright_bg ();
610
611 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
612 be defensive anyway. */
613 if (screen_virtual_segment)
614 dosv_refresh_virtual_screen (0, *cols * *rows);
615 }
616
617 /* If we write a character in the position where the mouse is,
618 the mouse cursor may need to be refreshed. */
619
620 static void
621 mouse_off_maybe ()
622 {
623 int x, y;
624
625 if (!mouse_visible)
626 return;
627
628 mouse_get_xy (&x, &y);
629 if (y != new_pos_Y || x < new_pos_X)
630 return;
631
632 mouse_off ();
633 }
634
635 static void
636 IT_ring_bell (void)
637 {
638 if (visible_bell)
639 {
640 mouse_off ();
641 ScreenVisualBell ();
642 }
643 else
644 {
645 union REGS inregs, outregs;
646 inregs.h.ah = 2;
647 inregs.h.dl = 7;
648 intdos (&inregs, &outregs);
649 }
650 }
651
652 static void
653 IT_set_face (int face)
654 {
655 struct face *fp;
656 extern struct face *intern_face (/* FRAME_PTR, struct face * */);
657
658 if (face == 1 || (face == 0 && highlight))
659 fp = FRAME_MODE_LINE_FACE (foo);
660 else if (face <= 0 || face >= FRAME_N_COMPUTED_FACES (foo))
661 fp = FRAME_DEFAULT_FACE (foo);
662 else
663 fp = intern_face (selected_frame, FRAME_COMPUTED_FACES (foo)[face]);
664 if (termscript)
665 fprintf (termscript, "<FACE %d: %d/%d>",
666 face, FACE_FOREGROUND (fp), FACE_BACKGROUND (fp));
667 screen_face = face;
668 ScreenAttrib = (FACE_BACKGROUND (fp) << 4) | FACE_FOREGROUND (fp);
669 }
670
671 static void
672 IT_write_glyphs (GLYPH *str, int len)
673 {
674 int newface;
675 int ch, l = len;
676 unsigned char *buf, *bp;
677 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
678
679 if (len == 0) return;
680
681 buf = bp = alloca (len * 2);
682
683 while (--l >= 0)
684 {
685 newface = FAST_GLYPH_FACE (*str);
686 if (newface != screen_face)
687 IT_set_face (newface);
688 ch = FAST_GLYPH_CHAR (*str);
689 *bp++ = (unsigned char)ch;
690 *bp++ = ScreenAttrib;
691
692 if (termscript)
693 fputc (ch, termscript);
694 str++;
695 }
696
697 mouse_off_maybe ();
698 dosmemput (buf, 2 * len, (int)ScreenPrimary + offset);
699 if (screen_virtual_segment)
700 dosv_refresh_virtual_screen (offset, len);
701 new_pos_X += len;
702 }
703
704 static void
705 IT_clear_end_of_line (int first_unused)
706 {
707 char *spaces, *sp;
708 int i, j;
709 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
710
711 IT_set_face (0);
712 if (termscript)
713 fprintf (termscript, "<CLR:EOL>");
714 i = (j = screen_size_X - new_pos_X) * 2;
715 spaces = sp = alloca (i);
716
717 while (--j >= 0)
718 {
719 *sp++ = ' ';
720 *sp++ = ScreenAttrib;
721 }
722
723 mouse_off_maybe ();
724 dosmemput (spaces, i, (int)ScreenPrimary + offset);
725 if (screen_virtual_segment)
726 dosv_refresh_virtual_screen (offset, i / 2);
727 }
728
729 static void
730 IT_clear_screen (void)
731 {
732 if (termscript)
733 fprintf (termscript, "<CLR:SCR>");
734 IT_set_face (0);
735 mouse_off ();
736 ScreenClear ();
737 if (screen_virtual_segment)
738 dosv_refresh_virtual_screen (0, screen_size);
739 new_pos_X = new_pos_Y = 0;
740 }
741
742 static void
743 IT_clear_to_end (void)
744 {
745 if (termscript)
746 fprintf (termscript, "<CLR:EOS>");
747
748 while (new_pos_Y < screen_size_Y) {
749 new_pos_X = 0;
750 IT_clear_end_of_line (0);
751 new_pos_Y++;
752 }
753 }
754
755 static void
756 IT_cursor_to (int y, int x)
757 {
758 if (termscript)
759 fprintf (termscript, "\n<XY=%dx%d>", x, y);
760 new_pos_X = x;
761 new_pos_Y = y;
762 }
763
764 static int cursor_cleared;
765
766 static
767 IT_display_cursor (int on)
768 {
769 if (on && cursor_cleared)
770 {
771 ScreenSetCursor (current_pos_Y, current_pos_X);
772 cursor_cleared = 0;
773 }
774 else if (!on && !cursor_cleared)
775 {
776 ScreenSetCursor (-1, -1);
777 cursor_cleared = 1;
778 }
779 }
780
781 /* Emacs calls cursor-movement functions a lot when it updates the
782 display (probably a legacy of old terminals where you cannot
783 update a screen line without first moving the cursor there).
784 However, cursor movement is expensive on MSDOS (it calls a slow
785 BIOS function and requires 2 mode switches), while actual screen
786 updates access the video memory directly and don't depend on
787 cursor position. To avoid slowing down the redisplay, we cheat:
788 all functions that move the cursor only set internal variables
789 which record the cursor position, whereas the cursor is only
790 moved to its final position whenever screen update is complete.
791
792 `IT_cmgoto' is called from the keyboard reading loop and when the
793 frame update is complete. This means that we are ready for user
794 input, so we update the cursor position to show where the point is,
795 and also make the mouse pointer visible.
796
797 Special treatment is required when the cursor is in the echo area,
798 to put the cursor at the end of the text displayed there. */
799
800 static void
801 IT_cmgoto (FRAME_PTR f)
802 {
803 /* Only set the cursor to where it should be if the display is
804 already in sync with the window contents. */
805 int update_cursor_pos = MODIFF == unchanged_modified;
806 static int previous_pos_X = -1;
807
808 /* If the display is in sync, forget any previous knowledge about
809 cursor position. This is primarily for unexpected events like
810 C-g in the minibuffer. */
811 if (update_cursor_pos && previous_pos_X >= 0)
812 previous_pos_X = -1;
813 /* If we are in the echo area, put the cursor at the
814 end of the echo area message. */
815 if (!update_cursor_pos
816 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y)
817 {
818 int tem_X = current_pos_X, dummy;
819
820 if (echo_area_glyphs)
821 {
822 tem_X = echo_area_glyphs_length;
823 /* Save current cursor position, to be restored after the
824 echo area message is erased. Only remember one level
825 of previous cursor position. */
826 if (previous_pos_X == -1)
827 ScreenGetCursor (&dummy, &previous_pos_X);
828 }
829 else if (previous_pos_X >= 0)
830 {
831 /* We wind up here after the echo area message is erased.
832 Restore the cursor position we remembered above. */
833 tem_X = previous_pos_X;
834 previous_pos_X = -1;
835 }
836
837 if (current_pos_X != tem_X)
838 {
839 new_pos_X = tem_X;
840 update_cursor_pos = 1;
841 }
842 }
843
844 if (update_cursor_pos
845 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
846 {
847 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
848 if (termscript)
849 fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
850 }
851
852 /* Maybe cursor is invisible, so make it visible. */
853 IT_display_cursor (1);
854
855 /* Mouse pointer should be always visible if we are waiting for
856 keyboard input. */
857 if (!mouse_visible)
858 mouse_on ();
859 }
860
861 static void
862 IT_reassert_line_highlight (int new, int vpos)
863 {
864 highlight = new;
865 IT_set_face (0); /* To possibly clear the highlighting. */
866 }
867
868 static void
869 IT_change_line_highlight (int new_highlight, int vpos, int first_unused_hpos)
870 {
871 highlight = new_highlight;
872 IT_set_face (0); /* To possibly clear the highlighting. */
873 IT_cursor_to (vpos, 0);
874 IT_clear_end_of_line (first_unused_hpos);
875 }
876
877 static void
878 IT_update_begin (struct frame *foo)
879 {
880 highlight = 0;
881 IT_set_face (0); /* To possibly clear the highlighting. */
882 screen_face = -1;
883 }
884
885 static void
886 IT_update_end (struct frame *foo)
887 {
888 }
889
890 /* set-window-configuration on window.c needs this. */
891 void
892 x_set_menu_bar_lines (f, value, oldval)
893 struct frame *f;
894 Lisp_Object value, oldval;
895 {
896 set_menu_bar_lines (f, value, oldval);
897 }
898
899 /* This was copied from xfns.c */
900
901 Lisp_Object Qbackground_color;
902 Lisp_Object Qforeground_color;
903 extern Lisp_Object Qtitle;
904
905 /* IT_set_terminal_modes is called when emacs is started,
906 resumed, and whenever the screen is redrawn! */
907
908 static void
909 IT_set_terminal_modes (void)
910 {
911 if (termscript)
912 fprintf (termscript, "\n<SET_TERM>");
913 highlight = 0;
914
915 screen_size_X = ScreenCols ();
916 screen_size_Y = ScreenRows ();
917 screen_size = screen_size_X * screen_size_Y;
918
919 new_pos_X = new_pos_Y = 0;
920 current_pos_X = current_pos_Y = -1;
921
922 if (term_setup_done)
923 return;
924 term_setup_done = 1;
925
926 startup_screen_size_X = screen_size_X;
927 startup_screen_size_Y = screen_size_Y;
928 startup_screen_attrib = ScreenAttrib;
929
930 #if __DJGPP__ > 1
931 /* Is DOS/V (or any other RSIS software which relocates
932 the screen) installed? */
933 {
934 unsigned short es_value;
935 __dpmi_regs regs;
936
937 regs.h.ah = 0xfe; /* get relocated screen address */
938 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
939 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
940 else if (screen_old_address) /* already switched to Japanese mode once */
941 regs.x.es = (screen_old_address >> 4) & 0xffff;
942 else
943 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
944 regs.x.di = 0;
945 es_value = regs.x.es;
946 __dpmi_int (0x10, &regs);
947
948 if (regs.x.es != es_value && regs.x.es != (ScreenPrimary >> 4) & 0xffff)
949 {
950 screen_old_address = ScreenPrimary;
951 screen_virtual_segment = regs.x.es;
952 screen_virtual_offset = regs.x.di;
953 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
954 }
955 }
956 #endif /* __DJGPP__ > 1 */
957
958 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
959 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
960
961 if (termscript)
962 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
963 screen_size_X, screen_size_Y);
964
965 bright_bg ();
966 }
967
968 /* IT_reset_terminal_modes is called when emacs is
969 suspended or killed. */
970
971 static void
972 IT_reset_terminal_modes (void)
973 {
974 int display_row_start = (int) ScreenPrimary;
975 int saved_row_len = startup_screen_size_X * 2;
976 int update_row_len = ScreenCols () * 2;
977 int current_rows = ScreenRows ();
978 int to_next_row = update_row_len;
979 unsigned char *saved_row = startup_screen_buffer;
980 int cursor_pos_X = ScreenCols () - 1;
981 int cursor_pos_Y = ScreenRows () - 1;
982
983 if (termscript)
984 fprintf (termscript, "\n<RESET_TERM>");
985
986 highlight = 0;
987
988 if (!term_setup_done)
989 return;
990
991 mouse_off ();
992
993 /* Leave the video system in the same state as we found it,
994 as far as the blink/bright-background bit is concerned. */
995 maybe_enable_blinking ();
996
997 /* We have a situation here.
998 We cannot just do ScreenUpdate(startup_screen_buffer) because
999 the luser could have changed screen dimensions inside Emacs
1000 and failed (or didn't want) to restore them before killing
1001 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1002 thus will happily use memory outside what was allocated for
1003 `startup_screen_buffer'.
1004 Thus we only restore as much as the current screen dimensions
1005 can hold, and clear the rest (if the saved screen is smaller than
1006 the current) with the color attribute saved at startup. The cursor
1007 is also restored within the visible dimensions. */
1008
1009 ScreenAttrib = startup_screen_attrib;
1010 ScreenClear ();
1011 if (screen_virtual_segment)
1012 dosv_refresh_virtual_screen (0, screen_size);
1013
1014 if (update_row_len > saved_row_len)
1015 update_row_len = saved_row_len;
1016 if (current_rows > startup_screen_size_Y)
1017 current_rows = startup_screen_size_Y;
1018
1019 if (termscript)
1020 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
1021 update_row_len / 2, current_rows);
1022
1023 while (current_rows--)
1024 {
1025 dosmemput (saved_row, update_row_len, display_row_start);
1026 if (screen_virtual_segment)
1027 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
1028 update_row_len / 2);
1029 saved_row += saved_row_len;
1030 display_row_start += to_next_row;
1031 }
1032 if (startup_pos_X < cursor_pos_X)
1033 cursor_pos_X = startup_pos_X;
1034 if (startup_pos_Y < cursor_pos_Y)
1035 cursor_pos_Y = startup_pos_Y;
1036
1037 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
1038 xfree (startup_screen_buffer);
1039
1040 term_setup_done = 0;
1041 }
1042
1043 static void
1044 IT_set_terminal_window (int foo)
1045 {
1046 }
1047
1048 void
1049 IT_set_frame_parameters (f, alist)
1050 FRAME_PTR f;
1051 Lisp_Object alist;
1052 {
1053 Lisp_Object tail;
1054 int length = XINT (Flength (alist));
1055 int i;
1056 Lisp_Object *parms
1057 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
1058 Lisp_Object *values
1059 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
1060 int redraw;
1061 extern unsigned long load_color ();
1062
1063 redraw = 0;
1064
1065 /* Extract parm names and values into those vectors. */
1066 i = 0;
1067 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
1068 {
1069 Lisp_Object elt;
1070
1071 elt = Fcar (tail);
1072 parms[i] = Fcar (elt);
1073 CHECK_SYMBOL (parms[i], 1);
1074 values[i] = Fcdr (elt);
1075 i++;
1076 }
1077
1078
1079 /* Now process them in reverse of specified order. */
1080 for (i--; i >= 0; i--)
1081 {
1082 Lisp_Object prop = parms[i];
1083 Lisp_Object val = values[i];
1084
1085 if (EQ (prop, Qforeground_color))
1086 {
1087 unsigned long new_color = load_color (f, val);
1088 if (new_color != ~0)
1089 {
1090 FRAME_FOREGROUND_PIXEL (f) = new_color;
1091 redraw = 1;
1092 if (termscript)
1093 fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
1094 }
1095 }
1096 else if (EQ (prop, Qbackground_color))
1097 {
1098 unsigned long new_color = load_color (f, val);
1099 if (new_color != ~0)
1100 {
1101 FRAME_BACKGROUND_PIXEL (f) = new_color;
1102 redraw = 1;
1103 if (termscript)
1104 fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
1105 }
1106 }
1107 else if (EQ (prop, Qtitle))
1108 {
1109 x_set_title (f, val);
1110 if (termscript)
1111 fprintf (termscript, "<TITLE: %s>\n", XSTRING (val)->data);
1112 }
1113 else if (EQ (prop, intern ("reverse")) && EQ (val, Qt))
1114 {
1115 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
1116
1117 FRAME_FOREGROUND_PIXEL (f) = FRAME_BACKGROUND_PIXEL (f);
1118 FRAME_BACKGROUND_PIXEL (f) = fg;
1119 if (termscript)
1120 fprintf (termscript, "<INVERSE-VIDEO>\n");
1121 }
1122 store_frame_param (f, prop, val);
1123
1124 }
1125
1126 if (redraw)
1127 {
1128 extern void recompute_basic_faces (FRAME_PTR);
1129 extern void redraw_frame (FRAME_PTR);
1130
1131 recompute_basic_faces (f);
1132 if (f == selected_frame)
1133 redraw_frame (f);
1134 }
1135 }
1136
1137 extern void init_frame_faces (FRAME_PTR);
1138
1139 #endif /* !HAVE_X_WINDOWS */
1140
1141
1142 /* Do we need the internal terminal? */
1143
1144 void
1145 internal_terminal_init ()
1146 {
1147 char *term = getenv ("TERM");
1148 char *colors;
1149
1150 #ifdef HAVE_X_WINDOWS
1151 if (!inhibit_window_system)
1152 return;
1153 #endif
1154
1155 internal_terminal
1156 = (!noninteractive) && term && !strcmp (term, "internal");
1157
1158 if (getenv ("EMACSTEST"))
1159 termscript = fopen (getenv ("EMACSTEST"), "wt");
1160
1161 #ifndef HAVE_X_WINDOWS
1162 if (!internal_terminal || inhibit_window_system)
1163 {
1164 selected_frame->output_method = output_termcap;
1165 return;
1166 }
1167
1168 Vwindow_system = intern ("pc");
1169 Vwindow_system_version = make_number (1);
1170
1171 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
1172 screen_old_address = 0;
1173
1174 bzero (&the_only_x_display, sizeof the_only_x_display);
1175 the_only_x_display.background_pixel = 7; /* White */
1176 the_only_x_display.foreground_pixel = 0; /* Black */
1177 bright_bg ();
1178 colors = getenv ("EMACSCOLORS");
1179 if (colors && strlen (colors) >= 2)
1180 {
1181 /* The colors use 4 bits each (we enable bright background). */
1182 if (isdigit (colors[0]))
1183 colors[0] -= '0';
1184 else if (isxdigit (colors[0]))
1185 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1186 if (colors[0] >= 0 && colors[0] < 16)
1187 the_only_x_display.foreground_pixel = colors[0];
1188 if (isdigit (colors[1]))
1189 colors[1] -= '0';
1190 else if (isxdigit (colors[1]))
1191 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
1192 if (colors[1] >= 0 && colors[1] < 16)
1193 the_only_x_display.background_pixel = colors[1];
1194 }
1195 the_only_x_display.line_height = 1;
1196 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
1197
1198 init_frame_faces (selected_frame);
1199
1200 ring_bell_hook = IT_ring_bell;
1201 write_glyphs_hook = IT_write_glyphs;
1202 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
1203 clear_to_end_hook = IT_clear_to_end;
1204 clear_end_of_line_hook = IT_clear_end_of_line;
1205 clear_frame_hook = IT_clear_screen;
1206 change_line_highlight_hook = IT_change_line_highlight;
1207 update_begin_hook = IT_update_begin;
1208 update_end_hook = IT_update_end;
1209 reassert_line_highlight_hook = IT_reassert_line_highlight;
1210 frame_up_to_date_hook = IT_cmgoto; /* position cursor when update is done */
1211
1212 /* These hooks are called by term.c without being checked. */
1213 set_terminal_modes_hook = IT_set_terminal_modes;
1214 reset_terminal_modes_hook = IT_reset_terminal_modes;
1215 set_terminal_window_hook = IT_set_terminal_window;
1216 #endif
1217 }
1218
1219 dos_get_saved_screen (screen, rows, cols)
1220 char **screen;
1221 int *rows;
1222 int *cols;
1223 {
1224 #ifndef HAVE_X_WINDOWS
1225 *screen = startup_screen_buffer;
1226 *cols = startup_screen_size_X;
1227 *rows = startup_screen_size_Y;
1228 return *screen != (char *)0;
1229 #else
1230 return 0;
1231 #endif
1232 }
1233
1234 #ifndef HAVE_X_WINDOWS
1235
1236 /* We are not X, but we can emulate it well enough for our needs... */
1237 void
1238 check_x (void)
1239 {
1240 if (! FRAME_MSDOS_P (selected_frame))
1241 error ("Not running under a windows system");
1242 }
1243
1244 #endif
1245
1246 \f
1247 /* ----------------------- Keyboard control ----------------------
1248 *
1249 * Keymaps reflect the following keyboard layout:
1250 *
1251 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1252 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1253 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1254 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1255 * SPACE
1256 */
1257
1258 static int extended_kbd; /* 101 (102) keyboard present. */
1259
1260 struct dos_keyboard_map
1261 {
1262 char *unshifted;
1263 char *shifted;
1264 char *alt_gr;
1265 };
1266
1267
1268 static struct dos_keyboard_map us_keyboard = {
1269 /* 0 1 2 3 4 5 */
1270 /* 01234567890123456789012345678901234567890 12345678901234 */
1271 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1272 /* 0123456789012345678901234567890123456789 012345678901234 */
1273 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1274 0 /* no Alt-Gr key */
1275 };
1276
1277 static struct dos_keyboard_map fr_keyboard = {
1278 /* 0 1 2 3 4 5 */
1279 /* 012 3456789012345678901234567890123456789012345678901234 */
1280 "ý&\82\",(-\8a_\80\85)= azertyuiop^$ qsdfghjklm\97* wxcvbnm;:! ",
1281 /* 0123456789012345678901234567890123456789012345678901234 */
1282 " 1234567890ø+ AZERTYUIOPù\9c QSDFGHJKLM%æ WXCVBN?./õ ",
1283 /* 01234567 89012345678901234567890123456789012345678901234 */
1284 " ~#{[|`\\^@]} Ï "
1285 };
1286
1287 /*
1288 * Italian keyboard support, country code 39.
1289 * '<' 56:3c*0000
1290 * '>' 56:3e*0000
1291 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
1292 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
1293 */
1294 static struct dos_keyboard_map it_keyboard = {
1295 /* 0 1 2 3 4 5 */
1296 /* 0 123456789012345678901234567890123456789012345678901234 */
1297 "\\1234567890'\8d qwertyuiop\8a+ asdfghjkl\95\85\97 zxcvbnm,.- ",
1298 /* 01 23456789012345678901234567890123456789012345678901234 */
1299 "|!\"\9c$%&/()=?^ QWERTYUIOP\82* ASDFGHJKL\87øõ ZXCVBNM;:_ ",
1300 /* 0123456789012345678901234567890123456789012345678901234 */
1301 " {}~` [] @# "
1302 };
1303
1304 static struct dos_keyboard_map dk_keyboard = {
1305 /* 0 1 2 3 4 5 */
1306 /* 0123456789012345678901234567890123456789012345678901234 */
1307 "«1234567890+| qwertyuiop\86~ asdfghjkl\91\9b' zxcvbnm,.- ",
1308 /* 01 23456789012345678901234567890123456789012345678901234 */
1309 "õ!\"#$%&/()=?` QWERTYUIOP\8f^ ASDFGHJKL\92\9d* ZXCVBNM;:_ ",
1310 /* 0123456789012345678901234567890123456789012345678901234 */
1311 " @\9c$ {[]} | "
1312 };
1313
1314 static struct keyboard_layout_list
1315 {
1316 int country_code;
1317 struct dos_keyboard_map *keyboard_map;
1318 } keyboard_layout_list[] =
1319 {
1320 1, &us_keyboard,
1321 33, &fr_keyboard,
1322 39, &it_keyboard,
1323 45, &dk_keyboard
1324 };
1325
1326 static struct dos_keyboard_map *keyboard;
1327 static int keyboard_map_all;
1328 static int international_keyboard;
1329
1330 int
1331 dos_set_keyboard (code, always)
1332 int code;
1333 int always;
1334 {
1335 int i;
1336 _go32_dpmi_registers regs;
1337
1338 /* See if Keyb.Com is installed (for international keyboard support).
1339 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
1340 of Windows 9X! So don't do that! */
1341 regs.x.ax = 0xad80;
1342 regs.x.ss = regs.x.sp = regs.x.flags = 0;
1343 _go32_dpmi_simulate_int (0x2f, &regs);
1344 if (regs.h.al == 0xff)
1345 international_keyboard = 1;
1346
1347 /* Initialize to US settings, for countries that don't have their own. */
1348 keyboard = keyboard_layout_list[0].keyboard_map;
1349 keyboard_map_all = always;
1350 dos_keyboard_layout = 1;
1351
1352 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
1353 if (code == keyboard_layout_list[i].country_code)
1354 {
1355 keyboard = keyboard_layout_list[i].keyboard_map;
1356 keyboard_map_all = always;
1357 dos_keyboard_layout = code;
1358 return 1;
1359 }
1360 return 0;
1361 }
1362 \f
1363 #define Ignore 0x0000
1364 #define Normal 0x0000 /* normal key - alt changes scan-code */
1365 #define FctKey 0x1000 /* func key if c == 0, else c */
1366 #define Special 0x2000 /* func key even if c != 0 */
1367 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1368 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1369 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1370 #define Grey 0x6000 /* Grey keypad key */
1371
1372 #define Alt 0x0100 /* alt scan-code */
1373 #define Ctrl 0x0200 /* ctrl scan-code */
1374 #define Shift 0x0400 /* shift scan-code */
1375
1376 static struct
1377 {
1378 unsigned char char_code; /* normal code */
1379 unsigned char meta_code; /* M- code */
1380 unsigned char keypad_code; /* keypad code */
1381 unsigned char editkey_code; /* edit key */
1382 } keypad_translate_map[] = {
1383 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1384 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1385 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1386 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1387 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1388 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1389 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1390 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1391 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1392 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1393 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1394 };
1395
1396 static struct
1397 {
1398 unsigned char char_code; /* normal code */
1399 unsigned char keypad_code; /* keypad code */
1400 } grey_key_translate_map[] = {
1401 '/', 0xaf, /* kp-decimal */
1402 '*', 0xaa, /* kp-multiply */
1403 '-', 0xad, /* kp-subtract */
1404 '+', 0xab, /* kp-add */
1405 '\r', 0x8d /* kp-enter */
1406 };
1407
1408 static unsigned short
1409 ibmpc_translate_map[] =
1410 {
1411 /* --------------- 00 to 0f --------------- */
1412 Normal | 0xff, /* Ctrl Break + Alt-NNN */
1413 Alt | ModFct | 0x1b, /* Escape */
1414 Normal | 1, /* '1' */
1415 Normal | 2, /* '2' */
1416 Normal | 3, /* '3' */
1417 Normal | 4, /* '4' */
1418 Normal | 5, /* '5' */
1419 Normal | 6, /* '6' */
1420 Normal | 7, /* '7' */
1421 Normal | 8, /* '8' */
1422 Normal | 9, /* '9' */
1423 Normal | 10, /* '0' */
1424 Normal | 11, /* '-' */
1425 Normal | 12, /* '=' */
1426 Special | 0x08, /* Backspace */
1427 ModFct | 0x74, /* Tab/Backtab */
1428
1429 /* --------------- 10 to 1f --------------- */
1430 Map | 15, /* 'q' */
1431 Map | 16, /* 'w' */
1432 Map | 17, /* 'e' */
1433 Map | 18, /* 'r' */
1434 Map | 19, /* 't' */
1435 Map | 20, /* 'y' */
1436 Map | 21, /* 'u' */
1437 Map | 22, /* 'i' */
1438 Map | 23, /* 'o' */
1439 Map | 24, /* 'p' */
1440 Map | 25, /* '[' */
1441 Map | 26, /* ']' */
1442 ModFct | 0x0d, /* Return */
1443 Ignore, /* Ctrl */
1444 Map | 30, /* 'a' */
1445 Map | 31, /* 's' */
1446
1447 /* --------------- 20 to 2f --------------- */
1448 Map | 32, /* 'd' */
1449 Map | 33, /* 'f' */
1450 Map | 34, /* 'g' */
1451 Map | 35, /* 'h' */
1452 Map | 36, /* 'j' */
1453 Map | 37, /* 'k' */
1454 Map | 38, /* 'l' */
1455 Map | 39, /* ';' */
1456 Map | 40, /* '\'' */
1457 Map | 0, /* '`' */
1458 Ignore, /* Left shift */
1459 Map | 41, /* '\\' */
1460 Map | 45, /* 'z' */
1461 Map | 46, /* 'x' */
1462 Map | 47, /* 'c' */
1463 Map | 48, /* 'v' */
1464
1465 /* --------------- 30 to 3f --------------- */
1466 Map | 49, /* 'b' */
1467 Map | 50, /* 'n' */
1468 Map | 51, /* 'm' */
1469 Map | 52, /* ',' */
1470 Map | 53, /* '.' */
1471 Map | 54, /* '/' */
1472 Ignore, /* Right shift */
1473 Grey | 1, /* Grey * */
1474 Ignore, /* Alt */
1475 Normal | ' ', /* ' ' */
1476 Ignore, /* Caps Lock */
1477 FctKey | 0xbe, /* F1 */
1478 FctKey | 0xbf, /* F2 */
1479 FctKey | 0xc0, /* F3 */
1480 FctKey | 0xc1, /* F4 */
1481 FctKey | 0xc2, /* F5 */
1482
1483 /* --------------- 40 to 4f --------------- */
1484 FctKey | 0xc3, /* F6 */
1485 FctKey | 0xc4, /* F7 */
1486 FctKey | 0xc5, /* F8 */
1487 FctKey | 0xc6, /* F9 */
1488 FctKey | 0xc7, /* F10 */
1489 Ignore, /* Num Lock */
1490 Ignore, /* Scroll Lock */
1491 KeyPad | 7, /* Home */
1492 KeyPad | 8, /* Up */
1493 KeyPad | 9, /* Page Up */
1494 Grey | 2, /* Grey - */
1495 KeyPad | 4, /* Left */
1496 KeyPad | 5, /* Keypad 5 */
1497 KeyPad | 6, /* Right */
1498 Grey | 3, /* Grey + */
1499 KeyPad | 1, /* End */
1500
1501 /* --------------- 50 to 5f --------------- */
1502 KeyPad | 2, /* Down */
1503 KeyPad | 3, /* Page Down */
1504 KeyPad | 0, /* Insert */
1505 KeyPad | 10, /* Delete */
1506 Shift | FctKey | 0xbe, /* (Shift) F1 */
1507 Shift | FctKey | 0xbf, /* (Shift) F2 */
1508 Shift | FctKey | 0xc0, /* (Shift) F3 */
1509 Shift | FctKey | 0xc1, /* (Shift) F4 */
1510 Shift | FctKey | 0xc2, /* (Shift) F5 */
1511 Shift | FctKey | 0xc3, /* (Shift) F6 */
1512 Shift | FctKey | 0xc4, /* (Shift) F7 */
1513 Shift | FctKey | 0xc5, /* (Shift) F8 */
1514 Shift | FctKey | 0xc6, /* (Shift) F9 */
1515 Shift | FctKey | 0xc7, /* (Shift) F10 */
1516 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
1517 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
1518
1519 /* --------------- 60 to 6f --------------- */
1520 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
1521 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
1522 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
1523 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
1524 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
1525 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
1526 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
1527 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
1528 Alt | FctKey | 0xbe, /* (Alt) F1 */
1529 Alt | FctKey | 0xbf, /* (Alt) F2 */
1530 Alt | FctKey | 0xc0, /* (Alt) F3 */
1531 Alt | FctKey | 0xc1, /* (Alt) F4 */
1532 Alt | FctKey | 0xc2, /* (Alt) F5 */
1533 Alt | FctKey | 0xc3, /* (Alt) F6 */
1534 Alt | FctKey | 0xc4, /* (Alt) F7 */
1535 Alt | FctKey | 0xc5, /* (Alt) F8 */
1536
1537 /* --------------- 70 to 7f --------------- */
1538 Alt | FctKey | 0xc6, /* (Alt) F9 */
1539 Alt | FctKey | 0xc7, /* (Alt) F10 */
1540 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
1541 Ctrl | KeyPad | 4, /* (Ctrl) Left */
1542 Ctrl | KeyPad | 6, /* (Ctrl) Right */
1543 Ctrl | KeyPad | 1, /* (Ctrl) End */
1544 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
1545 Ctrl | KeyPad | 7, /* (Ctrl) Home */
1546 Alt | Map | 1, /* '1' */
1547 Alt | Map | 2, /* '2' */
1548 Alt | Map | 3, /* '3' */
1549 Alt | Map | 4, /* '4' */
1550 Alt | Map | 5, /* '5' */
1551 Alt | Map | 6, /* '6' */
1552 Alt | Map | 7, /* '7' */
1553 Alt | Map | 8, /* '8' */
1554
1555 /* --------------- 80 to 8f --------------- */
1556 Alt | Map | 9, /* '9' */
1557 Alt | Map | 10, /* '0' */
1558 Alt | Map | 11, /* '-' */
1559 Alt | Map | 12, /* '=' */
1560 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
1561 FctKey | 0xc8, /* F11 */
1562 FctKey | 0xc9, /* F12 */
1563 Shift | FctKey | 0xc8, /* (Shift) F11 */
1564 Shift | FctKey | 0xc9, /* (Shift) F12 */
1565 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
1566 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
1567 Alt | FctKey | 0xc8, /* (Alt) F11 */
1568 Alt | FctKey | 0xc9, /* (Alt) F12 */
1569 Ctrl | KeyPad | 8, /* (Ctrl) Up */
1570 Ctrl | Grey | 2, /* (Ctrl) Grey - */
1571 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
1572
1573 /* --------------- 90 to 9f --------------- */
1574 Ctrl | Grey | 3, /* (Ctrl) Grey + */
1575 Ctrl | KeyPad | 2, /* (Ctrl) Down */
1576 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
1577 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
1578 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
1579 Ctrl | Grey | 0, /* (Ctrl) Grey / */
1580 Ctrl | Grey | 1, /* (Ctrl) Grey * */
1581 Alt | FctKey | 0x50, /* (Alt) Home */
1582 Alt | FctKey | 0x52, /* (Alt) Up */
1583 Alt | FctKey | 0x55, /* (Alt) Page Up */
1584 Ignore, /* NO KEY */
1585 Alt | FctKey | 0x51, /* (Alt) Left */
1586 Ignore, /* NO KEY */
1587 Alt | FctKey | 0x53, /* (Alt) Right */
1588 Ignore, /* NO KEY */
1589 Alt | FctKey | 0x57, /* (Alt) End */
1590
1591 /* --------------- a0 to af --------------- */
1592 Alt | KeyPad | 2, /* (Alt) Down */
1593 Alt | KeyPad | 3, /* (Alt) Page Down */
1594 Alt | KeyPad | 0, /* (Alt) Insert */
1595 Alt | KeyPad | 10, /* (Alt) Delete */
1596 Alt | Grey | 0, /* (Alt) Grey / */
1597 Alt | FctKey | 0x09, /* (Alt) Tab */
1598 Alt | Grey | 4 /* (Alt) Keypad Enter */
1599 };
1600 \f
1601 /* These bit-positions corresponds to values returned by BIOS */
1602 #define SHIFT_P 0x0003 /* two bits! */
1603 #define CTRL_P 0x0004
1604 #define ALT_P 0x0008
1605 #define SCRLOCK_P 0x0010
1606 #define NUMLOCK_P 0x0020
1607 #define CAPSLOCK_P 0x0040
1608 #define ALT_GR_P 0x0800
1609 #define SUPER_P 0x4000 /* pseudo */
1610 #define HYPER_P 0x8000 /* pseudo */
1611
1612 static int
1613 dos_get_modifiers (keymask)
1614 int *keymask;
1615 {
1616 union REGS regs;
1617 int mask;
1618 int modifiers = 0;
1619
1620 /* Calculate modifier bits */
1621 regs.h.ah = extended_kbd ? 0x12 : 0x02;
1622 int86 (0x16, &regs, &regs);
1623
1624 if (!extended_kbd)
1625 {
1626 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
1627 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1628 }
1629 else
1630 {
1631 mask = regs.h.al & (SHIFT_P |
1632 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1633
1634 /* Do not break international keyboard support. */
1635 /* When Keyb.Com is loaded, the right Alt key is */
1636 /* used for accessing characters like { and } */
1637 if (regs.h.ah & 2) /* Left ALT pressed ? */
1638 mask |= ALT_P;
1639
1640 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
1641 {
1642 mask |= ALT_GR_P;
1643 if (dos_hyper_key == 1)
1644 {
1645 mask |= HYPER_P;
1646 modifiers |= hyper_modifier;
1647 }
1648 else if (dos_super_key == 1)
1649 {
1650 mask |= SUPER_P;
1651 modifiers |= super_modifier;
1652 }
1653 else if (!international_keyboard)
1654 {
1655 /* If Keyb.Com is NOT installed, let Right Alt behave
1656 like the Left Alt. */
1657 mask &= ~ALT_GR_P;
1658 mask |= ALT_P;
1659 }
1660 }
1661
1662 if (regs.h.ah & 1) /* Left CTRL pressed ? */
1663 mask |= CTRL_P;
1664
1665 if (regs.h.ah & 4) /* Right CTRL pressed ? */
1666 {
1667 if (dos_hyper_key == 2)
1668 {
1669 mask |= HYPER_P;
1670 modifiers |= hyper_modifier;
1671 }
1672 else if (dos_super_key == 2)
1673 {
1674 mask |= SUPER_P;
1675 modifiers |= super_modifier;
1676 }
1677 else
1678 mask |= CTRL_P;
1679 }
1680 }
1681
1682 if (mask & SHIFT_P)
1683 modifiers |= shift_modifier;
1684 if (mask & CTRL_P)
1685 modifiers |= ctrl_modifier;
1686 if (mask & ALT_P)
1687 modifiers |= meta_modifier;
1688
1689 if (keymask)
1690 *keymask = mask;
1691 return modifiers;
1692 }
1693
1694 #define NUM_RECENT_DOSKEYS (100)
1695 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
1696 int total_doskeys; /* Total number of elements stored into recent_doskeys */
1697 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
1698
1699 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
1700 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1701 Each input key receives two values in this vector: first the ASCII code,\n\
1702 and then the scan code.")
1703 ()
1704 {
1705 Lisp_Object *keys = XVECTOR (recent_doskeys)->contents;
1706 Lisp_Object val;
1707
1708 if (total_doskeys < NUM_RECENT_DOSKEYS)
1709 return Fvector (total_doskeys, keys);
1710 else
1711 {
1712 val = Fvector (NUM_RECENT_DOSKEYS, keys);
1713 bcopy (keys + recent_doskeys_index,
1714 XVECTOR (val)->contents,
1715 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
1716 bcopy (keys,
1717 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
1718 recent_doskeys_index * sizeof (Lisp_Object));
1719 return val;
1720 }
1721 }
1722
1723 /* Get a char from keyboard. Function keys are put into the event queue. */
1724
1725 extern void kbd_buffer_store_event (struct input_event *);
1726 static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
1727
1728 static int
1729 dos_rawgetc ()
1730 {
1731 struct input_event event;
1732 union REGS regs;
1733
1734 #ifndef HAVE_X_WINDOWS
1735 /* Maybe put the cursor where it should be. */
1736 IT_cmgoto (selected_frame);
1737 #endif
1738
1739 /* The following condition is equivalent to `kbhit ()', except that
1740 it uses the bios to do its job. This pleases DESQview/X. */
1741 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
1742 int86 (0x16, &regs, &regs),
1743 (regs.x.flags & 0x40) == 0)
1744 {
1745 union REGS regs;
1746 register unsigned char c;
1747 int sc, code, mask, kp_mode;
1748 int modifiers;
1749
1750 regs.h.ah = extended_kbd ? 0x10 : 0x00;
1751 int86 (0x16, &regs, &regs);
1752 c = regs.h.al;
1753 sc = regs.h.ah;
1754
1755 total_doskeys += 2;
1756 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1757 = make_number (c);
1758 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1759 recent_doskeys_index = 0;
1760 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1761 = make_number (sc);
1762 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1763 recent_doskeys_index = 0;
1764
1765 modifiers = dos_get_modifiers (&mask);
1766
1767 #ifndef HAVE_X_WINDOWS
1768 if (!NILP (Vdos_display_scancodes))
1769 {
1770 char buf[11];
1771 sprintf (buf, "%02x:%02x*%04x",
1772 (unsigned) (sc&0xff), (unsigned) c, mask);
1773 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
1774 }
1775 #endif
1776
1777 if (sc == 0xe0)
1778 {
1779 switch (c)
1780 {
1781 case 10: /* Ctrl Grey Enter */
1782 code = Ctrl | Grey | 4;
1783 break;
1784 case 13: /* Grey Enter */
1785 code = Grey | 4;
1786 break;
1787 case '/': /* Grey / */
1788 code = Grey | 0;
1789 break;
1790 default:
1791 continue;
1792 };
1793 c = 0;
1794 }
1795 else
1796 {
1797 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
1798 continue;
1799 if ((code = ibmpc_translate_map[sc]) == Ignore)
1800 continue;
1801 }
1802
1803 if (c == 0)
1804 {
1805 /* We only look at the keyboard Ctrl/Shift/Alt keys when
1806 Emacs is ready to read a key. Therefore, if they press
1807 `Alt-x' when Emacs is busy, by the time we get to
1808 `dos_get_modifiers', they might have already released the
1809 Alt key, and Emacs gets just `x', which is BAD.
1810 However, for keys with the `Map' property set, the ASCII
1811 code returns zero iff Alt is pressed. So, when we DON'T
1812 have to support international_keyboard, we don't have to
1813 distinguish between the left and right Alt keys, and we
1814 can set the META modifier for any keys with the `Map'
1815 property if they return zero ASCII code (c = 0). */
1816 if ( (code & Alt)
1817 || ( (code & 0xf000) == Map && !international_keyboard))
1818 modifiers |= meta_modifier;
1819 if (code & Ctrl)
1820 modifiers |= ctrl_modifier;
1821 if (code & Shift)
1822 modifiers |= shift_modifier;
1823 }
1824
1825 switch (code & 0xf000)
1826 {
1827 case ModFct:
1828 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
1829 return c;
1830 c = 0; /* Special */
1831
1832 case FctKey:
1833 if (c != 0)
1834 return c;
1835
1836 case Special:
1837 code |= 0xff00;
1838 break;
1839
1840 case Normal:
1841 if (sc == 0)
1842 {
1843 if (c == 0) /* ctrl-break */
1844 continue;
1845 return c; /* ALT-nnn */
1846 }
1847 if (!keyboard_map_all)
1848 {
1849 if (c != ' ')
1850 return c;
1851 code = c;
1852 break;
1853 }
1854
1855 case Map:
1856 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
1857 if (!keyboard_map_all)
1858 return c;
1859
1860 code &= 0xff;
1861 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
1862 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
1863
1864 if (mask & SHIFT_P)
1865 {
1866 code = keyboard->shifted[code];
1867 mask -= SHIFT_P;
1868 modifiers &= ~shift_modifier;
1869 }
1870 else
1871 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
1872 code = keyboard->alt_gr[code];
1873 else
1874 code = keyboard->unshifted[code];
1875 break;
1876
1877 case KeyPad:
1878 code &= 0xff;
1879 if (c == 0xe0) /* edit key */
1880 kp_mode = 3;
1881 else
1882 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
1883 kp_mode = dos_keypad_mode & 0x03;
1884 else
1885 kp_mode = (dos_keypad_mode >> 4) & 0x03;
1886
1887 switch (kp_mode)
1888 {
1889 case 0:
1890 if (code == 10 && dos_decimal_point)
1891 return dos_decimal_point;
1892 return keypad_translate_map[code].char_code;
1893
1894 case 1:
1895 code = 0xff00 | keypad_translate_map[code].keypad_code;
1896 break;
1897
1898 case 2:
1899 code = keypad_translate_map[code].meta_code;
1900 modifiers = meta_modifier;
1901 break;
1902
1903 case 3:
1904 code = 0xff00 | keypad_translate_map[code].editkey_code;
1905 break;
1906 }
1907 break;
1908
1909 case Grey:
1910 code &= 0xff;
1911 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
1912 if (dos_keypad_mode & kp_mode)
1913 code = 0xff00 | grey_key_translate_map[code].keypad_code;
1914 else
1915 code = grey_key_translate_map[code].char_code;
1916 break;
1917 }
1918
1919 make_event:
1920 if (code == 0)
1921 continue;
1922
1923 if (code >= 0x100)
1924 event.kind = non_ascii_keystroke;
1925 else
1926 event.kind = ascii_keystroke;
1927 event.code = code;
1928 event.modifiers = modifiers;
1929 XSETFRAME (event.frame_or_window, selected_frame);
1930 event.timestamp = event_timestamp ();
1931 kbd_buffer_store_event (&event);
1932 }
1933
1934 if (have_mouse > 0 && !mouse_preempted)
1935 {
1936 int but, press, x, y, ok;
1937
1938 /* Check for mouse movement *before* buttons. */
1939 mouse_check_moved ();
1940
1941 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
1942 for (press = 0; press < 2; press++)
1943 {
1944 int button_num = but;
1945
1946 if (press)
1947 ok = mouse_pressed (but, &x, &y);
1948 else
1949 ok = mouse_released (but, &x, &y);
1950 if (ok)
1951 {
1952 /* Allow a simultaneous press/release of Mouse-1 and
1953 Mouse-2 to simulate Mouse-3 on two-button mice. */
1954 if (mouse_button_count == 2 && but < 2)
1955 {
1956 int x2, y2; /* don't clobber original coordinates */
1957
1958 /* If only one button is pressed, wait 100 msec and
1959 check again. This way, Speedy Gonzales isn't
1960 punished, while the slow get their chance. */
1961 if (press && mouse_pressed (1-but, &x2, &y2)
1962 || !press && mouse_released (1-but, &x2, &y2))
1963 button_num = 2;
1964 else
1965 {
1966 delay (100);
1967 if (press && mouse_pressed (1-but, &x2, &y2)
1968 || !press && mouse_released (1-but, &x2, &y2))
1969 button_num = 2;
1970 }
1971 }
1972
1973 event.kind = mouse_click;
1974 event.code = button_num;
1975 event.modifiers = dos_get_modifiers (0)
1976 | (press ? down_modifier : up_modifier);
1977 event.x = x;
1978 event.y = y;
1979 XSETFRAME (event.frame_or_window, selected_frame);
1980 event.timestamp = event_timestamp ();
1981 kbd_buffer_store_event (&event);
1982 }
1983 }
1984 }
1985
1986 return -1;
1987 }
1988
1989 static int prev_get_char = -1;
1990
1991 /* Return 1 if a key is ready to be read without suspending execution. */
1992
1993 dos_keysns ()
1994 {
1995 if (prev_get_char != -1)
1996 return 1;
1997 else
1998 return ((prev_get_char = dos_rawgetc ()) != -1);
1999 }
2000
2001 /* Read a key. Return -1 if no key is ready. */
2002
2003 dos_keyread ()
2004 {
2005 if (prev_get_char != -1)
2006 {
2007 int c = prev_get_char;
2008 prev_get_char = -1;
2009 return c;
2010 }
2011 else
2012 return dos_rawgetc ();
2013 }
2014 \f
2015 #ifndef HAVE_X_WINDOWS
2016 /* See xterm.c for more info. */
2017 void
2018 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
2019 FRAME_PTR f;
2020 register int pix_x, pix_y;
2021 register int *x, *y;
2022 XRectangle *bounds;
2023 int noclip;
2024 {
2025 if (bounds) abort ();
2026
2027 /* Ignore clipping. */
2028
2029 *x = pix_x;
2030 *y = pix_y;
2031 }
2032
2033 void
2034 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
2035 FRAME_PTR f;
2036 register int x, y;
2037 register int *pix_x, *pix_y;
2038 {
2039 *pix_x = x;
2040 *pix_y = y;
2041 }
2042 \f
2043 /* Simulation of X's menus. Nothing too fancy here -- just make it work
2044 for now.
2045
2046 Actually, I don't know the meaning of all the parameters of the functions
2047 here -- I only know how they are called by xmenu.c. I could of course
2048 grab the nearest Xlib manual (down the hall, second-to-last door on the
2049 left), but I don't think it's worth the effort. */
2050
2051 static XMenu *
2052 IT_menu_create ()
2053 {
2054 XMenu *menu;
2055
2056 menu = (XMenu *) xmalloc (sizeof (XMenu));
2057 menu->allocated = menu->count = menu->panecount = menu->width = 0;
2058 return menu;
2059 }
2060
2061 /* Allocate some (more) memory for MENU ensuring that there is room for one
2062 for item. */
2063
2064 static void
2065 IT_menu_make_room (XMenu *menu)
2066 {
2067 if (menu->allocated == 0)
2068 {
2069 int count = menu->allocated = 10;
2070 menu->text = (char **) xmalloc (count * sizeof (char *));
2071 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
2072 menu->panenumber = (int *) xmalloc (count * sizeof (int));
2073 }
2074 else if (menu->allocated == menu->count)
2075 {
2076 int count = menu->allocated = menu->allocated + 10;
2077 menu->text
2078 = (char **) xrealloc (menu->text, count * sizeof (char *));
2079 menu->submenu
2080 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
2081 menu->panenumber
2082 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
2083 }
2084 }
2085
2086 /* Search the given menu structure for a given pane number. */
2087
2088 static XMenu *
2089 IT_menu_search_pane (XMenu *menu, int pane)
2090 {
2091 int i;
2092 XMenu *try;
2093
2094 for (i = 0; i < menu->count; i++)
2095 if (menu->submenu[i])
2096 {
2097 if (pane == menu->panenumber[i])
2098 return menu->submenu[i];
2099 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
2100 return try;
2101 }
2102 return (XMenu *) 0;
2103 }
2104
2105 /* Determine how much screen space a given menu needs. */
2106
2107 static void
2108 IT_menu_calc_size (XMenu *menu, int *width, int *height)
2109 {
2110 int i, h2, w2, maxsubwidth, maxheight;
2111
2112 maxsubwidth = 0;
2113 maxheight = menu->count;
2114 for (i = 0; i < menu->count; i++)
2115 {
2116 if (menu->submenu[i])
2117 {
2118 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
2119 if (w2 > maxsubwidth) maxsubwidth = w2;
2120 if (i + h2 > maxheight) maxheight = i + h2;
2121 }
2122 }
2123 *width = menu->width + maxsubwidth;
2124 *height = maxheight;
2125 }
2126
2127 /* Display MENU at (X,Y) using FACES. */
2128
2129 static void
2130 IT_menu_display (XMenu *menu, int y, int x, int *faces)
2131 {
2132 int i, j, face, width;
2133 GLYPH *text, *p;
2134 char *q;
2135 int mx, my;
2136 int enabled, mousehere;
2137 int row, col;
2138
2139 width = menu->width;
2140 text = (GLYPH *) xmalloc ((width + 2) * sizeof (GLYPH));
2141 ScreenGetCursor (&row, &col);
2142 mouse_get_xy (&mx, &my);
2143 IT_update_begin (selected_frame);
2144 for (i = 0; i < menu->count; i++)
2145 {
2146 IT_cursor_to (y + i, x);
2147 enabled
2148 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
2149 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
2150 face = faces[enabled + mousehere * 2];
2151 p = text;
2152 *p++ = FAST_MAKE_GLYPH (' ', face);
2153 for (j = 0, q = menu->text[i]; *q; j++)
2154 {
2155 if (*q > 26)
2156 *p++ = FAST_MAKE_GLYPH (*q++, face);
2157 else /* make '^x' */
2158 {
2159 *p++ = FAST_MAKE_GLYPH ('^', face);
2160 j++;
2161 *p++ = FAST_MAKE_GLYPH (*q++ + 64, face);
2162 }
2163 }
2164
2165 for (; j < width; j++)
2166 *p++ = FAST_MAKE_GLYPH (' ', face);
2167 *p++ = FAST_MAKE_GLYPH (menu->submenu[i] ? 16 : ' ', face);
2168 IT_write_glyphs (text, width + 2);
2169 }
2170 IT_update_end (selected_frame);
2171 IT_cursor_to (row, col);
2172 xfree (text);
2173 }
2174 \f
2175 /* --------------------------- X Menu emulation ---------------------- */
2176
2177 /* Report availability of menus. */
2178
2179 int
2180 have_menus_p ()
2181 {
2182 return 1;
2183 }
2184
2185 /* Create a brand new menu structure. */
2186
2187 XMenu *
2188 XMenuCreate (Display *foo1, Window foo2, char *foo3)
2189 {
2190 return IT_menu_create ();
2191 }
2192
2193 /* Create a new pane and place it on the outer-most level. It is not
2194 clear that it should be placed out there, but I don't know what else
2195 to do. */
2196
2197 int
2198 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
2199 {
2200 int len;
2201 char *p;
2202
2203 if (!enable)
2204 abort ();
2205
2206 IT_menu_make_room (menu);
2207 menu->submenu[menu->count] = IT_menu_create ();
2208 menu->text[menu->count] = txt;
2209 menu->panenumber[menu->count] = ++menu->panecount;
2210 menu->count++;
2211
2212 /* Adjust length for possible control characters (which will
2213 be written as ^x). */
2214 for (len = strlen (txt), p = txt; *p; p++)
2215 if (*p < 27)
2216 len++;
2217
2218 if (len > menu->width)
2219 menu->width = len;
2220
2221 return menu->panecount;
2222 }
2223
2224 /* Create a new item in a menu pane. */
2225
2226 int
2227 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
2228 int foo, char *txt, int enable)
2229 {
2230 int len;
2231 char *p;
2232
2233 if (pane)
2234 if (!(menu = IT_menu_search_pane (menu, pane)))
2235 return XM_FAILURE;
2236 IT_menu_make_room (menu);
2237 menu->submenu[menu->count] = (XMenu *) 0;
2238 menu->text[menu->count] = txt;
2239 menu->panenumber[menu->count] = enable;
2240 menu->count++;
2241
2242 /* Adjust length for possible control characters (which will
2243 be written as ^x). */
2244 for (len = strlen (txt), p = txt; *p; p++)
2245 if (*p < 27)
2246 len++;
2247
2248 if (len > menu->width)
2249 menu->width = len;
2250
2251 return XM_SUCCESS;
2252 }
2253
2254 /* Decide where the menu would be placed if requested at (X,Y). */
2255
2256 void
2257 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
2258 int *ulx, int *uly, int *width, int *height)
2259 {
2260 IT_menu_calc_size (menu, width, height);
2261 *ulx = x + 1;
2262 *uly = y;
2263 *width += 2;
2264 }
2265
2266 struct IT_menu_state
2267 {
2268 void *screen_behind;
2269 XMenu *menu;
2270 int pane;
2271 int x, y;
2272 };
2273
2274
2275 /* Display menu, wait for user's response, and return that response. */
2276
2277 int
2278 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
2279 int x0, int y0, unsigned ButtonMask, char **txt)
2280 {
2281 struct IT_menu_state *state;
2282 int statecount;
2283 int x, y, i, b;
2284 int screensize;
2285 int faces[4], selectface;
2286 int leave, result, onepane;
2287 int title_faces[4]; /* face to display the menu title */
2288 int buffers_num_deleted = 0;
2289
2290 /* Just in case we got here without a mouse present... */
2291 if (have_mouse <= 0)
2292 return XM_IA_SELECT;
2293 /* Don't allow non-positive x0 and y0, lest the menu will wrap
2294 around the display. */
2295 if (x0 <= 0)
2296 x0 = 1;
2297 if (y0 <= 0)
2298 y0 = 1;
2299
2300 /* We will process all the mouse events directly, so we had
2301 better prevented dos_rawgetc from stealing them from us. */
2302 mouse_preempted++;
2303
2304 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
2305 screensize = screen_size * 2;
2306 faces[0]
2307 = compute_glyph_face (selected_frame,
2308 face_name_id_number
2309 (selected_frame,
2310 intern ("msdos-menu-passive-face")),
2311 0);
2312 faces[1]
2313 = compute_glyph_face (selected_frame,
2314 face_name_id_number
2315 (selected_frame,
2316 intern ("msdos-menu-active-face")),
2317 0);
2318 selectface
2319 = face_name_id_number (selected_frame, intern ("msdos-menu-select-face"));
2320 faces[2] = compute_glyph_face (selected_frame, selectface, faces[0]);
2321 faces[3] = compute_glyph_face (selected_frame, selectface, faces[1]);
2322
2323 /* Make sure the menu title is always displayed with
2324 `msdos-menu-active-face', no matter where the mouse pointer is. */
2325 for (i = 0; i < 4; i++)
2326 title_faces[i] = faces[3];
2327
2328 statecount = 1;
2329
2330 /* Don't let the title for the "Buffers" popup menu include a
2331 digit (which is ugly).
2332
2333 This is a terrible kludge, but I think the "Buffers" case is
2334 the only one where the title includes a number, so it doesn't
2335 seem to be necessary to make this more general. */
2336 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
2337 {
2338 menu->text[0][7] = '\0';
2339 buffers_num_deleted = 1;
2340 }
2341 state[0].menu = menu;
2342 mouse_off ();
2343 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
2344
2345 /* Turn off the cursor. Otherwise it shows through the menu
2346 panes, which is ugly. */
2347 IT_display_cursor (0);
2348
2349 IT_menu_display (menu, y0 - 1, x0 - 1, title_faces); /* display menu title */
2350 if (buffers_num_deleted)
2351 menu->text[0][7] = ' ';
2352 if ((onepane = menu->count == 1 && menu->submenu[0]))
2353 {
2354 menu->width = menu->submenu[0]->width;
2355 state[0].menu = menu->submenu[0];
2356 }
2357 else
2358 {
2359 state[0].menu = menu;
2360 }
2361 state[0].x = x0 - 1;
2362 state[0].y = y0;
2363 state[0].pane = onepane;
2364
2365 mouse_last_x = -1; /* A hack that forces display. */
2366 leave = 0;
2367 while (!leave)
2368 {
2369 if (!mouse_visible) mouse_on ();
2370 mouse_check_moved ();
2371 if (selected_frame->mouse_moved)
2372 {
2373 selected_frame->mouse_moved = 0;
2374 result = XM_IA_SELECT;
2375 mouse_get_xy (&x, &y);
2376 for (i = 0; i < statecount; i++)
2377 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
2378 {
2379 int dy = y - state[i].y;
2380 if (0 <= dy && dy < state[i].menu->count)
2381 {
2382 if (!state[i].menu->submenu[dy])
2383 if (state[i].menu->panenumber[dy])
2384 result = XM_SUCCESS;
2385 else
2386 result = XM_IA_SELECT;
2387 *pane = state[i].pane - 1;
2388 *selidx = dy;
2389 /* We hit some part of a menu, so drop extra menus that
2390 have been opened. That does not include an open and
2391 active submenu. */
2392 if (i != statecount - 2
2393 || state[i].menu->submenu[dy] != state[i+1].menu)
2394 while (i != statecount - 1)
2395 {
2396 statecount--;
2397 mouse_off ();
2398 ScreenUpdate (state[statecount].screen_behind);
2399 if (screen_virtual_segment)
2400 dosv_refresh_virtual_screen (0, screen_size);
2401 xfree (state[statecount].screen_behind);
2402 }
2403 if (i == statecount - 1 && state[i].menu->submenu[dy])
2404 {
2405 IT_menu_display (state[i].menu,
2406 state[i].y,
2407 state[i].x,
2408 faces);
2409 state[statecount].menu = state[i].menu->submenu[dy];
2410 state[statecount].pane = state[i].menu->panenumber[dy];
2411 mouse_off ();
2412 ScreenRetrieve (state[statecount].screen_behind
2413 = xmalloc (screensize));
2414 state[statecount].x
2415 = state[i].x + state[i].menu->width + 2;
2416 state[statecount].y = y;
2417 statecount++;
2418 }
2419 }
2420 }
2421 IT_menu_display (state[statecount - 1].menu,
2422 state[statecount - 1].y,
2423 state[statecount - 1].x,
2424 faces);
2425 }
2426 else
2427 /* We are busy-waiting for the mouse to move, so let's be nice
2428 to other Windows applications by releasing our time slice. */
2429 __dpmi_yield ();
2430 for (b = 0; b < mouse_button_count && !leave; b++)
2431 {
2432 /* Only leave if user both pressed and released the mouse, and in
2433 that order. This avoids popping down the menu pane unless
2434 the user is really done with it. */
2435 if (mouse_pressed (b, &x, &y))
2436 {
2437 while (mouse_button_depressed (b, &x, &y))
2438 __dpmi_yield ();
2439 leave = 1;
2440 }
2441 (void) mouse_released (b, &x, &y);
2442 }
2443 }
2444
2445 mouse_off ();
2446 ScreenUpdate (state[0].screen_behind);
2447 if (screen_virtual_segment)
2448 dosv_refresh_virtual_screen (0, screen_size);
2449 while (statecount--)
2450 xfree (state[statecount].screen_behind);
2451 IT_display_cursor (1); /* turn cursor back on */
2452 /* Clean up any mouse events that are waiting inside Emacs event queue.
2453 These events are likely to be generated before the menu was even
2454 displayed, probably because the user pressed and released the button
2455 (which invoked the menu) too quickly. If we don't remove these events,
2456 Emacs will process them after we return and surprise the user. */
2457 discard_mouse_events ();
2458 /* Allow mouse events generation by dos_rawgetc. */
2459 mouse_preempted--;
2460 return result;
2461 }
2462
2463 /* Dispose of a menu. */
2464
2465 void
2466 XMenuDestroy (Display *foo, XMenu *menu)
2467 {
2468 int i;
2469 if (menu->allocated)
2470 {
2471 for (i = 0; i < menu->count; i++)
2472 if (menu->submenu[i])
2473 XMenuDestroy (foo, menu->submenu[i]);
2474 xfree (menu->text);
2475 xfree (menu->submenu);
2476 xfree (menu->panenumber);
2477 }
2478 xfree (menu);
2479 }
2480
2481 int
2482 x_pixel_width (struct frame *f)
2483 {
2484 return FRAME_WIDTH (f);
2485 }
2486
2487 int
2488 x_pixel_height (struct frame *f)
2489 {
2490 return FRAME_HEIGHT (f);
2491 }
2492 #endif /* !HAVE_X_WINDOWS */
2493 \f
2494 /* ----------------------- DOS / UNIX conversion --------------------- */
2495
2496 void msdos_downcase_filename (unsigned char *);
2497
2498 /* Destructively turn backslashes into slashes. */
2499
2500 void
2501 dostounix_filename (p)
2502 register char *p;
2503 {
2504 msdos_downcase_filename (p);
2505
2506 while (*p)
2507 {
2508 if (*p == '\\')
2509 *p = '/';
2510 p++;
2511 }
2512 }
2513
2514 /* Destructively turn slashes into backslashes. */
2515
2516 void
2517 unixtodos_filename (p)
2518 register char *p;
2519 {
2520 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
2521 {
2522 *p += 'a' - 'A';
2523 p += 2;
2524 }
2525
2526 while (*p)
2527 {
2528 if (*p == '/')
2529 *p = '\\';
2530 p++;
2531 }
2532 }
2533
2534 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2535
2536 int
2537 getdefdir (drive, dst)
2538 int drive;
2539 char *dst;
2540 {
2541 char in_path[4], *p = in_path;
2542 int e = errno;
2543
2544 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2545 if (drive != 0)
2546 {
2547 *p++ = drive + 'A' - 1;
2548 *p++ = ':';
2549 }
2550
2551 *p++ = '.';
2552 *p = '\0';
2553 errno = 0;
2554 _fixpath (in_path, dst);
2555 if (errno)
2556 return 0;
2557
2558 msdos_downcase_filename (dst);
2559
2560 errno = e;
2561 return 1;
2562 }
2563
2564 /* Remove all CR's that are followed by a LF. */
2565
2566 int
2567 crlf_to_lf (n, buf)
2568 register int n;
2569 register unsigned char *buf;
2570 {
2571 unsigned char *np = buf;
2572 unsigned char *startp = buf;
2573 unsigned char *endp = buf + n;
2574
2575 if (n == 0)
2576 return n;
2577 while (buf < endp - 1)
2578 {
2579 if (*buf == 0x0d)
2580 {
2581 if (*(++buf) != 0x0a)
2582 *np++ = 0x0d;
2583 }
2584 else
2585 *np++ = *buf++;
2586 }
2587 if (buf < endp)
2588 *np++ = *buf++;
2589 return np - startp;
2590 }
2591
2592 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
2593
2594 /* In DJGPP v2.0, library `write' can call `malloc', which might
2595 cause relocation of the buffer whose address we get in ADDR.
2596 Here is a version of `write' that avoids calling `malloc',
2597 to serve us until such time as the library is fixed.
2598 Actually, what we define here is called `__write', because
2599 `write' is a stub that just jmp's to `__write' (to be
2600 POSIXLY-correct with respect to the global name-space). */
2601
2602 #include <io.h> /* for _write */
2603 #include <libc/dosio.h> /* for __file_handle_modes[] */
2604
2605 static char xbuf[64 * 1024]; /* DOS cannot write more in one chunk */
2606
2607 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
2608
2609 int
2610 __write (int handle, const void *buffer, size_t count)
2611 {
2612 if (count == 0)
2613 return 0;
2614
2615 if(__file_handle_modes[handle] & O_BINARY)
2616 return _write (handle, buffer, count);
2617 else
2618 {
2619 char *xbp = xbuf;
2620 const char *bp = buffer;
2621 int total_written = 0;
2622 int nmoved = 0, ncr = 0;
2623
2624 while (count)
2625 {
2626 /* The next test makes sure there's space for at least 2 more
2627 characters in xbuf[], so both CR and LF can be put there. */
2628 if (xbp < XBUF_END)
2629 {
2630 if (*bp == '\n')
2631 {
2632 ncr++;
2633 *xbp++ = '\r';
2634 }
2635 *xbp++ = *bp++;
2636 nmoved++;
2637 count--;
2638 }
2639 if (xbp >= XBUF_END || !count)
2640 {
2641 size_t to_write = nmoved + ncr;
2642 int written = _write (handle, xbuf, to_write);
2643
2644 if (written == -1)
2645 return -1;
2646 else
2647 total_written += nmoved; /* CRs aren't counted in ret value */
2648
2649 /* If some, but not all were written (disk full?), return
2650 an estimate of the total written bytes not counting CRs. */
2651 if (written < to_write)
2652 return total_written - (to_write - written) * nmoved/to_write;
2653
2654 nmoved = 0;
2655 ncr = 0;
2656 xbp = xbuf;
2657 }
2658 }
2659 return total_written;
2660 }
2661 }
2662
2663 /* A low-level file-renaming function which works around Windows 95 bug.
2664 This is pulled directly out of DJGPP v2.01 library sources, and only
2665 used when you compile with DJGPP v2.0. */
2666
2667 #include <io.h>
2668
2669 int _rename(const char *old, const char *new)
2670 {
2671 __dpmi_regs r;
2672 int olen = strlen(old) + 1;
2673 int i;
2674 int use_lfn = _USE_LFN;
2675 char tempfile[FILENAME_MAX];
2676 const char *orig = old;
2677 int lfn_fd = -1;
2678
2679 r.x.dx = __tb_offset;
2680 r.x.di = __tb_offset + olen;
2681 r.x.ds = r.x.es = __tb_segment;
2682
2683 if (use_lfn)
2684 {
2685 /* Windows 95 bug: for some filenames, when you rename
2686 file -> file~ (as in Emacs, to leave a backup), the
2687 short 8+3 alias doesn't change, which effectively
2688 makes OLD and NEW the same file. We must rename
2689 through a temporary file to work around this. */
2690
2691 char *pbase = 0, *p;
2692 static char try_char[] = "abcdefghijklmnopqrstuvwxyz012345789";
2693 int idx = sizeof(try_char) - 1;
2694
2695 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
2696 might point to another drive, which will fail the DOS call. */
2697 strcpy(tempfile, old);
2698 for (p = tempfile; *p; p++) /* ensure temporary is on the same drive */
2699 if (*p == '/' || *p == '\\' || *p == ':')
2700 pbase = p;
2701 if (pbase)
2702 pbase++;
2703 else
2704 pbase = tempfile;
2705 strcpy(pbase, "X$$djren$$.$$temp$$");
2706
2707 do
2708 {
2709 if (idx <= 0)
2710 return -1;
2711 *pbase = try_char[--idx];
2712 } while (_chmod(tempfile, 0) != -1);
2713
2714 r.x.ax = 0x7156;
2715 _put_path2(tempfile, olen);
2716 _put_path(old);
2717 __dpmi_int(0x21, &r);
2718 if (r.x.flags & 1)
2719 {
2720 errno = __doserr_to_errno(r.x.ax);
2721 return -1;
2722 }
2723
2724 /* Now create a file with the original name. This will
2725 ensure that NEW will always have a 8+3 alias
2726 different from that of OLD. (Seems to be required
2727 when NameNumericTail in the Registry is set to 0.) */
2728 lfn_fd = _creat(old, 0);
2729
2730 olen = strlen(tempfile) + 1;
2731 old = tempfile;
2732 r.x.di = __tb_offset + olen;
2733 }
2734
2735 for (i=0; i<2; i++)
2736 {
2737 if(use_lfn)
2738 r.x.ax = 0x7156;
2739 else
2740 r.h.ah = 0x56;
2741 _put_path2(new, olen);
2742 _put_path(old);
2743 __dpmi_int(0x21, &r);
2744 if(r.x.flags & 1)
2745 {
2746 if (r.x.ax == 5 && i == 0) /* access denied */
2747 remove(new); /* and try again */
2748 else
2749 {
2750 errno = __doserr_to_errno(r.x.ax);
2751
2752 /* Restore to original name if we renamed it to temporary. */
2753 if (use_lfn)
2754 {
2755 if (lfn_fd != -1)
2756 {
2757 _close (lfn_fd);
2758 remove (orig);
2759 }
2760 _put_path2(orig, olen);
2761 _put_path(tempfile);
2762 r.x.ax = 0x7156;
2763 __dpmi_int(0x21, &r);
2764 }
2765 return -1;
2766 }
2767 }
2768 else
2769 break;
2770 }
2771
2772 /* Success. Delete the file possibly created to work
2773 around the Windows 95 bug. */
2774 if (lfn_fd != -1)
2775 return (_close (lfn_fd) == 0) ? remove (orig) : -1;
2776 return 0;
2777 }
2778
2779 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
2780
2781 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
2782 0, 0, 0,
2783 "Return non-nil if long file names are supported on MSDOS.")
2784 ()
2785 {
2786 return (_USE_LFN ? Qt : Qnil);
2787 }
2788
2789 /* Convert alphabetic characters in a filename to lower-case. */
2790
2791 void
2792 msdos_downcase_filename (p)
2793 register unsigned char *p;
2794 {
2795 /* Always lower-case drive letters a-z, even if the filesystem
2796 preserves case in filenames.
2797 This is so MSDOS filenames could be compared by string comparison
2798 functions that are case-sensitive. Even case-preserving filesystems
2799 do not distinguish case in drive letters. */
2800 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
2801 {
2802 *p += 'a' - 'A';
2803 p += 2;
2804 }
2805
2806 /* Under LFN we expect to get pathnames in their true case. */
2807 if (NILP (Fmsdos_long_file_names ()))
2808 for ( ; *p; p++)
2809 if (*p >= 'A' && *p <= 'Z')
2810 *p += 'a' - 'A';
2811 }
2812
2813 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
2814 1, 1, 0,
2815 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
2816 When long filenames are supported, doesn't change FILENAME.\n\
2817 If FILENAME is not a string, returns nil.\n\
2818 The argument object is never altered--the value is a copy.")
2819 (filename)
2820 Lisp_Object filename;
2821 {
2822 Lisp_Object tem;
2823
2824 if (! STRINGP (filename))
2825 return Qnil;
2826
2827 tem = Fcopy_sequence (filename);
2828 msdos_downcase_filename (XSTRING (tem)->data);
2829 return tem;
2830 }
2831 \f
2832 /* The Emacs root directory as determined by init_environment. */
2833
2834 static char emacsroot[MAXPATHLEN];
2835
2836 char *
2837 rootrelativepath (rel)
2838 char *rel;
2839 {
2840 static char result[MAXPATHLEN + 10];
2841
2842 strcpy (result, emacsroot);
2843 strcat (result, "/");
2844 strcat (result, rel);
2845 return result;
2846 }
2847
2848 /* Define a lot of environment variables if not already defined. Don't
2849 remove anything unless you know what you're doing -- lots of code will
2850 break if one or more of these are missing. */
2851
2852 void
2853 init_environment (argc, argv, skip_args)
2854 int argc;
2855 char **argv;
2856 int skip_args;
2857 {
2858 char *s, *t, *root;
2859 int len;
2860 static const char * const tempdirs[] = {
2861 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2862 };
2863 int i;
2864 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
2865
2866 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2867 temporary files and assume "/tmp" if $TMPDIR is unset, which
2868 will break on DOS/Windows. Refuse to work if we cannot find
2869 a directory, not even "c:/", usable for that purpose. */
2870 for (i = 0; i < imax ; i++)
2871 {
2872 const char *tmp = tempdirs[i];
2873
2874 if (*tmp == '$')
2875 tmp = getenv (tmp + 1);
2876 /* Note that `access' can lie to us if the directory resides on a
2877 read-only filesystem, like CD-ROM or a write-protected floppy.
2878 The only way to be really sure is to actually create a file and
2879 see if it succeeds. But I think that's too much to ask. */
2880 if (tmp && access (tmp, D_OK) == 0)
2881 {
2882 setenv ("TMPDIR", tmp, 1);
2883 break;
2884 }
2885 }
2886 if (i >= imax)
2887 cmd_error_internal
2888 (Fcons (Qerror,
2889 Fcons (build_string ("no usable temporary directories found!!"),
2890 Qnil)),
2891 "While setting TMPDIR: ");
2892
2893 /* Find our root from argv[0]. Assuming argv[0] is, say,
2894 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
2895 root = alloca (MAXPATHLEN + 20);
2896 _fixpath (argv[0], root);
2897 msdos_downcase_filename (root);
2898 len = strlen (root);
2899 while (len > 0 && root[len] != '/' && root[len] != ':')
2900 len--;
2901 root[len] = '\0';
2902 if (len > 4
2903 && (strcmp (root + len - 4, "/bin") == 0
2904 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
2905 root[len - 4] = '\0';
2906 else
2907 strcpy (root, "c:/emacs"); /* let's be defensive */
2908 len = strlen (root);
2909 strcpy (emacsroot, root);
2910
2911 /* We default HOME to our root. */
2912 setenv ("HOME", root, 0);
2913
2914 /* We default EMACSPATH to root + "/bin". */
2915 strcpy (root + len, "/bin");
2916 setenv ("EMACSPATH", root, 0);
2917
2918 /* I don't expect anybody to ever use other terminals so the internal
2919 terminal is the default. */
2920 setenv ("TERM", "internal", 0);
2921
2922 #ifdef HAVE_X_WINDOWS
2923 /* Emacs expects DISPLAY to be set. */
2924 setenv ("DISPLAY", "unix:0.0", 0);
2925 #endif
2926
2927 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
2928 downcase it and mirror the backslashes. */
2929 s = getenv ("COMSPEC");
2930 if (!s) s = "c:/command.com";
2931 t = alloca (strlen (s) + 1);
2932 strcpy (t, s);
2933 dostounix_filename (t);
2934 setenv ("SHELL", t, 0);
2935
2936 /* PATH is also downcased and backslashes mirrored. */
2937 s = getenv ("PATH");
2938 if (!s) s = "";
2939 t = alloca (strlen (s) + 3);
2940 /* Current directory is always considered part of MsDos's path but it is
2941 not normally mentioned. Now it is. */
2942 strcat (strcpy (t, ".;"), s);
2943 dostounix_filename (t); /* Not a single file name, but this should work. */
2944 setenv ("PATH", t, 1);
2945
2946 /* In some sense all dos users have root privileges, so... */
2947 setenv ("USER", "root", 0);
2948 setenv ("NAME", getenv ("USER"), 0);
2949
2950 /* Time zone determined from country code. To make this possible, the
2951 country code may not span more than one time zone. In other words,
2952 in the USA, you lose. */
2953 if (!getenv ("TZ"))
2954 switch (dos_country_code)
2955 {
2956 case 31: /* Belgium */
2957 case 32: /* The Netherlands */
2958 case 33: /* France */
2959 case 34: /* Spain */
2960 case 36: /* Hungary */
2961 case 38: /* Yugoslavia (or what's left of it?) */
2962 case 39: /* Italy */
2963 case 41: /* Switzerland */
2964 case 42: /* Tjekia */
2965 case 45: /* Denmark */
2966 case 46: /* Sweden */
2967 case 47: /* Norway */
2968 case 48: /* Poland */
2969 case 49: /* Germany */
2970 /* Daylight saving from last Sunday in March to last Sunday in
2971 September, both at 2AM. */
2972 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2973 break;
2974 case 44: /* United Kingdom */
2975 case 351: /* Portugal */
2976 case 354: /* Iceland */
2977 setenv ("TZ", "GMT+00", 0);
2978 break;
2979 case 81: /* Japan */
2980 case 82: /* Korea */
2981 setenv ("TZ", "JST-09", 0);
2982 break;
2983 case 90: /* Turkey */
2984 case 358: /* Finland */
2985 setenv ("TZ", "EET-02", 0);
2986 break;
2987 case 972: /* Israel */
2988 /* This is an approximation. (For exact rules, use the
2989 `zoneinfo/israel' file which comes with DJGPP, but you need
2990 to install it in `/usr/share/zoneinfo/' directory first.) */
2991 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2992 break;
2993 }
2994 tzset ();
2995 }
2996
2997 \f
2998
2999 static int break_stat; /* BREAK check mode status. */
3000 static int stdin_stat; /* stdin IOCTL status. */
3001
3002 #if __DJGPP__ < 2
3003
3004 /* These must be global. */
3005 static _go32_dpmi_seginfo ctrl_break_vector;
3006 static _go32_dpmi_registers ctrl_break_regs;
3007 static int ctrlbreakinstalled = 0;
3008
3009 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
3010
3011 void
3012 ctrl_break_func (regs)
3013 _go32_dpmi_registers *regs;
3014 {
3015 Vquit_flag = Qt;
3016 }
3017
3018 void
3019 install_ctrl_break_check ()
3020 {
3021 if (!ctrlbreakinstalled)
3022 {
3023 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
3024 was compiler with Djgpp 1.11 maintenance level 5 or later! */
3025 ctrlbreakinstalled = 1;
3026 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
3027 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
3028 &ctrl_break_regs);
3029 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
3030 }
3031 }
3032
3033 #endif /* __DJGPP__ < 2 */
3034
3035 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
3036 control chars by DOS. Determine the keyboard type. */
3037
3038 int
3039 dos_ttraw ()
3040 {
3041 union REGS inregs, outregs;
3042 static int first_time = 1;
3043
3044 break_stat = getcbrk ();
3045 setcbrk (0);
3046 #if __DJGPP__ < 2
3047 install_ctrl_break_check ();
3048 #endif
3049
3050 if (first_time)
3051 {
3052 inregs.h.ah = 0xc0;
3053 int86 (0x15, &inregs, &outregs);
3054 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
3055
3056 have_mouse = 0;
3057
3058 if (internal_terminal
3059 #ifdef HAVE_X_WINDOWS
3060 && inhibit_window_system
3061 #endif
3062 )
3063 {
3064 inregs.x.ax = 0x0021;
3065 int86 (0x33, &inregs, &outregs);
3066 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
3067 if (!have_mouse)
3068 {
3069 /* Reportedly, the above doesn't work for some mouse drivers. There
3070 is an additional detection method that should work, but might be
3071 a little slower. Use that as an alternative. */
3072 inregs.x.ax = 0x0000;
3073 int86 (0x33, &inregs, &outregs);
3074 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
3075 }
3076
3077 if (have_mouse)
3078 {
3079 have_mouse = 1; /* enable mouse */
3080 mouse_visible = 0;
3081
3082 if (outregs.x.bx == 3)
3083 {
3084 mouse_button_count = 3;
3085 mouse_button_translate[0] = 0; /* Left */
3086 mouse_button_translate[1] = 2; /* Middle */
3087 mouse_button_translate[2] = 1; /* Right */
3088 }
3089 else
3090 {
3091 mouse_button_count = 2;
3092 mouse_button_translate[0] = 0;
3093 mouse_button_translate[1] = 1;
3094 }
3095 mouse_position_hook = &mouse_get_pos;
3096 mouse_init ();
3097 }
3098 }
3099
3100 first_time = 0;
3101
3102 #if __DJGPP__ >= 2
3103
3104 stdin_stat = setmode (fileno (stdin), O_BINARY);
3105 return (stdin_stat != -1);
3106 }
3107 else
3108 return (setmode (fileno (stdin), O_BINARY) != -1);
3109
3110 #else /* __DJGPP__ < 2 */
3111
3112 }
3113
3114 /* I think it is wrong to overwrite `stdin_stat' every time
3115 but the first one this function is called, but I don't
3116 want to change the way it used to work in v1.x.--EZ */
3117
3118 inregs.x.ax = 0x4400; /* Get IOCTL status. */
3119 inregs.x.bx = 0x00; /* 0 = stdin. */
3120 intdos (&inregs, &outregs);
3121 stdin_stat = outregs.h.dl;
3122
3123 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
3124 inregs.x.ax = 0x4401; /* Set IOCTL status */
3125 intdos (&inregs, &outregs);
3126 return !outregs.x.cflag;
3127
3128 #endif /* __DJGPP__ < 2 */
3129 }
3130
3131 /* Restore status of standard input and Ctrl-C checking. */
3132
3133 int
3134 dos_ttcooked ()
3135 {
3136 union REGS inregs, outregs;
3137
3138 setcbrk (break_stat);
3139 mouse_off ();
3140
3141 #if __DJGPP__ >= 2
3142
3143 return (setmode (fileno (stdin), stdin_stat) != -1);
3144
3145 #else /* not __DJGPP__ >= 2 */
3146
3147 inregs.x.ax = 0x4401; /* Set IOCTL status. */
3148 inregs.x.bx = 0x00; /* 0 = stdin. */
3149 inregs.x.dx = stdin_stat;
3150 intdos (&inregs, &outregs);
3151 return !outregs.x.cflag;
3152
3153 #endif /* not __DJGPP__ >= 2 */
3154 }
3155
3156 \f
3157 /* Run command as specified by ARGV in directory DIR.
3158 The command is run with input from TEMPIN, output to
3159 file TEMPOUT and stderr to TEMPERR. */
3160
3161 int
3162 run_msdos_command (argv, working_dir, tempin, tempout, temperr, envv)
3163 unsigned char **argv;
3164 const char *working_dir;
3165 int tempin, tempout, temperr;
3166 char **envv;
3167 {
3168 char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
3169 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
3170 int msshell, result = -1;
3171 int inbak, outbak, errbak;
3172 int x, y;
3173 Lisp_Object cmd;
3174
3175 /* Get current directory as MSDOS cwd is not per-process. */
3176 getwd (oldwd);
3177
3178 /* If argv[0] is the shell, it might come in any lettercase.
3179 Since `Fmember' is case-sensitive, we need to downcase
3180 argv[0], even if we are on case-preserving filesystems. */
3181 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
3182 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
3183 {
3184 *pl = *pa++;
3185 if (*pl >= 'A' && *pl <= 'Z')
3186 *pl += 'a' - 'A';
3187 }
3188 *pl = '\0';
3189
3190 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
3191 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
3192 && !strcmp ("-c", argv[1]);
3193 if (msshell)
3194 {
3195 saveargv1 = argv[1];
3196 saveargv2 = argv[2];
3197 argv[1] = "/c";
3198 if (argv[2])
3199 {
3200 char *p = alloca (strlen (argv[2]) + 1);
3201
3202 strcpy (argv[2] = p, saveargv2);
3203 while (*p && isspace (*p))
3204 p++;
3205 while (*p && !isspace (*p))
3206 if (*p == '/')
3207 *p++ = '\\';
3208 else
3209 p++;
3210 }
3211 }
3212
3213 chdir (working_dir);
3214 inbak = dup (0);
3215 outbak = dup (1);
3216 errbak = dup (2);
3217 if (inbak < 0 || outbak < 0 || errbak < 0)
3218 goto done; /* Allocation might fail due to lack of descriptors. */
3219
3220 if (have_mouse > 0)
3221 mouse_get_xy (&x, &y);
3222
3223 dos_ttcooked (); /* do it here while 0 = stdin */
3224
3225 dup2 (tempin, 0);
3226 dup2 (tempout, 1);
3227 dup2 (temperr, 2);
3228
3229 #if __DJGPP__ > 1
3230
3231 if (msshell && !argv[3])
3232 {
3233 /* MS-DOS native shells are too restrictive. For starters, they
3234 cannot grok commands longer than 126 characters. In DJGPP v2
3235 and later, `system' is much smarter, so we'll call it instead. */
3236
3237 const char *cmnd;
3238
3239 /* A shell gets a single argument--its full command
3240 line--whose original was saved in `saveargv2'. */
3241
3242 /* Don't let them pass empty command lines to `system', since
3243 with some shells it will try to invoke an interactive shell,
3244 which will hang Emacs. */
3245 for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
3246 ;
3247 if (*cmnd)
3248 {
3249 extern char **environ;
3250 int save_system_flags = __system_flags;
3251
3252 /* Request the most powerful version of `system'. We need
3253 all the help we can get to avoid calling stock DOS shells. */
3254 __system_flags = (__system_redirect
3255 | __system_use_shell
3256 | __system_allow_multiple_cmds
3257 | __system_allow_long_cmds
3258 | __system_handle_null_commands
3259 | __system_emulate_chdir);
3260
3261 environ = envv;
3262 result = system (cmnd);
3263 __system_flags = save_system_flags;
3264 }
3265 else
3266 result = 0; /* emulate Unixy shell behavior with empty cmd line */
3267 }
3268 else
3269
3270 #endif /* __DJGPP__ > 1 */
3271
3272 result = spawnve (P_WAIT, argv[0], argv, envv);
3273
3274 dup2 (inbak, 0);
3275 dup2 (outbak, 1);
3276 dup2 (errbak, 2);
3277 close (inbak);
3278 close (outbak);
3279 close (errbak);
3280
3281 dos_ttraw ();
3282 if (have_mouse > 0)
3283 {
3284 mouse_init ();
3285 mouse_moveto (x, y);
3286 }
3287
3288 /* Some programs might change the meaning of the highest bit of the
3289 text attribute byte, so we get blinking characters instead of the
3290 bright background colors. Restore that. */
3291 bright_bg ();
3292
3293 done:
3294 chdir (oldwd);
3295 if (msshell)
3296 {
3297 argv[1] = saveargv1;
3298 argv[2] = saveargv2;
3299 }
3300 return result;
3301 }
3302
3303 croak (badfunc)
3304 char *badfunc;
3305 {
3306 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
3307 reset_sys_modes ();
3308 exit (1);
3309 }
3310 \f
3311 #if __DJGPP__ < 2
3312
3313 /* ------------------------- Compatibility functions -------------------
3314 * gethostname
3315 * gettimeofday
3316 */
3317
3318 /* Hostnames for a pc are not really funny,
3319 but they are used in change log so we emulate the best we can. */
3320
3321 gethostname (p, size)
3322 char *p;
3323 int size;
3324 {
3325 char *q = egetenv ("HOSTNAME");
3326
3327 if (!q) q = "pc";
3328 strcpy (p, q);
3329 return 0;
3330 }
3331
3332 /* When time zones are set from Ms-Dos too many C-libraries are playing
3333 tricks with time values. We solve this by defining our own version
3334 of `gettimeofday' bypassing GO32. Our version needs to be initialized
3335 once and after each call to `tzset' with TZ changed. That is
3336 accomplished by aliasing tzset to init_gettimeofday. */
3337
3338 static struct tm time_rec;
3339
3340 int
3341 gettimeofday (struct timeval *tp, struct timezone *tzp)
3342 {
3343 if (tp)
3344 {
3345 struct time t;
3346 struct tm tm;
3347
3348 gettime (&t);
3349 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
3350 {
3351 struct date d;
3352 getdate (&d);
3353 time_rec.tm_year = d.da_year - 1900;
3354 time_rec.tm_mon = d.da_mon - 1;
3355 time_rec.tm_mday = d.da_day;
3356 }
3357
3358 time_rec.tm_hour = t.ti_hour;
3359 time_rec.tm_min = t.ti_min;
3360 time_rec.tm_sec = t.ti_sec;
3361
3362 tm = time_rec;
3363 tm.tm_gmtoff = dos_timezone_offset;
3364
3365 tp->tv_sec = mktime (&tm); /* may modify tm */
3366 tp->tv_usec = t.ti_hund * (1000000 / 100);
3367 }
3368 /* Ignore tzp; it's obsolescent. */
3369 return 0;
3370 }
3371
3372 #endif /* __DJGPP__ < 2 */
3373
3374 /*
3375 * A list of unimplemented functions that we silently ignore.
3376 */
3377
3378 #if __DJGPP__ < 2
3379 unsigned alarm (s) unsigned s; {}
3380 fork () { return 0; }
3381 int kill (x, y) int x, y; { return -1; }
3382 nice (p) int p; {}
3383 void volatile pause () {}
3384 sigsetmask (x) int x; { return 0; }
3385 sigblock (mask) int mask; { return 0; }
3386 #endif
3387
3388 void request_sigio (void) {}
3389 setpgrp () {return 0; }
3390 setpriority (x,y,z) int x,y,z; { return 0; }
3391 void unrequest_sigio (void) {}
3392
3393 #if __DJGPP__ > 1
3394
3395 #ifdef POSIX_SIGNALS
3396
3397 /* Augment DJGPP library POSIX signal functions. This is needed
3398 as of DJGPP v2.01, but might be in the library in later releases. */
3399
3400 #include <libc/bss.h>
3401
3402 /* A counter to know when to re-initialize the static sets. */
3403 static int sigprocmask_count = -1;
3404
3405 /* Which signals are currently blocked (initially none). */
3406 static sigset_t current_mask;
3407
3408 /* Which signals are pending (initially none). */
3409 static sigset_t pending_signals;
3410
3411 /* Previous handlers to restore when the blocked signals are unblocked. */
3412 typedef void (*sighandler_t)(int);
3413 static sighandler_t prev_handlers[320];
3414
3415 /* A signal handler which just records that a signal occured
3416 (it will be raised later, if and when the signal is unblocked). */
3417 static void
3418 sig_suspender (signo)
3419 int signo;
3420 {
3421 sigaddset (&pending_signals, signo);
3422 }
3423
3424 int
3425 sigprocmask (how, new_set, old_set)
3426 int how;
3427 const sigset_t *new_set;
3428 sigset_t *old_set;
3429 {
3430 int signo;
3431 sigset_t new_mask;
3432
3433 /* If called for the first time, initialize. */
3434 if (sigprocmask_count != __bss_count)
3435 {
3436 sigprocmask_count = __bss_count;
3437 sigemptyset (&pending_signals);
3438 sigemptyset (&current_mask);
3439 for (signo = 0; signo < 320; signo++)
3440 prev_handlers[signo] = SIG_ERR;
3441 }
3442
3443 if (old_set)
3444 *old_set = current_mask;
3445
3446 if (new_set == 0)
3447 return 0;
3448
3449 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
3450 {
3451 errno = EINVAL;
3452 return -1;
3453 }
3454
3455 sigemptyset (&new_mask);
3456
3457 /* DJGPP supports upto 320 signals. */
3458 for (signo = 0; signo < 320; signo++)
3459 {
3460 if (sigismember (&current_mask, signo))
3461 sigaddset (&new_mask, signo);
3462 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
3463 {
3464 sigaddset (&new_mask, signo);
3465
3466 /* SIGKILL is silently ignored, as on other platforms. */
3467 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
3468 prev_handlers[signo] = signal (signo, sig_suspender);
3469 }
3470 if (( how == SIG_UNBLOCK
3471 && sigismember (&new_mask, signo)
3472 && sigismember (new_set, signo))
3473 || (how == SIG_SETMASK
3474 && sigismember (&new_mask, signo)
3475 && !sigismember (new_set, signo)))
3476 {
3477 sigdelset (&new_mask, signo);
3478 if (prev_handlers[signo] != SIG_ERR)
3479 {
3480 signal (signo, prev_handlers[signo]);
3481 prev_handlers[signo] = SIG_ERR;
3482 }
3483 if (sigismember (&pending_signals, signo))
3484 {
3485 sigdelset (&pending_signals, signo);
3486 raise (signo);
3487 }
3488 }
3489 }
3490 current_mask = new_mask;
3491 return 0;
3492 }
3493
3494 #else /* not POSIX_SIGNALS */
3495
3496 sigsetmask (x) int x; { return 0; }
3497 sigblock (mask) int mask; { return 0; }
3498
3499 #endif /* not POSIX_SIGNALS */
3500 #endif /* __DJGPP__ > 1 */
3501
3502 #ifndef HAVE_SELECT
3503 #include "sysselect.h"
3504
3505 #ifndef EMACS_TIME_ZERO_OR_NEG_P
3506 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
3507 ((long)(time).tv_sec < 0 \
3508 || ((time).tv_sec == 0 \
3509 && (long)(time).tv_usec <= 0))
3510 #endif
3511
3512 /* This yields the rest of the current time slice to the task manager.
3513 It should be called by any code which knows that it has nothing
3514 useful to do except idle.
3515
3516 I don't use __dpmi_yield here, since versions of library before 2.02
3517 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
3518 on some versions of Windows 9X. */
3519
3520 void
3521 dos_yield_time_slice (void)
3522 {
3523 _go32_dpmi_registers r;
3524
3525 r.x.ax = 0x1680;
3526 r.x.ss = r.x.sp = r.x.flags = 0;
3527 _go32_dpmi_simulate_int (0x2f, &r);
3528 if (r.h.al == 0x80)
3529 errno = ENOSYS;
3530 }
3531
3532 /* Only event queue is checked. */
3533 /* We don't have to call timer_check here
3534 because wait_reading_process_input takes care of that. */
3535 int
3536 sys_select (nfds, rfds, wfds, efds, timeout)
3537 int nfds;
3538 SELECT_TYPE *rfds, *wfds, *efds;
3539 EMACS_TIME *timeout;
3540 {
3541 int check_input;
3542 struct time t;
3543
3544 check_input = 0;
3545 if (rfds)
3546 {
3547 check_input = FD_ISSET (0, rfds);
3548 FD_ZERO (rfds);
3549 }
3550 if (wfds)
3551 FD_ZERO (wfds);
3552 if (efds)
3553 FD_ZERO (efds);
3554
3555 if (nfds != 1)
3556 abort ();
3557
3558 /* If we are looking only for the terminal, with no timeout,
3559 just read it and wait -- that's more efficient. */
3560 if (!timeout)
3561 {
3562 while (!detect_input_pending ())
3563 {
3564 dos_yield_time_slice ();
3565 }
3566 }
3567 else
3568 {
3569 EMACS_TIME clnow, cllast, cldiff;
3570
3571 gettime (&t);
3572 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
3573
3574 while (!check_input || !detect_input_pending ())
3575 {
3576 gettime (&t);
3577 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
3578 EMACS_SUB_TIME (cldiff, clnow, cllast);
3579
3580 /* When seconds wrap around, we assume that no more than
3581 1 minute passed since last `gettime'. */
3582 if (EMACS_TIME_NEG_P (cldiff))
3583 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
3584 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
3585
3586 /* Stop when timeout value crosses zero. */
3587 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
3588 return 0;
3589 cllast = clnow;
3590 dos_yield_time_slice ();
3591 }
3592 }
3593
3594 FD_SET (0, rfds);
3595 return 1;
3596 }
3597 #endif
3598
3599 /*
3600 * Define overlaid functions:
3601 *
3602 * chdir -> sys_chdir
3603 * tzset -> init_gettimeofday
3604 * abort -> dos_abort
3605 */
3606
3607 #ifdef chdir
3608 #undef chdir
3609 extern int chdir ();
3610
3611 int
3612 sys_chdir (path)
3613 const char* path;
3614 {
3615 int len = strlen (path);
3616 char *tmp = (char *)path;
3617
3618 if (*tmp && tmp[1] == ':')
3619 {
3620 if (getdisk () != tolower (tmp[0]) - 'a')
3621 setdisk (tolower (tmp[0]) - 'a');
3622 tmp += 2; /* strip drive: KFS 1995-07-06 */
3623 len -= 2;
3624 }
3625
3626 if (len > 1 && (tmp[len - 1] == '/'))
3627 {
3628 char *tmp1 = (char *) alloca (len + 1);
3629 strcpy (tmp1, tmp);
3630 tmp1[len - 1] = 0;
3631 tmp = tmp1;
3632 }
3633 return chdir (tmp);
3634 }
3635 #endif
3636
3637 #ifdef tzset
3638 #undef tzset
3639 extern void tzset (void);
3640
3641 void
3642 init_gettimeofday ()
3643 {
3644 time_t ltm, gtm;
3645 struct tm *lstm;
3646
3647 tzset ();
3648 ltm = gtm = time (NULL);
3649 ltm = mktime (lstm = localtime (&ltm));
3650 gtm = mktime (gmtime (&gtm));
3651 time_rec.tm_hour = 99; /* force gettimeofday to get date */
3652 time_rec.tm_isdst = lstm->tm_isdst;
3653 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
3654 }
3655 #endif
3656
3657 #ifdef abort
3658 #undef abort
3659 void
3660 dos_abort (file, line)
3661 char *file;
3662 int line;
3663 {
3664 char buffer1[200], buffer2[400];
3665 int i, j;
3666
3667 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
3668 for (i = j = 0; buffer1[i]; i++) {
3669 buffer2[j++] = buffer1[i];
3670 buffer2[j++] = 0x70;
3671 }
3672 dosmemput (buffer2, j, (int)ScreenPrimary);
3673 ScreenSetCursor (2, 0);
3674 abort ();
3675 }
3676 #else
3677 void
3678 abort ()
3679 {
3680 dos_ttcooked ();
3681 ScreenSetCursor (10, 0);
3682 cputs ("\r\n\nEmacs aborted!\r\n");
3683 #if __DJGPP__ > 1
3684 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
3685 if (screen_virtual_segment)
3686 dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
3687 #endif /* __DJGPP_MINOR__ < 2 */
3688 /* Generate traceback, so we could tell whodunit. */
3689 signal (SIGINT, SIG_DFL);
3690 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
3691 #endif
3692 exit (2);
3693 }
3694 #endif
3695
3696 /* The following two are required so that customization feature
3697 won't complain about unbound variables. */
3698 #ifndef HAVE_X_WINDOWS
3699 /* Search path for bitmap files (xfns.c). */
3700 Lisp_Object Vx_bitmap_file_path;
3701 #endif
3702 #ifndef subprocesses
3703 /* Nonzero means delete a process right away if it exits (process.c). */
3704 static int delete_exited_processes;
3705 #endif
3706
3707 syms_of_msdos ()
3708 {
3709 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
3710 staticpro (&recent_doskeys);
3711 #ifndef HAVE_X_WINDOWS
3712 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
3713 "List of directories to search for bitmap files for X.");
3714 Vx_bitmap_file_path = decode_env_path ((char *) 0, ".");
3715
3716 /* The following two are from xfns.c: */
3717 Qbackground_color = intern ("background-color");
3718 staticpro (&Qbackground_color);
3719 Qforeground_color = intern ("foreground-color");
3720 staticpro (&Qforeground_color);
3721 #endif
3722 #ifndef subprocesses
3723 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
3724 "*Non-nil means delete processes immediately when they exit.\n\
3725 nil means don't delete them until `list-processes' is run.");
3726 delete_exited_processes = 0;
3727 #endif
3728
3729 defsubr (&Srecent_doskeys);
3730 defsubr (&Smsdos_long_file_names);
3731 defsubr (&Smsdos_downcase_filename);
3732 }
3733
3734 #endif /* MSDOS */
3735