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