(fill-individual-paragraphs): Calculate new
[emacs.git] / src / msdos.c
blobb73b8e7a5f79ee8b21d2997d6ee2f052c47a1af4
1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
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.
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.
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. */
21 /* Contributed by Morten Welinder */
22 /* New display, keyboard, and mouse control by Kim F. Storm */
24 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
26 #include <config.h>
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
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
70 #ifndef _USE_LFN
71 #define _USE_LFN 0
72 #endif
74 #ifndef _dos_ds
75 #define _dos_ds _go32_info_block.selector_for_linear_memory
76 #endif
78 #if __DJGPP__ > 1
80 #include <signal.h>
81 #include "syssignal.h"
83 #ifndef SYSTEM_MALLOC
85 #ifdef GNU_MALLOC
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>
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 */
100 #endif /* not SYSTEM_MALLOC */
101 #endif /* __DJGPP__ > 1 */
103 static unsigned long
104 event_timestamp ()
106 struct time t;
107 unsigned long s;
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;
116 return s;
120 /* ------------------------ Mouse control ---------------------------
122 * Coordinates are in screen positions and zero based.
123 * Mouse buttons are numbered from left to right and also zero based.
126 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
127 static int mouse_visible;
129 static int mouse_last_x;
130 static int mouse_last_y;
132 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
133 static int mouse_button_count;
135 void
136 mouse_on ()
138 union REGS regs;
140 if (have_mouse > 0 && !mouse_visible)
142 if (termscript)
143 fprintf (termscript, "<M_ON>");
144 regs.x.ax = 0x0001;
145 int86 (0x33, &regs, &regs);
146 mouse_visible = 1;
150 void
151 mouse_off ()
153 union REGS regs;
155 if (have_mouse > 0 && mouse_visible)
157 if (termscript)
158 fprintf (termscript, "<M_OFF>");
159 regs.x.ax = 0x0002;
160 int86 (0x33, &regs, &regs);
161 mouse_visible = 0;
165 static void
166 mouse_get_xy (int *x, int *y)
168 union REGS regs;
170 regs.x.ax = 0x0003;
171 int86 (0x33, &regs, &regs);
172 *x = regs.x.cx / 8;
173 *y = regs.x.dx / 8;
176 void
177 mouse_moveto (x, y)
178 int x, y;
180 union REGS regs;
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);
190 static int
191 mouse_pressed (b, xp, yp)
192 int b, *xp, *yp;
194 union REGS regs;
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);
206 static int
207 mouse_released (b, xp, yp)
208 int b, *xp, *yp;
210 union REGS regs;
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);
222 static int
223 mouse_button_depressed (b, xp, yp)
224 int b, *xp, *yp;
226 union REGS regs;
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)
234 *xp = regs.x.cx / 8;
235 *yp = regs.x.dx / 8;
236 return 1;
238 return 0;
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;
249 int ix, iy;
250 Lisp_Object frame, tail;
252 /* Clear the mouse-moved flag for every frame on this display. */
253 FOR_EACH_FRAME (tail, frame)
254 XFRAME (frame)->mouse_moved = 0;
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);
264 static void
265 mouse_check_moved ()
267 int x, y;
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;
275 void
276 mouse_init ()
278 union REGS regs;
279 int b;
281 if (termscript)
282 fprintf (termscript, "<M_INIT>");
284 regs.x.ax = 0x0021;
285 int86 (0x33, &regs, &regs);
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++)
293 int dummy_x, dummy_y;
295 (void) mouse_pressed (b, &dummy_x, &dummy_y);
296 (void) mouse_released (b, &dummy_x, &dummy_y);
299 regs.x.ax = 0x0007;
300 regs.x.cx = 0;
301 regs.x.dx = 8 * (ScreenCols () - 1);
302 int86 (0x33, &regs, &regs);
304 regs.x.ax = 0x0008;
305 regs.x.cx = 0;
306 regs.x.dx = 8 * (ScreenRows () - 1);
307 int86 (0x33, &regs, &regs);
309 mouse_moveto (0, 0);
310 mouse_visible = 0;
313 /* ------------------------- Screen control ----------------------
317 static int internal_terminal = 0;
319 #ifndef HAVE_X_WINDOWS
320 extern unsigned char ScreenAttrib;
321 static int screen_face;
322 static int highlight;
324 static int screen_size_X;
325 static int screen_size_Y;
326 static int screen_size;
328 static int current_pos_X;
329 static int current_pos_Y;
330 static int new_pos_X;
331 static int new_pos_Y;
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;
340 static clock_t startup_time;
342 static int term_setup_done;
344 /* Similar to the_only_frame. */
345 struct x_output the_only_x_display;
347 /* This is never dereferenced. */
348 Display *x_current_display;
350 /* Support for DOS/V (allows Japanese characters to be displayed on
351 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
353 /* Holds the address of the text-mode screen buffer. */
354 static unsigned long screen_old_address = 0;
355 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
356 static unsigned short screen_virtual_segment = 0;
357 static unsigned short screen_virtual_offset = 0;
358 /* A flag to control how to display unibyte 8-bit characters. */
359 extern int unibyte_display_via_language_environment;
361 #if __DJGPP__ > 1
362 /* Update the screen from a part of relocated DOS/V screen buffer which
363 begins at OFFSET and includes COUNT characters. */
364 static void
365 dosv_refresh_virtual_screen (int offset, int count)
367 __dpmi_regs regs;
369 if (offset < 0 || count < 0) /* paranoia; illegal values crash DOS/V */
370 return;
372 regs.h.ah = 0xff; /* update relocated screen */
373 regs.x.es = screen_virtual_segment;
374 regs.x.di = screen_virtual_offset + offset;
375 regs.x.cx = count;
376 __dpmi_int (0x10, &regs);
378 #endif
380 static void
381 dos_direct_output (y, x, buf, len)
382 int y;
383 int x;
384 char *buf;
385 int len;
387 int t0 = 2 * (x + y * screen_size_X);
388 int t = t0 + (int) ScreenPrimary;
389 int l0 = len;
391 #if (__DJGPP__ < 2)
392 while (--len >= 0) {
393 dosmemput (buf++, 1, t);
394 t += 2;
396 #else
397 /* This is faster. */
398 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
399 _farnspokeb (t, *buf);
401 if (screen_virtual_segment)
402 dosv_refresh_virtual_screen (t0, l0);
403 #endif
405 #endif
407 /* Flash the screen as a substitute for BEEPs. */
409 #if (__DJGPP__ < 2)
410 static void
411 do_visible_bell (xorattr)
412 unsigned char xorattr;
414 asm volatile
415 (" movb $1,%%dl
416 visible_bell_0:
417 movl _ScreenPrimary,%%eax
418 call dosmemsetup
419 movl %%eax,%%ebx
420 movl %1,%%ecx
421 movb %0,%%al
422 incl %%ebx
423 visible_bell_1:
424 xorb %%al,%%gs:(%%ebx)
425 addl $2,%%ebx
426 decl %%ecx
427 jne visible_bell_1
428 decb %%dl
429 jne visible_bell_3
430 visible_bell_2:
431 movzwl %%ax,%%eax
432 movzwl %%ax,%%eax
433 movzwl %%ax,%%eax
434 movzwl %%ax,%%eax
435 decw %%cx
436 jne visible_bell_2
437 jmp visible_bell_0
438 visible_bell_3:"
439 : /* no output */
440 : "m" (xorattr), "g" (screen_size)
441 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
444 static void
445 ScreenVisualBell (void)
447 /* This creates an xor-mask that will swap the default fore- and
448 background colors. */
449 do_visible_bell (((the_only_x_display.foreground_pixel
450 ^ the_only_x_display.background_pixel)
451 * 0x11) & 0x7f);
453 #endif
455 #ifndef HAVE_X_WINDOWS
457 static int blink_bit = -1; /* the state of the blink bit at startup */
459 /* Enable bright background colors. */
460 static void
461 bright_bg (void)
463 union REGS regs;
465 /* Remember the original state of the blink/bright-background bit.
466 It is stored at 0040:0065h in the BIOS data area. */
467 if (blink_bit == -1)
468 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
470 regs.h.bl = 0;
471 regs.x.ax = 0x1003;
472 int86 (0x10, &regs, &regs);
475 /* Disable bright background colors (and enable blinking) if we found
476 the video system in that state at startup. */
477 static void
478 maybe_enable_blinking (void)
480 if (blink_bit == 1)
482 union REGS regs;
484 regs.h.bl = 1;
485 regs.x.ax = 0x1003;
486 int86 (0x10, &regs, &regs);
490 /* Set the screen dimensions so that it can show no less than
491 ROWS x COLS frame. */
493 void
494 dos_set_window_size (rows, cols)
495 int *rows, *cols;
497 char video_name[30];
498 Lisp_Object video_mode;
499 int video_mode_value;
500 int have_vga = 0;
501 union REGS regs;
502 int current_rows = ScreenRows (), current_cols = ScreenCols ();
504 if (*rows == current_rows && *cols == current_cols)
505 return;
507 /* Do we have a VGA? */
508 regs.x.ax = 0x1a00;
509 int86 (0x10, &regs, &regs);
510 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
511 have_vga = 1;
513 mouse_off ();
515 /* If the user specified a special video mode for these dimensions,
516 use that mode. */
517 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
518 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
519 Qnil))-> value;
521 if (INTEGERP (video_mode)
522 && (video_mode_value = XINT (video_mode)) > 0)
524 regs.x.ax = video_mode_value;
525 int86 (0x10, &regs, &regs);
527 if (have_mouse)
529 /* Must hardware-reset the mouse, or else it won't update
530 its notion of screen dimensions for some non-standard
531 video modes. This is *painfully* slow... */
532 regs.x.ax = 0;
533 int86 (0x33, &regs, &regs);
537 /* Find one of the dimensions supported by standard EGA/VGA
538 which gives us at least the required dimensions. */
540 #if __DJGPP__ > 1
542 else
544 static struct {
545 int rows;
546 int need_vga;
547 } std_dimension[] = {
548 {25, 0},
549 {28, 1},
550 {35, 0},
551 {40, 1},
552 {43, 0},
553 {50, 1}
555 int i = 0;
557 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
559 if (std_dimension[i].need_vga <= have_vga
560 && std_dimension[i].rows >= *rows)
562 if (std_dimension[i].rows != current_rows
563 || *cols != current_cols)
564 _set_screen_lines (std_dimension[i].rows);
565 break;
567 i++;
571 #else /* not __DJGPP__ > 1 */
573 else if (*rows <= 25)
575 if (current_rows != 25 || current_cols != 80)
577 regs.x.ax = 3;
578 int86 (0x10, &regs, &regs);
579 regs.x.ax = 0x1101;
580 regs.h.bl = 0;
581 int86 (0x10, &regs, &regs);
582 regs.x.ax = 0x1200;
583 regs.h.bl = 32;
584 int86 (0x10, &regs, &regs);
585 regs.x.ax = 3;
586 int86 (0x10, &regs, &regs);
589 else if (*rows <= 50)
590 if (have_vga && (current_rows != 50 || current_cols != 80)
591 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
593 regs.x.ax = 3;
594 int86 (0x10, &regs, &regs);
595 regs.x.ax = 0x1112;
596 regs.h.bl = 0;
597 int86 (0x10, &regs, &regs);
598 regs.x.ax = 0x1200;
599 regs.h.bl = 32;
600 int86 (0x10, &regs, &regs);
601 regs.x.ax = 0x0100;
602 regs.x.cx = 7;
603 int86 (0x10, &regs, &regs);
605 #endif /* not __DJGPP__ > 1 */
607 if (have_mouse)
609 mouse_init ();
610 mouse_on ();
613 /* Tell the caller what dimensions have been REALLY set. */
614 *rows = ScreenRows ();
615 *cols = ScreenCols ();
617 /* Enable bright background colors. */
618 bright_bg ();
620 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
621 be defensive anyway. */
622 if (screen_virtual_segment)
623 dosv_refresh_virtual_screen (0, *cols * *rows);
626 /* If we write a character in the position where the mouse is,
627 the mouse cursor may need to be refreshed. */
629 static void
630 mouse_off_maybe ()
632 int x, y;
634 if (!mouse_visible)
635 return;
637 mouse_get_xy (&x, &y);
638 if (y != new_pos_Y || x < new_pos_X)
639 return;
641 mouse_off ();
644 static void
645 IT_ring_bell (void)
647 if (visible_bell)
649 mouse_off ();
650 ScreenVisualBell ();
652 else
654 union REGS inregs, outregs;
655 inregs.h.ah = 2;
656 inregs.h.dl = 7;
657 intdos (&inregs, &outregs);
661 /* Given a face id FACE, extract the face parameters to be used for
662 display until the face changes. The face parameters (actually, its
663 color) are used to construct the video attribute byte for each
664 glyph during the construction of the buffer that is then blitted to
665 the video RAM. */
666 static void
667 IT_set_face (int face)
669 struct face *fp = FACE_FROM_ID (selected_frame, face);
670 unsigned long fg, bg;
672 if (!fp)
673 fp = FACE_FROM_ID (selected_frame, DEFAULT_FACE_ID);
674 screen_face = face;
675 fg = fp->foreground;
676 bg = fp->background;
678 /* Don't use invalid colors. In particular, a color of -1 means use
679 the colors of the default face, except that if highlight is on,
680 invert the foreground and the background. Note that we assume
681 all 16 colors to be available for the background, since Emacs
682 switches on this mode (and loses the blinking attribute) at
683 startup. */
684 if (fg == (unsigned long)-1)
685 fg = highlight ? FRAME_BACKGROUND_PIXEL (selected_frame)
686 : FRAME_FOREGROUND_PIXEL (selected_frame);
687 if (bg == (unsigned long)-1)
688 bg = highlight ? FRAME_FOREGROUND_PIXEL (selected_frame)
689 : FRAME_BACKGROUND_PIXEL (selected_frame);
690 if (termscript)
691 fprintf (termscript, "<FACE %d%s: %d/%d>",
692 face, highlight ? "H" : "", fp->foreground, fp->background);
693 if (fg >= 0 && fg < 16)
695 ScreenAttrib &= 0xf0;
696 ScreenAttrib |= fg;
698 if (bg >= 0 && bg < 16)
700 ScreenAttrib &= 0x0f;
701 ScreenAttrib |= ((bg & 0x0f) << 4);
705 Lisp_Object Vdos_unsupported_char_glyph;
707 static void
708 IT_write_glyphs (struct glyph *str, int str_len)
710 unsigned char *screen_buf, *screen_bp, *screen_buf_end, *bp;
711 int unsupported_face = FAST_GLYPH_FACE (Vdos_unsupported_char_glyph);
712 unsigned unsupported_char= FAST_GLYPH_CHAR (Vdos_unsupported_char_glyph);
713 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
714 register int sl = str_len;
715 register int tlen = GLYPH_TABLE_LENGTH;
716 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
718 struct coding_system *coding = (CODING_REQUIRE_ENCODING (&terminal_coding)
719 ? &terminal_coding
720 : &safe_terminal_coding);
722 /* Do we need to consider conversion of unibyte characters to
723 multibyte? */
724 int convert_unibyte_characters
725 = (NILP (current_buffer->enable_multibyte_characters)
726 && unibyte_display_via_language_environment);
728 if (str_len == 0) return;
730 screen_buf = screen_bp = alloca (str_len * 2);
731 screen_buf_end = screen_buf + str_len * 2;
733 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
734 the tail. */
735 terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
736 while (sl)
738 int cf, chlen, enclen;
739 unsigned char workbuf[4], *buf;
740 unsigned ch;
741 register GLYPH g = GLYPH_FROM_CHAR_GLYPH (*str);
743 /* Find the actual glyph to display by traversing the entire
744 aliases chain for this glyph. */
745 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
747 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
748 only for the redisplay code to know how many columns does
749 this character occupy on the screen. Skip padding glyphs. */
750 if (CHAR_GLYPH_PADDING_P (*str))
752 str++;
753 sl--;
755 else
757 /* Convert the character code to multibyte, if they
758 requested display via language environment. */
759 ch = FAST_GLYPH_CHAR (g);
760 /* We only want to convert unibyte characters to multibyte
761 in unibyte buffers! Otherwise, the 8-bit code might come
762 from the display table set up to display foreign characters. */
763 if (SINGLE_BYTE_CHAR_P (ch) && convert_unibyte_characters
764 && (ch >= 0240
765 || (ch >= 0200 && !NILP (Vnonascii_translation_table))))
766 ch = unibyte_char_to_multibyte (ch);
768 /* Invalid characters are displayed with a special glyph. */
769 if (! GLYPH_CHAR_VALID_P (ch))
771 g = !NILP (Vdos_unsupported_char_glyph)
772 ? Vdos_unsupported_char_glyph
773 : MAKE_GLYPH (selected_frame, '\177',
774 GLYPH_FACE (selected_frame, g));
775 ch = FAST_GLYPH_CHAR (g);
777 if (COMPOSITE_CHAR_P (ch))
779 /* If CH is a composite character, we can display
780 only the first component. */
781 g = cmpchar_table[COMPOSITE_CHAR_ID (ch)]->glyph[0],
782 ch = GLYPH_CHAR (selected_frame, g);
783 cf = FAST_GLYPH_FACE (g);
786 /* If the face of this glyph is different from the current
787 screen face, update the screen attribute byte. */
788 cf = FAST_GLYPH_FACE (g);
789 if (cf != screen_face)
790 IT_set_face (cf); /* handles invalid faces gracefully */
792 if (GLYPH_SIMPLE_P (tbase, tlen, g))
793 /* We generate the multi-byte form of CH in BUF. */
794 chlen = CHAR_STRING (ch, workbuf, buf);
795 else
797 /* We have a string in Vglyph_table. */
798 chlen = GLYPH_LENGTH (tbase, g);
799 buf = GLYPH_STRING (tbase, g);
802 /* If the character is not multibyte, don't bother converting it. */
803 if (chlen == 1)
805 *conversion_buffer = (unsigned char)ch;
806 chlen = 0;
807 enclen = 1;
809 else
811 encode_coding (coding, buf, conversion_buffer, chlen,
812 conversion_buffer_size);
813 chlen -= coding->consumed;
814 enclen = coding->produced;
816 /* Replace glyph codes that cannot be converted by
817 terminal_coding with Vdos_unsupported_char_glyph. */
818 if (*conversion_buffer == '?')
820 char *cbp = conversion_buffer;
822 while (cbp < conversion_buffer + enclen && *cbp == '?')
823 *cbp++ = unsupported_char;
824 if (unsupported_face != screen_face)
825 IT_set_face (unsupported_face);
829 if (enclen + chlen > screen_buf_end - screen_bp)
831 /* The allocated buffer for screen writes is too small.
832 Flush it and loop again without incrementing STR, so
833 that the next loop will begin with the same glyph. */
834 int nbytes = screen_bp - screen_buf;
836 mouse_off_maybe ();
837 dosmemput (screen_buf, nbytes, (int)ScreenPrimary + offset);
838 if (screen_virtual_segment)
839 dosv_refresh_virtual_screen (offset, nbytes / 2);
840 new_pos_X += nbytes / 2;
841 offset += nbytes;
843 /* Prepare to reuse the same buffer again. */
844 screen_bp = screen_buf;
846 else
848 /* There's enough place in the allocated buffer to add
849 the encoding of this glyph. */
851 /* First, copy the encoded bytes. */
852 for (bp = conversion_buffer; enclen--; bp++)
854 *screen_bp++ = (unsigned char)*bp;
855 *screen_bp++ = ScreenAttrib;
856 if (termscript)
857 fputc (*bp, termscript);
860 /* Now copy the bytes not consumed by the encoding. */
861 if (chlen > 0)
863 buf += coding->consumed;
864 while (chlen--)
866 if (termscript)
867 fputc (*buf, termscript);
868 *screen_bp++ = (unsigned char)*buf++;
869 *screen_bp++ = ScreenAttrib;
873 /* Update STR and its remaining length. */
874 str++;
875 sl--;
880 /* Dump whatever is left in the screen buffer. */
881 mouse_off_maybe ();
882 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
883 if (screen_virtual_segment)
884 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
885 new_pos_X += (screen_bp - screen_buf) / 2;
887 /* We may have to output some codes to terminate the writing. */
888 if (CODING_REQUIRE_FLUSHING (coding))
890 coding->mode |= CODING_MODE_LAST_BLOCK;
891 encode_coding (coding, "", conversion_buffer, 0, conversion_buffer_size);
892 if (coding->produced > 0)
894 for (screen_bp = screen_buf, bp = conversion_buffer;
895 coding->produced--; bp++)
897 *screen_bp++ = (unsigned char)*bp;
898 *screen_bp++ = ScreenAttrib;
899 if (termscript)
900 fputc (*bp, termscript);
902 offset += screen_bp - screen_buf;
903 mouse_off_maybe ();
904 dosmemput (screen_buf, screen_bp - screen_buf,
905 (int)ScreenPrimary + offset);
906 if (screen_virtual_segment)
907 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
908 new_pos_X += (screen_bp - screen_buf) / 2;
913 static void
914 IT_clear_end_of_line (int first_unused)
916 char *spaces, *sp;
917 int i, j;
918 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
919 extern int fatal_error_in_progress;
921 if (fatal_error_in_progress)
922 return;
924 IT_set_face (0);
925 if (termscript)
926 fprintf (termscript, "<CLR:EOL>");
927 i = (j = screen_size_X - new_pos_X) * 2;
928 spaces = sp = alloca (i);
930 while (--j >= 0)
932 *sp++ = ' ';
933 *sp++ = ScreenAttrib;
936 mouse_off_maybe ();
937 dosmemput (spaces, i, (int)ScreenPrimary + offset);
938 if (screen_virtual_segment)
939 dosv_refresh_virtual_screen (offset, i / 2);
942 static void
943 IT_clear_screen (void)
945 if (termscript)
946 fprintf (termscript, "<CLR:SCR>");
947 IT_set_face (0);
948 mouse_off ();
949 ScreenClear ();
950 if (screen_virtual_segment)
951 dosv_refresh_virtual_screen (0, screen_size);
952 new_pos_X = new_pos_Y = 0;
955 static void
956 IT_clear_to_end (void)
958 if (termscript)
959 fprintf (termscript, "<CLR:EOS>");
961 while (new_pos_Y < screen_size_Y) {
962 new_pos_X = 0;
963 IT_clear_end_of_line (0);
964 new_pos_Y++;
968 static void
969 IT_cursor_to (int y, int x)
971 if (termscript)
972 fprintf (termscript, "\n<XY=%dx%d>", x, y);
973 new_pos_X = x;
974 new_pos_Y = y;
977 static int cursor_cleared;
979 static void
980 IT_display_cursor (int on)
982 if (on && cursor_cleared)
984 ScreenSetCursor (current_pos_Y, current_pos_X);
985 cursor_cleared = 0;
987 else if (!on && !cursor_cleared)
989 ScreenSetCursor (-1, -1);
990 cursor_cleared = 1;
994 /* Emacs calls cursor-movement functions a lot when it updates the
995 display (probably a legacy of old terminals where you cannot
996 update a screen line without first moving the cursor there).
997 However, cursor movement is expensive on MSDOS (it calls a slow
998 BIOS function and requires 2 mode switches), while actual screen
999 updates access the video memory directly and don't depend on
1000 cursor position. To avoid slowing down the redisplay, we cheat:
1001 all functions that move the cursor only set internal variables
1002 which record the cursor position, whereas the cursor is only
1003 moved to its final position whenever screen update is complete.
1005 `IT_cmgoto' is called from the keyboard reading loop and when the
1006 frame update is complete. This means that we are ready for user
1007 input, so we update the cursor position to show where the point is,
1008 and also make the mouse pointer visible.
1010 Special treatment is required when the cursor is in the echo area,
1011 to put the cursor at the end of the text displayed there. */
1013 static void
1014 IT_cmgoto (FRAME_PTR f)
1016 /* Only set the cursor to where it should be if the display is
1017 already in sync with the window contents. */
1018 int update_cursor_pos = MODIFF == unchanged_modified;
1019 static int previous_pos_X = -1;
1021 /* If the display is in sync, forget any previous knowledge about
1022 cursor position. This is primarily for unexpected events like
1023 C-g in the minibuffer. */
1024 if (update_cursor_pos && previous_pos_X >= 0)
1025 previous_pos_X = -1;
1026 /* If we are in the echo area, put the cursor at the
1027 end of the echo area message. */
1028 if (!update_cursor_pos
1029 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y)
1031 int tem_X = current_pos_X, dummy;
1033 if (echo_area_glyphs)
1035 tem_X = echo_area_glyphs_length;
1036 /* Save current cursor position, to be restored after the
1037 echo area message is erased. Only remember one level
1038 of previous cursor position. */
1039 if (previous_pos_X == -1)
1040 ScreenGetCursor (&dummy, &previous_pos_X);
1042 else if (previous_pos_X >= 0)
1044 /* We wind up here after the echo area message is erased.
1045 Restore the cursor position we remembered above. */
1046 tem_X = previous_pos_X;
1047 previous_pos_X = -1;
1050 if (current_pos_X != tem_X)
1052 new_pos_X = tem_X;
1053 update_cursor_pos = 1;
1057 if (update_cursor_pos
1058 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1060 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1061 if (termscript)
1062 fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1065 /* Maybe cursor is invisible, so make it visible. */
1066 IT_display_cursor (1);
1068 /* Mouse pointer should be always visible if we are waiting for
1069 keyboard input. */
1070 if (!mouse_visible)
1071 mouse_on ();
1074 static void
1075 IT_reassert_line_highlight (int new, int vpos)
1077 highlight = new;
1078 IT_set_face (0); /* To possibly clear the highlighting. */
1081 static void
1082 IT_change_line_highlight (int new_highlight, int y, int vpos, int first_unused_hpos)
1084 highlight = new_highlight;
1085 IT_set_face (0); /* To possibly clear the highlighting. */
1086 IT_cursor_to (vpos, 0);
1087 IT_clear_end_of_line (first_unused_hpos);
1090 static void
1091 IT_update_begin (struct frame *foo)
1093 highlight = 0;
1094 IT_set_face (0); /* To possibly clear the highlighting. */
1095 screen_face = -1;
1098 static void
1099 IT_update_end (struct frame *foo)
1103 /* Copy LEN glyphs displayed on a single line whose vertical position
1104 is YPOS, beginning at horizontal position XFROM to horizontal
1105 position XTO, by moving blocks in the video memory. Used by
1106 functions that insert and delete glyphs. */
1107 static void
1108 IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1110 /* The offsets of source and destination relative to the
1111 conventional memorty selector. */
1112 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1113 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1115 if (from == to || len <= 0)
1116 return;
1118 _farsetsel (_dos_ds);
1120 /* The source and destination might overlap, so we need to move
1121 glyphs non-destructively. */
1122 if (from > to)
1124 for ( ; len; from += 2, to += 2, len--)
1125 _farnspokew (to, _farnspeekw (from));
1127 else
1129 from += (len - 1) * 2;
1130 to += (len - 1) * 2;
1131 for ( ; len; from -= 2, to -= 2, len--)
1132 _farnspokew (to, _farnspeekw (from));
1134 if (screen_virtual_segment)
1135 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1138 /* Insert and delete glyphs. */
1139 static void
1140 IT_insert_glyphs (start, len)
1141 register struct glyph *start;
1142 register int len;
1144 int shift_by_width = screen_size_X - (new_pos_X + len);
1146 /* Shift right the glyphs from the nominal cursor position to the
1147 end of this line. */
1148 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
1150 /* Now write the glyphs to be inserted. */
1151 IT_write_glyphs (start, len);
1154 static void
1155 IT_delete_glyphs (n)
1156 register int n;
1158 abort ();
1161 /* set-window-configuration on window.c needs this. */
1162 void
1163 x_set_menu_bar_lines (f, value, oldval)
1164 struct frame *f;
1165 Lisp_Object value, oldval;
1167 set_menu_bar_lines (f, value, oldval);
1170 /* This was copied from xfns.c */
1172 Lisp_Object Qbackground_color;
1173 Lisp_Object Qforeground_color;
1174 extern Lisp_Object Qtitle;
1176 /* IT_set_terminal_modes is called when emacs is started,
1177 resumed, and whenever the screen is redrawn! */
1179 static void
1180 IT_set_terminal_modes (void)
1182 if (termscript)
1183 fprintf (termscript, "\n<SET_TERM>");
1184 highlight = 0;
1186 screen_size_X = ScreenCols ();
1187 screen_size_Y = ScreenRows ();
1188 screen_size = screen_size_X * screen_size_Y;
1190 new_pos_X = new_pos_Y = 0;
1191 current_pos_X = current_pos_Y = -1;
1193 if (term_setup_done)
1194 return;
1195 term_setup_done = 1;
1197 startup_screen_size_X = screen_size_X;
1198 startup_screen_size_Y = screen_size_Y;
1199 startup_screen_attrib = ScreenAttrib;
1201 #if __DJGPP__ > 1
1202 /* Is DOS/V (or any other RSIS software which relocates
1203 the screen) installed? */
1205 unsigned short es_value;
1206 __dpmi_regs regs;
1208 regs.h.ah = 0xfe; /* get relocated screen address */
1209 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
1210 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
1211 else if (screen_old_address) /* already switched to Japanese mode once */
1212 regs.x.es = (screen_old_address >> 4) & 0xffff;
1213 else
1214 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
1215 regs.x.di = 0;
1216 es_value = regs.x.es;
1217 __dpmi_int (0x10, &regs);
1219 if (regs.x.es != es_value)
1221 /* screen_old_address is only set if ScreenPrimary does NOT
1222 already point to the relocated buffer address returned by
1223 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1224 ScreenPrimary to that address at startup under DOS/V. */
1225 if (regs.x.es != (ScreenPrimary >> 4) & 0xffff)
1226 screen_old_address = ScreenPrimary;
1227 screen_virtual_segment = regs.x.es;
1228 screen_virtual_offset = regs.x.di;
1229 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
1232 #endif /* __DJGPP__ > 1 */
1234 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
1235 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
1237 if (termscript)
1238 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
1239 screen_size_X, screen_size_Y);
1241 bright_bg ();
1244 /* IT_reset_terminal_modes is called when emacs is
1245 suspended or killed. */
1247 static void
1248 IT_reset_terminal_modes (void)
1250 int display_row_start = (int) ScreenPrimary;
1251 int saved_row_len = startup_screen_size_X * 2;
1252 int update_row_len = ScreenCols () * 2;
1253 int current_rows = ScreenRows ();
1254 int to_next_row = update_row_len;
1255 unsigned char *saved_row = startup_screen_buffer;
1256 int cursor_pos_X = ScreenCols () - 1;
1257 int cursor_pos_Y = ScreenRows () - 1;
1259 if (termscript)
1260 fprintf (termscript, "\n<RESET_TERM>");
1262 highlight = 0;
1264 if (!term_setup_done)
1265 return;
1267 mouse_off ();
1269 /* Leave the video system in the same state as we found it,
1270 as far as the blink/bright-background bit is concerned. */
1271 maybe_enable_blinking ();
1273 /* We have a situation here.
1274 We cannot just do ScreenUpdate(startup_screen_buffer) because
1275 the luser could have changed screen dimensions inside Emacs
1276 and failed (or didn't want) to restore them before killing
1277 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1278 thus will happily use memory outside what was allocated for
1279 `startup_screen_buffer'.
1280 Thus we only restore as much as the current screen dimensions
1281 can hold, and clear the rest (if the saved screen is smaller than
1282 the current) with the color attribute saved at startup. The cursor
1283 is also restored within the visible dimensions. */
1285 ScreenAttrib = startup_screen_attrib;
1287 /* Don't restore the screen if we are exiting less than 2 seconds
1288 after startup: we might be crashing, and the screen might show
1289 some vital clues to what's wrong. */
1290 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
1292 ScreenClear ();
1293 if (screen_virtual_segment)
1294 dosv_refresh_virtual_screen (0, screen_size);
1296 if (update_row_len > saved_row_len)
1297 update_row_len = saved_row_len;
1298 if (current_rows > startup_screen_size_Y)
1299 current_rows = startup_screen_size_Y;
1301 if (termscript)
1302 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
1303 update_row_len / 2, current_rows);
1305 while (current_rows--)
1307 dosmemput (saved_row, update_row_len, display_row_start);
1308 if (screen_virtual_segment)
1309 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
1310 update_row_len / 2);
1311 saved_row += saved_row_len;
1312 display_row_start += to_next_row;
1315 if (startup_pos_X < cursor_pos_X)
1316 cursor_pos_X = startup_pos_X;
1317 if (startup_pos_Y < cursor_pos_Y)
1318 cursor_pos_Y = startup_pos_Y;
1320 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
1321 xfree (startup_screen_buffer);
1323 term_setup_done = 0;
1326 static void
1327 IT_set_terminal_window (int foo)
1331 void
1332 IT_set_frame_parameters (f, alist)
1333 struct frame *f;
1334 Lisp_Object alist;
1336 Lisp_Object tail;
1337 int length = XINT (Flength (alist));
1338 int i;
1339 Lisp_Object *parms
1340 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
1341 Lisp_Object *values
1342 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
1343 int redraw;
1344 struct face *dflt = NULL;
1346 if (FRAME_FACE_CACHE (f))
1347 dflt = FACE_FROM_ID (f, DEFAULT_FACE_ID);
1349 redraw = 0;
1351 /* Extract parm names and values into those vectors. */
1352 i = 0;
1353 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
1355 Lisp_Object elt;
1357 elt = Fcar (tail);
1358 parms[i] = Fcar (elt);
1359 CHECK_SYMBOL (parms[i], 1);
1360 values[i] = Fcdr (elt);
1361 i++;
1365 /* Now process them in reverse of specified order. */
1366 for (i--; i >= 0; i--)
1368 Lisp_Object prop = parms[i];
1369 Lisp_Object val = values[i];
1371 if (EQ (prop, Qforeground_color))
1373 unsigned long new_color = load_color (f, NULL, val,
1374 LFACE_FOREGROUND_INDEX);
1375 if (new_color != ~0)
1377 if (!dflt)
1378 abort ();
1379 FRAME_FOREGROUND_PIXEL (f) = new_color;
1380 dflt->foreground = new_color;
1381 redraw = 1;
1382 if (termscript)
1383 fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
1386 else if (EQ (prop, Qbackground_color))
1388 unsigned long new_color = load_color (f, NULL, val,
1389 LFACE_BACKGROUND_INDEX);
1390 if (new_color != ~0)
1392 if (!dflt)
1393 abort ();
1394 FRAME_BACKGROUND_PIXEL (f) = new_color;
1395 dflt->background = new_color;
1396 redraw = 1;
1397 if (termscript)
1398 fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
1401 else if (EQ (prop, Qtitle))
1403 x_set_title (f, val);
1404 if (termscript)
1405 fprintf (termscript, "<TITLE: %s>\n", XSTRING (val)->data);
1407 else if (EQ (prop, intern ("reverse")) && EQ (val, Qt))
1409 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
1411 if (!dflt)
1412 abort ();
1413 FRAME_FOREGROUND_PIXEL (f) = FRAME_BACKGROUND_PIXEL (f); /* FIXME! */
1414 FRAME_BACKGROUND_PIXEL (f) = fg;
1415 dflt->foreground = FRAME_FOREGROUND_PIXEL (f);
1416 dflt->foreground = fg;
1417 if (termscript)
1418 fprintf (termscript, "<INVERSE-VIDEO>\n");
1420 store_frame_param (f, prop, val);
1424 if (redraw)
1426 recompute_basic_faces (f);
1427 if (f == selected_frame)
1428 redraw_frame (f);
1432 extern void init_frame_faces (FRAME_PTR);
1434 #endif /* !HAVE_X_WINDOWS */
1437 /* Do we need the internal terminal? */
1439 void
1440 internal_terminal_init ()
1442 char *term = getenv ("TERM");
1443 char *colors;
1445 #ifdef HAVE_X_WINDOWS
1446 if (!inhibit_window_system)
1447 return;
1448 #endif
1450 internal_terminal
1451 = (!noninteractive) && term && !strcmp (term, "internal");
1453 if (getenv ("EMACSTEST"))
1454 termscript = fopen (getenv ("EMACSTEST"), "wt");
1456 #ifndef HAVE_X_WINDOWS
1457 if (!internal_terminal || inhibit_window_system)
1459 selected_frame->output_method = output_termcap;
1460 return;
1463 Vwindow_system = intern ("pc");
1464 Vwindow_system_version = make_number (1);
1466 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
1467 screen_old_address = 0;
1469 bzero (&the_only_x_display, sizeof the_only_x_display);
1470 the_only_x_display.background_pixel = 7; /* White */
1471 the_only_x_display.foreground_pixel = 0; /* Black */
1472 bright_bg ();
1473 colors = getenv ("EMACSCOLORS");
1474 if (colors && strlen (colors) >= 2)
1476 /* The colors use 4 bits each (we enable bright background). */
1477 if (isdigit (colors[0]))
1478 colors[0] -= '0';
1479 else if (isxdigit (colors[0]))
1480 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1481 if (colors[0] >= 0 && colors[0] < 16)
1482 the_only_x_display.foreground_pixel = colors[0];
1483 if (isdigit (colors[1]))
1484 colors[1] -= '0';
1485 else if (isxdigit (colors[1]))
1486 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
1487 if (colors[1] >= 0 && colors[1] < 16)
1488 the_only_x_display.background_pixel = colors[1];
1490 the_only_x_display.line_height = 1;
1491 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
1493 init_frame_faces (selected_frame);
1495 ring_bell_hook = IT_ring_bell;
1496 insert_glyphs_hook = IT_insert_glyphs;
1497 delete_glyphs_hook = IT_delete_glyphs;
1498 write_glyphs_hook = IT_write_glyphs;
1499 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
1500 clear_to_end_hook = IT_clear_to_end;
1501 clear_end_of_line_hook = IT_clear_end_of_line;
1502 clear_frame_hook = IT_clear_screen;
1503 change_line_highlight_hook = IT_change_line_highlight;
1504 update_begin_hook = IT_update_begin;
1505 update_end_hook = IT_update_end;
1506 reassert_line_highlight_hook = IT_reassert_line_highlight;
1507 frame_up_to_date_hook = IT_cmgoto; /* position cursor when update is done */
1509 /* These hooks are called by term.c without being checked. */
1510 set_terminal_modes_hook = IT_set_terminal_modes;
1511 reset_terminal_modes_hook = IT_reset_terminal_modes;
1512 set_terminal_window_hook = IT_set_terminal_window;
1513 char_ins_del_ok = 0;
1514 #endif
1517 dos_get_saved_screen (screen, rows, cols)
1518 char **screen;
1519 int *rows;
1520 int *cols;
1522 #ifndef HAVE_X_WINDOWS
1523 *screen = startup_screen_buffer;
1524 *cols = startup_screen_size_X;
1525 *rows = startup_screen_size_Y;
1526 return *screen != (char *)0;
1527 #else
1528 return 0;
1529 #endif
1532 #ifndef HAVE_X_WINDOWS
1534 /* We are not X, but we can emulate it well enough for our needs... */
1535 void
1536 check_x (void)
1538 if (! FRAME_MSDOS_P (selected_frame))
1539 error ("Not running under a windows system");
1542 #endif
1545 /* ----------------------- Keyboard control ----------------------
1547 * Keymaps reflect the following keyboard layout:
1549 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1550 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1551 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1552 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1553 * SPACE
1556 #define Ignore 0x0000
1557 #define Normal 0x0000 /* normal key - alt changes scan-code */
1558 #define FctKey 0x1000 /* func key if c == 0, else c */
1559 #define Special 0x2000 /* func key even if c != 0 */
1560 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1561 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1562 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1563 #define Grey 0x6000 /* Grey keypad key */
1565 #define Alt 0x0100 /* alt scan-code */
1566 #define Ctrl 0x0200 /* ctrl scan-code */
1567 #define Shift 0x0400 /* shift scan-code */
1569 static int extended_kbd; /* 101 (102) keyboard present. */
1571 struct kbd_translate {
1572 unsigned char sc;
1573 unsigned char ch;
1574 unsigned short code;
1577 struct dos_keyboard_map
1579 char *unshifted;
1580 char *shifted;
1581 char *alt_gr;
1582 struct kbd_translate *translate_table;
1586 static struct dos_keyboard_map us_keyboard = {
1587 /* 0 1 2 3 4 5 */
1588 /* 01234567890123456789012345678901234567890 12345678901234 */
1589 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1590 /* 0123456789012345678901234567890123456789 012345678901234 */
1591 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1592 0, /* no Alt-Gr key */
1593 0 /* no translate table */
1596 static struct dos_keyboard_map fr_keyboard = {
1597 /* 0 1 2 3 4 5 */
1598 /* 012 3456789012345678901234567890123456789012345678901234 */
1599 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
1600 /* 0123456789012345678901234567890123456789012345678901234 */
1601 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
1602 /* 01234567 89012345678901234567890123456789012345678901234 */
1603 " ~#{[|`\\^@]} Ï ",
1604 0 /* no translate table */
1608 * Italian keyboard support, country code 39.
1609 * '<' 56:3c*0000
1610 * '>' 56:3e*0000
1611 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
1612 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
1615 static struct kbd_translate it_kbd_translate_table[] = {
1616 { 0x56, 0x3c, Normal | 13 },
1617 { 0x56, 0x3e, Normal | 27 },
1618 { 0, 0, 0 }
1620 static struct dos_keyboard_map it_keyboard = {
1621 /* 0 1 2 3 4 5 */
1622 /* 0 123456789012345678901234567890123456789012345678901234 */
1623 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
1624 /* 01 23456789012345678901234567890123456789012345678901234 */
1625 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
1626 /* 0123456789012345678901234567890123456789012345678901234 */
1627 " {}~` [] @# ",
1628 it_kbd_translate_table
1631 static struct dos_keyboard_map dk_keyboard = {
1632 /* 0 1 2 3 4 5 */
1633 /* 0123456789012345678901234567890123456789012345678901234 */
1634 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
1635 /* 01 23456789012345678901234567890123456789012345678901234 */
1636 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
1637 /* 0123456789012345678901234567890123456789012345678901234 */
1638 " @œ$ {[]} | ",
1639 0 /* no translate table */
1642 static struct kbd_translate jp_kbd_translate_table[] = {
1643 { 0x73, 0x5c, Normal | 0 },
1644 { 0x73, 0x5f, Normal | 0 },
1645 { 0x73, 0x1c, Map | 0 },
1646 { 0x7d, 0x5c, Normal | 13 },
1647 { 0x7d, 0x7c, Normal | 13 },
1648 { 0x7d, 0x1c, Map | 13 },
1649 { 0, 0, 0 }
1651 static struct dos_keyboard_map jp_keyboard = {
1652 /* 0 1 2 3 4 5 */
1653 /* 0123456789012 345678901234567890123456789012345678901234 */
1654 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
1655 /* 01 23456789012345678901234567890123456789012345678901234 */
1656 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
1657 0, /* no Alt-Gr key */
1658 jp_kbd_translate_table
1661 static struct keyboard_layout_list
1663 int country_code;
1664 struct dos_keyboard_map *keyboard_map;
1665 } keyboard_layout_list[] =
1667 1, &us_keyboard,
1668 33, &fr_keyboard,
1669 39, &it_keyboard,
1670 45, &dk_keyboard,
1671 81, &jp_keyboard
1674 static struct dos_keyboard_map *keyboard;
1675 static int keyboard_map_all;
1676 static int international_keyboard;
1679 dos_set_keyboard (code, always)
1680 int code;
1681 int always;
1683 int i;
1684 _go32_dpmi_registers regs;
1686 /* See if Keyb.Com is installed (for international keyboard support).
1687 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
1688 of Windows 9X! So don't do that! */
1689 regs.x.ax = 0xad80;
1690 regs.x.ss = regs.x.sp = regs.x.flags = 0;
1691 _go32_dpmi_simulate_int (0x2f, &regs);
1692 if (regs.h.al == 0xff)
1693 international_keyboard = 1;
1695 /* Initialize to US settings, for countries that don't have their own. */
1696 keyboard = keyboard_layout_list[0].keyboard_map;
1697 keyboard_map_all = always;
1698 dos_keyboard_layout = 1;
1700 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
1701 if (code == keyboard_layout_list[i].country_code)
1703 keyboard = keyboard_layout_list[i].keyboard_map;
1704 keyboard_map_all = always;
1705 dos_keyboard_layout = code;
1706 return 1;
1708 return 0;
1711 static struct
1713 unsigned char char_code; /* normal code */
1714 unsigned char meta_code; /* M- code */
1715 unsigned char keypad_code; /* keypad code */
1716 unsigned char editkey_code; /* edit key */
1717 } keypad_translate_map[] = {
1718 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1719 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1720 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1721 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1722 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1723 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1724 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1725 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1726 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1727 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1728 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1731 static struct
1733 unsigned char char_code; /* normal code */
1734 unsigned char keypad_code; /* keypad code */
1735 } grey_key_translate_map[] = {
1736 '/', 0xaf, /* kp-decimal */
1737 '*', 0xaa, /* kp-multiply */
1738 '-', 0xad, /* kp-subtract */
1739 '+', 0xab, /* kp-add */
1740 '\r', 0x8d /* kp-enter */
1743 static unsigned short
1744 ibmpc_translate_map[] =
1746 /* --------------- 00 to 0f --------------- */
1747 Normal | 0xff, /* Ctrl Break + Alt-NNN */
1748 Alt | ModFct | 0x1b, /* Escape */
1749 Normal | 1, /* '1' */
1750 Normal | 2, /* '2' */
1751 Normal | 3, /* '3' */
1752 Normal | 4, /* '4' */
1753 Normal | 5, /* '5' */
1754 Normal | 6, /* '6' */
1755 Normal | 7, /* '7' */
1756 Normal | 8, /* '8' */
1757 Normal | 9, /* '9' */
1758 Normal | 10, /* '0' */
1759 Normal | 11, /* '-' */
1760 Normal | 12, /* '=' */
1761 Special | 0x08, /* Backspace */
1762 ModFct | 0x74, /* Tab/Backtab */
1764 /* --------------- 10 to 1f --------------- */
1765 Map | 15, /* 'q' */
1766 Map | 16, /* 'w' */
1767 Map | 17, /* 'e' */
1768 Map | 18, /* 'r' */
1769 Map | 19, /* 't' */
1770 Map | 20, /* 'y' */
1771 Map | 21, /* 'u' */
1772 Map | 22, /* 'i' */
1773 Map | 23, /* 'o' */
1774 Map | 24, /* 'p' */
1775 Map | 25, /* '[' */
1776 Map | 26, /* ']' */
1777 ModFct | 0x0d, /* Return */
1778 Ignore, /* Ctrl */
1779 Map | 30, /* 'a' */
1780 Map | 31, /* 's' */
1782 /* --------------- 20 to 2f --------------- */
1783 Map | 32, /* 'd' */
1784 Map | 33, /* 'f' */
1785 Map | 34, /* 'g' */
1786 Map | 35, /* 'h' */
1787 Map | 36, /* 'j' */
1788 Map | 37, /* 'k' */
1789 Map | 38, /* 'l' */
1790 Map | 39, /* ';' */
1791 Map | 40, /* '\'' */
1792 Map | 0, /* '`' */
1793 Ignore, /* Left shift */
1794 Map | 41, /* '\\' */
1795 Map | 45, /* 'z' */
1796 Map | 46, /* 'x' */
1797 Map | 47, /* 'c' */
1798 Map | 48, /* 'v' */
1800 /* --------------- 30 to 3f --------------- */
1801 Map | 49, /* 'b' */
1802 Map | 50, /* 'n' */
1803 Map | 51, /* 'm' */
1804 Map | 52, /* ',' */
1805 Map | 53, /* '.' */
1806 Map | 54, /* '/' */
1807 Ignore, /* Right shift */
1808 Grey | 1, /* Grey * */
1809 Ignore, /* Alt */
1810 Normal | 55, /* ' ' */
1811 Ignore, /* Caps Lock */
1812 FctKey | 0xbe, /* F1 */
1813 FctKey | 0xbf, /* F2 */
1814 FctKey | 0xc0, /* F3 */
1815 FctKey | 0xc1, /* F4 */
1816 FctKey | 0xc2, /* F5 */
1818 /* --------------- 40 to 4f --------------- */
1819 FctKey | 0xc3, /* F6 */
1820 FctKey | 0xc4, /* F7 */
1821 FctKey | 0xc5, /* F8 */
1822 FctKey | 0xc6, /* F9 */
1823 FctKey | 0xc7, /* F10 */
1824 Ignore, /* Num Lock */
1825 Ignore, /* Scroll Lock */
1826 KeyPad | 7, /* Home */
1827 KeyPad | 8, /* Up */
1828 KeyPad | 9, /* Page Up */
1829 Grey | 2, /* Grey - */
1830 KeyPad | 4, /* Left */
1831 KeyPad | 5, /* Keypad 5 */
1832 KeyPad | 6, /* Right */
1833 Grey | 3, /* Grey + */
1834 KeyPad | 1, /* End */
1836 /* --------------- 50 to 5f --------------- */
1837 KeyPad | 2, /* Down */
1838 KeyPad | 3, /* Page Down */
1839 KeyPad | 0, /* Insert */
1840 KeyPad | 10, /* Delete */
1841 Shift | FctKey | 0xbe, /* (Shift) F1 */
1842 Shift | FctKey | 0xbf, /* (Shift) F2 */
1843 Shift | FctKey | 0xc0, /* (Shift) F3 */
1844 Shift | FctKey | 0xc1, /* (Shift) F4 */
1845 Shift | FctKey | 0xc2, /* (Shift) F5 */
1846 Shift | FctKey | 0xc3, /* (Shift) F6 */
1847 Shift | FctKey | 0xc4, /* (Shift) F7 */
1848 Shift | FctKey | 0xc5, /* (Shift) F8 */
1849 Shift | FctKey | 0xc6, /* (Shift) F9 */
1850 Shift | FctKey | 0xc7, /* (Shift) F10 */
1851 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
1852 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
1854 /* --------------- 60 to 6f --------------- */
1855 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
1856 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
1857 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
1858 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
1859 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
1860 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
1861 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
1862 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
1863 Alt | FctKey | 0xbe, /* (Alt) F1 */
1864 Alt | FctKey | 0xbf, /* (Alt) F2 */
1865 Alt | FctKey | 0xc0, /* (Alt) F3 */
1866 Alt | FctKey | 0xc1, /* (Alt) F4 */
1867 Alt | FctKey | 0xc2, /* (Alt) F5 */
1868 Alt | FctKey | 0xc3, /* (Alt) F6 */
1869 Alt | FctKey | 0xc4, /* (Alt) F7 */
1870 Alt | FctKey | 0xc5, /* (Alt) F8 */
1872 /* --------------- 70 to 7f --------------- */
1873 Alt | FctKey | 0xc6, /* (Alt) F9 */
1874 Alt | FctKey | 0xc7, /* (Alt) F10 */
1875 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
1876 Ctrl | KeyPad | 4, /* (Ctrl) Left */
1877 Ctrl | KeyPad | 6, /* (Ctrl) Right */
1878 Ctrl | KeyPad | 1, /* (Ctrl) End */
1879 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
1880 Ctrl | KeyPad | 7, /* (Ctrl) Home */
1881 Alt | Map | 1, /* '1' */
1882 Alt | Map | 2, /* '2' */
1883 Alt | Map | 3, /* '3' */
1884 Alt | Map | 4, /* '4' */
1885 Alt | Map | 5, /* '5' */
1886 Alt | Map | 6, /* '6' */
1887 Alt | Map | 7, /* '7' */
1888 Alt | Map | 8, /* '8' */
1890 /* --------------- 80 to 8f --------------- */
1891 Alt | Map | 9, /* '9' */
1892 Alt | Map | 10, /* '0' */
1893 Alt | Map | 11, /* '-' */
1894 Alt | Map | 12, /* '=' */
1895 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
1896 FctKey | 0xc8, /* F11 */
1897 FctKey | 0xc9, /* F12 */
1898 Shift | FctKey | 0xc8, /* (Shift) F11 */
1899 Shift | FctKey | 0xc9, /* (Shift) F12 */
1900 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
1901 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
1902 Alt | FctKey | 0xc8, /* (Alt) F11 */
1903 Alt | FctKey | 0xc9, /* (Alt) F12 */
1904 Ctrl | KeyPad | 8, /* (Ctrl) Up */
1905 Ctrl | Grey | 2, /* (Ctrl) Grey - */
1906 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
1908 /* --------------- 90 to 9f --------------- */
1909 Ctrl | Grey | 3, /* (Ctrl) Grey + */
1910 Ctrl | KeyPad | 2, /* (Ctrl) Down */
1911 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
1912 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
1913 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
1914 Ctrl | Grey | 0, /* (Ctrl) Grey / */
1915 Ctrl | Grey | 1, /* (Ctrl) Grey * */
1916 Alt | FctKey | 0x50, /* (Alt) Home */
1917 Alt | FctKey | 0x52, /* (Alt) Up */
1918 Alt | FctKey | 0x55, /* (Alt) Page Up */
1919 Ignore, /* NO KEY */
1920 Alt | FctKey | 0x51, /* (Alt) Left */
1921 Ignore, /* NO KEY */
1922 Alt | FctKey | 0x53, /* (Alt) Right */
1923 Ignore, /* NO KEY */
1924 Alt | FctKey | 0x57, /* (Alt) End */
1926 /* --------------- a0 to af --------------- */
1927 Alt | KeyPad | 2, /* (Alt) Down */
1928 Alt | KeyPad | 3, /* (Alt) Page Down */
1929 Alt | KeyPad | 0, /* (Alt) Insert */
1930 Alt | KeyPad | 10, /* (Alt) Delete */
1931 Alt | Grey | 0, /* (Alt) Grey / */
1932 Alt | FctKey | 0x09, /* (Alt) Tab */
1933 Alt | Grey | 4 /* (Alt) Keypad Enter */
1936 /* These bit-positions corresponds to values returned by BIOS */
1937 #define SHIFT_P 0x0003 /* two bits! */
1938 #define CTRL_P 0x0004
1939 #define ALT_P 0x0008
1940 #define SCRLOCK_P 0x0010
1941 #define NUMLOCK_P 0x0020
1942 #define CAPSLOCK_P 0x0040
1943 #define ALT_GR_P 0x0800
1944 #define SUPER_P 0x4000 /* pseudo */
1945 #define HYPER_P 0x8000 /* pseudo */
1947 static int
1948 dos_get_modifiers (keymask)
1949 int *keymask;
1951 union REGS regs;
1952 int mask;
1953 int modifiers = 0;
1955 /* Calculate modifier bits */
1956 regs.h.ah = extended_kbd ? 0x12 : 0x02;
1957 int86 (0x16, &regs, &regs);
1959 if (!extended_kbd)
1961 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
1962 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1964 else
1966 mask = regs.h.al & (SHIFT_P |
1967 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1969 /* Do not break international keyboard support. */
1970 /* When Keyb.Com is loaded, the right Alt key is */
1971 /* used for accessing characters like { and } */
1972 if (regs.h.ah & 2) /* Left ALT pressed ? */
1973 mask |= ALT_P;
1975 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
1977 mask |= ALT_GR_P;
1978 if (dos_hyper_key == 1)
1980 mask |= HYPER_P;
1981 modifiers |= hyper_modifier;
1983 else if (dos_super_key == 1)
1985 mask |= SUPER_P;
1986 modifiers |= super_modifier;
1988 else if (!international_keyboard)
1990 /* If Keyb.Com is NOT installed, let Right Alt behave
1991 like the Left Alt. */
1992 mask &= ~ALT_GR_P;
1993 mask |= ALT_P;
1997 if (regs.h.ah & 1) /* Left CTRL pressed ? */
1998 mask |= CTRL_P;
2000 if (regs.h.ah & 4) /* Right CTRL pressed ? */
2002 if (dos_hyper_key == 2)
2004 mask |= HYPER_P;
2005 modifiers |= hyper_modifier;
2007 else if (dos_super_key == 2)
2009 mask |= SUPER_P;
2010 modifiers |= super_modifier;
2012 else
2013 mask |= CTRL_P;
2017 if (mask & SHIFT_P)
2018 modifiers |= shift_modifier;
2019 if (mask & CTRL_P)
2020 modifiers |= ctrl_modifier;
2021 if (mask & ALT_P)
2022 modifiers |= meta_modifier;
2024 if (keymask)
2025 *keymask = mask;
2026 return modifiers;
2029 #define NUM_RECENT_DOSKEYS (100)
2030 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
2031 int total_doskeys; /* Total number of elements stored into recent_doskeys */
2032 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
2034 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
2035 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
2036 Each input key receives two values in this vector: first the ASCII code,\n\
2037 and then the scan code.")
2040 Lisp_Object *keys = XVECTOR (recent_doskeys)->contents;
2041 Lisp_Object val;
2043 if (total_doskeys < NUM_RECENT_DOSKEYS)
2044 return Fvector (total_doskeys, keys);
2045 else
2047 val = Fvector (NUM_RECENT_DOSKEYS, keys);
2048 bcopy (keys + recent_doskeys_index,
2049 XVECTOR (val)->contents,
2050 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
2051 bcopy (keys,
2052 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
2053 recent_doskeys_index * sizeof (Lisp_Object));
2054 return val;
2058 /* Get a char from keyboard. Function keys are put into the event queue. */
2060 extern void kbd_buffer_store_event (struct input_event *);
2061 static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
2063 static int
2064 dos_rawgetc ()
2066 struct input_event event;
2067 union REGS regs;
2069 #ifndef HAVE_X_WINDOWS
2070 /* Maybe put the cursor where it should be. */
2071 IT_cmgoto (selected_frame);
2072 #endif
2074 /* The following condition is equivalent to `kbhit ()', except that
2075 it uses the bios to do its job. This pleases DESQview/X. */
2076 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
2077 int86 (0x16, &regs, &regs),
2078 (regs.x.flags & 0x40) == 0)
2080 union REGS regs;
2081 register unsigned char c;
2082 int sc, code = -1, mask, kp_mode;
2083 int modifiers;
2085 regs.h.ah = extended_kbd ? 0x10 : 0x00;
2086 int86 (0x16, &regs, &regs);
2087 c = regs.h.al;
2088 sc = regs.h.ah;
2090 total_doskeys += 2;
2091 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2092 = make_number (c);
2093 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2094 recent_doskeys_index = 0;
2095 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2096 = make_number (sc);
2097 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2098 recent_doskeys_index = 0;
2100 modifiers = dos_get_modifiers (&mask);
2102 #ifndef HAVE_X_WINDOWS
2103 if (!NILP (Vdos_display_scancodes))
2105 char buf[11];
2106 sprintf (buf, "%02x:%02x*%04x",
2107 (unsigned) (sc&0xff), (unsigned) c, mask);
2108 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
2110 #endif
2112 if (sc == 0xe0)
2114 switch (c)
2116 case 10: /* Ctrl Grey Enter */
2117 code = Ctrl | Grey | 4;
2118 break;
2119 case 13: /* Grey Enter */
2120 code = Grey | 4;
2121 break;
2122 case '/': /* Grey / */
2123 code = Grey | 0;
2124 break;
2125 default:
2126 continue;
2128 c = 0;
2130 else
2132 /* Try the keyboard-private translation table first. */
2133 if (keyboard->translate_table)
2135 struct kbd_translate *p = keyboard->translate_table;
2137 while (p->sc)
2139 if (p->sc == sc && p->ch == c)
2141 code = p->code;
2142 break;
2144 p++;
2147 /* If the private table didn't translate it, use the general
2148 one. */
2149 if (code == -1)
2151 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
2152 continue;
2153 if ((code = ibmpc_translate_map[sc]) == Ignore)
2154 continue;
2158 if (c == 0)
2160 /* We only look at the keyboard Ctrl/Shift/Alt keys when
2161 Emacs is ready to read a key. Therefore, if they press
2162 `Alt-x' when Emacs is busy, by the time we get to
2163 `dos_get_modifiers', they might have already released the
2164 Alt key, and Emacs gets just `x', which is BAD.
2165 However, for keys with the `Map' property set, the ASCII
2166 code returns zero iff Alt is pressed. So, when we DON'T
2167 have to support international_keyboard, we don't have to
2168 distinguish between the left and right Alt keys, and we
2169 can set the META modifier for any keys with the `Map'
2170 property if they return zero ASCII code (c = 0). */
2171 if ( (code & Alt)
2172 || ( (code & 0xf000) == Map && !international_keyboard))
2173 modifiers |= meta_modifier;
2174 if (code & Ctrl)
2175 modifiers |= ctrl_modifier;
2176 if (code & Shift)
2177 modifiers |= shift_modifier;
2180 switch (code & 0xf000)
2182 case ModFct:
2183 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
2184 return c;
2185 c = 0; /* Special */
2187 case FctKey:
2188 if (c != 0)
2189 return c;
2191 case Special:
2192 code |= 0xff00;
2193 break;
2195 case Normal:
2196 if (sc == 0)
2198 if (c == 0) /* ctrl-break */
2199 continue;
2200 return c; /* ALT-nnn */
2202 if (!keyboard_map_all)
2204 if (c != ' ')
2205 return c;
2206 code = c;
2207 break;
2210 case Map:
2211 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
2212 if (!keyboard_map_all)
2213 return c;
2215 code &= 0xff;
2216 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
2217 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
2219 if (mask & SHIFT_P)
2221 code = keyboard->shifted[code];
2222 mask -= SHIFT_P;
2223 modifiers &= ~shift_modifier;
2225 else
2226 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
2227 code = keyboard->alt_gr[code];
2228 else
2229 code = keyboard->unshifted[code];
2230 break;
2232 case KeyPad:
2233 code &= 0xff;
2234 if (c == 0xe0) /* edit key */
2235 kp_mode = 3;
2236 else
2237 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
2238 kp_mode = dos_keypad_mode & 0x03;
2239 else
2240 kp_mode = (dos_keypad_mode >> 4) & 0x03;
2242 switch (kp_mode)
2244 case 0:
2245 if (code == 10 && dos_decimal_point)
2246 return dos_decimal_point;
2247 return keypad_translate_map[code].char_code;
2249 case 1:
2250 code = 0xff00 | keypad_translate_map[code].keypad_code;
2251 break;
2253 case 2:
2254 code = keypad_translate_map[code].meta_code;
2255 modifiers = meta_modifier;
2256 break;
2258 case 3:
2259 code = 0xff00 | keypad_translate_map[code].editkey_code;
2260 break;
2262 break;
2264 case Grey:
2265 code &= 0xff;
2266 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
2267 if (dos_keypad_mode & kp_mode)
2268 code = 0xff00 | grey_key_translate_map[code].keypad_code;
2269 else
2270 code = grey_key_translate_map[code].char_code;
2271 break;
2274 make_event:
2275 if (code == 0)
2276 continue;
2278 if (code >= 0x100)
2279 event.kind = non_ascii_keystroke;
2280 else
2281 event.kind = ascii_keystroke;
2282 event.code = code;
2283 event.modifiers = modifiers;
2284 XSETFRAME (event.frame_or_window, selected_frame);
2285 event.timestamp = event_timestamp ();
2286 kbd_buffer_store_event (&event);
2289 if (have_mouse > 0 && !mouse_preempted)
2291 int but, press, x, y, ok;
2293 /* Check for mouse movement *before* buttons. */
2294 mouse_check_moved ();
2296 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
2297 for (press = 0; press < 2; press++)
2299 int button_num = but;
2301 if (press)
2302 ok = mouse_pressed (but, &x, &y);
2303 else
2304 ok = mouse_released (but, &x, &y);
2305 if (ok)
2307 /* Allow a simultaneous press/release of Mouse-1 and
2308 Mouse-2 to simulate Mouse-3 on two-button mice. */
2309 if (mouse_button_count == 2 && but < 2)
2311 int x2, y2; /* don't clobber original coordinates */
2313 /* If only one button is pressed, wait 100 msec and
2314 check again. This way, Speedy Gonzales isn't
2315 punished, while the slow get their chance. */
2316 if (press && mouse_pressed (1-but, &x2, &y2)
2317 || !press && mouse_released (1-but, &x2, &y2))
2318 button_num = 2;
2319 else
2321 delay (100);
2322 if (press && mouse_pressed (1-but, &x2, &y2)
2323 || !press && mouse_released (1-but, &x2, &y2))
2324 button_num = 2;
2328 event.kind = mouse_click;
2329 event.code = button_num;
2330 event.modifiers = dos_get_modifiers (0)
2331 | (press ? down_modifier : up_modifier);
2332 event.x = x;
2333 event.y = y;
2334 XSETFRAME (event.frame_or_window, selected_frame);
2335 event.timestamp = event_timestamp ();
2336 kbd_buffer_store_event (&event);
2341 return -1;
2344 static int prev_get_char = -1;
2346 /* Return 1 if a key is ready to be read without suspending execution. */
2348 dos_keysns ()
2350 if (prev_get_char != -1)
2351 return 1;
2352 else
2353 return ((prev_get_char = dos_rawgetc ()) != -1);
2356 /* Read a key. Return -1 if no key is ready. */
2358 dos_keyread ()
2360 if (prev_get_char != -1)
2362 int c = prev_get_char;
2363 prev_get_char = -1;
2364 return c;
2366 else
2367 return dos_rawgetc ();
2370 #ifndef HAVE_X_WINDOWS
2371 /* See xterm.c for more info. */
2372 void
2373 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
2374 FRAME_PTR f;
2375 register int pix_x, pix_y;
2376 register int *x, *y;
2377 XRectangle *bounds;
2378 int noclip;
2380 if (bounds) abort ();
2382 /* Ignore clipping. */
2384 *x = pix_x;
2385 *y = pix_y;
2388 void
2389 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
2390 FRAME_PTR f;
2391 register int x, y;
2392 register int *pix_x, *pix_y;
2394 *pix_x = x;
2395 *pix_y = y;
2398 /* Simulation of X's menus. Nothing too fancy here -- just make it work
2399 for now.
2401 Actually, I don't know the meaning of all the parameters of the functions
2402 here -- I only know how they are called by xmenu.c. I could of course
2403 grab the nearest Xlib manual (down the hall, second-to-last door on the
2404 left), but I don't think it's worth the effort. */
2406 static XMenu *
2407 IT_menu_create ()
2409 XMenu *menu;
2411 menu = (XMenu *) xmalloc (sizeof (XMenu));
2412 menu->allocated = menu->count = menu->panecount = menu->width = 0;
2413 return menu;
2416 /* Allocate some (more) memory for MENU ensuring that there is room for one
2417 for item. */
2419 static void
2420 IT_menu_make_room (XMenu *menu)
2422 if (menu->allocated == 0)
2424 int count = menu->allocated = 10;
2425 menu->text = (char **) xmalloc (count * sizeof (char *));
2426 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
2427 menu->panenumber = (int *) xmalloc (count * sizeof (int));
2429 else if (menu->allocated == menu->count)
2431 int count = menu->allocated = menu->allocated + 10;
2432 menu->text
2433 = (char **) xrealloc (menu->text, count * sizeof (char *));
2434 menu->submenu
2435 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
2436 menu->panenumber
2437 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
2441 /* Search the given menu structure for a given pane number. */
2443 static XMenu *
2444 IT_menu_search_pane (XMenu *menu, int pane)
2446 int i;
2447 XMenu *try;
2449 for (i = 0; i < menu->count; i++)
2450 if (menu->submenu[i])
2452 if (pane == menu->panenumber[i])
2453 return menu->submenu[i];
2454 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
2455 return try;
2457 return (XMenu *) 0;
2460 /* Determine how much screen space a given menu needs. */
2462 static void
2463 IT_menu_calc_size (XMenu *menu, int *width, int *height)
2465 int i, h2, w2, maxsubwidth, maxheight;
2467 maxsubwidth = 0;
2468 maxheight = menu->count;
2469 for (i = 0; i < menu->count; i++)
2471 if (menu->submenu[i])
2473 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
2474 if (w2 > maxsubwidth) maxsubwidth = w2;
2475 if (i + h2 > maxheight) maxheight = i + h2;
2478 *width = menu->width + maxsubwidth;
2479 *height = maxheight;
2482 /* Display MENU at (X,Y) using FACES. */
2484 static void
2485 IT_menu_display (XMenu *menu, int y, int x, int *faces)
2487 int i, j, face, width;
2488 struct glyph *text, *p;
2489 char *q;
2490 int mx, my;
2491 int enabled, mousehere;
2492 int row, col;
2494 width = menu->width;
2495 text = (struct glyph *) xmalloc ((width + 2) * sizeof (struct glyph));
2496 ScreenGetCursor (&row, &col);
2497 mouse_get_xy (&mx, &my);
2498 IT_update_begin (selected_frame);
2499 for (i = 0; i < menu->count; i++)
2501 IT_cursor_to (y + i, x);
2502 enabled
2503 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
2504 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
2505 face = faces[enabled + mousehere * 2];
2506 p = text;
2507 SET_CHAR_GLYPH (*p, ' ', face, 0);
2508 p++;
2509 for (j = 0, q = menu->text[i]; *q; j++)
2511 if (*q > 26)
2513 SET_CHAR_GLYPH (*p, *q++, face, 0);
2514 p++;
2516 else /* make '^x' */
2518 SET_CHAR_GLYPH (*p, '^', face, 0);
2519 p++;
2520 j++;
2521 SET_CHAR_GLYPH (*p, *q++ + 64, face, 0);
2522 p++;
2526 for (; j < width; j++, p++)
2527 SET_CHAR_GLYPH (*p, ' ', face, 0);
2529 SET_CHAR_GLYPH (*p, menu->submenu[i] ? 16 : ' ', face, 0);
2530 p++;
2531 IT_write_glyphs (text, width + 2);
2533 IT_update_end (selected_frame);
2534 IT_cursor_to (row, col);
2535 xfree (text);
2538 /* --------------------------- X Menu emulation ---------------------- */
2540 /* Report availability of menus. */
2543 have_menus_p ()
2545 return 1;
2548 /* Create a brand new menu structure. */
2550 XMenu *
2551 XMenuCreate (Display *foo1, Window foo2, char *foo3)
2553 return IT_menu_create ();
2556 /* Create a new pane and place it on the outer-most level. It is not
2557 clear that it should be placed out there, but I don't know what else
2558 to do. */
2561 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
2563 int len;
2564 char *p;
2566 if (!enable)
2567 abort ();
2569 IT_menu_make_room (menu);
2570 menu->submenu[menu->count] = IT_menu_create ();
2571 menu->text[menu->count] = txt;
2572 menu->panenumber[menu->count] = ++menu->panecount;
2573 menu->count++;
2575 /* Adjust length for possible control characters (which will
2576 be written as ^x). */
2577 for (len = strlen (txt), p = txt; *p; p++)
2578 if (*p < 27)
2579 len++;
2581 if (len > menu->width)
2582 menu->width = len;
2584 return menu->panecount;
2587 /* Create a new item in a menu pane. */
2590 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
2591 int foo, char *txt, int enable)
2593 int len;
2594 char *p;
2596 if (pane)
2597 if (!(menu = IT_menu_search_pane (menu, pane)))
2598 return XM_FAILURE;
2599 IT_menu_make_room (menu);
2600 menu->submenu[menu->count] = (XMenu *) 0;
2601 menu->text[menu->count] = txt;
2602 menu->panenumber[menu->count] = enable;
2603 menu->count++;
2605 /* Adjust length for possible control characters (which will
2606 be written as ^x). */
2607 for (len = strlen (txt), p = txt; *p; p++)
2608 if (*p < 27)
2609 len++;
2611 if (len > menu->width)
2612 menu->width = len;
2614 return XM_SUCCESS;
2617 /* Decide where the menu would be placed if requested at (X,Y). */
2619 void
2620 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
2621 int *ulx, int *uly, int *width, int *height)
2623 IT_menu_calc_size (menu, width, height);
2624 *ulx = x + 1;
2625 *uly = y;
2626 *width += 2;
2629 struct IT_menu_state
2631 void *screen_behind;
2632 XMenu *menu;
2633 int pane;
2634 int x, y;
2638 /* Display menu, wait for user's response, and return that response. */
2641 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
2642 int x0, int y0, unsigned ButtonMask, char **txt)
2644 struct IT_menu_state *state;
2645 int statecount;
2646 int x, y, i, b;
2647 int screensize;
2648 int faces[4];
2649 Lisp_Object selectface;
2650 int leave, result, onepane;
2651 int title_faces[4]; /* face to display the menu title */
2652 int buffers_num_deleted = 0;
2654 /* Just in case we got here without a mouse present... */
2655 if (have_mouse <= 0)
2656 return XM_IA_SELECT;
2657 /* Don't allow non-positive x0 and y0, lest the menu will wrap
2658 around the display. */
2659 if (x0 <= 0)
2660 x0 = 1;
2661 if (y0 <= 0)
2662 y0 = 1;
2664 /* We will process all the mouse events directly, so we had
2665 better prevented dos_rawgetc from stealing them from us. */
2666 mouse_preempted++;
2668 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
2669 screensize = screen_size * 2;
2670 faces[0]
2671 = lookup_derived_face (selected_frame, intern ("msdos-menu-passive-face"),
2672 CHARSET_ASCII, DEFAULT_FACE_ID);
2673 faces[1]
2674 = lookup_derived_face (selected_frame, intern ("msdos-menu-active-face"),
2675 CHARSET_ASCII, DEFAULT_FACE_ID);
2676 selectface = intern ("msdos-menu-select-face");
2677 faces[2] = lookup_derived_face (selected_frame, selectface,
2678 CHARSET_ASCII, faces[0]);
2679 faces[3] = lookup_derived_face (selected_frame, selectface,
2680 CHARSET_ASCII, faces[1]);
2682 /* Make sure the menu title is always displayed with
2683 `msdos-menu-active-face', no matter where the mouse pointer is. */
2684 for (i = 0; i < 4; i++)
2685 title_faces[i] = faces[3];
2687 statecount = 1;
2689 /* Don't let the title for the "Buffers" popup menu include a
2690 digit (which is ugly).
2692 This is a terrible kludge, but I think the "Buffers" case is
2693 the only one where the title includes a number, so it doesn't
2694 seem to be necessary to make this more general. */
2695 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
2697 menu->text[0][7] = '\0';
2698 buffers_num_deleted = 1;
2700 state[0].menu = menu;
2701 mouse_off ();
2702 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
2704 /* Turn off the cursor. Otherwise it shows through the menu
2705 panes, which is ugly. */
2706 IT_display_cursor (0);
2708 IT_menu_display (menu, y0 - 1, x0 - 1, title_faces); /* display menu title */
2709 if (buffers_num_deleted)
2710 menu->text[0][7] = ' ';
2711 if ((onepane = menu->count == 1 && menu->submenu[0]))
2713 menu->width = menu->submenu[0]->width;
2714 state[0].menu = menu->submenu[0];
2716 else
2718 state[0].menu = menu;
2720 state[0].x = x0 - 1;
2721 state[0].y = y0;
2722 state[0].pane = onepane;
2724 mouse_last_x = -1; /* A hack that forces display. */
2725 leave = 0;
2726 while (!leave)
2728 if (!mouse_visible) mouse_on ();
2729 mouse_check_moved ();
2730 if (selected_frame->mouse_moved)
2732 selected_frame->mouse_moved = 0;
2733 result = XM_IA_SELECT;
2734 mouse_get_xy (&x, &y);
2735 for (i = 0; i < statecount; i++)
2736 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
2738 int dy = y - state[i].y;
2739 if (0 <= dy && dy < state[i].menu->count)
2741 if (!state[i].menu->submenu[dy])
2742 if (state[i].menu->panenumber[dy])
2743 result = XM_SUCCESS;
2744 else
2745 result = XM_IA_SELECT;
2746 *pane = state[i].pane - 1;
2747 *selidx = dy;
2748 /* We hit some part of a menu, so drop extra menus that
2749 have been opened. That does not include an open and
2750 active submenu. */
2751 if (i != statecount - 2
2752 || state[i].menu->submenu[dy] != state[i+1].menu)
2753 while (i != statecount - 1)
2755 statecount--;
2756 mouse_off ();
2757 ScreenUpdate (state[statecount].screen_behind);
2758 if (screen_virtual_segment)
2759 dosv_refresh_virtual_screen (0, screen_size);
2760 xfree (state[statecount].screen_behind);
2762 if (i == statecount - 1 && state[i].menu->submenu[dy])
2764 IT_menu_display (state[i].menu,
2765 state[i].y,
2766 state[i].x,
2767 faces);
2768 state[statecount].menu = state[i].menu->submenu[dy];
2769 state[statecount].pane = state[i].menu->panenumber[dy];
2770 mouse_off ();
2771 ScreenRetrieve (state[statecount].screen_behind
2772 = xmalloc (screensize));
2773 state[statecount].x
2774 = state[i].x + state[i].menu->width + 2;
2775 state[statecount].y = y;
2776 statecount++;
2780 IT_menu_display (state[statecount - 1].menu,
2781 state[statecount - 1].y,
2782 state[statecount - 1].x,
2783 faces);
2785 else
2786 /* We are busy-waiting for the mouse to move, so let's be nice
2787 to other Windows applications by releasing our time slice. */
2788 __dpmi_yield ();
2789 for (b = 0; b < mouse_button_count && !leave; b++)
2791 /* Only leave if user both pressed and released the mouse, and in
2792 that order. This avoids popping down the menu pane unless
2793 the user is really done with it. */
2794 if (mouse_pressed (b, &x, &y))
2796 while (mouse_button_depressed (b, &x, &y))
2797 __dpmi_yield ();
2798 leave = 1;
2800 (void) mouse_released (b, &x, &y);
2804 mouse_off ();
2805 ScreenUpdate (state[0].screen_behind);
2806 if (screen_virtual_segment)
2807 dosv_refresh_virtual_screen (0, screen_size);
2808 while (statecount--)
2809 xfree (state[statecount].screen_behind);
2810 IT_display_cursor (1); /* turn cursor back on */
2811 /* Clean up any mouse events that are waiting inside Emacs event queue.
2812 These events are likely to be generated before the menu was even
2813 displayed, probably because the user pressed and released the button
2814 (which invoked the menu) too quickly. If we don't remove these events,
2815 Emacs will process them after we return and surprise the user. */
2816 discard_mouse_events ();
2817 /* Allow mouse events generation by dos_rawgetc. */
2818 mouse_preempted--;
2819 return result;
2822 /* Dispose of a menu. */
2824 void
2825 XMenuDestroy (Display *foo, XMenu *menu)
2827 int i;
2828 if (menu->allocated)
2830 for (i = 0; i < menu->count; i++)
2831 if (menu->submenu[i])
2832 XMenuDestroy (foo, menu->submenu[i]);
2833 xfree (menu->text);
2834 xfree (menu->submenu);
2835 xfree (menu->panenumber);
2837 xfree (menu);
2841 x_pixel_width (struct frame *f)
2843 return FRAME_WIDTH (f);
2847 x_pixel_height (struct frame *f)
2849 return FRAME_HEIGHT (f);
2851 #endif /* !HAVE_X_WINDOWS */
2853 /* ----------------------- DOS / UNIX conversion --------------------- */
2855 void msdos_downcase_filename (unsigned char *);
2857 /* Destructively turn backslashes into slashes. */
2859 void
2860 dostounix_filename (p)
2861 register char *p;
2863 msdos_downcase_filename (p);
2865 while (*p)
2867 if (*p == '\\')
2868 *p = '/';
2869 p++;
2873 /* Destructively turn slashes into backslashes. */
2875 void
2876 unixtodos_filename (p)
2877 register char *p;
2879 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
2881 *p += 'a' - 'A';
2882 p += 2;
2885 while (*p)
2887 if (*p == '/')
2888 *p = '\\';
2889 p++;
2893 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2896 getdefdir (drive, dst)
2897 int drive;
2898 char *dst;
2900 char in_path[4], *p = in_path;
2901 int e = errno;
2903 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2904 if (drive != 0)
2906 *p++ = drive + 'A' - 1;
2907 *p++ = ':';
2910 *p++ = '.';
2911 *p = '\0';
2912 errno = 0;
2913 _fixpath (in_path, dst);
2914 /* _fixpath can set errno to ENOSYS on non-LFN systems because
2915 it queries the LFN support, so ignore that error. */
2916 if ((errno && errno != ENOSYS) || *dst == '\0')
2917 return 0;
2919 msdos_downcase_filename (dst);
2921 errno = e;
2922 return 1;
2925 /* Remove all CR's that are followed by a LF. */
2928 crlf_to_lf (n, buf)
2929 register int n;
2930 register unsigned char *buf;
2932 unsigned char *np = buf;
2933 unsigned char *startp = buf;
2934 unsigned char *endp = buf + n;
2936 if (n == 0)
2937 return n;
2938 while (buf < endp - 1)
2940 if (*buf == 0x0d)
2942 if (*(++buf) != 0x0a)
2943 *np++ = 0x0d;
2945 else
2946 *np++ = *buf++;
2948 if (buf < endp)
2949 *np++ = *buf++;
2950 return np - startp;
2953 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
2955 /* In DJGPP v2.0, library `write' can call `malloc', which might
2956 cause relocation of the buffer whose address we get in ADDR.
2957 Here is a version of `write' that avoids calling `malloc',
2958 to serve us until such time as the library is fixed.
2959 Actually, what we define here is called `__write', because
2960 `write' is a stub that just jmp's to `__write' (to be
2961 POSIXLY-correct with respect to the global name-space). */
2963 #include <io.h> /* for _write */
2964 #include <libc/dosio.h> /* for __file_handle_modes[] */
2966 static char xbuf[64 * 1024]; /* DOS cannot write more in one chunk */
2968 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
2971 __write (int handle, const void *buffer, size_t count)
2973 if (count == 0)
2974 return 0;
2976 if(__file_handle_modes[handle] & O_BINARY)
2977 return _write (handle, buffer, count);
2978 else
2980 char *xbp = xbuf;
2981 const char *bp = buffer;
2982 int total_written = 0;
2983 int nmoved = 0, ncr = 0;
2985 while (count)
2987 /* The next test makes sure there's space for at least 2 more
2988 characters in xbuf[], so both CR and LF can be put there. */
2989 if (xbp < XBUF_END)
2991 if (*bp == '\n')
2993 ncr++;
2994 *xbp++ = '\r';
2996 *xbp++ = *bp++;
2997 nmoved++;
2998 count--;
3000 if (xbp >= XBUF_END || !count)
3002 size_t to_write = nmoved + ncr;
3003 int written = _write (handle, xbuf, to_write);
3005 if (written == -1)
3006 return -1;
3007 else
3008 total_written += nmoved; /* CRs aren't counted in ret value */
3010 /* If some, but not all were written (disk full?), return
3011 an estimate of the total written bytes not counting CRs. */
3012 if (written < to_write)
3013 return total_written - (to_write - written) * nmoved/to_write;
3015 nmoved = 0;
3016 ncr = 0;
3017 xbp = xbuf;
3020 return total_written;
3024 /* A low-level file-renaming function which works around Windows 95 bug.
3025 This is pulled directly out of DJGPP v2.01 library sources, and only
3026 used when you compile with DJGPP v2.0. */
3028 #include <io.h>
3030 int _rename(const char *old, const char *new)
3032 __dpmi_regs r;
3033 int olen = strlen(old) + 1;
3034 int i;
3035 int use_lfn = _USE_LFN;
3036 char tempfile[FILENAME_MAX];
3037 const char *orig = old;
3038 int lfn_fd = -1;
3040 r.x.dx = __tb_offset;
3041 r.x.di = __tb_offset + olen;
3042 r.x.ds = r.x.es = __tb_segment;
3044 if (use_lfn)
3046 /* Windows 95 bug: for some filenames, when you rename
3047 file -> file~ (as in Emacs, to leave a backup), the
3048 short 8+3 alias doesn't change, which effectively
3049 makes OLD and NEW the same file. We must rename
3050 through a temporary file to work around this. */
3052 char *pbase = 0, *p;
3053 static char try_char[] = "abcdefghijklmnopqrstuvwxyz012345789";
3054 int idx = sizeof(try_char) - 1;
3056 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
3057 might point to another drive, which will fail the DOS call. */
3058 strcpy(tempfile, old);
3059 for (p = tempfile; *p; p++) /* ensure temporary is on the same drive */
3060 if (*p == '/' || *p == '\\' || *p == ':')
3061 pbase = p;
3062 if (pbase)
3063 pbase++;
3064 else
3065 pbase = tempfile;
3066 strcpy(pbase, "X$$djren$$.$$temp$$");
3070 if (idx <= 0)
3071 return -1;
3072 *pbase = try_char[--idx];
3073 } while (_chmod(tempfile, 0) != -1);
3075 r.x.ax = 0x7156;
3076 _put_path2(tempfile, olen);
3077 _put_path(old);
3078 __dpmi_int(0x21, &r);
3079 if (r.x.flags & 1)
3081 errno = __doserr_to_errno(r.x.ax);
3082 return -1;
3085 /* Now create a file with the original name. This will
3086 ensure that NEW will always have a 8+3 alias
3087 different from that of OLD. (Seems to be required
3088 when NameNumericTail in the Registry is set to 0.) */
3089 lfn_fd = _creat(old, 0);
3091 olen = strlen(tempfile) + 1;
3092 old = tempfile;
3093 r.x.di = __tb_offset + olen;
3096 for (i=0; i<2; i++)
3098 if(use_lfn)
3099 r.x.ax = 0x7156;
3100 else
3101 r.h.ah = 0x56;
3102 _put_path2(new, olen);
3103 _put_path(old);
3104 __dpmi_int(0x21, &r);
3105 if(r.x.flags & 1)
3107 if (r.x.ax == 5 && i == 0) /* access denied */
3108 remove(new); /* and try again */
3109 else
3111 errno = __doserr_to_errno(r.x.ax);
3113 /* Restore to original name if we renamed it to temporary. */
3114 if (use_lfn)
3116 if (lfn_fd != -1)
3118 _close (lfn_fd);
3119 remove (orig);
3121 _put_path2(orig, olen);
3122 _put_path(tempfile);
3123 r.x.ax = 0x7156;
3124 __dpmi_int(0x21, &r);
3126 return -1;
3129 else
3130 break;
3133 /* Success. Delete the file possibly created to work
3134 around the Windows 95 bug. */
3135 if (lfn_fd != -1)
3136 return (_close (lfn_fd) == 0) ? remove (orig) : -1;
3137 return 0;
3140 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
3142 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
3143 0, 0, 0,
3144 "Return non-nil if long file names are supported on MSDOS.")
3147 return (_USE_LFN ? Qt : Qnil);
3150 /* Convert alphabetic characters in a filename to lower-case. */
3152 void
3153 msdos_downcase_filename (p)
3154 register unsigned char *p;
3156 /* Always lower-case drive letters a-z, even if the filesystem
3157 preserves case in filenames.
3158 This is so MSDOS filenames could be compared by string comparison
3159 functions that are case-sensitive. Even case-preserving filesystems
3160 do not distinguish case in drive letters. */
3161 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3163 *p += 'a' - 'A';
3164 p += 2;
3167 /* Under LFN we expect to get pathnames in their true case. */
3168 if (NILP (Fmsdos_long_file_names ()))
3169 for ( ; *p; p++)
3170 if (*p >= 'A' && *p <= 'Z')
3171 *p += 'a' - 'A';
3174 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
3175 1, 1, 0,
3176 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
3177 When long filenames are supported, doesn't change FILENAME.\n\
3178 If FILENAME is not a string, returns nil.\n\
3179 The argument object is never altered--the value is a copy.")
3180 (filename)
3181 Lisp_Object filename;
3183 Lisp_Object tem;
3185 if (! STRINGP (filename))
3186 return Qnil;
3188 tem = Fcopy_sequence (filename);
3189 msdos_downcase_filename (XSTRING (tem)->data);
3190 return tem;
3193 /* The Emacs root directory as determined by init_environment. */
3195 static char emacsroot[MAXPATHLEN];
3197 char *
3198 rootrelativepath (rel)
3199 char *rel;
3201 static char result[MAXPATHLEN + 10];
3203 strcpy (result, emacsroot);
3204 strcat (result, "/");
3205 strcat (result, rel);
3206 return result;
3209 /* Define a lot of environment variables if not already defined. Don't
3210 remove anything unless you know what you're doing -- lots of code will
3211 break if one or more of these are missing. */
3213 void
3214 init_environment (argc, argv, skip_args)
3215 int argc;
3216 char **argv;
3217 int skip_args;
3219 char *s, *t, *root;
3220 int len;
3221 static const char * const tempdirs[] = {
3222 "$TMPDIR", "$TEMP", "$TMP", "c:/"
3224 int i;
3225 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
3227 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
3228 temporary files and assume "/tmp" if $TMPDIR is unset, which
3229 will break on DOS/Windows. Refuse to work if we cannot find
3230 a directory, not even "c:/", usable for that purpose. */
3231 for (i = 0; i < imax ; i++)
3233 const char *tmp = tempdirs[i];
3235 if (*tmp == '$')
3236 tmp = getenv (tmp + 1);
3237 /* Note that `access' can lie to us if the directory resides on a
3238 read-only filesystem, like CD-ROM or a write-protected floppy.
3239 The only way to be really sure is to actually create a file and
3240 see if it succeeds. But I think that's too much to ask. */
3241 if (tmp && access (tmp, D_OK) == 0)
3243 setenv ("TMPDIR", tmp, 1);
3244 break;
3247 if (i >= imax)
3248 cmd_error_internal
3249 (Fcons (Qerror,
3250 Fcons (build_string ("no usable temporary directories found!!"),
3251 Qnil)),
3252 "While setting TMPDIR: ");
3254 /* Note the startup time, so we know not to clear the screen if we
3255 exit immediately; see IT_reset_terminal_modes.
3256 (Yes, I know `clock' returns zero the first time it's called, but
3257 I do this anyway, in case some wiseguy changes that at some point.) */
3258 startup_time = clock ();
3260 /* Find our root from argv[0]. Assuming argv[0] is, say,
3261 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
3262 root = alloca (MAXPATHLEN + 20);
3263 _fixpath (argv[0], root);
3264 msdos_downcase_filename (root);
3265 len = strlen (root);
3266 while (len > 0 && root[len] != '/' && root[len] != ':')
3267 len--;
3268 root[len] = '\0';
3269 if (len > 4
3270 && (strcmp (root + len - 4, "/bin") == 0
3271 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
3272 root[len - 4] = '\0';
3273 else
3274 strcpy (root, "c:/emacs"); /* let's be defensive */
3275 len = strlen (root);
3276 strcpy (emacsroot, root);
3278 /* We default HOME to our root. */
3279 setenv ("HOME", root, 0);
3281 /* We default EMACSPATH to root + "/bin". */
3282 strcpy (root + len, "/bin");
3283 setenv ("EMACSPATH", root, 0);
3285 /* I don't expect anybody to ever use other terminals so the internal
3286 terminal is the default. */
3287 setenv ("TERM", "internal", 0);
3289 #ifdef HAVE_X_WINDOWS
3290 /* Emacs expects DISPLAY to be set. */
3291 setenv ("DISPLAY", "unix:0.0", 0);
3292 #endif
3294 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
3295 downcase it and mirror the backslashes. */
3296 s = getenv ("COMSPEC");
3297 if (!s) s = "c:/command.com";
3298 t = alloca (strlen (s) + 1);
3299 strcpy (t, s);
3300 dostounix_filename (t);
3301 setenv ("SHELL", t, 0);
3303 /* PATH is also downcased and backslashes mirrored. */
3304 s = getenv ("PATH");
3305 if (!s) s = "";
3306 t = alloca (strlen (s) + 3);
3307 /* Current directory is always considered part of MsDos's path but it is
3308 not normally mentioned. Now it is. */
3309 strcat (strcpy (t, ".;"), s);
3310 dostounix_filename (t); /* Not a single file name, but this should work. */
3311 setenv ("PATH", t, 1);
3313 /* In some sense all dos users have root privileges, so... */
3314 setenv ("USER", "root", 0);
3315 setenv ("NAME", getenv ("USER"), 0);
3317 /* Time zone determined from country code. To make this possible, the
3318 country code may not span more than one time zone. In other words,
3319 in the USA, you lose. */
3320 if (!getenv ("TZ"))
3321 switch (dos_country_code)
3323 case 31: /* Belgium */
3324 case 32: /* The Netherlands */
3325 case 33: /* France */
3326 case 34: /* Spain */
3327 case 36: /* Hungary */
3328 case 38: /* Yugoslavia (or what's left of it?) */
3329 case 39: /* Italy */
3330 case 41: /* Switzerland */
3331 case 42: /* Tjekia */
3332 case 45: /* Denmark */
3333 case 46: /* Sweden */
3334 case 47: /* Norway */
3335 case 48: /* Poland */
3336 case 49: /* Germany */
3337 /* Daylight saving from last Sunday in March to last Sunday in
3338 September, both at 2AM. */
3339 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
3340 break;
3341 case 44: /* United Kingdom */
3342 case 351: /* Portugal */
3343 case 354: /* Iceland */
3344 setenv ("TZ", "GMT+00", 0);
3345 break;
3346 case 81: /* Japan */
3347 case 82: /* Korea */
3348 setenv ("TZ", "JST-09", 0);
3349 break;
3350 case 90: /* Turkey */
3351 case 358: /* Finland */
3352 setenv ("TZ", "EET-02", 0);
3353 break;
3354 case 972: /* Israel */
3355 /* This is an approximation. (For exact rules, use the
3356 `zoneinfo/israel' file which comes with DJGPP, but you need
3357 to install it in `/usr/share/zoneinfo/' directory first.) */
3358 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
3359 break;
3361 tzset ();
3366 static int break_stat; /* BREAK check mode status. */
3367 static int stdin_stat; /* stdin IOCTL status. */
3369 #if __DJGPP__ < 2
3371 /* These must be global. */
3372 static _go32_dpmi_seginfo ctrl_break_vector;
3373 static _go32_dpmi_registers ctrl_break_regs;
3374 static int ctrlbreakinstalled = 0;
3376 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
3378 void
3379 ctrl_break_func (regs)
3380 _go32_dpmi_registers *regs;
3382 Vquit_flag = Qt;
3385 void
3386 install_ctrl_break_check ()
3388 if (!ctrlbreakinstalled)
3390 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
3391 was compiler with Djgpp 1.11 maintenance level 5 or later! */
3392 ctrlbreakinstalled = 1;
3393 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
3394 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
3395 &ctrl_break_regs);
3396 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
3400 #endif /* __DJGPP__ < 2 */
3402 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
3403 control chars by DOS. Determine the keyboard type. */
3406 dos_ttraw ()
3408 union REGS inregs, outregs;
3409 static int first_time = 1;
3411 break_stat = getcbrk ();
3412 setcbrk (0);
3413 #if __DJGPP__ < 2
3414 install_ctrl_break_check ();
3415 #endif
3417 if (first_time)
3419 inregs.h.ah = 0xc0;
3420 int86 (0x15, &inregs, &outregs);
3421 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
3423 have_mouse = 0;
3425 if (internal_terminal
3426 #ifdef HAVE_X_WINDOWS
3427 && inhibit_window_system
3428 #endif
3431 inregs.x.ax = 0x0021;
3432 int86 (0x33, &inregs, &outregs);
3433 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
3434 if (!have_mouse)
3436 /* Reportedly, the above doesn't work for some mouse drivers. There
3437 is an additional detection method that should work, but might be
3438 a little slower. Use that as an alternative. */
3439 inregs.x.ax = 0x0000;
3440 int86 (0x33, &inregs, &outregs);
3441 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
3444 if (have_mouse)
3446 have_mouse = 1; /* enable mouse */
3447 mouse_visible = 0;
3449 if (outregs.x.bx == 3)
3451 mouse_button_count = 3;
3452 mouse_button_translate[0] = 0; /* Left */
3453 mouse_button_translate[1] = 2; /* Middle */
3454 mouse_button_translate[2] = 1; /* Right */
3456 else
3458 mouse_button_count = 2;
3459 mouse_button_translate[0] = 0;
3460 mouse_button_translate[1] = 1;
3462 mouse_position_hook = &mouse_get_pos;
3463 mouse_init ();
3467 first_time = 0;
3469 #if __DJGPP__ >= 2
3471 stdin_stat = setmode (fileno (stdin), O_BINARY);
3472 return (stdin_stat != -1);
3474 else
3475 return (setmode (fileno (stdin), O_BINARY) != -1);
3477 #else /* __DJGPP__ < 2 */
3481 /* I think it is wrong to overwrite `stdin_stat' every time
3482 but the first one this function is called, but I don't
3483 want to change the way it used to work in v1.x.--EZ */
3485 inregs.x.ax = 0x4400; /* Get IOCTL status. */
3486 inregs.x.bx = 0x00; /* 0 = stdin. */
3487 intdos (&inregs, &outregs);
3488 stdin_stat = outregs.h.dl;
3490 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
3491 inregs.x.ax = 0x4401; /* Set IOCTL status */
3492 intdos (&inregs, &outregs);
3493 return !outregs.x.cflag;
3495 #endif /* __DJGPP__ < 2 */
3498 /* Restore status of standard input and Ctrl-C checking. */
3501 dos_ttcooked ()
3503 union REGS inregs, outregs;
3505 setcbrk (break_stat);
3506 mouse_off ();
3508 #if __DJGPP__ >= 2
3510 return (setmode (fileno (stdin), stdin_stat) != -1);
3512 #else /* not __DJGPP__ >= 2 */
3514 inregs.x.ax = 0x4401; /* Set IOCTL status. */
3515 inregs.x.bx = 0x00; /* 0 = stdin. */
3516 inregs.x.dx = stdin_stat;
3517 intdos (&inregs, &outregs);
3518 return !outregs.x.cflag;
3520 #endif /* not __DJGPP__ >= 2 */
3524 /* Run command as specified by ARGV in directory DIR.
3525 The command is run with input from TEMPIN, output to
3526 file TEMPOUT and stderr to TEMPERR. */
3529 run_msdos_command (argv, working_dir, tempin, tempout, temperr, envv)
3530 unsigned char **argv;
3531 const char *working_dir;
3532 int tempin, tempout, temperr;
3533 char **envv;
3535 char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
3536 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
3537 int msshell, result = -1;
3538 int inbak, outbak, errbak;
3539 int x, y;
3540 Lisp_Object cmd;
3542 /* Get current directory as MSDOS cwd is not per-process. */
3543 getwd (oldwd);
3545 /* If argv[0] is the shell, it might come in any lettercase.
3546 Since `Fmember' is case-sensitive, we need to downcase
3547 argv[0], even if we are on case-preserving filesystems. */
3548 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
3549 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
3551 *pl = *pa++;
3552 if (*pl >= 'A' && *pl <= 'Z')
3553 *pl += 'a' - 'A';
3555 *pl = '\0';
3557 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
3558 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
3559 && !strcmp ("-c", argv[1]);
3560 if (msshell)
3562 saveargv1 = argv[1];
3563 saveargv2 = argv[2];
3564 argv[1] = "/c";
3565 if (argv[2])
3567 char *p = alloca (strlen (argv[2]) + 1);
3569 strcpy (argv[2] = p, saveargv2);
3570 while (*p && isspace (*p))
3571 p++;
3572 while (*p && !isspace (*p))
3573 if (*p == '/')
3574 *p++ = '\\';
3575 else
3576 p++;
3580 chdir (working_dir);
3581 inbak = dup (0);
3582 outbak = dup (1);
3583 errbak = dup (2);
3584 if (inbak < 0 || outbak < 0 || errbak < 0)
3585 goto done; /* Allocation might fail due to lack of descriptors. */
3587 if (have_mouse > 0)
3588 mouse_get_xy (&x, &y);
3590 dos_ttcooked (); /* do it here while 0 = stdin */
3592 dup2 (tempin, 0);
3593 dup2 (tempout, 1);
3594 dup2 (temperr, 2);
3596 #if __DJGPP__ > 1
3598 if (msshell && !argv[3])
3600 /* MS-DOS native shells are too restrictive. For starters, they
3601 cannot grok commands longer than 126 characters. In DJGPP v2
3602 and later, `system' is much smarter, so we'll call it instead. */
3604 const char *cmnd;
3606 /* A shell gets a single argument--its full command
3607 line--whose original was saved in `saveargv2'. */
3609 /* Don't let them pass empty command lines to `system', since
3610 with some shells it will try to invoke an interactive shell,
3611 which will hang Emacs. */
3612 for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
3614 if (*cmnd)
3616 extern char **environ;
3617 int save_system_flags = __system_flags;
3619 /* Request the most powerful version of `system'. We need
3620 all the help we can get to avoid calling stock DOS shells. */
3621 __system_flags = (__system_redirect
3622 | __system_use_shell
3623 | __system_allow_multiple_cmds
3624 | __system_allow_long_cmds
3625 | __system_handle_null_commands
3626 | __system_emulate_chdir);
3628 environ = envv;
3629 result = system (cmnd);
3630 __system_flags = save_system_flags;
3632 else
3633 result = 0; /* emulate Unixy shell behavior with empty cmd line */
3635 else
3637 #endif /* __DJGPP__ > 1 */
3639 result = spawnve (P_WAIT, argv[0], argv, envv);
3641 dup2 (inbak, 0);
3642 dup2 (outbak, 1);
3643 dup2 (errbak, 2);
3644 close (inbak);
3645 close (outbak);
3646 close (errbak);
3648 dos_ttraw ();
3649 if (have_mouse > 0)
3651 mouse_init ();
3652 mouse_moveto (x, y);
3655 /* Some programs might change the meaning of the highest bit of the
3656 text attribute byte, so we get blinking characters instead of the
3657 bright background colors. Restore that. */
3658 bright_bg ();
3660 done:
3661 chdir (oldwd);
3662 if (msshell)
3664 argv[1] = saveargv1;
3665 argv[2] = saveargv2;
3667 return result;
3670 croak (badfunc)
3671 char *badfunc;
3673 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
3674 reset_sys_modes ();
3675 exit (1);
3678 #if __DJGPP__ < 2
3680 /* ------------------------- Compatibility functions -------------------
3681 * gethostname
3682 * gettimeofday
3685 /* Hostnames for a pc are not really funny,
3686 but they are used in change log so we emulate the best we can. */
3688 gethostname (p, size)
3689 char *p;
3690 int size;
3692 char *q = egetenv ("HOSTNAME");
3694 if (!q) q = "pc";
3695 strcpy (p, q);
3696 return 0;
3699 /* When time zones are set from Ms-Dos too many C-libraries are playing
3700 tricks with time values. We solve this by defining our own version
3701 of `gettimeofday' bypassing GO32. Our version needs to be initialized
3702 once and after each call to `tzset' with TZ changed. That is
3703 accomplished by aliasing tzset to init_gettimeofday. */
3705 static struct tm time_rec;
3708 gettimeofday (struct timeval *tp, struct timezone *tzp)
3710 if (tp)
3712 struct time t;
3713 struct tm tm;
3715 gettime (&t);
3716 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
3718 struct date d;
3719 getdate (&d);
3720 time_rec.tm_year = d.da_year - 1900;
3721 time_rec.tm_mon = d.da_mon - 1;
3722 time_rec.tm_mday = d.da_day;
3725 time_rec.tm_hour = t.ti_hour;
3726 time_rec.tm_min = t.ti_min;
3727 time_rec.tm_sec = t.ti_sec;
3729 tm = time_rec;
3730 tm.tm_gmtoff = dos_timezone_offset;
3732 tp->tv_sec = mktime (&tm); /* may modify tm */
3733 tp->tv_usec = t.ti_hund * (1000000 / 100);
3735 /* Ignore tzp; it's obsolescent. */
3736 return 0;
3739 #endif /* __DJGPP__ < 2 */
3742 * A list of unimplemented functions that we silently ignore.
3745 #if __DJGPP__ < 2
3746 unsigned alarm (s) unsigned s; {}
3747 fork () { return 0; }
3748 int kill (x, y) int x, y; { return -1; }
3749 nice (p) int p; {}
3750 void volatile pause () {}
3751 sigsetmask (x) int x; { return 0; }
3752 sigblock (mask) int mask; { return 0; }
3753 #endif
3755 void request_sigio (void) {}
3756 setpgrp () {return 0; }
3757 setpriority (x,y,z) int x,y,z; { return 0; }
3758 void unrequest_sigio (void) {}
3760 #if __DJGPP__ > 1
3762 #ifdef POSIX_SIGNALS
3764 /* Augment DJGPP library POSIX signal functions. This is needed
3765 as of DJGPP v2.01, but might be in the library in later releases. */
3767 #include <libc/bss.h>
3769 /* A counter to know when to re-initialize the static sets. */
3770 static int sigprocmask_count = -1;
3772 /* Which signals are currently blocked (initially none). */
3773 static sigset_t current_mask;
3775 /* Which signals are pending (initially none). */
3776 static sigset_t pending_signals;
3778 /* Previous handlers to restore when the blocked signals are unblocked. */
3779 typedef void (*sighandler_t)(int);
3780 static sighandler_t prev_handlers[320];
3782 /* A signal handler which just records that a signal occured
3783 (it will be raised later, if and when the signal is unblocked). */
3784 static void
3785 sig_suspender (signo)
3786 int signo;
3788 sigaddset (&pending_signals, signo);
3792 sigprocmask (how, new_set, old_set)
3793 int how;
3794 const sigset_t *new_set;
3795 sigset_t *old_set;
3797 int signo;
3798 sigset_t new_mask;
3800 /* If called for the first time, initialize. */
3801 if (sigprocmask_count != __bss_count)
3803 sigprocmask_count = __bss_count;
3804 sigemptyset (&pending_signals);
3805 sigemptyset (&current_mask);
3806 for (signo = 0; signo < 320; signo++)
3807 prev_handlers[signo] = SIG_ERR;
3810 if (old_set)
3811 *old_set = current_mask;
3813 if (new_set == 0)
3814 return 0;
3816 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
3818 errno = EINVAL;
3819 return -1;
3822 sigemptyset (&new_mask);
3824 /* DJGPP supports upto 320 signals. */
3825 for (signo = 0; signo < 320; signo++)
3827 if (sigismember (&current_mask, signo))
3828 sigaddset (&new_mask, signo);
3829 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
3831 sigaddset (&new_mask, signo);
3833 /* SIGKILL is silently ignored, as on other platforms. */
3834 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
3835 prev_handlers[signo] = signal (signo, sig_suspender);
3837 if (( how == SIG_UNBLOCK
3838 && sigismember (&new_mask, signo)
3839 && sigismember (new_set, signo))
3840 || (how == SIG_SETMASK
3841 && sigismember (&new_mask, signo)
3842 && !sigismember (new_set, signo)))
3844 sigdelset (&new_mask, signo);
3845 if (prev_handlers[signo] != SIG_ERR)
3847 signal (signo, prev_handlers[signo]);
3848 prev_handlers[signo] = SIG_ERR;
3850 if (sigismember (&pending_signals, signo))
3852 sigdelset (&pending_signals, signo);
3853 raise (signo);
3857 current_mask = new_mask;
3858 return 0;
3861 #else /* not POSIX_SIGNALS */
3863 sigsetmask (x) int x; { return 0; }
3864 sigblock (mask) int mask; { return 0; }
3866 #endif /* not POSIX_SIGNALS */
3867 #endif /* __DJGPP__ > 1 */
3869 #ifndef HAVE_SELECT
3870 #include "sysselect.h"
3872 #ifndef EMACS_TIME_ZERO_OR_NEG_P
3873 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
3874 ((long)(time).tv_sec < 0 \
3875 || ((time).tv_sec == 0 \
3876 && (long)(time).tv_usec <= 0))
3877 #endif
3879 /* This yields the rest of the current time slice to the task manager.
3880 It should be called by any code which knows that it has nothing
3881 useful to do except idle.
3883 I don't use __dpmi_yield here, since versions of library before 2.02
3884 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
3885 on some versions of Windows 9X. */
3887 void
3888 dos_yield_time_slice (void)
3890 _go32_dpmi_registers r;
3892 r.x.ax = 0x1680;
3893 r.x.ss = r.x.sp = r.x.flags = 0;
3894 _go32_dpmi_simulate_int (0x2f, &r);
3895 if (r.h.al == 0x80)
3896 errno = ENOSYS;
3899 /* Only event queue is checked. */
3900 /* We don't have to call timer_check here
3901 because wait_reading_process_input takes care of that. */
3903 sys_select (nfds, rfds, wfds, efds, timeout)
3904 int nfds;
3905 SELECT_TYPE *rfds, *wfds, *efds;
3906 EMACS_TIME *timeout;
3908 int check_input;
3909 struct time t;
3911 check_input = 0;
3912 if (rfds)
3914 check_input = FD_ISSET (0, rfds);
3915 FD_ZERO (rfds);
3917 if (wfds)
3918 FD_ZERO (wfds);
3919 if (efds)
3920 FD_ZERO (efds);
3922 if (nfds != 1)
3923 abort ();
3925 /* If we are looking only for the terminal, with no timeout,
3926 just read it and wait -- that's more efficient. */
3927 if (!timeout)
3929 while (!detect_input_pending ())
3931 dos_yield_time_slice ();
3934 else
3936 EMACS_TIME clnow, cllast, cldiff;
3938 gettime (&t);
3939 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
3941 while (!check_input || !detect_input_pending ())
3943 gettime (&t);
3944 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
3945 EMACS_SUB_TIME (cldiff, clnow, cllast);
3947 /* When seconds wrap around, we assume that no more than
3948 1 minute passed since last `gettime'. */
3949 if (EMACS_TIME_NEG_P (cldiff))
3950 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
3951 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
3953 /* Stop when timeout value crosses zero. */
3954 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
3955 return 0;
3956 cllast = clnow;
3957 dos_yield_time_slice ();
3961 FD_SET (0, rfds);
3962 return 1;
3964 #endif
3967 * Define overlaid functions:
3969 * chdir -> sys_chdir
3970 * tzset -> init_gettimeofday
3971 * abort -> dos_abort
3974 #ifdef chdir
3975 #undef chdir
3976 extern int chdir ();
3979 sys_chdir (path)
3980 const char* path;
3982 int len = strlen (path);
3983 char *tmp = (char *)path;
3985 if (*tmp && tmp[1] == ':')
3987 if (getdisk () != tolower (tmp[0]) - 'a')
3988 setdisk (tolower (tmp[0]) - 'a');
3989 tmp += 2; /* strip drive: KFS 1995-07-06 */
3990 len -= 2;
3993 if (len > 1 && (tmp[len - 1] == '/'))
3995 char *tmp1 = (char *) alloca (len + 1);
3996 strcpy (tmp1, tmp);
3997 tmp1[len - 1] = 0;
3998 tmp = tmp1;
4000 return chdir (tmp);
4002 #endif
4004 #ifdef tzset
4005 #undef tzset
4006 extern void tzset (void);
4008 void
4009 init_gettimeofday ()
4011 time_t ltm, gtm;
4012 struct tm *lstm;
4014 tzset ();
4015 ltm = gtm = time (NULL);
4016 ltm = mktime (lstm = localtime (&ltm));
4017 gtm = mktime (gmtime (&gtm));
4018 time_rec.tm_hour = 99; /* force gettimeofday to get date */
4019 time_rec.tm_isdst = lstm->tm_isdst;
4020 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
4022 #endif
4024 #ifdef abort
4025 #undef abort
4026 void
4027 dos_abort (file, line)
4028 char *file;
4029 int line;
4031 char buffer1[200], buffer2[400];
4032 int i, j;
4034 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
4035 for (i = j = 0; buffer1[i]; i++) {
4036 buffer2[j++] = buffer1[i];
4037 buffer2[j++] = 0x70;
4039 dosmemput (buffer2, j, (int)ScreenPrimary);
4040 ScreenSetCursor (2, 0);
4041 abort ();
4043 #else
4044 void
4045 abort ()
4047 dos_ttcooked ();
4048 ScreenSetCursor (10, 0);
4049 cputs ("\r\n\nEmacs aborted!\r\n");
4050 #if __DJGPP__ > 1
4051 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4052 if (screen_virtual_segment)
4053 dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
4054 /* Generate traceback, so we could tell whodunit. */
4055 signal (SIGINT, SIG_DFL);
4056 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
4057 #else /* __DJGPP_MINOR__ >= 2 */
4058 raise (SIGABRT);
4059 #endif /* __DJGPP_MINOR__ >= 2 */
4060 #endif
4061 exit (2);
4063 #endif
4065 /* The following two are required so that customization feature
4066 won't complain about unbound variables. */
4067 #ifndef HAVE_X_WINDOWS
4068 /* Search path for bitmap files (xfns.c). */
4069 Lisp_Object Vx_bitmap_file_path;
4070 #endif
4071 #ifndef subprocesses
4072 /* Nonzero means delete a process right away if it exits (process.c). */
4073 static int delete_exited_processes;
4074 #endif
4076 syms_of_msdos ()
4078 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
4079 staticpro (&recent_doskeys);
4080 #ifndef HAVE_X_WINDOWS
4081 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
4082 "List of directories to search for bitmap files for X.");
4083 Vx_bitmap_file_path = decode_env_path ((char *) 0, ".");
4085 /* The following three are from xfns.c: */
4086 Qbackground_color = intern ("background-color");
4087 staticpro (&Qbackground_color);
4088 Qforeground_color = intern ("foreground-color");
4089 staticpro (&Qforeground_color);
4091 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph,
4092 "*Glyph to display instead of chars not supported by current codepage.\n\
4094 This variable is used only by MSDOS terminals.");
4095 Vdos_unsupported_char_glyph = '\177';
4096 #endif
4097 #ifndef subprocesses
4098 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
4099 "*Non-nil means delete processes immediately when they exit.\n\
4100 nil means don't delete them until `list-processes' is run.");
4101 delete_exited_processes = 0;
4102 #endif
4104 defsubr (&Srecent_doskeys);
4105 defsubr (&Smsdos_long_file_names);
4106 defsubr (&Smsdos_downcase_filename);
4109 #endif /* MSDOS */