Back to index

tetex-bin  3.0
pcterm.c
Go to the documentation of this file.
00001 /* pcterm.c -- How to handle the PC terminal for Info under MS-DOS/MS-Windows.
00002    $Id: pcterm.c,v 1.4 2004/04/11 17:56:46 karl Exp $
00003 
00004    Copyright (C) 1998, 1999, 2003, 2004 Free Software Foundation, Inc.
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2, or (at your option)
00009    any later version.
00010 
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015 
00016    You should have received a copy of the GNU General Public License along
00017    with this program; if not, write to the Free Software Foundation, Inc.,
00018    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
00019 
00020 
00021 /* WARNING WARNING WARNING!!!
00022    This probably won't work as is with anything but DJGPP!  However, Borland
00023    should come close, and other PC compilers will need minor modifications.  */
00024 
00025 /* intl/libintl.h defines a macro `gettext' which
00026    conflicts with conio.h header.  */
00027 #ifdef gettext
00028 # undef gettext
00029 # define gettext _gettext
00030 #endif
00031 
00032 #include <pc.h>
00033 #include <keys.h>
00034 #include <conio.h>
00035 
00036 #include "variables.h"
00037 
00038 extern int speech_friendly; /* defined in info.c */
00039 
00040 /* **************************************************************** */
00041 /*                                                                  */
00042 /*                PC Terminal Output Functions                      */
00043 /*                                                                  */
00044 /* **************************************************************** */
00045 
00046 static struct text_info outside_info;  /* holds screen params outside Info */
00047 static unsigned char    norm_attr, inv_attr;
00048 
00049 static unsigned const char * find_sequence (int);
00050 
00051 /* Turn on reverse video. */
00052 static void
00053 pc_begin_inverse (void)
00054 {
00055   textattr (inv_attr);
00056 }
00057 
00058 /* Turn off reverse video. */
00059 static void
00060 pc_end_inverse (void)
00061 {
00062   textattr (norm_attr);
00063 }
00064 
00065 /* Move the cursor up one line. */
00066 static void
00067 pc_up_line (void)
00068 {
00069   int x, y;
00070   ScreenGetCursor (&y, &x);
00071   ScreenSetCursor (MAX (y-1, 0), x);
00072 }
00073 
00074 /* Move the cursor down one line. */
00075 static void
00076 pc_down_line (void)
00077 {
00078   int x, y;
00079   ScreenGetCursor (&y, &x);
00080   ScreenSetCursor (MIN (screenheight-1, y+1), x);
00081 }
00082 
00083 /* Clear the entire terminal screen. */
00084 static void
00085 pc_clear_screen (void)
00086 {
00087   ScreenClear ();
00088 }
00089 
00090 /* Clear from the current position of the cursor to the end of the line. */
00091 static void
00092 pc_clear_to_eol (void)
00093 {
00094   clreol (); /* perhaps to be replaced by a loop */
00095 }
00096 
00097 /* Set the global variables SCREENWIDTH and SCREENHEIGHT. */
00098 static void
00099 pc_get_screen_size(void)
00100 {
00101   /* Current screen dimensions are the default.  */
00102   if (!outside_info.screenheight)  /* paranoia */
00103     gettextinfo (&outside_info);
00104   screenwidth  = outside_info.screenwidth;
00105   screenheight = outside_info.screenheight;
00106 
00107   /* Environment variable "LINES" overrides the default.  */
00108   if (getenv ("LINES") != NULL)
00109     screenheight = atoi (getenv ("LINES"));
00110 
00111   /* Environment variable "INFO_LINES" overrides "LINES".  */
00112   if (getenv ("INFO_LINES") != NULL)
00113     screenheight = atoi (getenv ("INFO_LINES"));
00114 }
00115 
00116 /* Move the cursor to the terminal location of X and Y. */
00117 static void
00118 pc_goto_xy (x, y)
00119      int x, y;
00120 {
00121   ScreenSetCursor (y, x); /* yes, pc.h says ScreenSetCursor (row, column) !! */
00122 }
00123 
00124 /* Print STRING to the terminal at the current position. */
00125 static void
00126 pc_put_text (string)
00127      char *string;
00128 {
00129   if (speech_friendly)
00130     fputs (string, stdout);
00131   else
00132     cputs (string);
00133 }
00134 
00135 /* Ring the terminal bell.  The bell is rung visibly if the terminal is
00136    capable of doing that, and if terminal_use_visible_bell_p is non-zero. */
00137 static void
00138 pc_ring_bell(void)
00139 {
00140   if (terminal_has_visible_bell_p && terminal_use_visible_bell_p)
00141     ScreenVisualBell ();
00142   else
00143     {
00144       printf ("%c",'\a');
00145       fflush (stdout);
00146     }
00147 }
00148 
00149 /* Print NCHARS from STRING to the terminal at the current position. */
00150 static void
00151 pc_write_chars (string, nchars)
00152     char *string;
00153     int nchars;
00154 {
00155   if (!nchars)
00156     return;
00157 
00158   if (speech_friendly)
00159     printf ("%.*s",nchars, string);
00160   else
00161     cprintf ("%..*s",nchars, string);
00162 }
00163 
00164 /* Scroll an area of the terminal from START to (and excluding) END,
00165    AMOUNT lines.  If AMOUNT is negative, the lines are scrolled
00166    towards the top of the screen, else they are scrolled towards the
00167    bottom of the screen.  The lines of the old region which do not
00168    overlap the new region are cleared, to mimic terminal operation.  */
00169 static void
00170 pc_scroll_terminal (start, end, amount)
00171     int start, end, amount;
00172 {
00173   int line_to_clear = amount > 0 ? start : end + amount;
00174 
00175   /* Move the text.  Note that `movetext' expects 1-based coordinates.  */
00176   movetext (1, start + 1, ScreenCols (), end, 1, start + amount + 1);
00177 
00178   /* Now clear the lines which were left unoccupied.  */
00179   if (amount < 0)
00180     amount = -amount;
00181   while (amount--)
00182     {
00183       ScreenSetCursor (line_to_clear++, 0);
00184       clreol ();
00185     }
00186 }
00187 
00188 /* Put the screen in the video mode and colors which Info will use.
00189    Prepare to start using the terminal to read characters singly.  */
00190 static void
00191 pc_prep_terminal (void)
00192 {
00193   int tty;
00194 
00195   /* Do not set screen height if we already have it, because
00196      doing so erases the screen.  */
00197   if (screenheight != ScreenRows ())
00198     _set_screen_lines (screenheight);
00199 
00200   /* Don't fail if they asked for screen dimensions that their
00201      hardware cannot support.  */
00202   screenheight = ScreenRows ();
00203   screenwidth  = ScreenCols ();
00204 
00205   /* Try setting the colors user asked for.  */
00206   textattr (norm_attr);
00207   ScreenClear ();
00208 
00209   /* Switch console reads to binary mode.  */
00210   tty = fileno (stdin);
00211 #ifdef __DJGPP__
00212   setmode (tty, O_BINARY);
00213   __djgpp_set_ctrl_c (1);   /* re-enable SIGINT generation by Ctrl-C */
00214 #endif
00215 }
00216 
00217 /* Restore the tty settings back to what they were before we started using
00218    this terminal. */
00219 static void
00220 pc_unprep_terminal (void)
00221 {
00222   int tty;
00223 
00224   textattr (outside_info.normattr);
00225 
00226   /* Do not set screen height if we already have it, because
00227      doing so erases the screen.  */
00228   if (outside_info.screenheight != ScreenRows ())
00229     {
00230       _set_screen_lines (outside_info.screenheight);
00231       textmode (LASTMODE);
00232     }
00233   else
00234     pc_clear_to_eol ();     /* for text attributes to really take effect */
00235 
00236   /* Switch back to text mode on stdin.  */
00237   tty = fileno (stdin);
00238 #ifdef __DJGPP__
00239   setmode (tty, O_TEXT);
00240 #endif
00241 }
00242 
00243 /* Initialize the terminal which is known as TERMINAL_NAME.  If this
00244    terminal doesn't have cursor addressability, `terminal_is_dumb_p'
00245    becomes nonzero.  The variables SCREENHEIGHT and SCREENWIDTH are set
00246    to the dimensions that this terminal actually has.  The variable
00247    TERMINAL_HAS_META_P becomes nonzero if this terminal supports a Meta
00248    key.  Finally, the terminal screen is cleared. */
00249 static void
00250 pc_initialize_terminal (term_name)
00251     char *term_name;
00252 {
00253   char *info_colors;
00254 
00255   if (!term_name)
00256     {
00257       term_name = getenv ("TERM");
00258       if (!term_name)
00259        term_name = "pc-dos";       /* ``what's in a name?'' */
00260     }
00261 
00262   /* Get current video information, to be restored later.  */
00263   if (outside_info.screenwidth == 0)
00264     gettextinfo (&outside_info);
00265 
00266   /* Current screen colors are the default.  */
00267   norm_attr    = outside_info.normattr;
00268   inv_attr     = (((outside_info.normattr &    7) << 4) |
00269                   ((outside_info.normattr & 0x7f) >> 4));
00270 
00271   /* Does the user want non-default colors?  */
00272   info_colors = getenv ("INFO_COLORS");
00273   if ((info_colors != (char *)0) && !speech_friendly)
00274     {
00275       /* Decode a color from a string descriptor.
00276         The descriptor string is a sequence of color specifiers separated
00277         by a non-numeric character.  Each color specifier should represent
00278         a small integer which fits into an unsigned char, and can be given
00279         in any base supported by strtoul.  Examples of valid descriptors:
00280 
00281               "10 31"
00282               "0x13/0x45"
00283               "007.077"
00284 
00285        The separator between two color specifiers can be any character which
00286        cannot be used in a printed representation of an integer number.  */
00287       char *endp;
00288       unsigned long color_desc = strtoul (info_colors, &endp, 0);
00289 
00290       if (color_desc <= UCHAR_MAX)
00291        {
00292          norm_attr = (unsigned char)color_desc;
00293          color_desc = strtoul (endp + 1, &endp, 0);
00294          if (color_desc <= UCHAR_MAX)
00295            inv_attr = (unsigned char)color_desc;
00296        }
00297     }
00298 
00299   /* We can scroll.  */
00300   terminal_can_scroll = 1;
00301 
00302   /* We know how to produce a visible bell, if somebody's looking...  */
00303   if (!speech_friendly)
00304     terminal_has_visible_bell_p = 1;
00305 
00306   /* We have a Meta key.  */
00307   terminal_has_meta_p = 1;
00308 
00309   /* We are *certainly* NOT dumb!  */
00310   terminal_is_dumb_p = 0;
00311 
00312   pc_get_screen_size ();
00313 
00314   /* Store the arrow keys.  */
00315   term_ku = (char *)find_sequence (K_Up);
00316   term_kd = (char *)find_sequence (K_Down);
00317   term_kr = (char *)find_sequence (K_Right);
00318   term_kl = (char *)find_sequence (K_Left);
00319 
00320   term_kP = (char *)find_sequence (K_PageUp);
00321   term_kN = (char *)find_sequence (K_PageDown);
00322 
00323 #if defined(INFOKEY)
00324   term_kh = (char *)find_sequence (K_Home);
00325   term_ke = (char *)find_sequence (K_End);
00326   term_ki = (char *)find_sequence (K_Insert);
00327   term_kx = (char *)find_sequence (K_Delete);
00328 #endif
00329 
00330   /* Set all the hooks to our PC-specific functions.  */
00331   terminal_begin_inverse_hook       = pc_begin_inverse;
00332   terminal_end_inverse_hook         = pc_end_inverse;
00333   terminal_prep_terminal_hook       = pc_prep_terminal;
00334   terminal_unprep_terminal_hook     = pc_unprep_terminal;
00335   terminal_up_line_hook             = pc_up_line;
00336   terminal_down_line_hook           = pc_down_line;
00337   terminal_clear_screen_hook        = pc_clear_screen;
00338   terminal_clear_to_eol_hook        = pc_clear_to_eol;
00339   terminal_get_screen_size_hook     = pc_get_screen_size;
00340   terminal_goto_xy_hook             = pc_goto_xy;
00341   terminal_put_text_hook            = pc_put_text;
00342   terminal_ring_bell_hook           = pc_ring_bell;
00343   terminal_write_chars_hook         = pc_write_chars;
00344   terminal_scroll_terminal_hook     = pc_scroll_terminal;
00345 }
00346 
00347 /* **************************************************************** */
00348 /*                                                                  */
00349 /*            How to Read Characters From the PC Terminal           */
00350 /*                                                                  */
00351 /* **************************************************************** */
00352 
00353 /* This will most certainly work ONLY with DJGPP.  */
00354 #ifdef __DJGPP__
00355 
00356 #include <errno.h>
00357 #include <sys/fsext.h>
00358 #include <dpmi.h>
00359 
00360 /* Translation table for some special keys.
00361    Arrow keys which are standard on other keyboards are translated into
00362    standard ESC-sequences, in case somebody rebinds the simple keys
00363    (like C-f, C-b, C-n, etc.).
00364 
00365    The strange "\033\061" prefix in some keys is a numeric argument of
00366    one, which means ``do the next command once''.  It is here so that
00367    when the according PC key is pressed in the middle of an incremental
00368    search, Info doesn't see just an ASCII character like `n' or `B',
00369    and doesn't add it to the search string; instead, it will exit the
00370    incremental search and then perform the command.  */
00371 static struct
00372 {
00373   int inkey;
00374   unsigned char const * const sequence;
00375 } DJGPP_keytab[] = {           /* these are for moving between nodes... */
00376   {K_Control_PageDown,  "\033\061n"},
00377   {K_Control_PageUp,    "\033\061p"},
00378   {K_Control_Up,        "\033\061u"},
00379   {K_Control_Down,      "\033\061m"},
00380   {K_Control_Center,    "\033\061l"},
00381 
00382 #if defined(INFOKEY)
00383   {K_Home,              "\033[H"}, /* ...and these are for moving IN a node */
00384   {K_End,               "\033[F"}, /* they're Numeric-Keypad-Keys, so       */
00385 #else
00386   {K_Home,              "\001"},
00387   {K_End,               "\005"},
00388 #endif
00389   {K_Left,              "\033[D"}, /* NUMLOCK should be off !!              */
00390   {K_Right,             "\033[C"},
00391   {K_Down,              "\033[B"},
00392   {K_Up,                "\033[A"},
00393   {K_PageDown,          "\033[G"},
00394   {K_PageUp,            "\033[I"},
00395   {K_Control_Left,      "\033b"},
00396   {K_Control_Right,     "\033f"},
00397   {K_Control_Home,      "\033<"},
00398   {K_Control_End,       "\033>"},
00399 
00400 #if defined(INFOKEY)
00401   {K_EHome,             "\033[H"}, /* these are also for moving IN a node */
00402   {K_EEnd,              "\033[F"}, /* they're the "extended" (Grey) keys  */
00403 #else
00404   {K_EHome,             "\001"},
00405   {K_EEnd,              "\005"},
00406 #endif
00407   {K_ELeft,             "\033[D"},
00408   {K_ERight,            "\033[C"},
00409   {K_EDown,             "\033[B"},
00410   {K_EUp,               "\033[A"},
00411   {K_EPageDown,         "\033[G"},
00412   {K_EPageUp,           "\033[I"},
00413   {K_Control_ELeft,     "\033b"},
00414   {K_Control_ERight,    "\033f"},
00415   {K_Control_EHome,     "\033<"},
00416   {K_Control_EEnd,      "\033>"},
00417 
00418   {K_BackTab,           "\033\011"},
00419   {K_F1,                "\10"},    /* YEAH, gimme that good old F-one-thing */
00420   {K_Delete,            "\177"},   /* to make Kp-Del be DEL (0x7f)          */
00421   {K_EDelete,           "\177"},   /* to make Delete be DEL (0x7f)          */
00422 #if defined(INFOKEY)
00423   {K_Insert,            "\033[L"},
00424   {K_EInsert,           "\033[L"},
00425 #endif
00426 
00427   /* These are here to map more Alt-X keys to ESC X sequences.  */
00428   {K_Alt_Q,             "\033q"},
00429   {K_Alt_W,             "\033w"},
00430   {K_Alt_E,             "\033e"},
00431   {K_Alt_R,             "\033r"},
00432   {K_Alt_T,             "\033t"},
00433   {K_Alt_Y,             "\033y"},
00434   {K_Alt_U,             "\033u"},
00435   {K_Alt_I,             "\033i"},
00436   {K_Alt_O,             "\033o"},
00437   {K_Alt_P,             "\033p"},
00438   {K_Alt_LBracket,      "\033["},
00439   {K_Alt_RBracket,      "\033]"},
00440   {K_Alt_Return,        "\033\015"},
00441   {K_Alt_A,             "\033a"},
00442   {K_Alt_S,             "\033s"},
00443   {K_Alt_D,             "\033d"},
00444   {K_Alt_F,             "\033f"},
00445   {K_Alt_G,             "\033g"},
00446   {K_Alt_H,             "\033h"},
00447   {K_Alt_J,             "\033j"},
00448   {K_Alt_K,             "\033k"},
00449   {K_Alt_L,             "\033l"},
00450   {K_Alt_Semicolon,     "\033;"},
00451   {K_Alt_Quote,         "\033'"},
00452   {K_Alt_Backquote,     "\033`"},
00453   {K_Alt_Backslash,     "\033\\"},
00454   {K_Alt_Z,             "\033z"},
00455   {K_Alt_X,             "\033x"},
00456   {K_Alt_C,             "\033c"},
00457   {K_Alt_V,             "\033v"},
00458   {K_Alt_B,             "\033b"},
00459   {K_Alt_N,             "\033n"},
00460   {K_Alt_M,             "\033m"},
00461   {K_Alt_Comma,         "\033<"}, /* our reader cannot distinguish between */
00462   {K_Alt_Period,        "\033>"}, /* Alt-. and Alt->, so we cheat a little */
00463   {K_Alt_Slash,         "\033?"}, /* ditto, to get Alt-?                   */
00464   {K_Alt_Backspace,     "\033\177"}, /* M-DEL, to delete word backwards */
00465   {K_Alt_1,             "\033\061"},
00466   {K_Alt_2,             "\033\062"},
00467   {K_Alt_3,             "\033\063"},
00468   {K_Alt_4,             "\033\064"},
00469   {K_Alt_5,             "\033\065"},
00470   {K_Alt_6,             "\033\066"},
00471   {K_Alt_7,             "\033\067"},
00472   {K_Alt_8,             "\033\070"},
00473   {K_Alt_9,             "\033\071"},
00474   {K_Alt_0,             "\033\060"},
00475   {K_Alt_Dash,          "\033\055"},
00476   {K_Alt_EPageUp,       "\033\033[I"},
00477   {K_Alt_EPageDown,     "\033\033[G"},
00478   {K_Alt_Equals,        "\033\075"},
00479   {K_Alt_EDelete,       "\033\177"},
00480   {K_Alt_Tab,           "\033\011"},
00481   {0, 0}
00482 };
00483 
00484 /* Given a key, return the sequence of characters which
00485    our keyboard driver generates.  */
00486 static unsigned const char *
00487 find_sequence (int key)
00488 {
00489   int i;
00490 
00491   for (i = 0; DJGPP_keytab[i].inkey; i++)
00492     if (key == DJGPP_keytab[i].inkey)
00493       return DJGPP_keytab[i].sequence;
00494 
00495   return (unsigned const char *)NULL;
00496 }
00497 
00498 /* Return zero if a key is pending in the
00499    keyboard buffer, non-zero otherwise.  */
00500 static int
00501 kbd_buffer_empty (void)
00502 {
00503   __dpmi_regs r;
00504   int retval;
00505 
00506   r.h.ah = 0x11;     /* Get enhanced keyboard status */
00507   __dpmi_int (0x16, &r);
00508 
00509   /* If the keyboard buffer is empty, the Zero Flag will be set.  */
00510   return (r.x.flags & 0x40) == 0x40;
00511 }
00512 
00513 /* The buffered characters pending to be read.
00514    Actually, Info usually reads a single character, but when we
00515    translate a key into a sequence of characters, we keep them here.  */
00516 static unsigned char buffered[512];
00517 
00518 /* Index of the next buffered character to be returned.  */
00519 static int buf_idx;
00520 
00521 /* Return the number of characters waiting to be read.  */
00522 long
00523 pc_term_chars_avail (void)
00524 {
00525   if (buf_idx >= sizeof (buffered)) /* paranoia */
00526     {
00527       buf_idx = 0;
00528       buffered[buf_idx] = '\0';
00529       return 0;
00530     }
00531   else
00532     return (long)strlen (buffered + buf_idx);
00533 }
00534 
00535 /* Our special terminal keyboard reader.  It will be called by
00536    low-level libc functions when the application calls `read' or
00537    the ANSI-standard stream-oriented read functions.  If the
00538    caller wants to read the terminal, we redirect the call to
00539    the BIOS keyboard functions, since that lets us recognize more
00540    keys than DOS does.  */
00541 static int
00542 keyboard_read (__FSEXT_Fnumber func, int *retval, va_list rest_args)
00543 {
00544   /* When we are called, REST_ARGS are: file_descriptor, buf, nbytes.  */
00545   unsigned char *buf;
00546   size_t nbytes, nread = 0;
00547   int fd = va_arg (rest_args, int);
00548 
00549   /* Is this call for us?  */
00550   if (func != __FSEXT_read || !isatty (fd))
00551     return 0; /* and the usual DOS call will be issued */
00552 
00553   buf = va_arg (rest_args, unsigned char *);
00554   nbytes = va_arg (rest_args, size_t);
00555 
00556   if (!buf)
00557     {
00558       errno = EINVAL;
00559       *retval = -1;
00560       return 1;
00561     }
00562   if (!nbytes)
00563     {
00564       *retval = 0;
00565       return 1;
00566     }
00567 
00568   /* Loop here until enough bytes has been read.  */
00569   do
00570     {
00571       int key;
00572 
00573       /* If any ``buffered characters'' are left, return as much
00574         of them as the caller wanted.  */
00575       while (buffered[buf_idx] && nbytes)
00576        {
00577          *buf++ = buffered[buf_idx++];
00578          nread++;
00579          nbytes--;
00580        }
00581 
00582       if (nbytes <= 0)
00583        break;
00584 
00585       /* Wait for another key.
00586         We do that in a busy-waiting loop so we don't get parked
00587         inside a BIOS call, which will effectively disable signals.
00588          While we wait for them to type something, we repeatedly
00589          release the rest of our time slice, so that other programs
00590          in a multitasking environment, such as Windows, get more cycles.  */
00591       while (kbd_buffer_empty ())
00592        __dpmi_yield ();
00593 
00594       key = getxkey ();
00595 
00596       /* Translate the key if necessary.
00597         Untranslated non-ASCII keys are silently ignored.  */
00598       if ((key & 0x300) != 0)
00599        {
00600          unsigned char const * key_sequence = find_sequence (key);
00601 
00602          if (key_sequence != NULL)
00603            {
00604              strcpy (buffered, key_sequence);
00605              buf_idx = 0;
00606            }
00607        }
00608       else if (key == K_Control_Z)
00609        raise (SIGUSR1);     /* we don't have SIGTSTP, so simulate it */
00610       else if (key <= 0xff)
00611        {
00612          *buf++ = key;
00613          nbytes--;
00614          nread++;
00615        }
00616     }
00617   while (nbytes > 0);
00618 
00619   *retval = nread;
00620   return 1;   /* meaning that we handled the call */
00621 }
00622 
00623 /* Install our keyboard handler.
00624    This is called by the startup code before `main'.  */
00625 static void __attribute__((constructor))
00626 install_keyboard_handler (void)
00627 {
00628   __FSEXT_set_function (fileno (stdin), keyboard_read);
00629 
00630   /* We need to set this single hook here; the rest
00631      will be set by pc_initialize_terminal when it is called.  */
00632   terminal_initialize_terminal_hook = pc_initialize_terminal;
00633 }
00634 
00635 #endif /* __DJGPP__ */
00636 
00637 /* **************************************************************** */
00638 /*                                                                  */
00639 /*                Emulation of SIGTSTP on Ctrl-Z                    */
00640 /*                                                                  */
00641 /* **************************************************************** */
00642 
00643 #include <limits.h>
00644 #include "signals.h"
00645 #include "session.h"
00646 
00647 #ifndef PATH_MAX
00648 # define PATH_MAX 512
00649 #endif
00650 
00651 /* Effectively disable signals which aren't defined
00652    (assuming no signal can ever be zero).
00653    SIGINT is ANSI, so we expect it to be always defined.  */
00654 #ifndef SIGUSR1
00655 # define SIGUSR1 0
00656 #endif
00657 #ifndef SIGQUIT
00658 # define SIGQUIT 0
00659 #endif
00660 
00661 int
00662 kill (pid_t pid, int sig)
00663 {
00664   static char interrupted_msg[] = "Interrupted\r\n";
00665   static char stopped_msg[] = "Stopped.  Type `exit RET' to return.\r\n";
00666   char cwd[PATH_MAX + 1];
00667 
00668   if (pid == getpid ()
00669       || pid == 0
00670       || pid == -1
00671       || pid == -getpid ())
00672     {
00673       switch (sig)
00674        {
00675        RETSIGTYPE (*old_INT)(int), (*old_QUIT)(int);
00676 
00677        case SIGINT:
00678 #ifdef __DJGPP__
00679          /* If SIGINT was generated by a readable key, we want to remove
00680             it from the PC keyboard buffer, so that DOS and other
00681             programs never see it.  DJGPP signal-handling mechanism
00682             doesn't remove the INT key from the keyboard buffer.  */
00683          if (!kbd_buffer_empty ())
00684            getxkey ();
00685 #endif
00686          pc_write_chars (interrupted_msg, sizeof (interrupted_msg) - 1);
00687          xexit (1);
00688        case SIGUSR1:
00689          /* Simulate SIGTSTP by invoking a subsidiary shell.  */
00690          pc_goto_xy (0, outside_info.screenheight - 1);
00691          pc_clear_to_eol ();
00692          pc_write_chars (stopped_msg, sizeof (stopped_msg) - 1);
00693 
00694          /* The child shell can change the working directory, so
00695             we need to save and restore it, since it is global.  */
00696          if (!getcwd (cwd, PATH_MAX)) /* should never happen */
00697            cwd[0] = '\0';
00698 
00699          /* We don't want to get fatal signals while the subshell runs.  */
00700          old_INT = signal (SIGINT, SIG_IGN);
00701          old_QUIT = signal (SIGQUIT, SIG_IGN);
00702          system ("");
00703          if (*cwd)
00704            chdir (cwd);
00705          signal (SIGINT, old_INT);
00706          signal (SIGQUIT, old_QUIT);
00707          break;
00708        default:
00709          if (sig)
00710            raise (sig);
00711          break;
00712        }
00713       return 0;
00714     }
00715   else
00716     return -1;
00717 }
00718 
00719 /* These should never be called, but they make the linker happy.  */
00720 
00721 void       tputs (char *a, int b, int (*c)())
00722 {
00723   perror ("tputs");
00724 }
00725 
00726 char*     tgoto (char*a, int b, int c)
00727 {
00728   perror ("tgoto"); return 0; /* here and below, added dummy retvals */
00729 }
00730 
00731 int       tgetnum (char*a)
00732 {
00733   perror ("tgetnum"); return 0;
00734 }
00735 
00736 int       tgetflag (char*a)
00737 {
00738   perror ("tgetflag"); return 0;
00739 }
00740 
00741 char*     tgetstr (char *a, char **b)
00742 {
00743   perror ("tgetstr"); return 0;
00744 }
00745 
00746 int       tgetent (char*a, char*b)
00747 {
00748   perror ("tgetent"); return 0;
00749 }
00750 
00751 int    tcgetattr(int fildes, struct termios *termios_p)
00752 {
00753   perror ("tcgetattr"); return 0;
00754 }
00755 
00756 int    tcsetattr(int fd, int opt_actions, const struct termios *termios_p)
00757 {
00758   perror ("tcsetattr"); return 0;
00759 }