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