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