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