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