]> code.delx.au - gnu-emacs/blob - src/msdos.c
(msdos_downcase_filename):
[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 /* Always lower-case drive letters a-z, even if the filesystem
2309 preserves case in filenames.
2310 This is so MSDOS filenames could be compared by string comparison
2311 functions that are case-sensitive. Even case-preserving filesystems
2312 do not distinguish case in drive letters. */
2313 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
2314 {
2315 *p += 'a' - 'A';
2316 p += 2;
2317 }
2318
2319 /* Under LFN we expect to get pathnames in their true case. */
2320 if (NILP (Fmsdos_long_file_names ()))
2321 for ( ; *p; p++)
2322 if (*p >= 'A' && *p <= 'Z')
2323 *p += 'a' - 'A';
2324 }
2325
2326 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
2327 1, 1, 0,
2328 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
2329 When long filenames are supported, doesn't change FILENAME.\n\
2330 If FILENAME is not a string, returns nil.\n\
2331 The argument object is never altered--the value is a copy.")
2332 (filename)
2333 Lisp_Object filename;
2334 {
2335 char *fname;
2336 Lisp_Object tem;
2337
2338 if (! STRINGP (filename))
2339 return Qnil;
2340
2341 tem = Fcopy_sequence (filename);
2342 msdos_downcase_filename (XSTRING (tem)->data);
2343 return tem;
2344 }
2345 \f
2346 /* The Emacs root directory as determined by init_environment. */
2347
2348 static char emacsroot[MAXPATHLEN];
2349
2350 char *
2351 rootrelativepath (rel)
2352 char *rel;
2353 {
2354 static char result[MAXPATHLEN + 10];
2355
2356 strcpy (result, emacsroot);
2357 strcat (result, "/");
2358 strcat (result, rel);
2359 return result;
2360 }
2361
2362 /* Define a lot of environment variables if not already defined. Don't
2363 remove anything unless you know what you're doing -- lots of code will
2364 break if one or more of these are missing. */
2365
2366 void
2367 init_environment (argc, argv, skip_args)
2368 int argc;
2369 char **argv;
2370 int skip_args;
2371 {
2372 char *s, *t, *root;
2373 int len;
2374
2375 /* Find our root from argv[0]. Assuming argv[0] is, say,
2376 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
2377 root = alloca (MAXPATHLEN + 20);
2378 _fixpath (argv[0], root);
2379 strlwr (root);
2380 len = strlen (root);
2381 while (len > 0 && root[len] != '/' && root[len] != ':')
2382 len--;
2383 root[len] = '\0';
2384 if (len > 4 && strcmp (root + len - 4, "/bin") == 0)
2385 root[len - 4] = '\0';
2386 else
2387 strcpy (root, "c:/emacs"); /* Only under debuggers, I think. */
2388 len = strlen (root);
2389 strcpy (emacsroot, root);
2390
2391 /* We default HOME to our root. */
2392 setenv ("HOME", root, 0);
2393
2394 /* We default EMACSPATH to root + "/bin". */
2395 strcpy (root + len, "/bin");
2396 setenv ("EMACSPATH", root, 0);
2397
2398 /* I don't expect anybody to ever use other terminals so the internal
2399 terminal is the default. */
2400 setenv ("TERM", "internal", 0);
2401
2402 #ifdef HAVE_X_WINDOWS
2403 /* Emacs expects DISPLAY to be set. */
2404 setenv ("DISPLAY", "unix:0.0", 0);
2405 #endif
2406
2407 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
2408 downcase it and mirror the backslashes. */
2409 s = getenv ("COMSPEC");
2410 if (!s) s = "c:/command.com";
2411 t = alloca (strlen (s) + 1);
2412 strcpy (t, s);
2413 strlwr (t);
2414 dostounix_filename (t);
2415 setenv ("SHELL", t, 0);
2416
2417 /* PATH is also downcased and backslashes mirrored. */
2418 s = getenv ("PATH");
2419 if (!s) s = "";
2420 t = alloca (strlen (s) + 3);
2421 /* Current directory is always considered part of MsDos's path but it is
2422 not normally mentioned. Now it is. */
2423 strcat (strcpy (t, ".;"), s);
2424 strlwr (t);
2425 dostounix_filename (t); /* Not a single file name, but this should work. */
2426 setenv ("PATH", t, 1);
2427
2428 /* In some sense all dos users have root privileges, so... */
2429 setenv ("USER", "root", 0);
2430 setenv ("NAME", getenv ("USER"), 0);
2431
2432 /* Time zone determined from country code. To make this possible, the
2433 country code may not span more than one time zone. In other words,
2434 in the USA, you lose. */
2435 if (!getenv ("TZ"))
2436 switch (dos_country_code)
2437 {
2438 case 31: /* Belgium */
2439 case 32: /* The Netherlands */
2440 case 33: /* France */
2441 case 34: /* Spain */
2442 case 36: /* Hungary */
2443 case 38: /* Yugoslavia (or what's left of it?) */
2444 case 39: /* Italy */
2445 case 41: /* Switzerland */
2446 case 42: /* Tjekia */
2447 case 45: /* Denmark */
2448 case 46: /* Sweden */
2449 case 47: /* Norway */
2450 case 48: /* Poland */
2451 case 49: /* Germany */
2452 /* Daylight saving from last Sunday in March to last Sunday in
2453 September, both at 2AM. */
2454 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2455 break;
2456 case 44: /* United Kingdom */
2457 case 351: /* Portugal */
2458 case 354: /* Iceland */
2459 setenv ("TZ", "GMT+00", 0);
2460 break;
2461 case 81: /* Japan */
2462 case 82: /* Korea */
2463 setenv ("TZ", "JST-09", 0);
2464 break;
2465 case 90: /* Turkey */
2466 case 358: /* Finland */
2467 setenv ("TZ", "EET-02", 0);
2468 break;
2469 case 972: /* Israel */
2470 /* This is an approximation. (For exact rules, use the
2471 `zoneinfo/israel' file which comes with DJGPP, but you need
2472 to install it in `/usr/share/zoneinfo/' directory first.) */
2473 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2474 break;
2475 }
2476 tzset ();
2477 }
2478
2479 \f
2480
2481 static int break_stat; /* BREAK check mode status. */
2482 static int stdin_stat; /* stdin IOCTL status. */
2483
2484 #if __DJGPP__ < 2
2485
2486 /* These must be global. */
2487 static _go32_dpmi_seginfo ctrl_break_vector;
2488 static _go32_dpmi_registers ctrl_break_regs;
2489 static int ctrlbreakinstalled = 0;
2490
2491 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2492
2493 void
2494 ctrl_break_func (regs)
2495 _go32_dpmi_registers *regs;
2496 {
2497 Vquit_flag = Qt;
2498 }
2499
2500 void
2501 install_ctrl_break_check ()
2502 {
2503 if (!ctrlbreakinstalled)
2504 {
2505 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2506 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2507 ctrlbreakinstalled = 1;
2508 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
2509 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
2510 &ctrl_break_regs);
2511 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
2512 }
2513 }
2514
2515 #endif /* __DJGPP__ < 2 */
2516
2517 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
2518 control chars by DOS. Determine the keyboard type. */
2519
2520 int
2521 dos_ttraw ()
2522 {
2523 union REGS inregs, outregs;
2524 static int first_time = 1;
2525
2526 break_stat = getcbrk ();
2527 setcbrk (0);
2528 #if __DJGPP__ < 2
2529 install_ctrl_break_check ();
2530 #endif
2531
2532 if (first_time)
2533 {
2534 inregs.h.ah = 0xc0;
2535 int86 (0x15, &inregs, &outregs);
2536 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
2537
2538 have_mouse = 0;
2539
2540 if (internal_terminal
2541 #ifdef HAVE_X_WINDOWS
2542 && inhibit_window_system
2543 #endif
2544 )
2545 {
2546 inregs.x.ax = 0x0021;
2547 int86 (0x33, &inregs, &outregs);
2548 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2549 if (!have_mouse)
2550 {
2551 /* Reportedly, the above doesn't work for some mouse drivers. There
2552 is an additional detection method that should work, but might be
2553 a little slower. Use that as an alternative. */
2554 inregs.x.ax = 0x0000;
2555 int86 (0x33, &inregs, &outregs);
2556 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2557 }
2558
2559 if (have_mouse)
2560 {
2561 have_mouse = 1; /* enable mouse */
2562 mouse_visible = 0;
2563
2564 if (outregs.x.bx == 3)
2565 {
2566 mouse_button_count = 3;
2567 mouse_button_translate[0] = 0; /* Left */
2568 mouse_button_translate[1] = 2; /* Middle */
2569 mouse_button_translate[2] = 1; /* Right */
2570 }
2571 else
2572 {
2573 mouse_button_count = 2;
2574 mouse_button_translate[0] = 0;
2575 mouse_button_translate[1] = 1;
2576 }
2577 mouse_position_hook = &mouse_get_pos;
2578 mouse_init ();
2579 }
2580 }
2581
2582 first_time = 0;
2583
2584 #if __DJGPP__ >= 2
2585
2586 stdin_stat = setmode (fileno (stdin), O_BINARY);
2587 return (stdin_stat != -1);
2588 }
2589 else
2590 return (setmode (fileno (stdin), O_BINARY) != -1);
2591
2592 #else /* __DJGPP__ < 2 */
2593
2594 }
2595
2596 /* I think it is wrong to overwrite `stdin_stat' every time
2597 but the first one this function is called, but I don't
2598 want to change the way it used to work in v1.x.--EZ */
2599
2600 inregs.x.ax = 0x4400; /* Get IOCTL status. */
2601 inregs.x.bx = 0x00; /* 0 = stdin. */
2602 intdos (&inregs, &outregs);
2603 stdin_stat = outregs.h.dl;
2604
2605 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
2606 inregs.x.ax = 0x4401; /* Set IOCTL status */
2607 intdos (&inregs, &outregs);
2608 return !outregs.x.cflag;
2609
2610 #endif /* __DJGPP__ < 2 */
2611 }
2612
2613 /* Restore status of standard input and Ctrl-C checking. */
2614
2615 int
2616 dos_ttcooked ()
2617 {
2618 union REGS inregs, outregs;
2619
2620 setcbrk (break_stat);
2621 mouse_off ();
2622
2623 #if __DJGPP__ >= 2
2624
2625 return (setmode (fileno (stdin), stdin_stat) != -1);
2626
2627 #else /* not __DJGPP__ >= 2 */
2628
2629 inregs.x.ax = 0x4401; /* Set IOCTL status. */
2630 inregs.x.bx = 0x00; /* 0 = stdin. */
2631 inregs.x.dx = stdin_stat;
2632 intdos (&inregs, &outregs);
2633 return !outregs.x.cflag;
2634
2635 #endif /* not __DJGPP__ >= 2 */
2636 }
2637
2638 \f
2639 /* Run command as specified by ARGV in directory DIR.
2640 The command is run with input from TEMPIN, output to
2641 file TEMPOUT and stderr to TEMPERR. */
2642
2643 int
2644 run_msdos_command (argv, dir, tempin, tempout, temperr)
2645 unsigned char **argv;
2646 Lisp_Object dir;
2647 int tempin, tempout, temperr;
2648 {
2649 char *saveargv1, *saveargv2, **envv;
2650 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
2651 int msshell, result = -1;
2652 int in, out, inbak, outbak, errbak;
2653 int x, y;
2654 Lisp_Object cmd;
2655
2656 /* Get current directory as MSDOS cwd is not per-process. */
2657 getwd (oldwd);
2658
2659 cmd = Ffile_name_nondirectory (build_string (argv[0]));
2660 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
2661 && !strcmp ("-c", argv[1]);
2662 if (msshell)
2663 {
2664 saveargv1 = argv[1];
2665 saveargv2 = argv[2];
2666 argv[1] = "/c";
2667 if (argv[2])
2668 {
2669 char *p = alloca (strlen (argv[2]) + 1);
2670
2671 strcpy (argv[2] = p, saveargv2);
2672 while (*p && isspace (*p))
2673 p++;
2674 while (*p && !isspace (*p))
2675 if (*p == '/')
2676 *p++ = '\\';
2677 else
2678 p++;
2679 }
2680 }
2681
2682 /* Build the environment array. */
2683 {
2684 extern Lisp_Object Vprocess_environment;
2685 Lisp_Object tmp, lst;
2686 int i, len;
2687
2688 lst = Vprocess_environment;
2689 len = XFASTINT (Flength (lst));
2690
2691 envv = alloca ((len + 1) * sizeof (char *));
2692 for (i = 0; i < len; i++)
2693 {
2694 tmp = Fcar (lst);
2695 lst = Fcdr (lst);
2696 CHECK_STRING (tmp, 0);
2697 envv[i] = alloca (XSTRING (tmp)->size + 1);
2698 strcpy (envv[i], XSTRING (tmp)->data);
2699 }
2700 envv[len] = (char *) 0;
2701 }
2702
2703 if (STRINGP (dir))
2704 chdir (XSTRING (dir)->data);
2705 inbak = dup (0);
2706 outbak = dup (1);
2707 errbak = dup (2);
2708 if (inbak < 0 || outbak < 0 || errbak < 0)
2709 goto done; /* Allocation might fail due to lack of descriptors. */
2710
2711 if (have_mouse > 0)
2712 mouse_get_xy (&x, &y);
2713
2714 dos_ttcooked (); /* do it here while 0 = stdin */
2715
2716 dup2 (tempin, 0);
2717 dup2 (tempout, 1);
2718 dup2 (temperr, 2);
2719
2720 #if __DJGPP__ > 1
2721
2722 if (msshell && !argv[3])
2723 {
2724 /* MS-DOS native shells are too restrictive. For starters, they
2725 cannot grok commands longer than 126 characters. In DJGPP v2
2726 and later, `system' is much smarter, so we'll call it instead. */
2727
2728 extern char **environ;
2729 environ = envv;
2730
2731 /* A shell gets a single argument--its full command
2732 line--whose original was saved in `saveargv2'. */
2733 result = system (saveargv2);
2734 }
2735 else
2736
2737 #endif /* __DJGPP__ > 1 */
2738
2739 result = spawnve (P_WAIT, argv[0], argv, envv);
2740
2741 dup2 (inbak, 0);
2742 dup2 (outbak, 1);
2743 dup2 (errbak, 2);
2744 close (inbak);
2745 close (outbak);
2746 close (errbak);
2747
2748 dos_ttraw ();
2749 if (have_mouse > 0)
2750 {
2751 mouse_init ();
2752 mouse_moveto (x, y);
2753 }
2754
2755 done:
2756 chdir (oldwd);
2757 if (msshell)
2758 {
2759 argv[1] = saveargv1;
2760 argv[2] = saveargv2;
2761 }
2762 return result;
2763 }
2764
2765 croak (badfunc)
2766 char *badfunc;
2767 {
2768 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
2769 reset_sys_modes ();
2770 exit (1);
2771 }
2772 \f
2773 #if __DJGPP__ < 2
2774
2775 /* ------------------------- Compatibility functions -------------------
2776 * gethostname
2777 * gettimeofday
2778 */
2779
2780 /* Hostnames for a pc are not really funny,
2781 but they are used in change log so we emulate the best we can. */
2782
2783 gethostname (p, size)
2784 char *p;
2785 int size;
2786 {
2787 char *q = egetenv ("HOSTNAME");
2788
2789 if (!q) q = "pc";
2790 strcpy (p, q);
2791 return 0;
2792 }
2793
2794 /* When time zones are set from Ms-Dos too many C-libraries are playing
2795 tricks with time values. We solve this by defining our own version
2796 of `gettimeofday' bypassing GO32. Our version needs to be initialized
2797 once and after each call to `tzset' with TZ changed. That is
2798 accomplished by aliasing tzset to init_gettimeofday. */
2799
2800 static struct tm time_rec;
2801
2802 int
2803 gettimeofday (struct timeval *tp, struct timezone *tzp)
2804 {
2805 if (tp)
2806 {
2807 struct time t;
2808 struct tm tm;
2809
2810 gettime (&t);
2811 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
2812 {
2813 struct date d;
2814 getdate (&d);
2815 time_rec.tm_year = d.da_year - 1900;
2816 time_rec.tm_mon = d.da_mon - 1;
2817 time_rec.tm_mday = d.da_day;
2818 }
2819
2820 time_rec.tm_hour = t.ti_hour;
2821 time_rec.tm_min = t.ti_min;
2822 time_rec.tm_sec = t.ti_sec;
2823
2824 tm = time_rec;
2825 tm.tm_gmtoff = dos_timezone_offset;
2826
2827 tp->tv_sec = mktime (&tm); /* may modify tm */
2828 tp->tv_usec = t.ti_hund * (1000000 / 100);
2829 }
2830 /* Ignore tzp; it's obsolescent. */
2831 return 0;
2832 }
2833
2834 #endif /* __DJGPP__ < 2 */
2835
2836 /*
2837 * A list of unimplemented functions that we silently ignore.
2838 */
2839
2840 #if __DJGPP__ < 2
2841 unsigned alarm (s) unsigned s; {}
2842 fork () { return 0; }
2843 int kill (x, y) int x, y; { return -1; }
2844 nice (p) int p; {}
2845 void volatile pause () {}
2846 sigsetmask (x) int x; { return 0; }
2847 #endif
2848
2849 request_sigio () {}
2850 setpgrp () {return 0; }
2851 setpriority (x,y,z) int x,y,z; { return 0; }
2852 sigblock (mask) int mask; { return 0; }
2853 unrequest_sigio () {}
2854
2855 #ifndef HAVE_SELECT
2856 #include "sysselect.h"
2857
2858 #ifndef EMACS_TIME_ZERO_OR_NEG_P
2859 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
2860 ((long)(time).tv_sec < 0 \
2861 || ((time).tv_sec == 0 \
2862 && (long)(time).tv_usec <= 0))
2863 #endif
2864
2865
2866 /* Only event queue is checked. */
2867 /* We don't have to call timer_check here
2868 because wait_reading_process_input takes care of that. */
2869 int
2870 sys_select (nfds, rfds, wfds, efds, timeout)
2871 int nfds;
2872 SELECT_TYPE *rfds, *wfds, *efds;
2873 EMACS_TIME *timeout;
2874 {
2875 int check_input;
2876 struct time t;
2877
2878 check_input = 0;
2879 if (rfds)
2880 {
2881 check_input = FD_ISSET (0, rfds);
2882 FD_ZERO (rfds);
2883 }
2884 if (wfds)
2885 FD_ZERO (wfds);
2886 if (efds)
2887 FD_ZERO (efds);
2888
2889 if (nfds != 1)
2890 abort ();
2891
2892 /* If we are looking only for the terminal, with no timeout,
2893 just read it and wait -- that's more efficient. */
2894 if (!timeout)
2895 {
2896 while (!detect_input_pending ())
2897 {
2898 #if __DJGPP__ >= 2
2899 __dpmi_yield ();
2900 #endif
2901 }
2902 }
2903 else
2904 {
2905 EMACS_TIME clnow, cllast, cldiff;
2906
2907 gettime (&t);
2908 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
2909
2910 while (!check_input || !detect_input_pending ())
2911 {
2912 gettime (&t);
2913 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
2914 EMACS_SUB_TIME (cldiff, clnow, cllast);
2915
2916 /* When seconds wrap around, we assume that no more than
2917 1 minute passed since last `gettime'. */
2918 if (EMACS_TIME_NEG_P (cldiff))
2919 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
2920 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
2921
2922 /* Stop when timeout value crosses zero. */
2923 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
2924 return 0;
2925 cllast = clnow;
2926 #if __DJGPP__ >= 2
2927 __dpmi_yield ();
2928 #endif
2929 }
2930 }
2931
2932 FD_SET (0, rfds);
2933 return 1;
2934 }
2935 #endif
2936
2937 /*
2938 * Define overlaid functions:
2939 *
2940 * chdir -> sys_chdir
2941 * tzset -> init_gettimeofday
2942 * abort -> dos_abort
2943 */
2944
2945 #ifdef chdir
2946 #undef chdir
2947 extern int chdir ();
2948
2949 int
2950 sys_chdir (path)
2951 const char* path;
2952 {
2953 int len = strlen (path);
2954 char *tmp = (char *)path;
2955
2956 if (*tmp && tmp[1] == ':')
2957 {
2958 if (getdisk () != tolower (tmp[0]) - 'a')
2959 setdisk (tolower (tmp[0]) - 'a');
2960 tmp += 2; /* strip drive: KFS 1995-07-06 */
2961 len -= 2;
2962 }
2963
2964 if (len > 1 && (tmp[len - 1] == '/'))
2965 {
2966 char *tmp1 = (char *) alloca (len + 1);
2967 strcpy (tmp1, tmp);
2968 tmp1[len - 1] = 0;
2969 tmp = tmp1;
2970 }
2971 return chdir (tmp);
2972 }
2973 #endif
2974
2975 #ifdef tzset
2976 #undef tzset
2977 extern void tzset (void);
2978
2979 void
2980 init_gettimeofday ()
2981 {
2982 time_t ltm, gtm;
2983 struct tm *lstm;
2984
2985 tzset ();
2986 ltm = gtm = time (NULL);
2987 ltm = mktime (lstm = localtime (&ltm));
2988 gtm = mktime (gmtime (&gtm));
2989 time_rec.tm_hour = 99; /* force gettimeofday to get date */
2990 time_rec.tm_isdst = lstm->tm_isdst;
2991 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
2992 }
2993 #endif
2994
2995 #ifdef abort
2996 #undef abort
2997 void
2998 dos_abort (file, line)
2999 char *file;
3000 int line;
3001 {
3002 char buffer1[200], buffer2[400];
3003 int i, j;
3004
3005 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
3006 for (i = j = 0; buffer1[i]; i++) {
3007 buffer2[j++] = buffer1[i];
3008 buffer2[j++] = 0x70;
3009 }
3010 dosmemput (buffer2, j, (int)ScreenPrimary);
3011 ScreenSetCursor (2, 0);
3012 abort ();
3013 }
3014 #else
3015 void
3016 abort ()
3017 {
3018 dos_ttcooked ();
3019 ScreenSetCursor (10, 0);
3020 cputs ("\r\n\nEmacs aborted!\r\n");
3021 #if __DJGPP__ > 1
3022 /* Generate traceback, so we could tell whodunit. */
3023 signal (SIGINT, SIG_DFL);
3024 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
3025 #endif
3026 exit (2);
3027 }
3028 #endif
3029
3030 syms_of_msdos ()
3031 {
3032 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
3033 staticpro (&recent_doskeys);
3034
3035 defsubr (&Srecent_doskeys);
3036 defsubr (&Smsdos_long_file_names);
3037 defsubr (&Smsdos_downcase_filename);
3038 }
3039
3040 #endif /* MSDOS */