[comp.sys.amiga] Urgent Help Needed.

andrewt%watsnew.waterloo.edu@cunyvm.cuny.edu (12/16/89)

I don't know how to do it on the amiga, but here is a method which
works on BSD, SunOS, Ultrix.  I tried to reply by mail but it bounced.
This code is guaranteed not at all.  No claim is made to it either.
Do what you will.

------------------- cbreak.c -----------------------
/* cbreak.c  written by Andrew Thomas
   andrewt@watsnew.waterloo.edu

   If you have ideas on how to make this more portable, I am keen to
   hear them.  I make no guarantees, no claims, no copyrights.
*/

#include        <sgtty.h>
#include        <signal.h>
#include        <stdio.h>
#include        <sys/file.h>
#include        <sys/ioctl.h>

/*  WARNING:  If this file is compiled with gcc (or any ansi compiler)
              you must privide the -traditional option, or modify the
              header files to adhere to ansi standard.
*/

/* The call you really want to use from here is the call to
   get_a_key(noecho,interrupt_status).  If noecho is non-zero, then
   the keys will not be echoed as they are typed.  Interrupt_status is
   explained in more detail later on.
*/

static  int             cbreak_on = 0;
static  int             tty = 0;
static  int             tty_set = 0;
static  int             cbreak_int_status = 0;
static  struct sgttyb   tty_desc;

void cbreak();
void nocbreak();

void cbreak_ignoresignal ()
{
}

void cbreak_killsignal ()
{
  nocbreak ();
  exit (1);
}

void cbreak_stopsignal ()
{
  nocbreak ();
  kill (getpid(), SIGSTOP);
  if (cbreak_on) cbreak(cbreak_on-1);
}

/* interrupt_status tells the system what to do with SIGTSTP, SIGTERM and
   SIGINT
   interrupt status is one of 0, 1, or 2:
   0: do nothing to alter the interrupts, or if interrupt status was
      changed before, make interrupts perform the default action.
   1: make interrupts cause a clean exit, resetting the interrupt status
      on exit and reentry
   2: ignore interrupts.
*/

void cbreak_open_tty (interrupt_status)
int     interrupt_status;
{
  tty_set = 1;
  tty = fileno (stdin);
  if (ioctl (tty, TIOCGETP, &tty_desc) == -1)
    perror ("ioctl: TIOCGETP");

  if (interrupt_status == 0 && cbreak_int_status != 0)
    {
      signal (SIGTSTP, SIG_DFL);
      signal (SIGTERM, SIG_DFL);
      signal (SIGINT, SIG_DFL);
    }
  else if (interrupt_status == 1)
    {
      signal (SIGTSTP, cbreak_stopsignal);
      signal (SIGTERM, cbreak_killsignal);
      signal (SIGINT, cbreak_killsignal);
    }
  else if (interrupt_status == 2)
    {
      signal (SIGTSTP, cbreak_ignoresignal);
      signal (SIGTERM, cbreak_ignoresignal);
      signal (SIGINT, cbreak_ignoresignal);
    }
  cbreak_int_status = interrupt_status;
}

/* noecho, if non-zero, causes the key stroke not to be echoed */

void cbreak (noecho, interrupt_status)
int     noecho, interrupt_status;
{
  if (!tty_set || interrupt_status != cbreak_int_status)
    cbreak_open_tty (interrupt_status);
  tty_desc.sg_flags |= CBREAK;
  if (noecho) tty_desc.sg_flags &= ~ECHO;
  if (ioctl (tty, TIOCSETN, &tty_desc) == -1)
    perror ("cbreak: ioctl: TIOCSETN");
}

void nocbreak ()
{
  if (!tty_set) cbreak_open_tty (cbreak_int_status);
  tty_desc.sg_flags &= ~CBREAK;
  tty_desc.sg_flags |= ECHO;
  if (ioctl (tty, TIOCSETN, &tty_desc) == -1)
    perror ("nocbreak: ioctl: TIOCSETN");
}

/* get a keystroke in cbreak mode, echoed or not echoed, with actions on
   interrupts specified.   Clear the stdin buffer first.  This is a
   bit of a kluge.  Suggestions welcome.
*/

char get_a_key (noecho, interrupt_status)
int     noecho, interrupt_status;
{
  char  x;

  while (stdin->_cnt > 0) if ((x=getchar()) != '\n') return (x);

  cbreak (noecho, interrupt_status);
  cbreak_on = 1+(noecho?1:0);
  x = getchar();
  nocbreak ();
  cbreak_on = 0;
  return (x);
}
--------------------------------------------------

Hope this helps.
--

Andrew Thomas
andrewt@watsnew.waterloo.edu    Systems Design Eng.     University of Waterloo
"If a million people do a stupid thing, it's still a stupid thing." - Opus