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