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