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