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