xref: /openbsd-src/gnu/usr.bin/texinfo/info/pcterm.c (revision a1acfa9b69ad64eb720639240c8438f11107dc85)
1*a1acfa9bSespie /* pcterm.c -- How to handle the PC terminal for Info under MS-DOS/MS-Windows.
2*a1acfa9bSespie    $Id: pcterm.c,v 1.1.1.3 2006/07/17 16:03:45 espie Exp $
31cc83814Sespie 
4*a1acfa9bSespie    Copyright (C) 1998, 1999, 2003, 2004 Free Software Foundation, Inc.
51cc83814Sespie 
61cc83814Sespie    This program is free software; you can redistribute it and/or modify
71cc83814Sespie    it under the terms of the GNU General Public License as published by
81cc83814Sespie    the Free Software Foundation; either version 2, or (at your option)
91cc83814Sespie    any later version.
101cc83814Sespie 
111cc83814Sespie    This program is distributed in the hope that it will be useful,
121cc83814Sespie    but WITHOUT ANY WARRANTY; without even the implied warranty of
131cc83814Sespie    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141cc83814Sespie    GNU General Public License for more details.
151cc83814Sespie 
161cc83814Sespie    You should have received a copy of the GNU General Public License along
171cc83814Sespie    with this program; if not, write to the Free Software Foundation, Inc.,
181cc83814Sespie    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
191cc83814Sespie 
201cc83814Sespie 
211cc83814Sespie /* WARNING WARNING WARNING!!!
221cc83814Sespie    This probably won't work as is with anything but DJGPP!  However, Borland
231cc83814Sespie    should come close, and other PC compilers will need minor modifications.  */
241cc83814Sespie 
251cc83814Sespie /* intl/libintl.h defines a macro `gettext' which
261cc83814Sespie    conflicts with conio.h header.  */
271cc83814Sespie #ifdef gettext
281cc83814Sespie # undef gettext
291cc83814Sespie # define gettext _gettext
301cc83814Sespie #endif
311cc83814Sespie 
321cc83814Sespie #include <pc.h>
331cc83814Sespie #include <keys.h>
341cc83814Sespie #include <conio.h>
351cc83814Sespie 
361cc83814Sespie #include "variables.h"
371cc83814Sespie 
381cc83814Sespie extern int speech_friendly;	/* defined in info.c */
391cc83814Sespie 
401cc83814Sespie /* **************************************************************** */
411cc83814Sespie /*                                                                  */
421cc83814Sespie /*                PC Terminal Output Functions                      */
431cc83814Sespie /*                                                                  */
441cc83814Sespie /* **************************************************************** */
451cc83814Sespie 
461cc83814Sespie static struct text_info outside_info;  /* holds screen params outside Info */
471cc83814Sespie static unsigned char    norm_attr, inv_attr;
481cc83814Sespie 
491cc83814Sespie static unsigned const char * find_sequence (int);
501cc83814Sespie 
511cc83814Sespie /* Turn on reverse video. */
521cc83814Sespie static void
pc_begin_inverse(void)531cc83814Sespie pc_begin_inverse (void)
541cc83814Sespie {
551cc83814Sespie   textattr (inv_attr);
561cc83814Sespie }
571cc83814Sespie 
581cc83814Sespie /* Turn off reverse video. */
591cc83814Sespie static void
pc_end_inverse(void)601cc83814Sespie pc_end_inverse (void)
611cc83814Sespie {
621cc83814Sespie   textattr (norm_attr);
631cc83814Sespie }
641cc83814Sespie 
651cc83814Sespie /* Move the cursor up one line. */
661cc83814Sespie static void
pc_up_line(void)671cc83814Sespie pc_up_line (void)
681cc83814Sespie {
691cc83814Sespie   int x, y;
701cc83814Sespie   ScreenGetCursor (&y, &x);
71*a1acfa9bSespie   ScreenSetCursor (MAX (y-1, 0), x);
721cc83814Sespie }
731cc83814Sespie 
741cc83814Sespie /* Move the cursor down one line. */
751cc83814Sespie static void
pc_down_line(void)761cc83814Sespie pc_down_line (void)
771cc83814Sespie {
781cc83814Sespie   int x, y;
791cc83814Sespie   ScreenGetCursor (&y, &x);
80*a1acfa9bSespie   ScreenSetCursor (MIN (screenheight-1, y+1), x);
811cc83814Sespie }
821cc83814Sespie 
831cc83814Sespie /* Clear the entire terminal screen. */
841cc83814Sespie static void
pc_clear_screen(void)851cc83814Sespie pc_clear_screen (void)
861cc83814Sespie {
871cc83814Sespie   ScreenClear ();
881cc83814Sespie }
891cc83814Sespie 
901cc83814Sespie /* Clear from the current position of the cursor to the end of the line. */
911cc83814Sespie static void
pc_clear_to_eol(void)921cc83814Sespie pc_clear_to_eol (void)
931cc83814Sespie {
941cc83814Sespie   clreol (); /* perhaps to be replaced by a loop */
951cc83814Sespie }
961cc83814Sespie 
971cc83814Sespie /* Set the global variables SCREENWIDTH and SCREENHEIGHT. */
981cc83814Sespie static void
pc_get_screen_size(void)991cc83814Sespie pc_get_screen_size(void)
1001cc83814Sespie {
1011cc83814Sespie   /* Current screen dimensions are the default.  */
1021cc83814Sespie   if (!outside_info.screenheight)	/* paranoia */
1031cc83814Sespie     gettextinfo (&outside_info);
1041cc83814Sespie   screenwidth  = outside_info.screenwidth;
1051cc83814Sespie   screenheight = outside_info.screenheight;
1061cc83814Sespie 
1071cc83814Sespie   /* Environment variable "LINES" overrides the default.  */
1081cc83814Sespie   if (getenv ("LINES") != NULL)
1091cc83814Sespie     screenheight = atoi (getenv ("LINES"));
1101cc83814Sespie 
1111cc83814Sespie   /* Environment variable "INFO_LINES" overrides "LINES".  */
1121cc83814Sespie   if (getenv ("INFO_LINES") != NULL)
1131cc83814Sespie     screenheight = atoi (getenv ("INFO_LINES"));
1141cc83814Sespie }
1151cc83814Sespie 
1161cc83814Sespie /* Move the cursor to the terminal location of X and Y. */
1171cc83814Sespie static void
pc_goto_xy(x,y)1181cc83814Sespie pc_goto_xy (x, y)
1191cc83814Sespie      int x, y;
1201cc83814Sespie {
1211cc83814Sespie   ScreenSetCursor (y, x); /* yes, pc.h says ScreenSetCursor (row, column) !! */
1221cc83814Sespie }
1231cc83814Sespie 
1241cc83814Sespie /* Print STRING to the terminal at the current position. */
1251cc83814Sespie static void
pc_put_text(string)1261cc83814Sespie pc_put_text (string)
1271cc83814Sespie      char *string;
1281cc83814Sespie {
1291cc83814Sespie   if (speech_friendly)
1301cc83814Sespie     fputs (string, stdout);
1311cc83814Sespie   else
1321cc83814Sespie     cputs (string);
1331cc83814Sespie }
1341cc83814Sespie 
1351cc83814Sespie /* Ring the terminal bell.  The bell is rung visibly if the terminal is
1361cc83814Sespie    capable of doing that, and if terminal_use_visible_bell_p is non-zero. */
1371cc83814Sespie static void
pc_ring_bell(void)1381cc83814Sespie pc_ring_bell(void)
1391cc83814Sespie {
1401cc83814Sespie   if (terminal_has_visible_bell_p && terminal_use_visible_bell_p)
1411cc83814Sespie     ScreenVisualBell ();
1421cc83814Sespie   else
1431cc83814Sespie     {
1441cc83814Sespie       printf ("%c",'\a');
1451cc83814Sespie       fflush (stdout);
1461cc83814Sespie     }
1471cc83814Sespie }
1481cc83814Sespie 
1491cc83814Sespie /* Print NCHARS from STRING to the terminal at the current position. */
1501cc83814Sespie static void
pc_write_chars(string,nchars)1511cc83814Sespie pc_write_chars (string, nchars)
1521cc83814Sespie     char *string;
1531cc83814Sespie     int nchars;
1541cc83814Sespie {
1551cc83814Sespie   if (!nchars)
1561cc83814Sespie     return;
1571cc83814Sespie 
1581cc83814Sespie   if (speech_friendly)
1591cc83814Sespie     printf ("%.*s",nchars, string);
1601cc83814Sespie   else
1611cc83814Sespie     cprintf ("%..*s",nchars, string);
1621cc83814Sespie }
1631cc83814Sespie 
1641cc83814Sespie /* Scroll an area of the terminal from START to (and excluding) END,
1651cc83814Sespie    AMOUNT lines.  If AMOUNT is negative, the lines are scrolled
1661cc83814Sespie    towards the top of the screen, else they are scrolled towards the
1671cc83814Sespie    bottom of the screen.  The lines of the old region which do not
1681cc83814Sespie    overlap the new region are cleared, to mimic terminal operation.  */
1691cc83814Sespie static void
pc_scroll_terminal(start,end,amount)1701cc83814Sespie pc_scroll_terminal (start, end, amount)
1711cc83814Sespie     int start, end, amount;
1721cc83814Sespie {
1731cc83814Sespie   int line_to_clear = amount > 0 ? start : end + amount;
1741cc83814Sespie 
1751cc83814Sespie   /* Move the text.  Note that `movetext' expects 1-based coordinates.  */
1761cc83814Sespie   movetext (1, start + 1, ScreenCols (), end, 1, start + amount + 1);
1771cc83814Sespie 
1781cc83814Sespie   /* Now clear the lines which were left unoccupied.  */
1791cc83814Sespie   if (amount < 0)
1801cc83814Sespie     amount = -amount;
1811cc83814Sespie   while (amount--)
1821cc83814Sespie     {
1831cc83814Sespie       ScreenSetCursor (line_to_clear++, 0);
1841cc83814Sespie       clreol ();
1851cc83814Sespie     }
1861cc83814Sespie }
1871cc83814Sespie 
1881cc83814Sespie /* Put the screen in the video mode and colors which Info will use.
1891cc83814Sespie    Prepare to start using the terminal to read characters singly.  */
1901cc83814Sespie static void
pc_prep_terminal(void)1911cc83814Sespie pc_prep_terminal (void)
1921cc83814Sespie {
1931cc83814Sespie   int tty;
1941cc83814Sespie 
1951cc83814Sespie   /* Do not set screen height if we already have it, because
1961cc83814Sespie      doing so erases the screen.  */
1971cc83814Sespie   if (screenheight != ScreenRows ())
1981cc83814Sespie     _set_screen_lines (screenheight);
1991cc83814Sespie 
2001cc83814Sespie   /* Don't fail if they asked for screen dimensions that their
2011cc83814Sespie      hardware cannot support.  */
2021cc83814Sespie   screenheight = ScreenRows ();
2031cc83814Sespie   screenwidth  = ScreenCols ();
2041cc83814Sespie 
2051cc83814Sespie   /* Try setting the colors user asked for.  */
2061cc83814Sespie   textattr (norm_attr);
2071cc83814Sespie   ScreenClear ();
2081cc83814Sespie 
2091cc83814Sespie   /* Switch console reads to binary mode.  */
2101cc83814Sespie   tty = fileno (stdin);
2111cc83814Sespie #ifdef __DJGPP__
2121cc83814Sespie   setmode (tty, O_BINARY);
2131cc83814Sespie   __djgpp_set_ctrl_c (1);	/* re-enable SIGINT generation by Ctrl-C */
2141cc83814Sespie #endif
2151cc83814Sespie }
2161cc83814Sespie 
2171cc83814Sespie /* Restore the tty settings back to what they were before we started using
2181cc83814Sespie    this terminal. */
2191cc83814Sespie static void
pc_unprep_terminal(void)2201cc83814Sespie pc_unprep_terminal (void)
2211cc83814Sespie {
2221cc83814Sespie   int tty;
2231cc83814Sespie 
2241cc83814Sespie   textattr (outside_info.normattr);
2251cc83814Sespie 
2261cc83814Sespie   /* Do not set screen height if we already have it, because
2271cc83814Sespie      doing so erases the screen.  */
2281cc83814Sespie   if (outside_info.screenheight != ScreenRows ())
2291cc83814Sespie     {
2301cc83814Sespie       _set_screen_lines (outside_info.screenheight);
2311cc83814Sespie       textmode (LASTMODE);
2321cc83814Sespie     }
2331cc83814Sespie   else
2341cc83814Sespie     pc_clear_to_eol ();	/* for text attributes to really take effect */
2351cc83814Sespie 
2361cc83814Sespie   /* Switch back to text mode on stdin.  */
2371cc83814Sespie   tty = fileno (stdin);
2381cc83814Sespie #ifdef __DJGPP__
2391cc83814Sespie   setmode (tty, O_TEXT);
2401cc83814Sespie #endif
2411cc83814Sespie }
2421cc83814Sespie 
2431cc83814Sespie /* Initialize the terminal which is known as TERMINAL_NAME.  If this
2441cc83814Sespie    terminal doesn't have cursor addressability, `terminal_is_dumb_p'
2451cc83814Sespie    becomes nonzero.  The variables SCREENHEIGHT and SCREENWIDTH are set
2461cc83814Sespie    to the dimensions that this terminal actually has.  The variable
2471cc83814Sespie    TERMINAL_HAS_META_P becomes nonzero if this terminal supports a Meta
2481cc83814Sespie    key.  Finally, the terminal screen is cleared. */
2491cc83814Sespie static void
pc_initialize_terminal(term_name)2501cc83814Sespie pc_initialize_terminal (term_name)
2511cc83814Sespie     char *term_name;
2521cc83814Sespie {
2531cc83814Sespie   char *info_colors;
2541cc83814Sespie 
2551cc83814Sespie   if (!term_name)
2561cc83814Sespie     {
2571cc83814Sespie       term_name = getenv ("TERM");
2581cc83814Sespie       if (!term_name)
2591cc83814Sespie 	term_name = "pc-dos";	/* ``what's in a name?'' */
2601cc83814Sespie     }
2611cc83814Sespie 
2621cc83814Sespie   /* Get current video information, to be restored later.  */
2631cc83814Sespie   if (outside_info.screenwidth == 0)
2641cc83814Sespie     gettextinfo (&outside_info);
2651cc83814Sespie 
2661cc83814Sespie   /* Current screen colors are the default.  */
2671cc83814Sespie   norm_attr    = outside_info.normattr;
2681cc83814Sespie   inv_attr     = (((outside_info.normattr &    7) << 4) |
2691cc83814Sespie                   ((outside_info.normattr & 0x7f) >> 4));
2701cc83814Sespie 
2711cc83814Sespie   /* Does the user want non-default colors?  */
2721cc83814Sespie   info_colors = getenv ("INFO_COLORS");
2731cc83814Sespie   if ((info_colors != (char *)0) && !speech_friendly)
2741cc83814Sespie     {
2751cc83814Sespie       /* Decode a color from a string descriptor.
2761cc83814Sespie 	 The descriptor string is a sequence of color specifiers separated
2771cc83814Sespie 	 by a non-numeric character.  Each color specifier should represent
2781cc83814Sespie 	 a small integer which fits into an unsigned char, and can be given
2791cc83814Sespie 	 in any base supported by strtoul.  Examples of valid descriptors:
2801cc83814Sespie 
2811cc83814Sespie 		"10 31"
2821cc83814Sespie 		"0x13/0x45"
2831cc83814Sespie 		"007.077"
2841cc83814Sespie 
2851cc83814Sespie 	The separator between two color specifiers can be any character which
2861cc83814Sespie 	cannot be used in a printed representation of an integer number.  */
2871cc83814Sespie       char *endp;
2881cc83814Sespie       unsigned long color_desc = strtoul (info_colors, &endp, 0);
2891cc83814Sespie 
2901cc83814Sespie       if (color_desc <= UCHAR_MAX)
2911cc83814Sespie 	{
2921cc83814Sespie 	  norm_attr = (unsigned char)color_desc;
2931cc83814Sespie 	  color_desc = strtoul (endp + 1, &endp, 0);
2941cc83814Sespie 	  if (color_desc <= UCHAR_MAX)
2951cc83814Sespie 	    inv_attr = (unsigned char)color_desc;
2961cc83814Sespie 	}
2971cc83814Sespie     }
2981cc83814Sespie 
2991cc83814Sespie   /* We can scroll.  */
3001cc83814Sespie   terminal_can_scroll = 1;
3011cc83814Sespie 
3021cc83814Sespie   /* We know how to produce a visible bell, if somebody's looking...  */
3031cc83814Sespie   if (!speech_friendly)
3041cc83814Sespie     terminal_has_visible_bell_p = 1;
3051cc83814Sespie 
3061cc83814Sespie   /* We have a Meta key.  */
3071cc83814Sespie   terminal_has_meta_p = 1;
3081cc83814Sespie 
3091cc83814Sespie   /* We are *certainly* NOT dumb!  */
3101cc83814Sespie   terminal_is_dumb_p = 0;
3111cc83814Sespie 
3121cc83814Sespie   pc_get_screen_size ();
3131cc83814Sespie 
3141cc83814Sespie   /* Store the arrow keys.  */
3151cc83814Sespie   term_ku = (char *)find_sequence (K_Up);
3161cc83814Sespie   term_kd = (char *)find_sequence (K_Down);
3171cc83814Sespie   term_kr = (char *)find_sequence (K_Right);
3181cc83814Sespie   term_kl = (char *)find_sequence (K_Left);
3191cc83814Sespie 
3201cc83814Sespie   term_kP = (char *)find_sequence (K_PageUp);
3211cc83814Sespie   term_kN = (char *)find_sequence (K_PageDown);
3221cc83814Sespie 
3233fb98d4aSespie #if defined(INFOKEY)
3243fb98d4aSespie   term_kh = (char *)find_sequence (K_Home);
3253fb98d4aSespie   term_ke = (char *)find_sequence (K_End);
3263fb98d4aSespie   term_ki = (char *)find_sequence (K_Insert);
3273fb98d4aSespie   term_kx = (char *)find_sequence (K_Delete);
3283fb98d4aSespie #endif
3293fb98d4aSespie 
3301cc83814Sespie   /* Set all the hooks to our PC-specific functions.  */
3311cc83814Sespie   terminal_begin_inverse_hook       = pc_begin_inverse;
3321cc83814Sespie   terminal_end_inverse_hook         = pc_end_inverse;
3331cc83814Sespie   terminal_prep_terminal_hook       = pc_prep_terminal;
3341cc83814Sespie   terminal_unprep_terminal_hook     = pc_unprep_terminal;
3351cc83814Sespie   terminal_up_line_hook             = pc_up_line;
3361cc83814Sespie   terminal_down_line_hook           = pc_down_line;
3371cc83814Sespie   terminal_clear_screen_hook        = pc_clear_screen;
3381cc83814Sespie   terminal_clear_to_eol_hook        = pc_clear_to_eol;
3391cc83814Sespie   terminal_get_screen_size_hook     = pc_get_screen_size;
3401cc83814Sespie   terminal_goto_xy_hook             = pc_goto_xy;
3411cc83814Sespie   terminal_put_text_hook            = pc_put_text;
3421cc83814Sespie   terminal_ring_bell_hook           = pc_ring_bell;
3431cc83814Sespie   terminal_write_chars_hook         = pc_write_chars;
3441cc83814Sespie   terminal_scroll_terminal_hook     = pc_scroll_terminal;
3451cc83814Sespie }
3461cc83814Sespie 
3471cc83814Sespie /* **************************************************************** */
3481cc83814Sespie /*                                                                  */
3491cc83814Sespie /*            How to Read Characters From the PC Terminal           */
3501cc83814Sespie /*                                                                  */
3511cc83814Sespie /* **************************************************************** */
3521cc83814Sespie 
3531cc83814Sespie /* This will most certainly work ONLY with DJGPP.  */
3541cc83814Sespie #ifdef __DJGPP__
3551cc83814Sespie 
3561cc83814Sespie #include <errno.h>
3571cc83814Sespie #include <sys/fsext.h>
3581cc83814Sespie #include <dpmi.h>
3591cc83814Sespie 
3601cc83814Sespie /* Translation table for some special keys.
3611cc83814Sespie    Arrow keys which are standard on other keyboards are translated into
3621cc83814Sespie    standard ESC-sequences, in case somebody rebinds the simple keys
3631cc83814Sespie    (like C-f, C-b, C-n, etc.).
3641cc83814Sespie 
3651cc83814Sespie    The strange "\033\061" prefix in some keys is a numeric argument of
3661cc83814Sespie    one, which means ``do the next command once''.  It is here so that
3671cc83814Sespie    when the according PC key is pressed in the middle of an incremental
3681cc83814Sespie    search, Info doesn't see just an ASCII character like `n' or `B',
3691cc83814Sespie    and doesn't add it to the search string; instead, it will exit the
3701cc83814Sespie    incremental search and then perform the command.  */
3711cc83814Sespie static struct
3721cc83814Sespie {
3731cc83814Sespie   int inkey;
3741cc83814Sespie   unsigned char const * const sequence;
3751cc83814Sespie } DJGPP_keytab[] = {		   /* these are for moving between nodes... */
3761cc83814Sespie   {K_Control_PageDown,  "\033\061n"},
3771cc83814Sespie   {K_Control_PageUp,    "\033\061p"},
3781cc83814Sespie   {K_Control_Up,        "\033\061u"},
3791cc83814Sespie   {K_Control_Down,      "\033\061m"},
3801cc83814Sespie   {K_Control_Center,    "\033\061l"},
3811cc83814Sespie 
3823fb98d4aSespie #if defined(INFOKEY)
3833fb98d4aSespie   {K_Home,              "\033[H"}, /* ...and these are for moving IN a node */
3843fb98d4aSespie   {K_End,               "\033[F"}, /* they're Numeric-Keypad-Keys, so       */
3853fb98d4aSespie #else
3863fb98d4aSespie   {K_Home,              "\001"},
3873fb98d4aSespie   {K_End,               "\005"},
3883fb98d4aSespie #endif
3891cc83814Sespie   {K_Left,              "\033[D"}, /* NUMLOCK should be off !!              */
3901cc83814Sespie   {K_Right,             "\033[C"},
3911cc83814Sespie   {K_Down,              "\033[B"},
3921cc83814Sespie   {K_Up,                "\033[A"},
3931cc83814Sespie   {K_PageDown,          "\033[G"},
3941cc83814Sespie   {K_PageUp,            "\033[I"},
3951cc83814Sespie   {K_Control_Left,      "\033b"},
3961cc83814Sespie   {K_Control_Right,     "\033f"},
3971cc83814Sespie   {K_Control_Home,      "\033<"},
3981cc83814Sespie   {K_Control_End,       "\033>"},
3991cc83814Sespie 
4003fb98d4aSespie #if defined(INFOKEY)
4013fb98d4aSespie   {K_EHome,             "\033[H"}, /* these are also for moving IN a node */
4023fb98d4aSespie   {K_EEnd,              "\033[F"}, /* they're the "extended" (Grey) keys  */
4033fb98d4aSespie #else
4043fb98d4aSespie   {K_EHome,             "\001"},
4053fb98d4aSespie   {K_EEnd,              "\005"},
4063fb98d4aSespie #endif
4071cc83814Sespie   {K_ELeft,             "\033[D"},
4081cc83814Sespie   {K_ERight,            "\033[C"},
4091cc83814Sespie   {K_EDown,             "\033[B"},
4101cc83814Sespie   {K_EUp,               "\033[A"},
4111cc83814Sespie   {K_EPageDown,         "\033[G"},
4121cc83814Sespie   {K_EPageUp,           "\033[I"},
4131cc83814Sespie   {K_Control_ELeft,     "\033b"},
4141cc83814Sespie   {K_Control_ERight,    "\033f"},
4151cc83814Sespie   {K_Control_EHome,     "\033<"},
4161cc83814Sespie   {K_Control_EEnd,      "\033>"},
4171cc83814Sespie 
4181cc83814Sespie   {K_BackTab,           "\033\011"},
4191cc83814Sespie   {K_F1,                "\10"},    /* YEAH, gimme that good old F-one-thing */
4201cc83814Sespie   {K_Delete,            "\177"},   /* to make Kp-Del be DEL (0x7f)          */
4211cc83814Sespie   {K_EDelete,           "\177"},   /* to make Delete be DEL (0x7f)          */
4223fb98d4aSespie #if defined(INFOKEY)
4233fb98d4aSespie   {K_Insert,            "\033[L"},
4243fb98d4aSespie   {K_EInsert,           "\033[L"},
4253fb98d4aSespie #endif
4261cc83814Sespie 
4271cc83814Sespie   /* These are here to map more Alt-X keys to ESC X sequences.  */
4281cc83814Sespie   {K_Alt_Q,             "\033q"},
4291cc83814Sespie   {K_Alt_W,             "\033w"},
4301cc83814Sespie   {K_Alt_E,             "\033e"},
4311cc83814Sespie   {K_Alt_R,             "\033r"},
4321cc83814Sespie   {K_Alt_T,             "\033t"},
4331cc83814Sespie   {K_Alt_Y,             "\033y"},
4341cc83814Sespie   {K_Alt_U,             "\033u"},
4351cc83814Sespie   {K_Alt_I,             "\033i"},
4361cc83814Sespie   {K_Alt_O,             "\033o"},
4371cc83814Sespie   {K_Alt_P,             "\033p"},
4381cc83814Sespie   {K_Alt_LBracket,      "\033["},
4391cc83814Sespie   {K_Alt_RBracket,      "\033]"},
4401cc83814Sespie   {K_Alt_Return,        "\033\015"},
4411cc83814Sespie   {K_Alt_A,             "\033a"},
4421cc83814Sespie   {K_Alt_S,             "\033s"},
4431cc83814Sespie   {K_Alt_D,             "\033d"},
4441cc83814Sespie   {K_Alt_F,             "\033f"},
4451cc83814Sespie   {K_Alt_G,             "\033g"},
4461cc83814Sespie   {K_Alt_H,             "\033h"},
4471cc83814Sespie   {K_Alt_J,             "\033j"},
4481cc83814Sespie   {K_Alt_K,             "\033k"},
4491cc83814Sespie   {K_Alt_L,             "\033l"},
4501cc83814Sespie   {K_Alt_Semicolon,     "\033;"},
4511cc83814Sespie   {K_Alt_Quote,         "\033'"},
4521cc83814Sespie   {K_Alt_Backquote,     "\033`"},
4531cc83814Sespie   {K_Alt_Backslash,     "\033\\"},
4541cc83814Sespie   {K_Alt_Z,             "\033z"},
4551cc83814Sespie   {K_Alt_X,             "\033x"},
4561cc83814Sespie   {K_Alt_C,             "\033c"},
4571cc83814Sespie   {K_Alt_V,             "\033v"},
4581cc83814Sespie   {K_Alt_B,             "\033b"},
4591cc83814Sespie   {K_Alt_N,             "\033n"},
4601cc83814Sespie   {K_Alt_M,             "\033m"},
4611cc83814Sespie   {K_Alt_Comma,         "\033<"}, /* our reader cannot distinguish between */
4621cc83814Sespie   {K_Alt_Period,        "\033>"}, /* Alt-. and Alt->, so we cheat a little */
4631cc83814Sespie   {K_Alt_Slash,         "\033?"}, /* ditto, to get Alt-?                   */
4641cc83814Sespie   {K_Alt_Backspace,     "\033\177"}, /* M-DEL, to delete word backwards */
4651cc83814Sespie   {K_Alt_1,             "\033\061"},
4661cc83814Sespie   {K_Alt_2,             "\033\062"},
4671cc83814Sespie   {K_Alt_3,             "\033\063"},
4681cc83814Sespie   {K_Alt_4,             "\033\064"},
4691cc83814Sespie   {K_Alt_5,             "\033\065"},
4701cc83814Sespie   {K_Alt_6,             "\033\066"},
4711cc83814Sespie   {K_Alt_7,             "\033\067"},
4721cc83814Sespie   {K_Alt_8,             "\033\070"},
4731cc83814Sespie   {K_Alt_9,             "\033\071"},
4741cc83814Sespie   {K_Alt_0,             "\033\060"},
4751cc83814Sespie   {K_Alt_Dash,          "\033\055"},
4761cc83814Sespie   {K_Alt_EPageUp,       "\033\033[I"},
4771cc83814Sespie   {K_Alt_EPageDown,     "\033\033[G"},
4781cc83814Sespie   {K_Alt_Equals,        "\033\075"},
4791cc83814Sespie   {K_Alt_EDelete,       "\033\177"},
4801cc83814Sespie   {K_Alt_Tab,           "\033\011"},
4811cc83814Sespie   {0, 0}
4821cc83814Sespie };
4831cc83814Sespie 
4841cc83814Sespie /* Given a key, return the sequence of characters which
4851cc83814Sespie    our keyboard driver generates.  */
4861cc83814Sespie static unsigned const char *
find_sequence(int key)4871cc83814Sespie find_sequence (int key)
4881cc83814Sespie {
4891cc83814Sespie   int i;
4901cc83814Sespie 
4911cc83814Sespie   for (i = 0; DJGPP_keytab[i].inkey; i++)
4921cc83814Sespie     if (key == DJGPP_keytab[i].inkey)
4931cc83814Sespie       return DJGPP_keytab[i].sequence;
4941cc83814Sespie 
4951cc83814Sespie   return (unsigned const char *)NULL;
4961cc83814Sespie }
4971cc83814Sespie 
4981cc83814Sespie /* Return zero if a key is pending in the
4991cc83814Sespie    keyboard buffer, non-zero otherwise.  */
5001cc83814Sespie static int
kbd_buffer_empty(void)5011cc83814Sespie kbd_buffer_empty (void)
5021cc83814Sespie {
5031cc83814Sespie   __dpmi_regs r;
5041cc83814Sespie   int retval;
5051cc83814Sespie 
5061cc83814Sespie   r.h.ah = 0x11;	/* Get enhanced keyboard status */
5071cc83814Sespie   __dpmi_int (0x16, &r);
5081cc83814Sespie 
5091cc83814Sespie   /* If the keyboard buffer is empty, the Zero Flag will be set.  */
5101cc83814Sespie   return (r.x.flags & 0x40) == 0x40;
5111cc83814Sespie }
5121cc83814Sespie 
5131cc83814Sespie /* The buffered characters pending to be read.
5141cc83814Sespie    Actually, Info usually reads a single character, but when we
5151cc83814Sespie    translate a key into a sequence of characters, we keep them here.  */
5161cc83814Sespie static unsigned char buffered[512];
5171cc83814Sespie 
5181cc83814Sespie /* Index of the next buffered character to be returned.  */
5191cc83814Sespie static int buf_idx;
5201cc83814Sespie 
5211cc83814Sespie /* Return the number of characters waiting to be read.  */
5221cc83814Sespie long
pc_term_chars_avail(void)5231cc83814Sespie pc_term_chars_avail (void)
5241cc83814Sespie {
5251cc83814Sespie   if (buf_idx >= sizeof (buffered)) /* paranoia */
5261cc83814Sespie     {
5271cc83814Sespie       buf_idx = 0;
5281cc83814Sespie       buffered[buf_idx] = '\0';
5291cc83814Sespie       return 0;
5301cc83814Sespie     }
5311cc83814Sespie   else
5321cc83814Sespie     return (long)strlen (buffered + buf_idx);
5331cc83814Sespie }
5341cc83814Sespie 
5351cc83814Sespie /* Our special terminal keyboard reader.  It will be called by
5361cc83814Sespie    low-level libc functions when the application calls `read' or
5371cc83814Sespie    the ANSI-standard stream-oriented read functions.  If the
5381cc83814Sespie    caller wants to read the terminal, we redirect the call to
5391cc83814Sespie    the BIOS keyboard functions, since that lets us recognize more
5401cc83814Sespie    keys than DOS does.  */
5411cc83814Sespie static int
keyboard_read(__FSEXT_Fnumber func,int * retval,va_list rest_args)5421cc83814Sespie keyboard_read (__FSEXT_Fnumber func, int *retval, va_list rest_args)
5431cc83814Sespie {
5441cc83814Sespie   /* When we are called, REST_ARGS are: file_descriptor, buf, nbytes.  */
5451cc83814Sespie   unsigned char *buf;
5461cc83814Sespie   size_t nbytes, nread = 0;
5471cc83814Sespie   int fd = va_arg (rest_args, int);
5481cc83814Sespie 
5491cc83814Sespie   /* Is this call for us?  */
5501cc83814Sespie   if (func != __FSEXT_read || !isatty (fd))
5511cc83814Sespie     return 0;	/* and the usual DOS call will be issued */
5521cc83814Sespie 
5531cc83814Sespie   buf = va_arg (rest_args, unsigned char *);
5541cc83814Sespie   nbytes = va_arg (rest_args, size_t);
5551cc83814Sespie 
5561cc83814Sespie   if (!buf)
5571cc83814Sespie     {
5581cc83814Sespie       errno = EINVAL;
5591cc83814Sespie       *retval = -1;
5601cc83814Sespie       return 1;
5611cc83814Sespie     }
5621cc83814Sespie   if (!nbytes)
5631cc83814Sespie     {
5641cc83814Sespie       *retval = 0;
5651cc83814Sespie       return 1;
5661cc83814Sespie     }
5671cc83814Sespie 
5681cc83814Sespie   /* Loop here until enough bytes has been read.  */
5691cc83814Sespie   do
5701cc83814Sespie     {
5711cc83814Sespie       int key;
5721cc83814Sespie 
5731cc83814Sespie       /* If any ``buffered characters'' are left, return as much
5741cc83814Sespie 	 of them as the caller wanted.  */
5751cc83814Sespie       while (buffered[buf_idx] && nbytes)
5761cc83814Sespie 	{
5771cc83814Sespie 	  *buf++ = buffered[buf_idx++];
5781cc83814Sespie 	  nread++;
5791cc83814Sespie 	  nbytes--;
5801cc83814Sespie 	}
5811cc83814Sespie 
5821cc83814Sespie       if (nbytes <= 0)
5831cc83814Sespie 	break;
5841cc83814Sespie 
5851cc83814Sespie       /* Wait for another key.
5861cc83814Sespie 	 We do that in a busy-waiting loop so we don't get parked
5871cc83814Sespie 	 inside a BIOS call, which will effectively disable signals.
5881cc83814Sespie          While we wait for them to type something, we repeatedly
5891cc83814Sespie          release the rest of our time slice, so that other programs
5901cc83814Sespie          in a multitasking environment, such as Windows, get more cycles.  */
5911cc83814Sespie       while (kbd_buffer_empty ())
5921cc83814Sespie 	__dpmi_yield ();
5931cc83814Sespie 
5941cc83814Sespie       key = getxkey ();
5951cc83814Sespie 
5961cc83814Sespie       /* Translate the key if necessary.
5971cc83814Sespie 	 Untranslated non-ASCII keys are silently ignored.  */
5981cc83814Sespie       if ((key & 0x300) != 0)
5991cc83814Sespie 	{
6001cc83814Sespie 	  unsigned char const * key_sequence = find_sequence (key);
6011cc83814Sespie 
6021cc83814Sespie 	  if (key_sequence != NULL)
6031cc83814Sespie 	    {
6041cc83814Sespie 	      strcpy (buffered, key_sequence);
6051cc83814Sespie 	      buf_idx = 0;
6061cc83814Sespie 	    }
6071cc83814Sespie 	}
6081cc83814Sespie       else if (key == K_Control_Z)
6091cc83814Sespie 	raise (SIGUSR1);	/* we don't have SIGTSTP, so simulate it */
6101cc83814Sespie       else if (key <= 0xff)
6111cc83814Sespie 	{
6121cc83814Sespie 	  *buf++ = key;
6131cc83814Sespie 	  nbytes--;
6141cc83814Sespie 	  nread++;
6151cc83814Sespie 	}
6161cc83814Sespie     }
6171cc83814Sespie   while (nbytes > 0);
6181cc83814Sespie 
6191cc83814Sespie   *retval = nread;
6201cc83814Sespie   return 1;	/* meaning that we handled the call */
6211cc83814Sespie }
6221cc83814Sespie 
6231cc83814Sespie /* Install our keyboard handler.
6241cc83814Sespie    This is called by the startup code before `main'.  */
6251cc83814Sespie static void __attribute__((constructor))
install_keyboard_handler(void)6261cc83814Sespie install_keyboard_handler (void)
6271cc83814Sespie {
6281cc83814Sespie   __FSEXT_set_function (fileno (stdin), keyboard_read);
6291cc83814Sespie 
6301cc83814Sespie   /* We need to set this single hook here; the rest
6311cc83814Sespie      will be set by pc_initialize_terminal when it is called.  */
6321cc83814Sespie   terminal_initialize_terminal_hook = pc_initialize_terminal;
6331cc83814Sespie }
6341cc83814Sespie 
6351cc83814Sespie #endif /* __DJGPP__ */
6361cc83814Sespie 
6371cc83814Sespie /* **************************************************************** */
6381cc83814Sespie /*                                                                  */
6391cc83814Sespie /*                Emulation of SIGTSTP on Ctrl-Z                    */
6401cc83814Sespie /*                                                                  */
6411cc83814Sespie /* **************************************************************** */
6421cc83814Sespie 
6431cc83814Sespie #include <limits.h>
6441cc83814Sespie #include "signals.h"
6451cc83814Sespie #include "session.h"
6461cc83814Sespie 
6471cc83814Sespie #ifndef PATH_MAX
6481cc83814Sespie # define PATH_MAX 512
6491cc83814Sespie #endif
6501cc83814Sespie 
6511cc83814Sespie /* Effectively disable signals which aren't defined
6521cc83814Sespie    (assuming no signal can ever be zero).
6531cc83814Sespie    SIGINT is ANSI, so we expect it to be always defined.  */
6541cc83814Sespie #ifndef SIGUSR1
6551cc83814Sespie # define SIGUSR1 0
6561cc83814Sespie #endif
6571cc83814Sespie #ifndef SIGQUIT
6581cc83814Sespie # define SIGQUIT 0
6591cc83814Sespie #endif
6601cc83814Sespie 
6611cc83814Sespie int
kill(pid_t pid,int sig)6621cc83814Sespie kill (pid_t pid, int sig)
6631cc83814Sespie {
6641cc83814Sespie   static char interrupted_msg[] = "Interrupted\r\n";
665*a1acfa9bSespie   static char stopped_msg[] = "Stopped.  Type `exit RET' to return.\r\n";
6661cc83814Sespie   char cwd[PATH_MAX + 1];
6671cc83814Sespie 
6681cc83814Sespie   if (pid == getpid ()
6691cc83814Sespie       || pid == 0
6701cc83814Sespie       || pid == -1
6711cc83814Sespie       || pid == -getpid ())
6721cc83814Sespie     {
6731cc83814Sespie       switch (sig)
6741cc83814Sespie 	{
6751cc83814Sespie 	RETSIGTYPE (*old_INT)(int), (*old_QUIT)(int);
6761cc83814Sespie 
6771cc83814Sespie 	case SIGINT:
6781cc83814Sespie #ifdef __DJGPP__
6791cc83814Sespie 	  /* If SIGINT was generated by a readable key, we want to remove
6801cc83814Sespie 	     it from the PC keyboard buffer, so that DOS and other
6811cc83814Sespie 	     programs never see it.  DJGPP signal-handling mechanism
6821cc83814Sespie 	     doesn't remove the INT key from the keyboard buffer.  */
6831cc83814Sespie 	  if (!kbd_buffer_empty ())
6841cc83814Sespie 	    getxkey ();
6851cc83814Sespie #endif
6861cc83814Sespie 	  pc_write_chars (interrupted_msg, sizeof (interrupted_msg) - 1);
6871cc83814Sespie 	  xexit (1);
6881cc83814Sespie 	case SIGUSR1:
6891cc83814Sespie 	  /* Simulate SIGTSTP by invoking a subsidiary shell.  */
6901cc83814Sespie 	  pc_goto_xy (0, outside_info.screenheight - 1);
6911cc83814Sespie 	  pc_clear_to_eol ();
6921cc83814Sespie 	  pc_write_chars (stopped_msg, sizeof (stopped_msg) - 1);
6931cc83814Sespie 
6941cc83814Sespie 	  /* The child shell can change the working directory, so
6951cc83814Sespie 	     we need to save and restore it, since it is global.  */
6961cc83814Sespie 	  if (!getcwd (cwd, PATH_MAX)) /* should never happen */
6971cc83814Sespie 	    cwd[0] = '\0';
6981cc83814Sespie 
6991cc83814Sespie 	  /* We don't want to get fatal signals while the subshell runs.  */
7001cc83814Sespie 	  old_INT = signal (SIGINT, SIG_IGN);
7011cc83814Sespie 	  old_QUIT = signal (SIGQUIT, SIG_IGN);
7021cc83814Sespie 	  system ("");
7031cc83814Sespie 	  if (*cwd)
7041cc83814Sespie 	    chdir (cwd);
7051cc83814Sespie 	  signal (SIGINT, old_INT);
7061cc83814Sespie 	  signal (SIGQUIT, old_QUIT);
7071cc83814Sespie 	  break;
7081cc83814Sespie 	default:
7091cc83814Sespie 	  if (sig)
7101cc83814Sespie 	    raise (sig);
7111cc83814Sespie 	  break;
7121cc83814Sespie 	}
7131cc83814Sespie       return 0;
7141cc83814Sespie     }
7151cc83814Sespie   else
7161cc83814Sespie     return -1;
7171cc83814Sespie }
7181cc83814Sespie 
7191cc83814Sespie /* These should never be called, but they make the linker happy.  */
7201cc83814Sespie 
tputs(char * a,int b,int (* c)())7211cc83814Sespie void       tputs (char *a, int b, int (*c)())
7221cc83814Sespie {
7231cc83814Sespie   perror ("tputs");
7241cc83814Sespie }
7251cc83814Sespie 
tgoto(char * a,int b,int c)7261cc83814Sespie char*     tgoto (char*a, int b, int c)
7271cc83814Sespie {
7281cc83814Sespie   perror ("tgoto"); return 0; /* here and below, added dummy retvals */
7291cc83814Sespie }
7301cc83814Sespie 
tgetnum(char * a)7311cc83814Sespie int       tgetnum (char*a)
7321cc83814Sespie {
7331cc83814Sespie   perror ("tgetnum"); return 0;
7341cc83814Sespie }
7351cc83814Sespie 
tgetflag(char * a)7361cc83814Sespie int       tgetflag (char*a)
7371cc83814Sespie {
7381cc83814Sespie   perror ("tgetflag"); return 0;
7391cc83814Sespie }
7401cc83814Sespie 
tgetstr(char * a,char ** b)7411cc83814Sespie char*     tgetstr (char *a, char **b)
7421cc83814Sespie {
7431cc83814Sespie   perror ("tgetstr"); return 0;
7441cc83814Sespie }
7451cc83814Sespie 
tgetent(char * a,char * b)7461cc83814Sespie int       tgetent (char*a, char*b)
7471cc83814Sespie {
7481cc83814Sespie   perror ("tgetent"); return 0;
7491cc83814Sespie }
7501cc83814Sespie 
tcgetattr(int fildes,struct termios * termios_p)7511cc83814Sespie int	tcgetattr(int fildes, struct termios *termios_p)
7521cc83814Sespie {
7531cc83814Sespie   perror ("tcgetattr"); return 0;
7541cc83814Sespie }
7551cc83814Sespie 
tcsetattr(int fd,int opt_actions,const struct termios * termios_p)7561cc83814Sespie int	tcsetattr(int fd, int opt_actions, const struct termios *termios_p)
7571cc83814Sespie {
7581cc83814Sespie   perror ("tcsetattr"); return 0;
7591cc83814Sespie }
760