]> code.delx.au - gnu-emacs/blob - src/msdos.c
(restrict_dos_process): Renamed from can_run_dos_process.
[gnu-emacs] / src / msdos.c
1 /* MS-DOS specific C utilities.
2 Copyright (C) 1993, 1994, 1995, 1996 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 <sys/stat.h> /* for _fixpath */
37 #if __DJGPP__ >= 2
38 #include <fcntl.h>
39 #include <libc/dosio.h> /* for _USE_LFN */
40 #endif
41
42 #include "dosfns.h"
43 #include "msdos.h"
44 #include "systime.h"
45 #include "termhooks.h"
46 #include "dispextern.h"
47 #include "termopts.h"
48 #include "frame.h"
49 #include "window.h"
50 #include <go32.h>
51 #include <pc.h>
52 #include <ctype.h>
53 /* #include <process.h> */
54 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
55 #define P_WAIT 1
56
57 #ifndef _USE_LFN
58 #define _USE_LFN 0
59 #endif
60
61 #if __DJGPP__ > 1
62
63 #include <signal.h>
64
65 #ifndef SYSTEM_MALLOC
66
67 #ifdef GNU_MALLOC
68
69 /* If other `malloc' than ours is used, force our `sbrk' behave like
70 Unix programs expect (resize memory blocks to keep them contiguous).
71 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
72 because that's what `gmalloc' expects to get. */
73 #include <crt0.h>
74
75 #ifdef REL_ALLOC
76 int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
77 #else /* not REL_ALLOC */
78 int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
79 #endif /* not REL_ALLOC */
80 #endif /* GNU_MALLOC */
81
82 #endif /* not SYSTEM_MALLOC */
83 #endif /* __DJGPP__ > 1 */
84
85 static unsigned long
86 event_timestamp ()
87 {
88 struct time t;
89 unsigned long s;
90
91 gettime (&t);
92 s = t.ti_min;
93 s *= 60;
94 s += t.ti_sec;
95 s *= 1000;
96 s += t.ti_hund * 10;
97
98 return s;
99 }
100
101 \f
102 /* ------------------------ Mouse control ---------------------------
103 *
104 * Coordinates are in screen positions and zero based.
105 * Mouse buttons are numbered from left to right and also zero based.
106 */
107
108 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
109 static int mouse_visible;
110
111 static int mouse_last_x;
112 static int mouse_last_y;
113
114 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
115 static int mouse_button_count;
116
117 void
118 mouse_on ()
119 {
120 union REGS regs;
121
122 if (have_mouse > 0 && !mouse_visible)
123 {
124 if (termscript)
125 fprintf (termscript, "<M_ON>");
126 regs.x.ax = 0x0001;
127 int86 (0x33, &regs, &regs);
128 mouse_visible = 1;
129 }
130 }
131
132 void
133 mouse_off ()
134 {
135 union REGS regs;
136
137 if (have_mouse > 0 && mouse_visible)
138 {
139 if (termscript)
140 fprintf (termscript, "<M_OFF>");
141 regs.x.ax = 0x0002;
142 int86 (0x33, &regs, &regs);
143 mouse_visible = 0;
144 }
145 }
146
147 void
148 mouse_moveto (x, y)
149 int x, y;
150 {
151 union REGS regs;
152
153 if (termscript)
154 fprintf (termscript, "<M_XY=%dx%d>", x, y);
155 regs.x.ax = 0x0004;
156 mouse_last_x = regs.x.cx = x * 8;
157 mouse_last_y = regs.x.dx = y * 8;
158 int86 (0x33, &regs, &regs);
159 }
160
161 static int
162 mouse_pressed (b, xp, yp)
163 int b, *xp, *yp;
164 {
165 union REGS regs;
166
167 if (b >= mouse_button_count)
168 return 0;
169 regs.x.ax = 0x0005;
170 regs.x.bx = mouse_button_translate[b];
171 int86 (0x33, &regs, &regs);
172 if (regs.x.bx)
173 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
174 return (regs.x.bx != 0);
175 }
176
177 static int
178 mouse_released (b, xp, yp)
179 int b, *xp, *yp;
180 {
181 union REGS regs;
182
183 if (b >= mouse_button_count)
184 return 0;
185 regs.x.ax = 0x0006;
186 regs.x.bx = mouse_button_translate[b];
187 int86 (0x33, &regs, &regs);
188 if (regs.x.bx)
189 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
190 return (regs.x.bx != 0);
191 }
192
193 static void
194 mouse_get_xy (int *x, int *y)
195 {
196 union REGS regs;
197
198 regs.x.ax = 0x0003;
199 int86 (0x33, &regs, &regs);
200 *x = regs.x.cx / 8;
201 *y = regs.x.dx / 8;
202 }
203
204 void
205 mouse_get_pos (f, insist, bar_window, part, x, y, time)
206 FRAME_PTR *f;
207 int insist;
208 Lisp_Object *bar_window, *x, *y;
209 enum scroll_bar_part *part;
210 unsigned long *time;
211 {
212 int ix, iy;
213 union REGS regs;
214
215 regs.x.ax = 0x0003;
216 int86 (0x33, &regs, &regs);
217 *f = selected_frame;
218 *bar_window = Qnil;
219 mouse_get_xy (&ix, &iy);
220 selected_frame->mouse_moved = 0;
221 *x = make_number (ix);
222 *y = make_number (iy);
223 *time = event_timestamp ();
224 }
225
226 static void
227 mouse_check_moved ()
228 {
229 int x, y;
230
231 mouse_get_xy (&x, &y);
232 selected_frame->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
233 mouse_last_x = x;
234 mouse_last_y = y;
235 }
236
237 void
238 mouse_init ()
239 {
240 union REGS regs;
241
242 if (termscript)
243 fprintf (termscript, "<M_INIT>");
244
245 regs.x.ax = 0x0021;
246 int86 (0x33, &regs, &regs);
247
248 regs.x.ax = 0x0007;
249 regs.x.cx = 0;
250 regs.x.dx = 8 * (ScreenCols () - 1);
251 int86 (0x33, &regs, &regs);
252
253 regs.x.ax = 0x0008;
254 regs.x.cx = 0;
255 regs.x.dx = 8 * (ScreenRows () - 1);
256 int86 (0x33, &regs, &regs);
257
258 mouse_moveto (0, 0);
259 mouse_visible = 0;
260 }
261 \f
262 /* ------------------------- Screen control ----------------------
263 *
264 */
265
266 static int internal_terminal = 0;
267
268 #ifndef HAVE_X_WINDOWS
269 extern unsigned char ScreenAttrib;
270 static int screen_face;
271 static int highlight;
272
273 static int screen_size_X;
274 static int screen_size_Y;
275 static int screen_size;
276
277 static int current_pos_X;
278 static int current_pos_Y;
279 static int new_pos_X;
280 static int new_pos_Y;
281
282 static void *startup_screen_buffer;
283 static int startup_screen_size_X;
284 static int startup_screen_size_Y;
285 static int startup_pos_X;
286 static int startup_pos_Y;
287 static unsigned char startup_screen_attrib;
288
289 static int term_setup_done;
290
291 /* Similar to the_only_frame. */
292 struct x_output the_only_x_display;
293
294 /* This is never dereferenced. */
295 Display *x_current_display;
296
297
298 #define SCREEN_SET_CURSOR() \
299 if (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y) \
300 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X)
301
302 static
303 dos_direct_output (y, x, buf, len)
304 int y;
305 int x;
306 char *buf;
307 int len;
308 {
309 int t = (int) ScreenPrimary + 2 * (x + y * screen_size_X);
310
311 while (--len >= 0) {
312 dosmemput (buf++, 1, t);
313 t += 2;
314 }
315 }
316 #endif
317
318 /* Flash the screen as a substitute for BEEPs. */
319
320 #if (__DJGPP__ < 2)
321 static void
322 do_visible_bell (xorattr)
323 unsigned char xorattr;
324 {
325 asm volatile
326 (" movb $1,%%dl
327 visible_bell_0:
328 movl _ScreenPrimary,%%eax
329 call dosmemsetup
330 movl %%eax,%%ebx
331 movl %1,%%ecx
332 movb %0,%%al
333 incl %%ebx
334 visible_bell_1:
335 xorb %%al,%%gs:(%%ebx)
336 addl $2,%%ebx
337 decl %%ecx
338 jne visible_bell_1
339 decb %%dl
340 jne visible_bell_3
341 visible_bell_2:
342 movzwl %%ax,%%eax
343 movzwl %%ax,%%eax
344 movzwl %%ax,%%eax
345 movzwl %%ax,%%eax
346 decw %%cx
347 jne visible_bell_2
348 jmp visible_bell_0
349 visible_bell_3:"
350 : /* no output */
351 : "m" (xorattr), "g" (screen_size)
352 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
353 }
354
355 static void
356 ScreenVisualBell (void)
357 {
358 /* This creates an xor-mask that will swap the default fore- and
359 background colors. */
360 do_visible_bell (((the_only_x_display.foreground_pixel
361 ^ the_only_x_display.background_pixel)
362 * 0x11) & 0x7f);
363 }
364 #endif
365
366 #ifndef HAVE_X_WINDOWS
367
368 /* Enable bright background colors. */
369 static void
370 bright_bg (void)
371 {
372 union REGS regs;
373
374 regs.h.bl = 0;
375 regs.x.ax = 0x1003;
376 int86 (0x10, &regs, &regs);
377 }
378
379 /* Set the screen dimensions so that it can show no less than
380 ROWS x COLS frame. */
381
382 void
383 dos_set_window_size (rows, cols)
384 int *rows, *cols;
385 {
386 char video_name[30];
387 Lisp_Object video_mode;
388 int video_mode_value;
389 int have_vga = 0;
390 union REGS regs;
391 int current_rows = ScreenRows (), current_cols = ScreenCols ();
392
393 if (*rows == current_rows && *cols == current_cols)
394 return;
395
396 /* Do we have a VGA? */
397 regs.x.ax = 0x1a00;
398 int86 (0x10, &regs, &regs);
399 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
400 have_vga = 1;
401
402 mouse_off ();
403
404 /* If the user specified a special video mode for these dimensions,
405 use that mode. */
406 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
407 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
408 Qnil))-> value;
409
410 if (INTEGERP (video_mode)
411 && (video_mode_value = XINT (video_mode)) > 0)
412 {
413 regs.x.ax = video_mode_value;
414 int86 (0x10, &regs, &regs);
415
416 if (have_mouse)
417 {
418 /* Must hardware-reset the mouse, or else it won't update
419 its notion of screen dimensions for some non-standard
420 video modes. This is *painfully* slow... */
421 regs.x.ax = 0;
422 int86 (0x33, &regs, &regs);
423 }
424 }
425
426 /* Find one of the dimensions supported by standard EGA/VGA
427 which gives us at least the required dimensions. */
428
429 #if __DJGPP__ > 1
430
431 else
432 {
433 static struct {
434 int rows;
435 int need_vga;
436 } std_dimension[] = {
437 {25, 0},
438 {28, 1},
439 {35, 0},
440 {40, 1},
441 {43, 0},
442 {50, 1}
443 };
444 int i = 0;
445
446 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
447 {
448 if (std_dimension[i].need_vga <= have_vga
449 && std_dimension[i].rows >= *rows)
450 {
451 if (std_dimension[i].rows != current_rows
452 || *cols != current_cols)
453 _set_screen_lines (std_dimension[i].rows);
454 break;
455 }
456 i++;
457 }
458 }
459
460 #else /* not __DJGPP__ > 1 */
461
462 else if (*rows <= 25)
463 {
464 if (current_rows != 25 || current_cols != 80)
465 {
466 regs.x.ax = 3;
467 int86 (0x10, &regs, &regs);
468 regs.x.ax = 0x1101;
469 regs.h.bl = 0;
470 int86 (0x10, &regs, &regs);
471 regs.x.ax = 0x1200;
472 regs.h.bl = 32;
473 int86 (0x10, &regs, &regs);
474 regs.x.ax = 3;
475 int86 (0x10, &regs, &regs);
476 }
477 }
478 else if (*rows <= 50)
479 if (have_vga && (current_rows != 50 || current_cols != 80)
480 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
481 {
482 regs.x.ax = 3;
483 int86 (0x10, &regs, &regs);
484 regs.x.ax = 0x1112;
485 regs.h.bl = 0;
486 int86 (0x10, &regs, &regs);
487 regs.x.ax = 0x1200;
488 regs.h.bl = 32;
489 int86 (0x10, &regs, &regs);
490 regs.x.ax = 0x0100;
491 regs.x.cx = 7;
492 int86 (0x10, &regs, &regs);
493 }
494 #endif /* not __DJGPP__ > 1 */
495
496 if (have_mouse)
497 {
498 mouse_init ();
499 mouse_on ();
500 }
501
502 /* Tell the caller what dimensions have been REALLY set. */
503 *rows = ScreenRows ();
504 *cols = ScreenCols ();
505
506 /* Enable bright background colors. */
507 bright_bg ();
508 }
509
510 /* If we write a character in the position where the mouse is,
511 the mouse cursor may need to be refreshed. */
512
513 static void
514 mouse_off_maybe ()
515 {
516 int x, y;
517
518 if (!mouse_visible)
519 return;
520
521 mouse_get_xy (&x, &y);
522 if (y != new_pos_Y || x < new_pos_X)
523 return;
524
525 mouse_off ();
526 }
527
528 static
529 IT_ring_bell ()
530 {
531 if (visible_bell)
532 {
533 mouse_off ();
534 ScreenVisualBell ();
535 }
536 else
537 {
538 union REGS inregs, outregs;
539 inregs.h.ah = 2;
540 inregs.h.dl = 7;
541 intdos (&inregs, &outregs);
542 }
543 }
544
545 static void
546 IT_set_face (int face)
547 {
548 struct face *fp;
549 extern struct face *intern_face (/* FRAME_PTR, struct face * */);
550
551 if (face == 1 || (face == 0 && highlight))
552 fp = FRAME_MODE_LINE_FACE (foo);
553 else if (face <= 0 || face >= FRAME_N_COMPUTED_FACES (foo))
554 fp = FRAME_DEFAULT_FACE (foo);
555 else
556 fp = intern_face (selected_frame, FRAME_COMPUTED_FACES (foo)[face]);
557 if (termscript)
558 fprintf (termscript, "<FACE:%d:%d>", FACE_FOREGROUND (fp), FACE_BACKGROUND (fp));
559 screen_face = face;
560 ScreenAttrib = (FACE_BACKGROUND (fp) << 4) | FACE_FOREGROUND (fp);
561 }
562
563 static
564 IT_write_glyphs (GLYPH *str, int len)
565 {
566 int newface;
567 int ch, l = len;
568 unsigned char *buf, *bp;
569
570 if (len == 0) return;
571
572 buf = bp = alloca (len * 2);
573
574 while (--l >= 0)
575 {
576 newface = FAST_GLYPH_FACE (*str);
577 if (newface != screen_face)
578 IT_set_face (newface);
579 ch = FAST_GLYPH_CHAR (*str);
580 *bp++ = (unsigned char)ch;
581 *bp++ = ScreenAttrib;
582
583 if (termscript)
584 fputc (ch, termscript);
585 str++;
586 }
587
588 mouse_off_maybe ();
589 dosmemput (buf, 2 * len,
590 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
591 new_pos_X += len;
592 }
593
594 static
595 IT_clear_end_of_line (first_unused)
596 {
597 char *spaces, *sp;
598 int i, j;
599
600 IT_set_face (0);
601 if (termscript)
602 fprintf (termscript, "<CLR:EOL>");
603 i = (j = screen_size_X - new_pos_X) * 2;
604 spaces = sp = alloca (i);
605
606 while (--j >= 0)
607 {
608 *sp++ = ' ';
609 *sp++ = ScreenAttrib;
610 }
611
612 mouse_off_maybe ();
613 dosmemput (spaces, i,
614 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
615 }
616
617 static
618 IT_clear_screen (void)
619 {
620 if (termscript)
621 fprintf (termscript, "<CLR:SCR>");
622 IT_set_face (0);
623 mouse_off ();
624 ScreenClear ();
625 new_pos_X = new_pos_Y = 0;
626 }
627
628 static
629 IT_clear_to_end (void)
630 {
631 if (termscript)
632 fprintf (termscript, "<CLR:EOS>");
633
634 while (new_pos_Y < screen_size_Y) {
635 new_pos_X = 0;
636 IT_clear_end_of_line (0);
637 new_pos_Y++;
638 }
639 }
640
641 static
642 IT_cursor_to (int y, int x)
643 {
644 if (termscript)
645 fprintf (termscript, "\n<XY=%dx%d>", x, y);
646 new_pos_X = x;
647 new_pos_Y = y;
648 }
649
650 static
651 IT_reassert_line_highlight (new, vpos)
652 int new, vpos;
653 {
654 highlight = new;
655 IT_set_face (0); /* To possibly clear the highlighting. */
656 }
657
658 static
659 IT_change_line_highlight (new_highlight, vpos, first_unused_hpos)
660 {
661 highlight = new_highlight;
662 IT_set_face (0); /* To possibly clear the highlighting. */
663 IT_cursor_to (vpos, 0);
664 IT_clear_end_of_line (first_unused_hpos);
665 }
666
667 static
668 IT_update_begin ()
669 {
670 highlight = 0;
671 IT_set_face (0); /* To possibly clear the highlighting. */
672 screen_face = -1;
673 }
674
675 static
676 IT_update_end ()
677 {
678 }
679
680 /* This was more or less copied from xterm.c
681
682 Nowadays, the corresponding function under X is `x_set_menu_bar_lines_1'
683 on xfns.c */
684
685 static void
686 IT_set_menu_bar_lines (window, n)
687 Lisp_Object window;
688 int n;
689 {
690 struct window *w = XWINDOW (window);
691
692 XSETFASTINT (w->last_modified, 0);
693 XSETFASTINT (w->top, XFASTINT (w->top) + n);
694 XSETFASTINT (w->height, XFASTINT (w->height) - n);
695
696 /* Handle just the top child in a vertical split. */
697 if (!NILP (w->vchild))
698 IT_set_menu_bar_lines (w->vchild, n);
699
700 /* Adjust all children in a horizontal split. */
701 for (window = w->hchild; !NILP (window); window = w->next)
702 {
703 w = XWINDOW (window);
704 IT_set_menu_bar_lines (window, n);
705 }
706 }
707
708 /* This was copied from xfns.c */
709
710 void
711 x_set_menu_bar_lines (f, value, oldval)
712 struct frame *f;
713 Lisp_Object value, oldval;
714 {
715 int nlines;
716 int olines = FRAME_MENU_BAR_LINES (f);
717
718 /* Right now, menu bars don't work properly in minibuf-only frames;
719 most of the commands try to apply themselves to the minibuffer
720 frame itslef, and get an error because you can't switch buffers
721 in or split the minibuffer window. */
722 if (FRAME_MINIBUF_ONLY_P (f))
723 return;
724
725 if (INTEGERP (value))
726 nlines = XINT (value);
727 else
728 nlines = 0;
729
730 FRAME_MENU_BAR_LINES (f) = nlines;
731 IT_set_menu_bar_lines (f->root_window, nlines - olines);
732 }
733
734 /* IT_set_terminal_modes is called when emacs is started,
735 resumed, and whenever the screen is redrawn! */
736
737 static
738 IT_set_terminal_modes (void)
739 {
740 char *colors;
741 FRAME_PTR f;
742 struct face *fp;
743
744 if (termscript)
745 fprintf (termscript, "\n<SET_TERM>");
746 highlight = 0;
747
748 screen_size_X = ScreenCols ();
749 screen_size_Y = ScreenRows ();
750 screen_size = screen_size_X * screen_size_Y;
751
752 new_pos_X = new_pos_Y = 0;
753 current_pos_X = current_pos_Y = -1;
754
755 if (term_setup_done)
756 return;
757 term_setup_done = 1;
758
759 startup_screen_size_X = screen_size_X;
760 startup_screen_size_Y = screen_size_Y;
761 startup_screen_attrib = ScreenAttrib;
762
763 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
764 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
765
766 if (termscript)
767 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
768 screen_size_X, screen_size_Y);
769
770 bright_bg ();
771 }
772
773 /* IT_reset_terminal_modes is called when emacs is
774 suspended or killed. */
775
776 static
777 IT_reset_terminal_modes (void)
778 {
779 int display_row_start = (int) ScreenPrimary;
780 int saved_row_len = startup_screen_size_X * 2;
781 int update_row_len = ScreenCols () * 2;
782 int current_rows = ScreenRows ();
783 int to_next_row = update_row_len;
784 unsigned char *saved_row = startup_screen_buffer;
785 int cursor_pos_X = ScreenCols () - 1;
786 int cursor_pos_Y = ScreenRows () - 1;
787
788 if (termscript)
789 fprintf (termscript, "\n<RESET_TERM>");
790
791 highlight = 0;
792
793 if (!term_setup_done)
794 return;
795
796 mouse_off ();
797
798 /* We have a situation here.
799 We cannot just do ScreenUpdate(startup_screen_buffer) because
800 the luser could have changed screen dimensions inside Emacs
801 and failed (or didn't want) to restore them before killing
802 Emacs. ScreenUpdate() uses the *current* screen dimensions and
803 thus will happily use memory outside what was allocated for
804 `startup_screen_buffer'.
805 Thus we only restore as much as the current screen dimensions
806 can hold, and clear the rest (if the saved screen is smaller than
807 the current) with the color attribute saved at startup. The cursor
808 is also restored within the visible dimensions. */
809
810 ScreenAttrib = startup_screen_attrib;
811 ScreenClear ();
812
813 if (update_row_len > saved_row_len)
814 update_row_len = saved_row_len;
815 if (current_rows > startup_screen_size_Y)
816 current_rows = startup_screen_size_Y;
817
818 if (termscript)
819 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
820 update_row_len / 2, current_rows);
821
822 while (current_rows--)
823 {
824 dosmemput (saved_row, update_row_len, display_row_start);
825 saved_row += saved_row_len;
826 display_row_start += to_next_row;
827 }
828 if (startup_pos_X < cursor_pos_X)
829 cursor_pos_X = startup_pos_X;
830 if (startup_pos_Y < cursor_pos_Y)
831 cursor_pos_Y = startup_pos_Y;
832
833 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
834 xfree (startup_screen_buffer);
835
836 term_setup_done = 0;
837 }
838
839 static
840 IT_set_terminal_window (void)
841 {
842 }
843
844 void
845 IT_set_frame_parameters (f, alist)
846 FRAME_PTR f;
847 Lisp_Object alist;
848 {
849 Lisp_Object tail;
850 int redraw;
851 extern unsigned long load_color ();
852
853 redraw = 0;
854 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
855 {
856 Lisp_Object elt, prop, val;
857
858 elt = Fcar (tail);
859 prop = Fcar (elt);
860 val = Fcdr (elt);
861 CHECK_SYMBOL (prop, 1);
862
863 if (EQ (prop, intern ("foreground-color")))
864 {
865 unsigned long new_color = load_color (f, val);
866 if (new_color != ~0)
867 {
868 FRAME_FOREGROUND_PIXEL (f) = new_color;
869 redraw = 1;
870 if (termscript)
871 fprintf (termscript, "<FGCOLOR %d>\n", new_color);
872 }
873 }
874 else if (EQ (prop, intern ("background-color")))
875 {
876 unsigned long new_color = load_color (f, val);
877 if (new_color != ~0)
878 {
879 FRAME_BACKGROUND_PIXEL (f) = new_color;
880 redraw = 1;
881 if (termscript)
882 fprintf (termscript, "<BGCOLOR %d>\n", new_color);
883 }
884 }
885 else if (EQ (prop, intern ("menu-bar-lines")))
886 x_set_menu_bar_lines (f, val, 0);
887 }
888
889 if (redraw)
890 {
891 recompute_basic_faces (f);
892 if (f == selected_frame)
893 redraw_frame (f);
894 }
895 }
896
897 #endif /* !HAVE_X_WINDOWS */
898
899
900 /* Do we need the internal terminal? */
901
902 void
903 internal_terminal_init ()
904 {
905 char *term = getenv ("TERM");
906 char *colors;
907
908 #ifdef HAVE_X_WINDOWS
909 if (!inhibit_window_system)
910 return;
911 #endif
912
913 internal_terminal
914 = (!noninteractive) && term && !strcmp (term, "internal");
915
916 if (getenv ("EMACSTEST"))
917 termscript = fopen (getenv ("EMACSTEST"), "wt");
918
919 #ifndef HAVE_X_WINDOWS
920 if (!internal_terminal || inhibit_window_system)
921 {
922 selected_frame->output_method = output_termcap;
923 return;
924 }
925
926 Vwindow_system = intern ("pc");
927 Vwindow_system_version = make_number (1);
928
929 bzero (&the_only_x_display, sizeof the_only_x_display);
930 the_only_x_display.background_pixel = 7; /* White */
931 the_only_x_display.foreground_pixel = 0; /* Black */
932 bright_bg ();
933 colors = getenv ("EMACSCOLORS");
934 if (colors && strlen (colors) >= 2)
935 {
936 /* The colors use 4 bits each (we enable bright background). */
937 if (isdigit (colors[0]))
938 colors[0] -= '0';
939 else if (isxdigit (colors[0]))
940 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
941 if (colors[0] >= 0 && colors[0] < 16)
942 the_only_x_display.foreground_pixel = colors[0];
943 if (isdigit (colors[1]))
944 colors[1] -= '0';
945 else if (isxdigit (colors[1]))
946 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
947 if (colors[1] >= 0 && colors[1] < 16)
948 the_only_x_display.background_pixel = colors[1];
949 }
950 the_only_x_display.line_height = 1;
951 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
952
953 init_frame_faces (selected_frame);
954
955 ring_bell_hook = IT_ring_bell;
956 write_glyphs_hook = IT_write_glyphs;
957 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
958 clear_to_end_hook = IT_clear_to_end;
959 clear_end_of_line_hook = IT_clear_end_of_line;
960 clear_frame_hook = IT_clear_screen;
961 change_line_highlight_hook = IT_change_line_highlight;
962 update_begin_hook = IT_update_begin;
963 update_end_hook = IT_update_end;
964 reassert_line_highlight_hook = IT_reassert_line_highlight;
965
966 /* These hooks are called by term.c without being checked. */
967 set_terminal_modes_hook = IT_set_terminal_modes;
968 reset_terminal_modes_hook = IT_reset_terminal_modes;
969 set_terminal_window_hook = IT_set_terminal_window;
970 #endif
971 }
972
973 dos_get_saved_screen (screen, rows, cols)
974 char **screen;
975 int *rows;
976 int *cols;
977 {
978 #ifndef HAVE_X_WINDOWS
979 *screen = startup_screen_buffer;
980 *cols = startup_screen_size_X;
981 *rows = startup_screen_size_Y;
982 return 1;
983 #else
984 return 0;
985 #endif
986 }
987
988 #ifndef HAVE_X_WINDOWS
989
990 /* We are not X, but we can emulate it well enough for our needs... */
991 void
992 check_x (void)
993 {
994 if (! FRAME_MSDOS_P (selected_frame))
995 error ("Not running under a windows system");
996 }
997
998 #endif
999
1000 \f
1001 /* ----------------------- Keyboard control ----------------------
1002 *
1003 * Keymaps reflect the following keyboard layout:
1004 *
1005 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1006 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1007 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1008 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1009 * SPACE
1010 */
1011
1012 static int extended_kbd; /* 101 (102) keyboard present. */
1013
1014 struct dos_keyboard_map
1015 {
1016 char *unshifted;
1017 char *shifted;
1018 char *alt_gr;
1019 };
1020
1021
1022 static struct dos_keyboard_map us_keyboard = {
1023 /* 0 1 2 3 4 5 */
1024 /* 01234567890123456789012345678901234567890 12345678901234 */
1025 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1026 /* 0123456789012345678901234567890123456789 012345678901234 */
1027 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1028 0 /* no Alt-Gr key */
1029 };
1030
1031 static struct dos_keyboard_map fr_keyboard = {
1032 /* 0 1 2 3 4 5 */
1033 /* 012 3456789012345678901234567890123456789012345678901234 */
1034 "ý&\82\",(-\8a_\80\85)= azertyuiop^$ qsdfghjklm\97* wxcvbnm;:! ",
1035 /* 0123456789012345678901234567890123456789012345678901234 */
1036 " 1234567890ø+ AZERTYUIOPù\9c QSDFGHJKLM%æ WXCVBN?./õ ",
1037 /* 01234567 89012345678901234567890123456789012345678901234 */
1038 " ~#{[|`\\^@]} Ï "
1039 };
1040
1041 static struct dos_keyboard_map dk_keyboard = {
1042 /* 0 1 2 3 4 5 */
1043 /* 0123456789012345678901234567890123456789012345678901234 */
1044 "«1234567890+| qwertyuiop\86~ asdfghjkl\91\9b' zxcvbnm,.- ",
1045 /* 01 23456789012345678901234567890123456789012345678901234 */
1046 "õ!\"#$%&/()=?` QWERTYUIOP\8f^ ASDFGHJKL\92\9d* ZXCVBNM;:_ ",
1047 /* 0123456789012345678901234567890123456789012345678901234 */
1048 " @\9c$ {[]} | "
1049 };
1050
1051 static struct keyboard_layout_list
1052 {
1053 int country_code;
1054 struct dos_keyboard_map *keyboard_map;
1055 } keyboard_layout_list[] =
1056 {
1057 1, &us_keyboard,
1058 33, &fr_keyboard,
1059 45, &dk_keyboard
1060 };
1061
1062 static struct dos_keyboard_map *keyboard;
1063 static int keyboard_map_all;
1064
1065 int
1066 dos_set_keyboard (code, always)
1067 int code;
1068 int always;
1069 {
1070 int i;
1071
1072 /* Initialize to US settings, for countries that don't have their own. */
1073 keyboard = keyboard_layout_list[0].keyboard_map;
1074 keyboard_map_all = always;
1075 dos_keyboard_layout = 1;
1076
1077 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
1078 if (code == keyboard_layout_list[i].country_code)
1079 {
1080 keyboard = keyboard_layout_list[i].keyboard_map;
1081 keyboard_map_all = always;
1082 dos_keyboard_layout = code;
1083 return 1;
1084 }
1085 return 0;
1086 }
1087 \f
1088 #define Ignore 0x0000
1089 #define Normal 0x0000 /* normal key - alt changes scan-code */
1090 #define FctKey 0x1000 /* func key if c == 0, else c */
1091 #define Special 0x2000 /* func key even if c != 0 */
1092 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1093 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1094 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1095 #define Grey 0x6000 /* Grey keypad key */
1096
1097 #define Alt 0x0100 /* alt scan-code */
1098 #define Ctrl 0x0200 /* ctrl scan-code */
1099 #define Shift 0x0400 /* shift scan-code */
1100
1101 static struct
1102 {
1103 unsigned char char_code; /* normal code */
1104 unsigned char meta_code; /* M- code */
1105 unsigned char keypad_code; /* keypad code */
1106 unsigned char editkey_code; /* edit key */
1107 } keypad_translate_map[] = {
1108 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1109 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1110 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1111 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1112 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1113 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1114 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1115 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1116 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1117 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1118 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1119 };
1120
1121 static struct
1122 {
1123 unsigned char char_code; /* normal code */
1124 unsigned char keypad_code; /* keypad code */
1125 } grey_key_translate_map[] = {
1126 '/', 0xaf, /* kp-decimal */
1127 '*', 0xaa, /* kp-multiply */
1128 '-', 0xad, /* kp-subtract */
1129 '+', 0xab, /* kp-add */
1130 '\r', 0x8d /* kp-enter */
1131 };
1132
1133 static unsigned short
1134 ibmpc_translate_map[] =
1135 {
1136 /* --------------- 00 to 0f --------------- */
1137 Normal | 0xff, /* Ctrl Break + Alt-NNN */
1138 Alt | ModFct | 0x1b, /* Escape */
1139 Normal | 1, /* '1' */
1140 Normal | 2, /* '2' */
1141 Normal | 3, /* '3' */
1142 Normal | 4, /* '4' */
1143 Normal | 5, /* '5' */
1144 Normal | 6, /* '6' */
1145 Normal | 7, /* '7' */
1146 Normal | 8, /* '8' */
1147 Normal | 9, /* '9' */
1148 Normal | 10, /* '0' */
1149 Normal | 11, /* '-' */
1150 Normal | 12, /* '=' */
1151 Special | 0x08, /* Backspace */
1152 ModFct | 0x74, /* Tab/Backtab */
1153
1154 /* --------------- 10 to 1f --------------- */
1155 Map | 15, /* 'q' */
1156 Map | 16, /* 'w' */
1157 Map | 17, /* 'e' */
1158 Map | 18, /* 'r' */
1159 Map | 19, /* 't' */
1160 Map | 20, /* 'y' */
1161 Map | 21, /* 'u' */
1162 Map | 22, /* 'i' */
1163 Map | 23, /* 'o' */
1164 Map | 24, /* 'p' */
1165 Map | 25, /* '[' */
1166 Map | 26, /* ']' */
1167 ModFct | 0x0d, /* Return */
1168 Ignore, /* Ctrl */
1169 Map | 30, /* 'a' */
1170 Map | 31, /* 's' */
1171
1172 /* --------------- 20 to 2f --------------- */
1173 Map | 32, /* 'd' */
1174 Map | 33, /* 'f' */
1175 Map | 34, /* 'g' */
1176 Map | 35, /* 'h' */
1177 Map | 36, /* 'j' */
1178 Map | 37, /* 'k' */
1179 Map | 38, /* 'l' */
1180 Map | 39, /* ';' */
1181 Map | 40, /* '\'' */
1182 Map | 0, /* '`' */
1183 Ignore, /* Left shift */
1184 Map | 41, /* '\\' */
1185 Map | 45, /* 'z' */
1186 Map | 46, /* 'x' */
1187 Map | 47, /* 'c' */
1188 Map | 48, /* 'v' */
1189
1190 /* --------------- 30 to 3f --------------- */
1191 Map | 49, /* 'b' */
1192 Map | 50, /* 'n' */
1193 Map | 51, /* 'm' */
1194 Map | 52, /* ',' */
1195 Map | 53, /* '.' */
1196 Map | 54, /* '/' */
1197 Ignore, /* Right shift */
1198 Grey | 1, /* Grey * */
1199 Ignore, /* Alt */
1200 Normal | ' ', /* ' ' */
1201 Ignore, /* Caps Lock */
1202 FctKey | 0xbe, /* F1 */
1203 FctKey | 0xbf, /* F2 */
1204 FctKey | 0xc0, /* F3 */
1205 FctKey | 0xc1, /* F4 */
1206 FctKey | 0xc2, /* F5 */
1207
1208 /* --------------- 40 to 4f --------------- */
1209 FctKey | 0xc3, /* F6 */
1210 FctKey | 0xc4, /* F7 */
1211 FctKey | 0xc5, /* F8 */
1212 FctKey | 0xc6, /* F9 */
1213 FctKey | 0xc7, /* F10 */
1214 Ignore, /* Num Lock */
1215 Ignore, /* Scroll Lock */
1216 KeyPad | 7, /* Home */
1217 KeyPad | 8, /* Up */
1218 KeyPad | 9, /* Page Up */
1219 Grey | 2, /* Grey - */
1220 KeyPad | 4, /* Left */
1221 KeyPad | 5, /* Keypad 5 */
1222 KeyPad | 6, /* Right */
1223 Grey | 3, /* Grey + */
1224 KeyPad | 1, /* End */
1225
1226 /* --------------- 50 to 5f --------------- */
1227 KeyPad | 2, /* Down */
1228 KeyPad | 3, /* Page Down */
1229 KeyPad | 0, /* Insert */
1230 KeyPad | 10, /* Delete */
1231 Shift | FctKey | 0xbe, /* (Shift) F1 */
1232 Shift | FctKey | 0xbf, /* (Shift) F2 */
1233 Shift | FctKey | 0xc0, /* (Shift) F3 */
1234 Shift | FctKey | 0xc1, /* (Shift) F4 */
1235 Shift | FctKey | 0xc2, /* (Shift) F5 */
1236 Shift | FctKey | 0xc3, /* (Shift) F6 */
1237 Shift | FctKey | 0xc4, /* (Shift) F7 */
1238 Shift | FctKey | 0xc5, /* (Shift) F8 */
1239 Shift | FctKey | 0xc6, /* (Shift) F9 */
1240 Shift | FctKey | 0xc7, /* (Shift) F10 */
1241 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
1242 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
1243
1244 /* --------------- 60 to 6f --------------- */
1245 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
1246 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
1247 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
1248 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
1249 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
1250 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
1251 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
1252 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
1253 Alt | FctKey | 0xbe, /* (Alt) F1 */
1254 Alt | FctKey | 0xbf, /* (Alt) F2 */
1255 Alt | FctKey | 0xc0, /* (Alt) F3 */
1256 Alt | FctKey | 0xc1, /* (Alt) F4 */
1257 Alt | FctKey | 0xc2, /* (Alt) F5 */
1258 Alt | FctKey | 0xc3, /* (Alt) F6 */
1259 Alt | FctKey | 0xc4, /* (Alt) F7 */
1260 Alt | FctKey | 0xc5, /* (Alt) F8 */
1261
1262 /* --------------- 70 to 7f --------------- */
1263 Alt | FctKey | 0xc6, /* (Alt) F9 */
1264 Alt | FctKey | 0xc7, /* (Alt) F10 */
1265 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
1266 Ctrl | KeyPad | 4, /* (Ctrl) Left */
1267 Ctrl | KeyPad | 6, /* (Ctrl) Right */
1268 Ctrl | KeyPad | 1, /* (Ctrl) End */
1269 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
1270 Ctrl | KeyPad | 7, /* (Ctrl) Home */
1271 Alt | Map | 1, /* '1' */
1272 Alt | Map | 2, /* '2' */
1273 Alt | Map | 3, /* '3' */
1274 Alt | Map | 4, /* '4' */
1275 Alt | Map | 5, /* '5' */
1276 Alt | Map | 6, /* '6' */
1277 Alt | Map | 7, /* '7' */
1278 Alt | Map | 8, /* '8' */
1279
1280 /* --------------- 80 to 8f --------------- */
1281 Alt | Map | 9, /* '9' */
1282 Alt | Map | 10, /* '0' */
1283 Alt | Map | 11, /* '-' */
1284 Alt | Map | 12, /* '=' */
1285 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
1286 FctKey | 0xc8, /* F11 */
1287 FctKey | 0xc9, /* F12 */
1288 Shift | FctKey | 0xc8, /* (Shift) F11 */
1289 Shift | FctKey | 0xc9, /* (Shift) F12 */
1290 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
1291 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
1292 Alt | FctKey | 0xc8, /* (Alt) F11 */
1293 Alt | FctKey | 0xc9, /* (Alt) F12 */
1294 Ctrl | KeyPad | 8, /* (Ctrl) Up */
1295 Ctrl | Grey | 2, /* (Ctrl) Grey - */
1296 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
1297
1298 /* --------------- 90 to 9f --------------- */
1299 Ctrl | Grey | 3, /* (Ctrl) Grey + */
1300 Ctrl | KeyPad | 2, /* (Ctrl) Down */
1301 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
1302 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
1303 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
1304 Ctrl | Grey | 0, /* (Ctrl) Grey / */
1305 Ctrl | Grey | 1, /* (Ctrl) Grey * */
1306 Alt | FctKey | 0x50, /* (Alt) Home */
1307 Alt | FctKey | 0x52, /* (Alt) Up */
1308 Alt | FctKey | 0x55, /* (Alt) Page Up */
1309 Ignore, /* NO KEY */
1310 Alt | FctKey | 0x51, /* (Alt) Left */
1311 Ignore, /* NO KEY */
1312 Alt | FctKey | 0x53, /* (Alt) Right */
1313 Ignore, /* NO KEY */
1314 Alt | FctKey | 0x57, /* (Alt) End */
1315
1316 /* --------------- a0 to af --------------- */
1317 Alt | KeyPad | 2, /* (Alt) Down */
1318 Alt | KeyPad | 3, /* (Alt) Page Down */
1319 Alt | KeyPad | 0, /* (Alt) Insert */
1320 Alt | KeyPad | 10, /* (Alt) Delete */
1321 Alt | Grey | 0, /* (Alt) Grey / */
1322 Alt | FctKey | 0x09, /* (Alt) Tab */
1323 Alt | Grey | 4 /* (Alt) Keypad Enter */
1324 };
1325 \f
1326 /* These bit-positions corresponds to values returned by BIOS */
1327 #define SHIFT_P 0x0003 /* two bits! */
1328 #define CTRL_P 0x0004
1329 #define ALT_P 0x0008
1330 #define SCRLOCK_P 0x0010
1331 #define NUMLOCK_P 0x0020
1332 #define CAPSLOCK_P 0x0040
1333 #define ALT_GR_P 0x0800
1334 #define SUPER_P 0x4000 /* pseudo */
1335 #define HYPER_P 0x8000 /* pseudo */
1336
1337 static int
1338 dos_get_modifiers (keymask)
1339 int *keymask;
1340 {
1341 union REGS regs;
1342 int mask;
1343 int modifiers = 0;
1344
1345 /* Calculate modifier bits */
1346 regs.h.ah = extended_kbd ? 0x12 : 0x02;
1347 int86 (0x16, &regs, &regs);
1348
1349 if (!extended_kbd)
1350 {
1351 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
1352 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1353 }
1354 else
1355 {
1356 mask = regs.h.al & (SHIFT_P |
1357 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1358
1359 /* Do not break international keyboard support. */
1360 /* When Keyb.Com is loaded, the right Alt key is */
1361 /* used for accessing characters like { and } */
1362 if (regs.h.ah & 2) /* Left ALT pressed ? */
1363 mask |= ALT_P;
1364
1365 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
1366 {
1367 mask |= ALT_GR_P;
1368 if (dos_hyper_key == 1)
1369 {
1370 mask |= HYPER_P;
1371 modifiers |= hyper_modifier;
1372 }
1373 else if (dos_super_key == 1)
1374 {
1375 mask |= SUPER_P;
1376 modifiers |= super_modifier;
1377 }
1378 }
1379
1380 if (regs.h.ah & 1) /* Left CTRL pressed ? */
1381 mask |= CTRL_P;
1382
1383 if (regs.h.ah & 4) /* Right CTRL pressed ? */
1384 {
1385 if (dos_hyper_key == 2)
1386 {
1387 mask |= HYPER_P;
1388 modifiers |= hyper_modifier;
1389 }
1390 else if (dos_super_key == 2)
1391 {
1392 mask |= SUPER_P;
1393 modifiers |= super_modifier;
1394 }
1395 else
1396 mask |= CTRL_P;
1397 }
1398 }
1399
1400 if (mask & SHIFT_P)
1401 modifiers |= shift_modifier;
1402 if (mask & CTRL_P)
1403 modifiers |= ctrl_modifier;
1404 if (mask & ALT_P)
1405 modifiers |= meta_modifier;
1406
1407 if (keymask)
1408 *keymask = mask;
1409 return modifiers;
1410 }
1411
1412 #define NUM_RECENT_DOSKEYS (100)
1413 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
1414 int total_doskeys; /* Total number of elements stored into recent_doskeys */
1415 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
1416
1417 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
1418 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1419 Each input key receives two values in this vector: first the ASCII code,\n\
1420 and then the scan code.")
1421 ()
1422 {
1423 Lisp_Object *keys = XVECTOR (recent_doskeys)->contents;
1424 Lisp_Object val;
1425
1426 if (total_doskeys < NUM_RECENT_DOSKEYS)
1427 return Fvector (total_doskeys, keys);
1428 else
1429 {
1430 val = Fvector (NUM_RECENT_DOSKEYS, keys);
1431 bcopy (keys + recent_doskeys_index,
1432 XVECTOR (val)->contents,
1433 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
1434 bcopy (keys,
1435 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
1436 recent_doskeys_index * sizeof (Lisp_Object));
1437 return val;
1438 }
1439 }
1440
1441 /* Get a char from keyboard. Function keys are put into the event queue. */
1442
1443 static int
1444 dos_rawgetc ()
1445 {
1446 struct input_event event;
1447 union REGS regs;
1448
1449 #ifndef HAVE_X_WINDOWS
1450 SCREEN_SET_CURSOR ();
1451 if (!mouse_visible) mouse_on ();
1452 #endif
1453
1454 /* The following condition is equivalent to `kbhit ()', except that
1455 it uses the bios to do its job. This pleases DESQview/X. */
1456 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
1457 int86 (0x16, &regs, &regs),
1458 (regs.x.flags & 0x40) == 0)
1459 {
1460 union REGS regs;
1461 register unsigned char c;
1462 int sc, code, mask, kp_mode;
1463 int modifiers;
1464
1465 regs.h.ah = extended_kbd ? 0x10 : 0x00;
1466 int86 (0x16, &regs, &regs);
1467 c = regs.h.al;
1468 sc = regs.h.ah;
1469
1470 total_doskeys += 2;
1471 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1472 = make_number (c);
1473 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1474 recent_doskeys_index = 0;
1475 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1476 = make_number (sc);
1477 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1478 recent_doskeys_index = 0;
1479
1480 modifiers = dos_get_modifiers (&mask);
1481
1482 #ifndef HAVE_X_WINDOWS
1483 if (!NILP (Vdos_display_scancodes))
1484 {
1485 char buf[11];
1486 sprintf (buf, "%02x:%02x*%04x",
1487 (unsigned) (sc&0xff), (unsigned) c, mask);
1488 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
1489 }
1490 #endif
1491
1492 if (sc == 0xe0)
1493 {
1494 switch (c)
1495 {
1496 case 10: /* Ctrl Grey Enter */
1497 code = Ctrl | Grey | 4;
1498 break;
1499 case 13: /* Grey Enter */
1500 code = Grey | 4;
1501 break;
1502 case '/': /* Grey / */
1503 code = Grey | 0;
1504 break;
1505 default:
1506 continue;
1507 };
1508 c = 0;
1509 }
1510 else
1511 {
1512 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
1513 continue;
1514 if ((code = ibmpc_translate_map[sc]) == Ignore)
1515 continue;
1516 }
1517
1518 if (c == 0)
1519 {
1520 if (code & Alt)
1521 modifiers |= meta_modifier;
1522 if (code & Ctrl)
1523 modifiers |= ctrl_modifier;
1524 if (code & Shift)
1525 modifiers |= shift_modifier;
1526 }
1527
1528 switch (code & 0xf000)
1529 {
1530 case ModFct:
1531 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
1532 return c;
1533 c = 0; /* Special */
1534
1535 case FctKey:
1536 if (c != 0)
1537 return c;
1538
1539 case Special:
1540 code |= 0xff00;
1541 break;
1542
1543 case Normal:
1544 if (sc == 0)
1545 {
1546 if (c == 0) /* ctrl-break */
1547 continue;
1548 return c; /* ALT-nnn */
1549 }
1550 if (!keyboard_map_all)
1551 {
1552 if (c != ' ')
1553 return c;
1554 code = c;
1555 break;
1556 }
1557
1558 case Map:
1559 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
1560 if (!keyboard_map_all)
1561 return c;
1562
1563 code &= 0xff;
1564 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
1565 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
1566
1567 if (mask & SHIFT_P)
1568 {
1569 code = keyboard->shifted[code];
1570 mask -= SHIFT_P;
1571 modifiers &= ~shift_modifier;
1572 }
1573 else
1574 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
1575 code = keyboard->alt_gr[code];
1576 else
1577 code = keyboard->unshifted[code];
1578 break;
1579
1580 case KeyPad:
1581 code &= 0xff;
1582 if (c == 0xe0) /* edit key */
1583 kp_mode = 3;
1584 else
1585 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
1586 kp_mode = dos_keypad_mode & 0x03;
1587 else
1588 kp_mode = (dos_keypad_mode >> 4) & 0x03;
1589
1590 switch (kp_mode)
1591 {
1592 case 0:
1593 if (code == 10 && dos_decimal_point)
1594 return dos_decimal_point;
1595 return keypad_translate_map[code].char_code;
1596
1597 case 1:
1598 code = 0xff00 | keypad_translate_map[code].keypad_code;
1599 break;
1600
1601 case 2:
1602 code = keypad_translate_map[code].meta_code;
1603 modifiers = meta_modifier;
1604 break;
1605
1606 case 3:
1607 code = 0xff00 | keypad_translate_map[code].editkey_code;
1608 break;
1609 }
1610 break;
1611
1612 case Grey:
1613 code &= 0xff;
1614 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
1615 if (dos_keypad_mode & kp_mode)
1616 code = 0xff00 | grey_key_translate_map[code].keypad_code;
1617 else
1618 code = grey_key_translate_map[code].char_code;
1619 break;
1620 }
1621
1622 make_event:
1623 if (code == 0)
1624 continue;
1625
1626 if (code >= 0x100)
1627 event.kind = non_ascii_keystroke;
1628 else
1629 event.kind = ascii_keystroke;
1630 event.code = code;
1631 event.modifiers = modifiers;
1632 XSETFRAME (event.frame_or_window, selected_frame);
1633 event.timestamp = event_timestamp ();
1634 kbd_buffer_store_event (&event);
1635 }
1636
1637 if (have_mouse > 0)
1638 {
1639 int but, press, x, y, ok;
1640
1641 /* Check for mouse movement *before* buttons. */
1642 mouse_check_moved ();
1643
1644 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
1645 for (press = 0; press < 2; press++)
1646 {
1647 int button_num = but;
1648
1649 if (press)
1650 ok = mouse_pressed (but, &x, &y);
1651 else
1652 ok = mouse_released (but, &x, &y);
1653 if (ok)
1654 {
1655 /* Allow a simultaneous press/release of Mouse-1 and
1656 Mouse-2 to simulate Mouse-3 on two-button mice. */
1657 if (mouse_button_count == 2 && but < 2)
1658 {
1659 int x2, y2; /* don't clobber original coordinates */
1660
1661 /* If only one button is pressed, wait 100 msec and
1662 check again. This way, Speedy Gonzales isn't
1663 punished, while the slow get their chance. */
1664 if (press && mouse_pressed (1-but, &x2, &y2)
1665 || !press && mouse_released (1-but, &x2, &y2))
1666 button_num = 2;
1667 else
1668 {
1669 delay (100);
1670 if (press && mouse_pressed (1-but, &x2, &y2)
1671 || !press && mouse_released (1-but, &x2, &y2))
1672 button_num = 2;
1673 }
1674 }
1675
1676 event.kind = mouse_click;
1677 event.code = button_num;
1678 event.modifiers = dos_get_modifiers (0)
1679 | (press ? down_modifier : up_modifier);
1680 event.x = x;
1681 event.y = y;
1682 XSETFRAME (event.frame_or_window, selected_frame);
1683 event.timestamp = event_timestamp ();
1684 kbd_buffer_store_event (&event);
1685 }
1686 }
1687 }
1688
1689 return -1;
1690 }
1691
1692 static int prev_get_char = -1;
1693
1694 /* Return 1 if a key is ready to be read without suspending execution. */
1695
1696 dos_keysns ()
1697 {
1698 if (prev_get_char != -1)
1699 return 1;
1700 else
1701 return ((prev_get_char = dos_rawgetc ()) != -1);
1702 }
1703
1704 /* Read a key. Return -1 if no key is ready. */
1705
1706 dos_keyread ()
1707 {
1708 if (prev_get_char != -1)
1709 {
1710 int c = prev_get_char;
1711 prev_get_char = -1;
1712 return c;
1713 }
1714 else
1715 return dos_rawgetc ();
1716 }
1717 \f
1718 #ifndef HAVE_X_WINDOWS
1719 /* See xterm.c for more info. */
1720 void
1721 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
1722 FRAME_PTR f;
1723 register int pix_x, pix_y;
1724 register int *x, *y;
1725 void /* XRectangle */ *bounds;
1726 int noclip;
1727 {
1728 if (bounds) abort ();
1729
1730 /* Ignore clipping. */
1731
1732 *x = pix_x;
1733 *y = pix_y;
1734 }
1735
1736 void
1737 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1738 FRAME_PTR f;
1739 register int x, y;
1740 register int *pix_x, *pix_y;
1741 {
1742 *pix_x = x;
1743 *pix_y = y;
1744 }
1745 \f
1746 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1747 for now.
1748
1749 Actually, I don't know the meaning of all the parameters of the functions
1750 here -- I only know how they are called by xmenu.c. I could of course
1751 grab the nearest Xlib manual (down the hall, second-to-last door on the
1752 left), but I don't think it's worth the effort. */
1753
1754 static XMenu *
1755 IT_menu_create ()
1756 {
1757 XMenu *menu;
1758
1759 menu = (XMenu *) xmalloc (sizeof (XMenu));
1760 menu->allocated = menu->count = menu->panecount = menu->width = 0;
1761 return menu;
1762 }
1763
1764 /* Allocate some (more) memory for MENU ensuring that there is room for one
1765 for item. */
1766
1767 static void
1768 IT_menu_make_room (XMenu *menu)
1769 {
1770 if (menu->allocated == 0)
1771 {
1772 int count = menu->allocated = 10;
1773 menu->text = (char **) xmalloc (count * sizeof (char *));
1774 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
1775 menu->panenumber = (int *) xmalloc (count * sizeof (int));
1776 }
1777 else if (menu->allocated == menu->count)
1778 {
1779 int count = menu->allocated = menu->allocated + 10;
1780 menu->text
1781 = (char **) xrealloc (menu->text, count * sizeof (char *));
1782 menu->submenu
1783 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
1784 menu->panenumber
1785 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
1786 }
1787 }
1788
1789 /* Search the given menu structure for a given pane number. */
1790
1791 static XMenu *
1792 IT_menu_search_pane (XMenu *menu, int pane)
1793 {
1794 int i;
1795 XMenu *try;
1796
1797 for (i = 0; i < menu->count; i++)
1798 if (menu->submenu[i])
1799 {
1800 if (pane == menu->panenumber[i])
1801 return menu->submenu[i];
1802 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
1803 return try;
1804 }
1805 return (XMenu *) 0;
1806 }
1807
1808 /* Determine how much screen space a given menu needs. */
1809
1810 static void
1811 IT_menu_calc_size (XMenu *menu, int *width, int *height)
1812 {
1813 int i, h2, w2, maxsubwidth, maxheight;
1814
1815 maxsubwidth = 0;
1816 maxheight = menu->count;
1817 for (i = 0; i < menu->count; i++)
1818 {
1819 if (menu->submenu[i])
1820 {
1821 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
1822 if (w2 > maxsubwidth) maxsubwidth = w2;
1823 if (i + h2 > maxheight) maxheight = i + h2;
1824 }
1825 }
1826 *width = menu->width + maxsubwidth;
1827 *height = maxheight;
1828 }
1829
1830 /* Display MENU at (X,Y) using FACES. */
1831
1832 static void
1833 IT_menu_display (XMenu *menu, int y, int x, int *faces)
1834 {
1835 int i, j, face, width;
1836 GLYPH *text, *p;
1837 char *q;
1838 int mx, my;
1839 int enabled, mousehere;
1840 int row, col;
1841
1842 width = menu->width;
1843 text = (GLYPH *) xmalloc ((width + 2) * sizeof (GLYPH));
1844 ScreenGetCursor (&row, &col);
1845 mouse_get_xy (&mx, &my);
1846 IT_update_begin ();
1847 for (i = 0; i < menu->count; i++)
1848 {
1849 IT_cursor_to (y + i, x);
1850 enabled
1851 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
1852 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
1853 face = faces[enabled + mousehere * 2];
1854 p = text;
1855 *p++ = FAST_MAKE_GLYPH (' ', face);
1856 for (j = 0, q = menu->text[i]; *q; j++)
1857 *p++ = FAST_MAKE_GLYPH (*q++, face);
1858 for (; j < width; j++)
1859 *p++ = FAST_MAKE_GLYPH (' ', face);
1860 *p++ = FAST_MAKE_GLYPH (menu->submenu[i] ? 16 : ' ', face);
1861 IT_write_glyphs (text, width + 2);
1862 }
1863 IT_update_end ();
1864 IT_cursor_to (row, col);
1865 xfree (text);
1866 }
1867 \f
1868 /* --------------------------- X Menu emulation ---------------------- */
1869
1870 /* Report availability of menus. */
1871
1872 int
1873 have_menus_p ()
1874 {
1875 return 1;
1876 }
1877
1878 /* Create a brand new menu structure. */
1879
1880 XMenu *
1881 XMenuCreate (Display *foo1, Window foo2, char *foo3)
1882 {
1883 return IT_menu_create ();
1884 }
1885
1886 /* Create a new pane and place it on the outer-most level. It is not
1887 clear that it should be placed out there, but I don't know what else
1888 to do. */
1889
1890 int
1891 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
1892 {
1893 int len;
1894
1895 if (!enable)
1896 abort ();
1897
1898 IT_menu_make_room (menu);
1899 menu->submenu[menu->count] = IT_menu_create ();
1900 menu->text[menu->count] = txt;
1901 menu->panenumber[menu->count] = ++menu->panecount;
1902 menu->count++;
1903 if ((len = strlen (txt)) > menu->width)
1904 menu->width = len;
1905 return menu->panecount;
1906 }
1907
1908 /* Create a new item in a menu pane. */
1909
1910 int
1911 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
1912 int foo, char *txt, int enable)
1913 {
1914 int len;
1915
1916 if (pane)
1917 if (!(menu = IT_menu_search_pane (menu, pane)))
1918 return XM_FAILURE;
1919 IT_menu_make_room (menu);
1920 menu->submenu[menu->count] = (XMenu *) 0;
1921 menu->text[menu->count] = txt;
1922 menu->panenumber[menu->count] = enable;
1923 menu->count++;
1924 if ((len = strlen (txt)) > menu->width)
1925 menu->width = len;
1926 return XM_SUCCESS;
1927 }
1928
1929 /* Decide where the menu would be placed if requested at (X,Y). */
1930
1931 void
1932 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
1933 int *ulx, int *uly, int *width, int *height)
1934 {
1935 IT_menu_calc_size (menu, width, height);
1936 *ulx = x + 1;
1937 *uly = y;
1938 *width += 2;
1939 }
1940
1941 struct IT_menu_state
1942 {
1943 void *screen_behind;
1944 XMenu *menu;
1945 int pane;
1946 int x, y;
1947 };
1948
1949
1950 /* Display menu, wait for user's response, and return that response. */
1951
1952 int
1953 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
1954 int x0, int y0, unsigned ButtonMask, char **txt)
1955 {
1956 struct IT_menu_state *state;
1957 int statecount;
1958 int x, y, i, b;
1959 int screensize;
1960 int faces[4], selectface;
1961 int leave, result, onepane;
1962 int title_faces[4]; /* face to display the menu title */
1963 int buffers_num_deleted = 0;
1964
1965 /* Just in case we got here without a mouse present... */
1966 if (have_mouse <= 0)
1967 return XM_IA_SELECT;
1968
1969 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
1970 screensize = screen_size * 2;
1971 faces[0]
1972 = compute_glyph_face (selected_frame,
1973 face_name_id_number
1974 (selected_frame,
1975 intern ("msdos-menu-passive-face")),
1976 0);
1977 faces[1]
1978 = compute_glyph_face (selected_frame,
1979 face_name_id_number
1980 (selected_frame,
1981 intern ("msdos-menu-active-face")),
1982 0);
1983 selectface
1984 = face_name_id_number (selected_frame, intern ("msdos-menu-select-face"));
1985 faces[2] = compute_glyph_face (selected_frame, selectface, faces[0]);
1986 faces[3] = compute_glyph_face (selected_frame, selectface, faces[1]);
1987
1988 /* Make sure the menu title is always displayed with
1989 `msdos-menu-active-face', no matter where the mouse pointer is. */
1990 for (i = 0; i < 4; i++)
1991 title_faces[i] = faces[3];
1992
1993 statecount = 1;
1994
1995 /* Don't let the title for the "Buffers" popup menu include a
1996 digit (which is ugly).
1997
1998 This is a terrible kludge, but I think the "Buffers" case is
1999 the only one where the title includes a number, so it doesn't
2000 seem to be necessary to make this more general. */
2001 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
2002 {
2003 menu->text[0][7] = '\0';
2004 buffers_num_deleted = 1;
2005 }
2006 state[0].menu = menu;
2007 mouse_off ();
2008 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
2009
2010 IT_menu_display (menu, y0 - 1, x0 - 1, title_faces); /* display menu title */
2011 if (buffers_num_deleted)
2012 menu->text[0][7] = ' ';
2013 if ((onepane = menu->count == 1 && menu->submenu[0]))
2014 {
2015 menu->width = menu->submenu[0]->width;
2016 state[0].menu = menu->submenu[0];
2017 }
2018 else
2019 {
2020 state[0].menu = menu;
2021 }
2022 state[0].x = x0 - 1;
2023 state[0].y = y0;
2024 state[0].pane = onepane;
2025
2026 mouse_last_x = -1; /* A hack that forces display. */
2027 leave = 0;
2028 while (!leave)
2029 {
2030 if (!mouse_visible) mouse_on ();
2031 mouse_check_moved ();
2032 if (selected_frame->mouse_moved)
2033 {
2034 selected_frame->mouse_moved = 0;
2035 result = XM_IA_SELECT;
2036 mouse_get_xy (&x, &y);
2037 for (i = 0; i < statecount; i++)
2038 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
2039 {
2040 int dy = y - state[i].y;
2041 if (0 <= dy && dy < state[i].menu->count)
2042 {
2043 if (!state[i].menu->submenu[dy])
2044 if (state[i].menu->panenumber[dy])
2045 result = XM_SUCCESS;
2046 else
2047 result = XM_IA_SELECT;
2048 *pane = state[i].pane - 1;
2049 *selidx = dy;
2050 /* We hit some part of a menu, so drop extra menus that
2051 have been opened. That does not include an open and
2052 active submenu. */
2053 if (i != statecount - 2
2054 || state[i].menu->submenu[dy] != state[i+1].menu)
2055 while (i != statecount - 1)
2056 {
2057 statecount--;
2058 mouse_off ();
2059 ScreenUpdate (state[statecount].screen_behind);
2060 xfree (state[statecount].screen_behind);
2061 }
2062 if (i == statecount - 1 && state[i].menu->submenu[dy])
2063 {
2064 IT_menu_display (state[i].menu,
2065 state[i].y,
2066 state[i].x,
2067 faces);
2068 state[statecount].menu = state[i].menu->submenu[dy];
2069 state[statecount].pane = state[i].menu->panenumber[dy];
2070 mouse_off ();
2071 ScreenRetrieve (state[statecount].screen_behind
2072 = xmalloc (screensize));
2073 state[statecount].x
2074 = state[i].x + state[i].menu->width + 2;
2075 state[statecount].y = y;
2076 statecount++;
2077 }
2078 }
2079 }
2080 IT_menu_display (state[statecount - 1].menu,
2081 state[statecount - 1].y,
2082 state[statecount - 1].x,
2083 faces);
2084 }
2085 for (b = 0; b < mouse_button_count; b++)
2086 {
2087 (void) mouse_pressed (b, &x, &y);
2088 if (mouse_released (b, &x, &y))
2089 leave = 1;
2090 }
2091 }
2092
2093 mouse_off ();
2094 ScreenUpdate (state[0].screen_behind);
2095 while (statecount--)
2096 xfree (state[statecount].screen_behind);
2097 return result;
2098 }
2099
2100 /* Dispose of a menu. */
2101
2102 void
2103 XMenuDestroy (Display *foo, XMenu *menu)
2104 {
2105 int i;
2106 if (menu->allocated)
2107 {
2108 for (i = 0; i < menu->count; i++)
2109 if (menu->submenu[i])
2110 XMenuDestroy (foo, menu->submenu[i]);
2111 xfree (menu->text);
2112 xfree (menu->submenu);
2113 xfree (menu->panenumber);
2114 }
2115 xfree (menu);
2116 }
2117
2118 int
2119 x_pixel_width (struct frame *f)
2120 {
2121 return FRAME_WIDTH (f);
2122 }
2123
2124 int
2125 x_pixel_height (struct frame *f)
2126 {
2127 return FRAME_HEIGHT (f);
2128 }
2129 #endif /* !HAVE_X_WINDOWS */
2130 \f
2131 /* ----------------------- DOS / UNIX conversion --------------------- */
2132
2133 /* Destructively turn backslashes into slashes. */
2134
2135 void
2136 dostounix_filename (p)
2137 register char *p;
2138 {
2139 while (*p)
2140 {
2141 if (*p == '\\')
2142 *p = '/';
2143 p++;
2144 }
2145 }
2146
2147 /* Destructively turn slashes into backslashes. */
2148
2149 void
2150 unixtodos_filename (p)
2151 register char *p;
2152 {
2153 while (*p)
2154 {
2155 if (*p == '/')
2156 *p = '\\';
2157 p++;
2158 }
2159 }
2160
2161 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2162 void msdos_downcase_filename (unsigned char *);
2163
2164 int
2165 getdefdir (drive, dst)
2166 int drive;
2167 char *dst;
2168 {
2169 char in_path[4], *p = in_path;
2170 int e = errno;
2171
2172 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2173 if (drive != 0)
2174 {
2175 *p++ = drive + 'A' - 1;
2176 *p++ = ':';
2177 }
2178
2179 *p++ = '.';
2180 *p = '\0';
2181 errno = 0;
2182 _fixpath (in_path, dst);
2183 if (errno)
2184 return 0;
2185
2186 msdos_downcase_filename (dst);
2187
2188 errno = e;
2189 return 1;
2190 }
2191
2192 /* Remove all CR's that are followed by a LF. */
2193
2194 int
2195 crlf_to_lf (n, buf)
2196 register int n;
2197 register unsigned char *buf;
2198 {
2199 unsigned char *np = buf;
2200 unsigned char *startp = buf;
2201 unsigned char *endp = buf + n;
2202 unsigned char c;
2203
2204 if (n == 0)
2205 return n;
2206 while (buf < endp - 1)
2207 {
2208 if (*buf == 0x0d)
2209 {
2210 if (*(++buf) != 0x0a)
2211 *np++ = 0x0d;
2212 }
2213 else
2214 *np++ = *buf++;
2215 }
2216 if (buf < endp)
2217 *np++ = *buf++;
2218 return np - startp;
2219 }
2220
2221 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
2222
2223 /* In DJGPP v2.0, library `write' can call `malloc', which might
2224 cause relocation of the buffer whose address we get in ADDR.
2225 Here is a version of `write' that avoids calling `malloc',
2226 to serve us until such time as the library is fixed.
2227 Actually, what we define here is called `__write', because
2228 `write' is a stub that just jmp's to `__write' (to be
2229 POSIXLY-correct with respect to the global name-space). */
2230
2231 #include <io.h> /* for _write */
2232 #include <libc/dosio.h> /* for __file_handle_modes[] */
2233
2234 static char xbuf[64 * 1024]; /* DOS cannot write more in one chunk */
2235
2236 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
2237
2238 int
2239 __write (int handle, const void *buffer, size_t count)
2240 {
2241 if (count == 0)
2242 return 0;
2243
2244 if(__file_handle_modes[handle] & O_BINARY)
2245 return _write (handle, buffer, count);
2246 else
2247 {
2248 char *xbp = xbuf;
2249 const char *bp = buffer;
2250 int total_written = 0;
2251 int nmoved = 0, ncr = 0;
2252
2253 while (count)
2254 {
2255 /* The next test makes sure there's space for at least 2 more
2256 characters in xbuf[], so both CR and LF can be put there. */
2257 if (xbp < XBUF_END)
2258 {
2259 if (*bp == '\n')
2260 {
2261 ncr++;
2262 *xbp++ = '\r';
2263 }
2264 *xbp++ = *bp++;
2265 nmoved++;
2266 count--;
2267 }
2268 if (xbp >= XBUF_END || !count)
2269 {
2270 size_t to_write = nmoved + ncr;
2271 int written = _write (handle, xbuf, to_write);
2272
2273 if (written == -1)
2274 return -1;
2275 else
2276 total_written += nmoved; /* CRs aren't counted in ret value */
2277
2278 /* If some, but not all were written (disk full?), return
2279 an estimate of the total written bytes not counting CRs. */
2280 if (written < to_write)
2281 return total_written - (to_write - written) * nmoved/to_write;
2282
2283 nmoved = 0;
2284 ncr = 0;
2285 xbp = xbuf;
2286 }
2287 }
2288 return total_written;
2289 }
2290 }
2291
2292 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
2293
2294 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
2295 0, 0, 0,
2296 "Return non-nil if long file names are supported on MSDOS.")
2297 ()
2298 {
2299 return (_USE_LFN ? Qt : Qnil);
2300 }
2301
2302 /* Convert alphabetic characters in a filename to lower-case. */
2303
2304 void
2305 msdos_downcase_filename (p)
2306 register unsigned char *p;
2307 {
2308 /* Under LFN we expect to get pathnames in their true case. */
2309 if (NILP (Fmsdos_long_file_names ()))
2310 for ( ; *p; p++)
2311 if (*p >= 'A' && *p <= 'Z')
2312 *p += 'a' - 'A';
2313 }
2314
2315 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
2316 1, 1, 0,
2317 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
2318 When long filenames are supported, doesn't change FILENAME.\n\
2319 If FILENAME is not a string, returns nil.\n\
2320 The argument object is never altered--the value is a copy.")
2321 (filename)
2322 Lisp_Object filename;
2323 {
2324 char *fname;
2325 Lisp_Object tem;
2326
2327 if (! STRINGP (filename))
2328 return Qnil;
2329
2330 tem = Fcopy_sequence (filename);
2331 msdos_downcase_filename (XSTRING (tem)->data);
2332 return tem;
2333 }
2334 \f
2335 /* The Emacs root directory as determined by init_environment. */
2336
2337 static char emacsroot[MAXPATHLEN];
2338
2339 char *
2340 rootrelativepath (rel)
2341 char *rel;
2342 {
2343 static char result[MAXPATHLEN + 10];
2344
2345 strcpy (result, emacsroot);
2346 strcat (result, "/");
2347 strcat (result, rel);
2348 return result;
2349 }
2350
2351 /* Define a lot of environment variables if not already defined. Don't
2352 remove anything unless you know what you're doing -- lots of code will
2353 break if one or more of these are missing. */
2354
2355 void
2356 init_environment (argc, argv, skip_args)
2357 int argc;
2358 char **argv;
2359 int skip_args;
2360 {
2361 char *s, *t, *root;
2362 int len;
2363
2364 /* Find our root from argv[0]. Assuming argv[0] is, say,
2365 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
2366 root = alloca (MAXPATHLEN + 20);
2367 _fixpath (argv[0], root);
2368 strlwr (root);
2369 len = strlen (root);
2370 while (len > 0 && root[len] != '/' && root[len] != ':')
2371 len--;
2372 root[len] = '\0';
2373 if (len > 4 && strcmp (root + len - 4, "/bin") == 0)
2374 root[len - 4] = '\0';
2375 else
2376 strcpy (root, "c:/emacs"); /* Only under debuggers, I think. */
2377 len = strlen (root);
2378 strcpy (emacsroot, root);
2379
2380 /* We default HOME to our root. */
2381 setenv ("HOME", root, 0);
2382
2383 /* We default EMACSPATH to root + "/bin". */
2384 strcpy (root + len, "/bin");
2385 setenv ("EMACSPATH", root, 0);
2386
2387 /* I don't expect anybody to ever use other terminals so the internal
2388 terminal is the default. */
2389 setenv ("TERM", "internal", 0);
2390
2391 #ifdef HAVE_X_WINDOWS
2392 /* Emacs expects DISPLAY to be set. */
2393 setenv ("DISPLAY", "unix:0.0", 0);
2394 #endif
2395
2396 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
2397 downcase it and mirror the backslashes. */
2398 s = getenv ("COMSPEC");
2399 if (!s) s = "c:/command.com";
2400 t = alloca (strlen (s) + 1);
2401 strcpy (t, s);
2402 strlwr (t);
2403 dostounix_filename (t);
2404 setenv ("SHELL", t, 0);
2405
2406 /* PATH is also downcased and backslashes mirrored. */
2407 s = getenv ("PATH");
2408 if (!s) s = "";
2409 t = alloca (strlen (s) + 3);
2410 /* Current directory is always considered part of MsDos's path but it is
2411 not normally mentioned. Now it is. */
2412 strcat (strcpy (t, ".;"), s);
2413 strlwr (t);
2414 dostounix_filename (t); /* Not a single file name, but this should work. */
2415 setenv ("PATH", t, 1);
2416
2417 /* In some sense all dos users have root privileges, so... */
2418 setenv ("USER", "root", 0);
2419 setenv ("NAME", getenv ("USER"), 0);
2420
2421 /* Time zone determined from country code. To make this possible, the
2422 country code may not span more than one time zone. In other words,
2423 in the USA, you lose. */
2424 if (!getenv ("TZ"))
2425 switch (dos_country_code)
2426 {
2427 case 31: /* Belgium */
2428 case 32: /* The Netherlands */
2429 case 33: /* France */
2430 case 34: /* Spain */
2431 case 36: /* Hungary */
2432 case 38: /* Yugoslavia (or what's left of it?) */
2433 case 39: /* Italy */
2434 case 41: /* Switzerland */
2435 case 42: /* Tjekia */
2436 case 45: /* Denmark */
2437 case 46: /* Sweden */
2438 case 47: /* Norway */
2439 case 48: /* Poland */
2440 case 49: /* Germany */
2441 /* Daylight saving from last Sunday in March to last Sunday in
2442 September, both at 2AM. */
2443 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2444 break;
2445 case 44: /* United Kingdom */
2446 case 351: /* Portugal */
2447 case 354: /* Iceland */
2448 setenv ("TZ", "GMT+00", 0);
2449 break;
2450 case 81: /* Japan */
2451 case 82: /* Korea */
2452 setenv ("TZ", "JST-09", 0);
2453 break;
2454 case 90: /* Turkey */
2455 case 358: /* Finland */
2456 setenv ("TZ", "EET-02", 0);
2457 break;
2458 case 972: /* Israel */
2459 /* This is an approximation. (For exact rules, use the
2460 `zoneinfo/israel' file which comes with DJGPP, but you need
2461 to install it in `/usr/share/zoneinfo/' directory first.) */
2462 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2463 break;
2464 }
2465 tzset ();
2466 }
2467
2468 \f
2469
2470 static int break_stat; /* BREAK check mode status. */
2471 static int stdin_stat; /* stdin IOCTL status. */
2472
2473 #if __DJGPP__ < 2
2474
2475 /* These must be global. */
2476 static _go32_dpmi_seginfo ctrl_break_vector;
2477 static _go32_dpmi_registers ctrl_break_regs;
2478 static int ctrlbreakinstalled = 0;
2479
2480 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2481
2482 void
2483 ctrl_break_func (regs)
2484 _go32_dpmi_registers *regs;
2485 {
2486 Vquit_flag = Qt;
2487 }
2488
2489 void
2490 install_ctrl_break_check ()
2491 {
2492 if (!ctrlbreakinstalled)
2493 {
2494 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2495 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2496 ctrlbreakinstalled = 1;
2497 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
2498 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
2499 &ctrl_break_regs);
2500 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
2501 }
2502 }
2503
2504 #endif /* __DJGPP__ < 2 */
2505
2506 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
2507 control chars by DOS. Determine the keyboard type. */
2508
2509 int
2510 dos_ttraw ()
2511 {
2512 union REGS inregs, outregs;
2513 static int first_time = 1;
2514
2515 break_stat = getcbrk ();
2516 setcbrk (0);
2517 #if __DJGPP__ < 2
2518 install_ctrl_break_check ();
2519 #endif
2520
2521 if (first_time)
2522 {
2523 inregs.h.ah = 0xc0;
2524 int86 (0x15, &inregs, &outregs);
2525 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
2526
2527 have_mouse = 0;
2528
2529 if (internal_terminal
2530 #ifdef HAVE_X_WINDOWS
2531 && inhibit_window_system
2532 #endif
2533 )
2534 {
2535 inregs.x.ax = 0x0021;
2536 int86 (0x33, &inregs, &outregs);
2537 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2538 if (!have_mouse)
2539 {
2540 /* Reportedly, the above doesn't work for some mouse drivers. There
2541 is an additional detection method that should work, but might be
2542 a little slower. Use that as an alternative. */
2543 inregs.x.ax = 0x0000;
2544 int86 (0x33, &inregs, &outregs);
2545 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2546 }
2547
2548 if (have_mouse)
2549 {
2550 have_mouse = 1; /* enable mouse */
2551 mouse_visible = 0;
2552
2553 if (outregs.x.bx == 3)
2554 {
2555 mouse_button_count = 3;
2556 mouse_button_translate[0] = 0; /* Left */
2557 mouse_button_translate[1] = 2; /* Middle */
2558 mouse_button_translate[2] = 1; /* Right */
2559 }
2560 else
2561 {
2562 mouse_button_count = 2;
2563 mouse_button_translate[0] = 0;
2564 mouse_button_translate[1] = 1;
2565 }
2566 mouse_position_hook = &mouse_get_pos;
2567 mouse_init ();
2568 }
2569 }
2570
2571 first_time = 0;
2572
2573 #if __DJGPP__ >= 2
2574
2575 stdin_stat = setmode (fileno (stdin), O_BINARY);
2576 return (stdin_stat != -1);
2577 }
2578 else
2579 return (setmode (fileno (stdin), O_BINARY) != -1);
2580
2581 #else /* __DJGPP__ < 2 */
2582
2583 }
2584
2585 /* I think it is wrong to overwrite `stdin_stat' every time
2586 but the first one this function is called, but I don't
2587 want to change the way it used to work in v1.x.--EZ */
2588
2589 inregs.x.ax = 0x4400; /* Get IOCTL status. */
2590 inregs.x.bx = 0x00; /* 0 = stdin. */
2591 intdos (&inregs, &outregs);
2592 stdin_stat = outregs.h.dl;
2593
2594 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
2595 inregs.x.ax = 0x4401; /* Set IOCTL status */
2596 intdos (&inregs, &outregs);
2597 return !outregs.x.cflag;
2598
2599 #endif /* __DJGPP__ < 2 */
2600 }
2601
2602 /* Restore status of standard input and Ctrl-C checking. */
2603
2604 int
2605 dos_ttcooked ()
2606 {
2607 union REGS inregs, outregs;
2608
2609 setcbrk (break_stat);
2610 mouse_off ();
2611
2612 #if __DJGPP__ >= 2
2613
2614 return (setmode (fileno (stdin), stdin_stat) != -1);
2615
2616 #else /* not __DJGPP__ >= 2 */
2617
2618 inregs.x.ax = 0x4401; /* Set IOCTL status. */
2619 inregs.x.bx = 0x00; /* 0 = stdin. */
2620 inregs.x.dx = stdin_stat;
2621 intdos (&inregs, &outregs);
2622 return !outregs.x.cflag;
2623
2624 #endif /* not __DJGPP__ >= 2 */
2625 }
2626
2627 \f
2628 /* Run command as specified by ARGV in directory DIR.
2629 The command is run with input from TEMPIN, output to
2630 file TEMPOUT and stderr to TEMPERR. */
2631
2632 int
2633 run_msdos_command (argv, dir, tempin, tempout, temperr)
2634 unsigned char **argv;
2635 Lisp_Object dir;
2636 int tempin, tempout, temperr;
2637 {
2638 char *saveargv1, *saveargv2, **envv;
2639 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
2640 int msshell, result = -1;
2641 int in, out, inbak, outbak, errbak;
2642 int x, y;
2643 Lisp_Object cmd;
2644
2645 /* Get current directory as MSDOS cwd is not per-process. */
2646 getwd (oldwd);
2647
2648 cmd = Ffile_name_nondirectory (build_string (argv[0]));
2649 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
2650 && !strcmp ("-c", argv[1]);
2651 if (msshell)
2652 {
2653 saveargv1 = argv[1];
2654 saveargv2 = argv[2];
2655 argv[1] = "/c";
2656 if (argv[2])
2657 {
2658 char *p = alloca (strlen (argv[2]) + 1);
2659
2660 strcpy (argv[2] = p, saveargv2);
2661 while (*p && isspace (*p))
2662 p++;
2663 while (*p && !isspace (*p))
2664 if (*p == '/')
2665 *p++ = '\\';
2666 else
2667 p++;
2668 }
2669 }
2670
2671 /* Build the environment array. */
2672 {
2673 extern Lisp_Object Vprocess_environment;
2674 Lisp_Object tmp, lst;
2675 int i, len;
2676
2677 lst = Vprocess_environment;
2678 len = XFASTINT (Flength (lst));
2679
2680 envv = alloca ((len + 1) * sizeof (char *));
2681 for (i = 0; i < len; i++)
2682 {
2683 tmp = Fcar (lst);
2684 lst = Fcdr (lst);
2685 CHECK_STRING (tmp, 0);
2686 envv[i] = alloca (XSTRING (tmp)->size + 1);
2687 strcpy (envv[i], XSTRING (tmp)->data);
2688 }
2689 envv[len] = (char *) 0;
2690 }
2691
2692 if (STRINGP (dir))
2693 chdir (XSTRING (dir)->data);
2694 inbak = dup (0);
2695 outbak = dup (1);
2696 errbak = dup (2);
2697 if (inbak < 0 || outbak < 0 || errbak < 0)
2698 goto done; /* Allocation might fail due to lack of descriptors. */
2699
2700 if (have_mouse > 0)
2701 mouse_get_xy (&x, &y);
2702
2703 dos_ttcooked (); /* do it here while 0 = stdin */
2704
2705 dup2 (tempin, 0);
2706 dup2 (tempout, 1);
2707 dup2 (temperr, 2);
2708
2709 #if __DJGPP__ > 1
2710
2711 if (msshell && !argv[3])
2712 {
2713 /* MS-DOS native shells are too restrictive. For starters, they
2714 cannot grok commands longer than 126 characters. In DJGPP v2
2715 and later, `system' is much smarter, so we'll call it instead. */
2716
2717 extern char **environ;
2718 environ = envv;
2719
2720 /* A shell gets a single argument--its full command
2721 line--whose original was saved in `saveargv2'. */
2722 result = system (saveargv2);
2723 }
2724 else
2725
2726 #endif /* __DJGPP__ > 1 */
2727
2728 result = spawnve (P_WAIT, argv[0], argv, envv);
2729
2730 dup2 (inbak, 0);
2731 dup2 (outbak, 1);
2732 dup2 (errbak, 2);
2733 close (inbak);
2734 close (outbak);
2735 close (errbak);
2736
2737 dos_ttraw ();
2738 if (have_mouse > 0)
2739 {
2740 mouse_init ();
2741 mouse_moveto (x, y);
2742 }
2743
2744 done:
2745 chdir (oldwd);
2746 if (msshell)
2747 {
2748 argv[1] = saveargv1;
2749 argv[2] = saveargv2;
2750 }
2751 return result;
2752 }
2753
2754 croak (badfunc)
2755 char *badfunc;
2756 {
2757 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
2758 reset_sys_modes ();
2759 exit (1);
2760 }
2761 \f
2762 #if __DJGPP__ < 2
2763
2764 /* ------------------------- Compatibility functions -------------------
2765 * gethostname
2766 * gettimeofday
2767 */
2768
2769 /* Hostnames for a pc are not really funny,
2770 but they are used in change log so we emulate the best we can. */
2771
2772 gethostname (p, size)
2773 char *p;
2774 int size;
2775 {
2776 char *q = egetenv ("HOSTNAME");
2777
2778 if (!q) q = "pc";
2779 strcpy (p, q);
2780 return 0;
2781 }
2782
2783 /* When time zones are set from Ms-Dos too many C-libraries are playing
2784 tricks with time values. We solve this by defining our own version
2785 of `gettimeofday' bypassing GO32. Our version needs to be initialized
2786 once and after each call to `tzset' with TZ changed. That is
2787 accomplished by aliasing tzset to init_gettimeofday. */
2788
2789 static struct tm time_rec;
2790
2791 int
2792 gettimeofday (struct timeval *tp, struct timezone *tzp)
2793 {
2794 if (tp)
2795 {
2796 struct time t;
2797 struct tm tm;
2798
2799 gettime (&t);
2800 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
2801 {
2802 struct date d;
2803 getdate (&d);
2804 time_rec.tm_year = d.da_year - 1900;
2805 time_rec.tm_mon = d.da_mon - 1;
2806 time_rec.tm_mday = d.da_day;
2807 }
2808
2809 time_rec.tm_hour = t.ti_hour;
2810 time_rec.tm_min = t.ti_min;
2811 time_rec.tm_sec = t.ti_sec;
2812
2813 tm = time_rec;
2814 tm.tm_gmtoff = dos_timezone_offset;
2815
2816 tp->tv_sec = mktime (&tm); /* may modify tm */
2817 tp->tv_usec = t.ti_hund * (1000000 / 100);
2818 }
2819 /* Ignore tzp; it's obsolescent. */
2820 return 0;
2821 }
2822
2823 #endif /* __DJGPP__ < 2 */
2824
2825 /*
2826 * A list of unimplemented functions that we silently ignore.
2827 */
2828
2829 #if __DJGPP__ < 2
2830 unsigned alarm (s) unsigned s; {}
2831 fork () { return 0; }
2832 int kill (x, y) int x, y; { return -1; }
2833 nice (p) int p; {}
2834 void volatile pause () {}
2835 sigsetmask (x) int x; { return 0; }
2836 #endif
2837
2838 request_sigio () {}
2839 setpgrp () {return 0; }
2840 setpriority (x,y,z) int x,y,z; { return 0; }
2841 sigblock (mask) int mask; { return 0; }
2842 unrequest_sigio () {}
2843
2844 #ifndef HAVE_SELECT
2845 #include "sysselect.h"
2846
2847 #ifndef EMACS_TIME_ZERO_OR_NEG_P
2848 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
2849 ((long)(time).tv_sec < 0 \
2850 || ((time).tv_sec == 0 \
2851 && (long)(time).tv_usec <= 0))
2852 #endif
2853
2854
2855 /* Only event queue is checked. */
2856 /* We don't have to call timer_check here
2857 because wait_reading_process_input takes care of that. */
2858 int
2859 sys_select (nfds, rfds, wfds, efds, timeout)
2860 int nfds;
2861 SELECT_TYPE *rfds, *wfds, *efds;
2862 EMACS_TIME *timeout;
2863 {
2864 int check_input;
2865 struct time t;
2866
2867 check_input = 0;
2868 if (rfds)
2869 {
2870 check_input = FD_ISSET (0, rfds);
2871 FD_ZERO (rfds);
2872 }
2873 if (wfds)
2874 FD_ZERO (wfds);
2875 if (efds)
2876 FD_ZERO (efds);
2877
2878 if (nfds != 1)
2879 abort ();
2880
2881 /* If we are looking only for the terminal, with no timeout,
2882 just read it and wait -- that's more efficient. */
2883 if (!timeout)
2884 {
2885 while (!detect_input_pending ())
2886 {
2887 #if __DJGPP__ >= 2
2888 __dpmi_yield ();
2889 #endif
2890 }
2891 }
2892 else
2893 {
2894 EMACS_TIME clnow, cllast, cldiff;
2895
2896 gettime (&t);
2897 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
2898
2899 while (!check_input || !detect_input_pending ())
2900 {
2901 gettime (&t);
2902 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
2903 EMACS_SUB_TIME (cldiff, clnow, cllast);
2904
2905 /* When seconds wrap around, we assume that no more than
2906 1 minute passed since last `gettime'. */
2907 if (EMACS_TIME_NEG_P (cldiff))
2908 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
2909 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
2910
2911 /* Stop when timeout value crosses zero. */
2912 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
2913 return 0;
2914 cllast = clnow;
2915 #if __DJGPP__ >= 2
2916 __dpmi_yield ();
2917 #endif
2918 }
2919 }
2920
2921 FD_SET (0, rfds);
2922 return 1;
2923 }
2924 #endif
2925
2926 /*
2927 * Define overlaid functions:
2928 *
2929 * chdir -> sys_chdir
2930 * tzset -> init_gettimeofday
2931 * abort -> dos_abort
2932 */
2933
2934 #ifdef chdir
2935 #undef chdir
2936 extern int chdir ();
2937
2938 int
2939 sys_chdir (path)
2940 const char* path;
2941 {
2942 int len = strlen (path);
2943 char *tmp = (char *)path;
2944
2945 if (*tmp && tmp[1] == ':')
2946 {
2947 if (getdisk () != tolower (tmp[0]) - 'a')
2948 setdisk (tolower (tmp[0]) - 'a');
2949 tmp += 2; /* strip drive: KFS 1995-07-06 */
2950 len -= 2;
2951 }
2952
2953 if (len > 1 && (tmp[len - 1] == '/'))
2954 {
2955 char *tmp1 = (char *) alloca (len + 1);
2956 strcpy (tmp1, tmp);
2957 tmp1[len - 1] = 0;
2958 tmp = tmp1;
2959 }
2960 return chdir (tmp);
2961 }
2962 #endif
2963
2964 #ifdef tzset
2965 #undef tzset
2966 extern void tzset (void);
2967
2968 void
2969 init_gettimeofday ()
2970 {
2971 time_t ltm, gtm;
2972 struct tm *lstm;
2973
2974 tzset ();
2975 ltm = gtm = time (NULL);
2976 ltm = mktime (lstm = localtime (&ltm));
2977 gtm = mktime (gmtime (&gtm));
2978 time_rec.tm_hour = 99; /* force gettimeofday to get date */
2979 time_rec.tm_isdst = lstm->tm_isdst;
2980 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
2981 }
2982 #endif
2983
2984 #ifdef abort
2985 #undef abort
2986 void
2987 dos_abort (file, line)
2988 char *file;
2989 int line;
2990 {
2991 char buffer1[200], buffer2[400];
2992 int i, j;
2993
2994 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
2995 for (i = j = 0; buffer1[i]; i++) {
2996 buffer2[j++] = buffer1[i];
2997 buffer2[j++] = 0x70;
2998 }
2999 dosmemput (buffer2, j, (int)ScreenPrimary);
3000 ScreenSetCursor (2, 0);
3001 abort ();
3002 }
3003 #else
3004 void
3005 abort ()
3006 {
3007 dos_ttcooked ();
3008 ScreenSetCursor (10, 0);
3009 cputs ("\r\n\nEmacs aborted!\r\n");
3010 #if __DJGPP__ > 1
3011 /* Generate traceback, so we could tell whodunit. */
3012 signal (SIGINT, SIG_DFL);
3013 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
3014 #endif
3015 exit (2);
3016 }
3017 #endif
3018
3019 syms_of_msdos ()
3020 {
3021 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
3022 staticpro (&recent_doskeys);
3023
3024 defsubr (&Srecent_doskeys);
3025 defsubr (&Smsdos_long_file_names);
3026 defsubr (&Smsdos_downcase_filename);
3027 }
3028
3029 #endif /* MSDOS */