freeswitch/libs/libzrtp/third_party/bnlib/test/kbunix.c

261 lines
4.6 KiB
C

/*
* Copyright (c) 1995 Colin Plumb. All rights reserved.
* For licensing and other legal details, see the file legal.c.
*
* kbunix.c - Unix keyboard input routines.
*/
/*
* Define NOTERMIO if you don't have the termios stuff
*/
#include "first.h"
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h> /* For exit() */
#include <sys/types.h>
/* How to get cbreak mode */
#if defined(NOTERMIO)
#include <sgtty.h> /* No termio: Use ioctl() TIOCGETP and TIOCSETP */
#elif defined(SVR2)
#include <termio.h> /* SVR2: Use ioctl() TCGETA and TCSETAF */
#else /* Usual case */
#include <termios.h> /* Posix: use tcgetattr/tcsetattr */
#endif
#ifdef sun /* including ioctl.h and termios.h gives a lot of warnings on sun */
#include <sys/filio.h>
#else
#include <sys/ioctl.h> /* for FIONREAD */
#endif /* sun */
#ifndef FIONREAD
#define FIONREAD TIOCINQ
#endif
#include "posix.h" /* For read(), sleep() */
#include "kb.h"
#if UNITTTEST
#define randEvent(c) (void)c
#else
#include "random.h"
#endif
#include "kludge.h"
/* The structure to hold the keyuboard's state */
#if defined(NOTERMIO)
static struct sgttyb kbState0, kbState1;
#elif defined(SVR2)
static struct termio kbState0, kbState1;
#else
static struct termios kbState0, kbState1;
#endif
#ifndef CBREAK
#define CBREAK RAW
#endif
/* The basic task of getting the terminal into CBREAK mode. */
static void
kbInternalCbreak(int fd)
{
#ifdef NOTERMIO
if (ioctl(fd, TIOCGETP, &kbState0) < 0) {
fprintf (stderr, "\nUnable to get terminal characteristics: ");
perror("ioctl");
exit(1);
}
kbState1 = kbState0;
kbState1.sg_flags |= CBREAK;
kbState1.sg_flags &= ~ECHO;
ioctl(fd, TIOCSETP, &kbState1);
#else /* !NOTERMIO - the usual case */
#ifdef SVR2
if (ioctl(fd, TCGETA, &kbState0) < 0)
#else
if (tcgetattr(fd, &kbState0) < 0)
#endif
{
fprintf (stderr, "\nUnable to get terminal characteristics: ");
perror("ioctl");
exit(1);
}
kbState1 = kbState0;
kbState1.c_cc[VMIN] = 1;
kbState1.c_cc[VTIME] = 0;
kbState1.c_lflag &= ~(ECHO|ICANON);
#ifdef SVR2
ioctl(fd, TCSETAF, &kbState1);
#else
tcsetattr(fd, TCSAFLUSH, &kbState1);
#endif /* not SVR2 */
#endif /* !NOTERMIO */
}
/* Restore the terminal to normal operation */
static void
kbInternalNorm(int fd)
{
#if defined(NOTERMIO)
ioctl(fd, TIOCSETP, &kbState0);
#elif defined(SVR2)
ioctl(fd, TCSETAF, &kbState0);
#else /* Usual case */
tcsetattr (fd, TCSAFLUSH, &kbState0);
#endif
}
/* State variables */
static volatile int kbCbreakFlag = 0;
static int kbFd = -1;
#ifdef SVR2
static int (*savesig)(int);
#else
static void (*savesig)(int);
#endif
/* A wrapper around SIGINT and SIGCONT to restore the terminal modes. */
static void
kbSig1(int sig)
{
if (kbCbreakFlag)
kbInternalNorm(kbFd);
if (sig == SIGINT)
signal(sig, savesig);
else
signal(sig, SIG_DFL);
raise(sig); /* Re-send the signal */
}
static void
kbAddSigs(void);
/* Resume cbreak after SIGCONT */
static void
kbSig2(int sig)
{
(void)sig;
if (kbCbreakFlag)
kbInternalCbreak(kbFd);
else
kbAddSigs();
}
static void
kbAddSigs(void)
{
savesig = signal (SIGINT, kbSig1);
#ifdef SIGTSTP
signal (SIGCONT, kbSig2);
signal (SIGTSTP, kbSig1);
#endif
}
static void
kbRemoveSigs(void)
{
signal (SIGINT, savesig);
#ifdef SIGTSTP
signal (SIGCONT, SIG_DFL);
signal (SIGTSTP, SIG_DFL);
#endif
}
/* Now, at last, the externally callable functions */
void
kbCbreak(void)
{
if (kbFd < 0) {
kbFd = open("/dev/tty", O_RDWR);
if (kbFd < 0) {
fputs("Can't open tty; using stdin\n", stderr);
kbFd = STDIN_FILENO;
}
}
kbAddSigs();
kbCbreakFlag = 1;
kbInternalCbreak(kbFd);
}
void
kbNorm(void)
{
kbInternalNorm(kbFd);
kbCbreakFlag = 0;
kbRemoveSigs();
}
int
kbGet(void)
{
int i;
char c;
i = read(kbFd, &c, 1);
if (i < 1)
return -1;
randEvent(c);
return c;
}
/*
* Flush any pending input. If "thorough" is set, tries to be more
* thorough about it. Ideally, wait for 1 second of quiet, but we
* may do something more primitive.
*
* kbCbreak() has the side effect of flushing the inout queue, so this
* is not too critical.
*/
void
kbFlush(int thorough)
{
if (thorough)
sleep(1);
#if defined(TCIFLUSH)
tcflush(kbFd, TCIFLUSH);
#elif defined(TIOCFLUSH)
#ifndef FREAD
#define FREAD 1 /* The usual value */
#endif
ioctl(kbFd, TIOCFLUSH, FREAD);
#endif
}
#if UNITTEST /* Self-contained test driver */
#include <ctype.h>
int
main(void)
{
int c;
puts("Going to cbreak mode...");
kbCbreak();
puts("In cbreak mode. Please type.");
for (;;) {
c = kbGet();
if (c == '\n' || c == '\r')
break;
printf("c = %d = '%c'\n", c, c);
kbFlush(isupper(c));
}
puts("Returning to normal mode...");
kbNorm();
puts("Done.");
return 0;
}
#endif /* UNITTEST */