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