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