xref: /openbsd/gnu/usr.bin/texinfo/info/pcterm.c (revision a1acfa9b)
1 /* pcterm.c -- How to handle the PC terminal for Info under MS-DOS/MS-Windows.
2    $Id: pcterm.c,v 1.1.1.3 2006/07/17 16:03:45 espie Exp $
3 
4    Copyright (C) 1998, 1999, 2003, 2004 Free Software Foundation, Inc.
5 
6    This program 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    This program 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 along
17    with this program; if not, write to the Free Software Foundation, Inc.,
18    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19 
20 
21 /* WARNING WARNING WARNING!!!
22    This probably won't work as is with anything but DJGPP!  However, Borland
23    should come close, and other PC compilers will need minor modifications.  */
24 
25 /* intl/libintl.h defines a macro `gettext' which
26    conflicts with conio.h header.  */
27 #ifdef gettext
28 # undef gettext
29 # define gettext _gettext
30 #endif
31 
32 #include <pc.h>
33 #include <keys.h>
34 #include <conio.h>
35 
36 #include "variables.h"
37 
38 extern int speech_friendly;	/* defined in info.c */
39 
40 /* **************************************************************** */
41 /*                                                                  */
42 /*                PC Terminal Output Functions                      */
43 /*                                                                  */
44 /* **************************************************************** */
45 
46 static struct text_info outside_info;  /* holds screen params outside Info */
47 static unsigned char    norm_attr, inv_attr;
48 
49 static unsigned const char * find_sequence (int);
50 
51 /* Turn on reverse video. */
52 static void
pc_begin_inverse(void)53 pc_begin_inverse (void)
54 {
55   textattr (inv_attr);
56 }
57 
58 /* Turn off reverse video. */
59 static void
pc_end_inverse(void)60 pc_end_inverse (void)
61 {
62   textattr (norm_attr);
63 }
64 
65 /* Move the cursor up one line. */
66 static void
pc_up_line(void)67 pc_up_line (void)
68 {
69   int x, y;
70   ScreenGetCursor (&y, &x);
71   ScreenSetCursor (MAX (y-1, 0), x);
72 }
73 
74 /* Move the cursor down one line. */
75 static void
pc_down_line(void)76 pc_down_line (void)
77 {
78   int x, y;
79   ScreenGetCursor (&y, &x);
80   ScreenSetCursor (MIN (screenheight-1, y+1), x);
81 }
82 
83 /* Clear the entire terminal screen. */
84 static void
pc_clear_screen(void)85 pc_clear_screen (void)
86 {
87   ScreenClear ();
88 }
89 
90 /* Clear from the current position of the cursor to the end of the line. */
91 static void
pc_clear_to_eol(void)92 pc_clear_to_eol (void)
93 {
94   clreol (); /* perhaps to be replaced by a loop */
95 }
96 
97 /* Set the global variables SCREENWIDTH and SCREENHEIGHT. */
98 static void
pc_get_screen_size(void)99 pc_get_screen_size(void)
100 {
101   /* Current screen dimensions are the default.  */
102   if (!outside_info.screenheight)	/* paranoia */
103     gettextinfo (&outside_info);
104   screenwidth  = outside_info.screenwidth;
105   screenheight = outside_info.screenheight;
106 
107   /* Environment variable "LINES" overrides the default.  */
108   if (getenv ("LINES") != NULL)
109     screenheight = atoi (getenv ("LINES"));
110 
111   /* Environment variable "INFO_LINES" overrides "LINES".  */
112   if (getenv ("INFO_LINES") != NULL)
113     screenheight = atoi (getenv ("INFO_LINES"));
114 }
115 
116 /* Move the cursor to the terminal location of X and Y. */
117 static void
pc_goto_xy(x,y)118 pc_goto_xy (x, y)
119      int x, y;
120 {
121   ScreenSetCursor (y, x); /* yes, pc.h says ScreenSetCursor (row, column) !! */
122 }
123 
124 /* Print STRING to the terminal at the current position. */
125 static void
pc_put_text(string)126 pc_put_text (string)
127      char *string;
128 {
129   if (speech_friendly)
130     fputs (string, stdout);
131   else
132     cputs (string);
133 }
134 
135 /* Ring the terminal bell.  The bell is rung visibly if the terminal is
136    capable of doing that, and if terminal_use_visible_bell_p is non-zero. */
137 static void
pc_ring_bell(void)138 pc_ring_bell(void)
139 {
140   if (terminal_has_visible_bell_p && terminal_use_visible_bell_p)
141     ScreenVisualBell ();
142   else
143     {
144       printf ("%c",'\a');
145       fflush (stdout);
146     }
147 }
148 
149 /* Print NCHARS from STRING to the terminal at the current position. */
150 static void
pc_write_chars(string,nchars)151 pc_write_chars (string, nchars)
152     char *string;
153     int nchars;
154 {
155   if (!nchars)
156     return;
157 
158   if (speech_friendly)
159     printf ("%.*s",nchars, string);
160   else
161     cprintf ("%..*s",nchars, string);
162 }
163 
164 /* Scroll an area of the terminal from START to (and excluding) END,
165    AMOUNT lines.  If AMOUNT is negative, the lines are scrolled
166    towards the top of the screen, else they are scrolled towards the
167    bottom of the screen.  The lines of the old region which do not
168    overlap the new region are cleared, to mimic terminal operation.  */
169 static void
pc_scroll_terminal(start,end,amount)170 pc_scroll_terminal (start, end, amount)
171     int start, end, amount;
172 {
173   int line_to_clear = amount > 0 ? start : end + amount;
174 
175   /* Move the text.  Note that `movetext' expects 1-based coordinates.  */
176   movetext (1, start + 1, ScreenCols (), end, 1, start + amount + 1);
177 
178   /* Now clear the lines which were left unoccupied.  */
179   if (amount < 0)
180     amount = -amount;
181   while (amount--)
182     {
183       ScreenSetCursor (line_to_clear++, 0);
184       clreol ();
185     }
186 }
187 
188 /* Put the screen in the video mode and colors which Info will use.
189    Prepare to start using the terminal to read characters singly.  */
190 static void
pc_prep_terminal(void)191 pc_prep_terminal (void)
192 {
193   int tty;
194 
195   /* Do not set screen height if we already have it, because
196      doing so erases the screen.  */
197   if (screenheight != ScreenRows ())
198     _set_screen_lines (screenheight);
199 
200   /* Don't fail if they asked for screen dimensions that their
201      hardware cannot support.  */
202   screenheight = ScreenRows ();
203   screenwidth  = ScreenCols ();
204 
205   /* Try setting the colors user asked for.  */
206   textattr (norm_attr);
207   ScreenClear ();
208 
209   /* Switch console reads to binary mode.  */
210   tty = fileno (stdin);
211 #ifdef __DJGPP__
212   setmode (tty, O_BINARY);
213   __djgpp_set_ctrl_c (1);	/* re-enable SIGINT generation by Ctrl-C */
214 #endif
215 }
216 
217 /* Restore the tty settings back to what they were before we started using
218    this terminal. */
219 static void
pc_unprep_terminal(void)220 pc_unprep_terminal (void)
221 {
222   int tty;
223 
224   textattr (outside_info.normattr);
225 
226   /* Do not set screen height if we already have it, because
227      doing so erases the screen.  */
228   if (outside_info.screenheight != ScreenRows ())
229     {
230       _set_screen_lines (outside_info.screenheight);
231       textmode (LASTMODE);
232     }
233   else
234     pc_clear_to_eol ();	/* for text attributes to really take effect */
235 
236   /* Switch back to text mode on stdin.  */
237   tty = fileno (stdin);
238 #ifdef __DJGPP__
239   setmode (tty, O_TEXT);
240 #endif
241 }
242 
243 /* Initialize the terminal which is known as TERMINAL_NAME.  If this
244    terminal doesn't have cursor addressability, `terminal_is_dumb_p'
245    becomes nonzero.  The variables SCREENHEIGHT and SCREENWIDTH are set
246    to the dimensions that this terminal actually has.  The variable
247    TERMINAL_HAS_META_P becomes nonzero if this terminal supports a Meta
248    key.  Finally, the terminal screen is cleared. */
249 static void
pc_initialize_terminal(term_name)250 pc_initialize_terminal (term_name)
251     char *term_name;
252 {
253   char *info_colors;
254 
255   if (!term_name)
256     {
257       term_name = getenv ("TERM");
258       if (!term_name)
259 	term_name = "pc-dos";	/* ``what's in a name?'' */
260     }
261 
262   /* Get current video information, to be restored later.  */
263   if (outside_info.screenwidth == 0)
264     gettextinfo (&outside_info);
265 
266   /* Current screen colors are the default.  */
267   norm_attr    = outside_info.normattr;
268   inv_attr     = (((outside_info.normattr &    7) << 4) |
269                   ((outside_info.normattr & 0x7f) >> 4));
270 
271   /* Does the user want non-default colors?  */
272   info_colors = getenv ("INFO_COLORS");
273   if ((info_colors != (char *)0) && !speech_friendly)
274     {
275       /* Decode a color from a string descriptor.
276 	 The descriptor string is a sequence of color specifiers separated
277 	 by a non-numeric character.  Each color specifier should represent
278 	 a small integer which fits into an unsigned char, and can be given
279 	 in any base supported by strtoul.  Examples of valid descriptors:
280 
281 		"10 31"
282 		"0x13/0x45"
283 		"007.077"
284 
285 	The separator between two color specifiers can be any character which
286 	cannot be used in a printed representation of an integer number.  */
287       char *endp;
288       unsigned long color_desc = strtoul (info_colors, &endp, 0);
289 
290       if (color_desc <= UCHAR_MAX)
291 	{
292 	  norm_attr = (unsigned char)color_desc;
293 	  color_desc = strtoul (endp + 1, &endp, 0);
294 	  if (color_desc <= UCHAR_MAX)
295 	    inv_attr = (unsigned char)color_desc;
296 	}
297     }
298 
299   /* We can scroll.  */
300   terminal_can_scroll = 1;
301 
302   /* We know how to produce a visible bell, if somebody's looking...  */
303   if (!speech_friendly)
304     terminal_has_visible_bell_p = 1;
305 
306   /* We have a Meta key.  */
307   terminal_has_meta_p = 1;
308 
309   /* We are *certainly* NOT dumb!  */
310   terminal_is_dumb_p = 0;
311 
312   pc_get_screen_size ();
313 
314   /* Store the arrow keys.  */
315   term_ku = (char *)find_sequence (K_Up);
316   term_kd = (char *)find_sequence (K_Down);
317   term_kr = (char *)find_sequence (K_Right);
318   term_kl = (char *)find_sequence (K_Left);
319 
320   term_kP = (char *)find_sequence (K_PageUp);
321   term_kN = (char *)find_sequence (K_PageDown);
322 
323 #if defined(INFOKEY)
324   term_kh = (char *)find_sequence (K_Home);
325   term_ke = (char *)find_sequence (K_End);
326   term_ki = (char *)find_sequence (K_Insert);
327   term_kx = (char *)find_sequence (K_Delete);
328 #endif
329 
330   /* Set all the hooks to our PC-specific functions.  */
331   terminal_begin_inverse_hook       = pc_begin_inverse;
332   terminal_end_inverse_hook         = pc_end_inverse;
333   terminal_prep_terminal_hook       = pc_prep_terminal;
334   terminal_unprep_terminal_hook     = pc_unprep_terminal;
335   terminal_up_line_hook             = pc_up_line;
336   terminal_down_line_hook           = pc_down_line;
337   terminal_clear_screen_hook        = pc_clear_screen;
338   terminal_clear_to_eol_hook        = pc_clear_to_eol;
339   terminal_get_screen_size_hook     = pc_get_screen_size;
340   terminal_goto_xy_hook             = pc_goto_xy;
341   terminal_put_text_hook            = pc_put_text;
342   terminal_ring_bell_hook           = pc_ring_bell;
343   terminal_write_chars_hook         = pc_write_chars;
344   terminal_scroll_terminal_hook     = pc_scroll_terminal;
345 }
346 
347 /* **************************************************************** */
348 /*                                                                  */
349 /*            How to Read Characters From the PC Terminal           */
350 /*                                                                  */
351 /* **************************************************************** */
352 
353 /* This will most certainly work ONLY with DJGPP.  */
354 #ifdef __DJGPP__
355 
356 #include <errno.h>
357 #include <sys/fsext.h>
358 #include <dpmi.h>
359 
360 /* Translation table for some special keys.
361    Arrow keys which are standard on other keyboards are translated into
362    standard ESC-sequences, in case somebody rebinds the simple keys
363    (like C-f, C-b, C-n, etc.).
364 
365    The strange "\033\061" prefix in some keys is a numeric argument of
366    one, which means ``do the next command once''.  It is here so that
367    when the according PC key is pressed in the middle of an incremental
368    search, Info doesn't see just an ASCII character like `n' or `B',
369    and doesn't add it to the search string; instead, it will exit the
370    incremental search and then perform the command.  */
371 static struct
372 {
373   int inkey;
374   unsigned char const * const sequence;
375 } DJGPP_keytab[] = {		   /* these are for moving between nodes... */
376   {K_Control_PageDown,  "\033\061n"},
377   {K_Control_PageUp,    "\033\061p"},
378   {K_Control_Up,        "\033\061u"},
379   {K_Control_Down,      "\033\061m"},
380   {K_Control_Center,    "\033\061l"},
381 
382 #if defined(INFOKEY)
383   {K_Home,              "\033[H"}, /* ...and these are for moving IN a node */
384   {K_End,               "\033[F"}, /* they're Numeric-Keypad-Keys, so       */
385 #else
386   {K_Home,              "\001"},
387   {K_End,               "\005"},
388 #endif
389   {K_Left,              "\033[D"}, /* NUMLOCK should be off !!              */
390   {K_Right,             "\033[C"},
391   {K_Down,              "\033[B"},
392   {K_Up,                "\033[A"},
393   {K_PageDown,          "\033[G"},
394   {K_PageUp,            "\033[I"},
395   {K_Control_Left,      "\033b"},
396   {K_Control_Right,     "\033f"},
397   {K_Control_Home,      "\033<"},
398   {K_Control_End,       "\033>"},
399 
400 #if defined(INFOKEY)
401   {K_EHome,             "\033[H"}, /* these are also for moving IN a node */
402   {K_EEnd,              "\033[F"}, /* they're the "extended" (Grey) keys  */
403 #else
404   {K_EHome,             "\001"},
405   {K_EEnd,              "\005"},
406 #endif
407   {K_ELeft,             "\033[D"},
408   {K_ERight,            "\033[C"},
409   {K_EDown,             "\033[B"},
410   {K_EUp,               "\033[A"},
411   {K_EPageDown,         "\033[G"},
412   {K_EPageUp,           "\033[I"},
413   {K_Control_ELeft,     "\033b"},
414   {K_Control_ERight,    "\033f"},
415   {K_Control_EHome,     "\033<"},
416   {K_Control_EEnd,      "\033>"},
417 
418   {K_BackTab,           "\033\011"},
419   {K_F1,                "\10"},    /* YEAH, gimme that good old F-one-thing */
420   {K_Delete,            "\177"},   /* to make Kp-Del be DEL (0x7f)          */
421   {K_EDelete,           "\177"},   /* to make Delete be DEL (0x7f)          */
422 #if defined(INFOKEY)
423   {K_Insert,            "\033[L"},
424   {K_EInsert,           "\033[L"},
425 #endif
426 
427   /* These are here to map more Alt-X keys to ESC X sequences.  */
428   {K_Alt_Q,             "\033q"},
429   {K_Alt_W,             "\033w"},
430   {K_Alt_E,             "\033e"},
431   {K_Alt_R,             "\033r"},
432   {K_Alt_T,             "\033t"},
433   {K_Alt_Y,             "\033y"},
434   {K_Alt_U,             "\033u"},
435   {K_Alt_I,             "\033i"},
436   {K_Alt_O,             "\033o"},
437   {K_Alt_P,             "\033p"},
438   {K_Alt_LBracket,      "\033["},
439   {K_Alt_RBracket,      "\033]"},
440   {K_Alt_Return,        "\033\015"},
441   {K_Alt_A,             "\033a"},
442   {K_Alt_S,             "\033s"},
443   {K_Alt_D,             "\033d"},
444   {K_Alt_F,             "\033f"},
445   {K_Alt_G,             "\033g"},
446   {K_Alt_H,             "\033h"},
447   {K_Alt_J,             "\033j"},
448   {K_Alt_K,             "\033k"},
449   {K_Alt_L,             "\033l"},
450   {K_Alt_Semicolon,     "\033;"},
451   {K_Alt_Quote,         "\033'"},
452   {K_Alt_Backquote,     "\033`"},
453   {K_Alt_Backslash,     "\033\\"},
454   {K_Alt_Z,             "\033z"},
455   {K_Alt_X,             "\033x"},
456   {K_Alt_C,             "\033c"},
457   {K_Alt_V,             "\033v"},
458   {K_Alt_B,             "\033b"},
459   {K_Alt_N,             "\033n"},
460   {K_Alt_M,             "\033m"},
461   {K_Alt_Comma,         "\033<"}, /* our reader cannot distinguish between */
462   {K_Alt_Period,        "\033>"}, /* Alt-. and Alt->, so we cheat a little */
463   {K_Alt_Slash,         "\033?"}, /* ditto, to get Alt-?                   */
464   {K_Alt_Backspace,     "\033\177"}, /* M-DEL, to delete word backwards */
465   {K_Alt_1,             "\033\061"},
466   {K_Alt_2,             "\033\062"},
467   {K_Alt_3,             "\033\063"},
468   {K_Alt_4,             "\033\064"},
469   {K_Alt_5,             "\033\065"},
470   {K_Alt_6,             "\033\066"},
471   {K_Alt_7,             "\033\067"},
472   {K_Alt_8,             "\033\070"},
473   {K_Alt_9,             "\033\071"},
474   {K_Alt_0,             "\033\060"},
475   {K_Alt_Dash,          "\033\055"},
476   {K_Alt_EPageUp,       "\033\033[I"},
477   {K_Alt_EPageDown,     "\033\033[G"},
478   {K_Alt_Equals,        "\033\075"},
479   {K_Alt_EDelete,       "\033\177"},
480   {K_Alt_Tab,           "\033\011"},
481   {0, 0}
482 };
483 
484 /* Given a key, return the sequence of characters which
485    our keyboard driver generates.  */
486 static unsigned const char *
find_sequence(int key)487 find_sequence (int key)
488 {
489   int i;
490 
491   for (i = 0; DJGPP_keytab[i].inkey; i++)
492     if (key == DJGPP_keytab[i].inkey)
493       return DJGPP_keytab[i].sequence;
494 
495   return (unsigned const char *)NULL;
496 }
497 
498 /* Return zero if a key is pending in the
499    keyboard buffer, non-zero otherwise.  */
500 static int
kbd_buffer_empty(void)501 kbd_buffer_empty (void)
502 {
503   __dpmi_regs r;
504   int retval;
505 
506   r.h.ah = 0x11;	/* Get enhanced keyboard status */
507   __dpmi_int (0x16, &r);
508 
509   /* If the keyboard buffer is empty, the Zero Flag will be set.  */
510   return (r.x.flags & 0x40) == 0x40;
511 }
512 
513 /* The buffered characters pending to be read.
514    Actually, Info usually reads a single character, but when we
515    translate a key into a sequence of characters, we keep them here.  */
516 static unsigned char buffered[512];
517 
518 /* Index of the next buffered character to be returned.  */
519 static int buf_idx;
520 
521 /* Return the number of characters waiting to be read.  */
522 long
pc_term_chars_avail(void)523 pc_term_chars_avail (void)
524 {
525   if (buf_idx >= sizeof (buffered)) /* paranoia */
526     {
527       buf_idx = 0;
528       buffered[buf_idx] = '\0';
529       return 0;
530     }
531   else
532     return (long)strlen (buffered + buf_idx);
533 }
534 
535 /* Our special terminal keyboard reader.  It will be called by
536    low-level libc functions when the application calls `read' or
537    the ANSI-standard stream-oriented read functions.  If the
538    caller wants to read the terminal, we redirect the call to
539    the BIOS keyboard functions, since that lets us recognize more
540    keys than DOS does.  */
541 static int
keyboard_read(__FSEXT_Fnumber func,int * retval,va_list rest_args)542 keyboard_read (__FSEXT_Fnumber func, int *retval, va_list rest_args)
543 {
544   /* When we are called, REST_ARGS are: file_descriptor, buf, nbytes.  */
545   unsigned char *buf;
546   size_t nbytes, nread = 0;
547   int fd = va_arg (rest_args, int);
548 
549   /* Is this call for us?  */
550   if (func != __FSEXT_read || !isatty (fd))
551     return 0;	/* and the usual DOS call will be issued */
552 
553   buf = va_arg (rest_args, unsigned char *);
554   nbytes = va_arg (rest_args, size_t);
555 
556   if (!buf)
557     {
558       errno = EINVAL;
559       *retval = -1;
560       return 1;
561     }
562   if (!nbytes)
563     {
564       *retval = 0;
565       return 1;
566     }
567 
568   /* Loop here until enough bytes has been read.  */
569   do
570     {
571       int key;
572 
573       /* If any ``buffered characters'' are left, return as much
574 	 of them as the caller wanted.  */
575       while (buffered[buf_idx] && nbytes)
576 	{
577 	  *buf++ = buffered[buf_idx++];
578 	  nread++;
579 	  nbytes--;
580 	}
581 
582       if (nbytes <= 0)
583 	break;
584 
585       /* Wait for another key.
586 	 We do that in a busy-waiting loop so we don't get parked
587 	 inside a BIOS call, which will effectively disable signals.
588          While we wait for them to type something, we repeatedly
589          release the rest of our time slice, so that other programs
590          in a multitasking environment, such as Windows, get more cycles.  */
591       while (kbd_buffer_empty ())
592 	__dpmi_yield ();
593 
594       key = getxkey ();
595 
596       /* Translate the key if necessary.
597 	 Untranslated non-ASCII keys are silently ignored.  */
598       if ((key & 0x300) != 0)
599 	{
600 	  unsigned char const * key_sequence = find_sequence (key);
601 
602 	  if (key_sequence != NULL)
603 	    {
604 	      strcpy (buffered, key_sequence);
605 	      buf_idx = 0;
606 	    }
607 	}
608       else if (key == K_Control_Z)
609 	raise (SIGUSR1);	/* we don't have SIGTSTP, so simulate it */
610       else if (key <= 0xff)
611 	{
612 	  *buf++ = key;
613 	  nbytes--;
614 	  nread++;
615 	}
616     }
617   while (nbytes > 0);
618 
619   *retval = nread;
620   return 1;	/* meaning that we handled the call */
621 }
622 
623 /* Install our keyboard handler.
624    This is called by the startup code before `main'.  */
625 static void __attribute__((constructor))
install_keyboard_handler(void)626 install_keyboard_handler (void)
627 {
628   __FSEXT_set_function (fileno (stdin), keyboard_read);
629 
630   /* We need to set this single hook here; the rest
631      will be set by pc_initialize_terminal when it is called.  */
632   terminal_initialize_terminal_hook = pc_initialize_terminal;
633 }
634 
635 #endif /* __DJGPP__ */
636 
637 /* **************************************************************** */
638 /*                                                                  */
639 /*                Emulation of SIGTSTP on Ctrl-Z                    */
640 /*                                                                  */
641 /* **************************************************************** */
642 
643 #include <limits.h>
644 #include "signals.h"
645 #include "session.h"
646 
647 #ifndef PATH_MAX
648 # define PATH_MAX 512
649 #endif
650 
651 /* Effectively disable signals which aren't defined
652    (assuming no signal can ever be zero).
653    SIGINT is ANSI, so we expect it to be always defined.  */
654 #ifndef SIGUSR1
655 # define SIGUSR1 0
656 #endif
657 #ifndef SIGQUIT
658 # define SIGQUIT 0
659 #endif
660 
661 int
kill(pid_t pid,int sig)662 kill (pid_t pid, int sig)
663 {
664   static char interrupted_msg[] = "Interrupted\r\n";
665   static char stopped_msg[] = "Stopped.  Type `exit RET' to return.\r\n";
666   char cwd[PATH_MAX + 1];
667 
668   if (pid == getpid ()
669       || pid == 0
670       || pid == -1
671       || pid == -getpid ())
672     {
673       switch (sig)
674 	{
675 	RETSIGTYPE (*old_INT)(int), (*old_QUIT)(int);
676 
677 	case SIGINT:
678 #ifdef __DJGPP__
679 	  /* If SIGINT was generated by a readable key, we want to remove
680 	     it from the PC keyboard buffer, so that DOS and other
681 	     programs never see it.  DJGPP signal-handling mechanism
682 	     doesn't remove the INT key from the keyboard buffer.  */
683 	  if (!kbd_buffer_empty ())
684 	    getxkey ();
685 #endif
686 	  pc_write_chars (interrupted_msg, sizeof (interrupted_msg) - 1);
687 	  xexit (1);
688 	case SIGUSR1:
689 	  /* Simulate SIGTSTP by invoking a subsidiary shell.  */
690 	  pc_goto_xy (0, outside_info.screenheight - 1);
691 	  pc_clear_to_eol ();
692 	  pc_write_chars (stopped_msg, sizeof (stopped_msg) - 1);
693 
694 	  /* The child shell can change the working directory, so
695 	     we need to save and restore it, since it is global.  */
696 	  if (!getcwd (cwd, PATH_MAX)) /* should never happen */
697 	    cwd[0] = '\0';
698 
699 	  /* We don't want to get fatal signals while the subshell runs.  */
700 	  old_INT = signal (SIGINT, SIG_IGN);
701 	  old_QUIT = signal (SIGQUIT, SIG_IGN);
702 	  system ("");
703 	  if (*cwd)
704 	    chdir (cwd);
705 	  signal (SIGINT, old_INT);
706 	  signal (SIGQUIT, old_QUIT);
707 	  break;
708 	default:
709 	  if (sig)
710 	    raise (sig);
711 	  break;
712 	}
713       return 0;
714     }
715   else
716     return -1;
717 }
718 
719 /* These should never be called, but they make the linker happy.  */
720 
tputs(char * a,int b,int (* c)())721 void       tputs (char *a, int b, int (*c)())
722 {
723   perror ("tputs");
724 }
725 
tgoto(char * a,int b,int c)726 char*     tgoto (char*a, int b, int c)
727 {
728   perror ("tgoto"); return 0; /* here and below, added dummy retvals */
729 }
730 
tgetnum(char * a)731 int       tgetnum (char*a)
732 {
733   perror ("tgetnum"); return 0;
734 }
735 
tgetflag(char * a)736 int       tgetflag (char*a)
737 {
738   perror ("tgetflag"); return 0;
739 }
740 
tgetstr(char * a,char ** b)741 char*     tgetstr (char *a, char **b)
742 {
743   perror ("tgetstr"); return 0;
744 }
745 
tgetent(char * a,char * b)746 int       tgetent (char*a, char*b)
747 {
748   perror ("tgetent"); return 0;
749 }
750 
tcgetattr(int fildes,struct termios * termios_p)751 int	tcgetattr(int fildes, struct termios *termios_p)
752 {
753   perror ("tcgetattr"); return 0;
754 }
755 
tcsetattr(int fd,int opt_actions,const struct termios * termios_p)756 int	tcsetattr(int fd, int opt_actions, const struct termios *termios_p)
757 {
758   perror ("tcsetattr"); return 0;
759 }
760