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