Logo Search packages:      
Sourcecode: tack version File versions  Download package

sysdep.c

/*
** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
**
** This file is part of TACK.
**
** TACK is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2, or (at your option)
** any later version.
**
** TACK is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with TACK; see the file COPYING.  If not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
** Boston, MA 02110-1301, USA
*/
/*
 * Operating system dependent functions.  We assume the POSIX API.
 * Note: on strict-POSIX systems (including BSD/OS) the select_delay_type
 * global has no effect.
 */

#include <tack.h>

#include <term.h>
#include <errno.h>

#if defined(__BEOS__)
#undef false
#undef true
#include <OS.h>
#endif

#if HAVE_SELECT
#if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT
#include <sys/time.h>
#endif
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#endif

MODULE_ID("$Id: sysdep.c,v 1.18 2007/04/29 23:45:23 tom Exp $")

#if DECL_ERRNO
extern int errno;
#endif

#ifdef TERMIOS
#define PUT_TTY(fd, buf) tcsetattr(fd, TCSAFLUSH, buf)
#else
#define PUT_TTY(fd, buf) stty(fd, buf)
#endif

/* globals */
int tty_frame_size;           /* asynch frame size times 2 */
unsigned tty_baud_rate;       /* baud rate - bits per second */
SIG_ATOMIC_T not_a_tty;       /* TRUE if output is not a tty (i.e. pipe) */
int nodelay_read;       /* TRUE if NDELAY is set */

#ifdef TERMIOS
#define TTY_IS_NOECHO   !(new_modes.c_lflag & ECHO)
#define TTY_IS_OUT_TRANS (new_modes.c_oflag & OPOST)
#define TTY_IS_CHAR_MODE !(new_modes.c_lflag & ICANON)
#define TTY_WAS_CS8 ((old_modes.c_cflag & CSIZE) == CS8)
#define TTY_WAS_XON_XOFF (old_modes.c_iflag & (IXON|IXOFF))
#else
#define TTY_IS_NOECHO   !(new_modes.sg_flags & (ECHO))
#define TTY_IS_OUT_TRANS (new_modes.sg_flags & (CRMOD))
#define TTY_IS_CHAR_MODE (new_modes.sg_flags & (RAW|CBREAK))
#define TTY_WAS_CS8      (old_modes.sg_flags & (PASS8))
#define TTY_WAS_XON_XOFF (old_modes.sg_flags & (TANDEM|MDMBUF|DECCTQ))
#endif

static TTY old_modes, new_modes;

void catchsig(void);

/*
 * These are a sneaky way of conditionalizing bit unsets so strict-POSIX
 * systems won't see them.
 */
#ifndef XCASE
#define XCASE     0
#endif
#ifndef OLCUC
#define OLCUC     0
#endif
#ifndef IUCLC
#define IUCLC     0
#endif
#ifndef TABDLY
#define     TABDLY      0
#endif
#ifndef IXANY
#define     IXANY 0
#endif

void
tty_raw(int minch GCC_UNUSED, int mask)
{                       /* set tty to raw noecho */
      new_modes = old_modes;
#ifdef TERMIOS
#if HAVE_SELECT
      new_modes.c_cc[VMIN] = 1;
#else
      new_modes.c_cc[VMIN] = minch;
#endif
      new_modes.c_cc[VTIME] = 2;
      new_modes.c_lflag &=
            ~(ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK | ECHONL);
#ifdef LOBLK
      new_modes.c_lflag &= ~LOBLK;
#endif
      new_modes.c_oflag &= ~(OPOST | OLCUC | TABDLY);
      if (mask == ALLOW_PARITY) {
            new_modes.c_cflag &= ~(CSIZE | PARENB | HUPCL);
            new_modes.c_cflag |= CS8;
      }
      new_modes.c_iflag &=
            ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL |
            IUCLC | IXON | IXANY | IXOFF);
#else
      new_modes.sg_flags |= RAW;
#endif
      if (not_a_tty)
            return;
      PUT_TTY(fileno(stdin), &new_modes);
}

void
tty_set(void)
{                       /* set tty to special modes */
      new_modes = old_modes;
#ifdef TERMIOS
      new_modes.c_cc[VMIN] = 1;
      new_modes.c_cc[VTIME] = 1;
      new_modes.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
#if defined(ONLCR) && defined(OCRNL) && defined(ONLRET) && defined(OFILL)
      new_modes.c_oflag &= ~(ONLCR | OCRNL | ONLRET | OFILL);
#else
      new_modes.c_oflag &= ~(OPOST);
#endif
      if (char_mask == ALLOW_PARITY)
            new_modes.c_iflag &= ~ISTRIP;
      switch (select_xon_xoff) {
      case 0:
            new_modes.c_iflag &= ~(IXON | IXOFF);
            break;
      case 1:
#if defined(sequent) && sequent
            /* the sequent System V emulation is broken */
            new_modes = old_modes;
            new_modes.c_cc[VEOL] = 6;     /* control F  (ACK) */
#endif
            new_modes.c_iflag |= IXON | IXOFF;
            break;
      }
      switch (select_delay_type) {
      case 0:
#ifdef NLDLY
            new_modes.c_oflag &=
                  ~(NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
#endif      /* NLDLY */
            break;
      case 1:
#ifdef NLDLY
            new_modes.c_oflag &=
                  ~(NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
#endif      /* NLDLY */
#ifdef NL1
            new_modes.c_oflag |= NL1 | CR2;
#endif      /* NL1 */
            break;
      }
      if ((new_modes.c_oflag & (unsigned long) ~OPOST) == 0)
            new_modes.c_oflag &= (unsigned long) ~OPOST;
#else
      new_modes.sg_flags |= RAW;
      if (not_a_tty)
            return;
#endif
      PUT_TTY(fileno(stdin), &new_modes);
}


void
tty_reset(void)
{                       /* reset the tty to the original modes */
      fflush(stdout);
      if (not_a_tty)
            return;
      PUT_TTY(fileno(stdin), &old_modes);
}


void
tty_init(void)
{                       /* ATT terminal init */
#if defined(F_GETFL) && defined(O_NDELAY)
      int flags;

      flags = fcntl(fileno(stdin), F_GETFL, 0);
      nodelay_read = flags & O_NDELAY;
#else
      nodelay_read = FALSE;
#endif
      not_a_tty = FALSE;
      if (GET_TTY(fileno(stdin), &old_modes) == -1) {
            if (errno == ENOTTY) {
                  tty_frame_size = 20;
                  not_a_tty = TRUE;
                  return;
            }
            printf("tcgetattr error: %d\n", errno);
            ExitProgram(EXIT_FAILURE);
      }
      /* if TAB3 is set then setterm() wipes out tabs (ht) */
      new_modes = old_modes;
#ifdef TERMIOS
#ifdef TABDLY
      new_modes.c_oflag &= ~TABDLY;
#endif      /* TABDLY */
#endif
      if (PUT_TTY(fileno(stdin), &new_modes) == -1) {
            printf("tcsetattr error: %d\n", errno);
            ExitProgram(EXIT_FAILURE);
      }
#ifdef sequent
      /* the sequent ATT emulation is broken soooo. */
      old_modes.c_cflag &= ~(CSIZE | CSTOPB);
      old_modes.c_cflag |= CS7 | PARENB;
#endif
      catchsig();
#ifdef TERMIOS
      switch (old_modes.c_cflag & CSIZE) {
#if defined(CS5) && (CS5 != 0)
      case CS5:
            tty_frame_size = 10;
            break;
#endif
#if defined(CS6) && (CS6 != 0)
      case CS6:
            tty_frame_size = 12;
            break;
#endif
#if defined(CS7) && (CS7 != 0)
      case CS7:
            tty_frame_size = 14;
            break;
#endif
#if defined(CS8) && (CS8 != 0)
      case CS8:
            tty_frame_size = 16;
            break;
#endif
      }
      tty_frame_size += 2 +
            ((old_modes.c_cflag & PARENB) ? 2 : 0) +
            ((old_modes.c_cflag & CSTOPB) ? 4 : 2);
#else
      tty_frame_size = 6 +
            (old_modes.sg_flags & PASS8) ? 16 : 14;
#endif
}

/*
**    stty_query(question)
**
**    Does the current driver settings have this property?
*/
int
stty_query(int q)
{
      switch (q) {
            case TTY_NOECHO:
            return TTY_IS_NOECHO;
      case TTY_OUT_TRANS:
            return TTY_IS_OUT_TRANS;
      case TTY_CHAR_MODE:
            return TTY_IS_CHAR_MODE;
      }
      return (-1);
}

/*
**    initial_stty_query(question)
**
**    Did the initial driver settings have this property?
*/
int
initial_stty_query(int q)
{
      switch (q) {
      case TTY_8_BIT:
            return TTY_WAS_CS8;
      case TTY_XON_XOFF:
            return TTY_WAS_XON_XOFF;
      }
      return (-1);
}

#if HAVE_SELECT && defined(FD_ZERO)
static int
char_ready(void)
{
      int n;
      fd_set ifds;
      struct timeval tv;

      FD_ZERO(&ifds);
      FD_SET(fileno(stdin), &ifds);
      tv.tv_sec = 0;
      tv.tv_usec = 200000;
      n = select(fileno(stdin)+1, &ifds, NULL, NULL, &tv);
      return (n != 0);
}

#else
#ifdef FIONREAD
int
char_ready(void)
{
      int i, j;

      /* the following loop has to be tuned for each computer */
      for (j = 0; j < 1000; j++) {
            ioctl(fileno(stdin), FIONREAD, &i);
            if (i)
                  return i;
      }
      return i;
}

#else
#if defined(__BEOS__)
int
char_ready(void)
{
      int n = 0;
      int howmany = ioctl(0, 'ichr', &n);
      return (howmany >= 0 && n > 0);
}
#else
#define char_ready() 1
#endif
#endif
#endif

/*
**    spin_flush()
**
**    Wait for the input stream to stop.
**    Throw away all input characters.
*/
void
spin_flush(void)
{
      unsigned char buf[64];

      fflush(stdout);
      event_start(TIME_FLUSH);      /* start the timer */
      do {
            if (char_ready()) {
                  (void) read(fileno(stdin), &buf, sizeof(buf));
            }
      } while (event_time(TIME_FLUSH) < 400000);
}

/*
**    read_key(input-buffer, length-of-buffer)
**
**    read one function key from the input stream.
**    A null character is converted to 0x80.
*/
void
read_key(char *buf, int max)
{
      int got, ask, i, l;
      char *s;

      *buf = '\0';
      s = buf;
      fflush(stdout);
      /* ATT unix may return 0 or 1, Berkeley Unix should be 1 */
      while (read(fileno(stdin), s, 1) == 0);
      ++s;
      --max;
      while (max > 0 && (ask = char_ready())) {
            if (ask > max) {
                  ask = max;
            }
            if ((got = read(fileno(stdin), s, (unsigned) ask))) {
                  s += got;
            } else {
                  break;
            }
            max -= got;
      }
      *s = '\0';
      l = s - buf;
      for (s = buf, i = 0; i < l; i++) {
            if ((*s & 0x7f) == 0) {
                  /* convert nulls to 0x80 */
                  *(unsigned char *)s = 128;
            } else {
                  /* strip high order bits (if any) */
                  *s &= char_mask;
            }
      }
}


void
ignoresig(void)
{
      /* ignore signals */
      signal(SIGINT, SIG_IGN);
      signal(SIGHUP, SIG_IGN);
      signal(SIGQUIT, SIG_IGN);
      signal(SIGTERM, SIG_IGN);
      signal(SIGALRM, SIG_IGN);
}

/*
 * onintr( )
 *
 * is the interrupt handling routine.
 * onintr turns off interrupts while doing clean-up.
 *
 * onintr always exits fatally
 */
static RETSIGTYPE
onintr(int sig GCC_UNUSED)
{
      ignoresig();
      tty_reset();
      ExitProgram(EXIT_FAILURE);
}


/*
 * catchsig( )
 *
 * set up to field interrupts (via function onintr( )) so that if interrupted
 * we can restore the correct terminal modes
 *
 * catchsig simply returns
 */
void
catchsig(void)
{
      if ((signal(SIGINT, SIG_IGN)) == SIG_DFL)
            signal(SIGINT, onintr);

      if ((signal(SIGHUP, SIG_IGN)) == SIG_DFL)
            signal(SIGHUP, onintr);

      if ((signal(SIGQUIT, SIG_IGN)) == SIG_DFL)
            signal(SIGQUIT, onintr);

      if ((signal(SIGTERM, SIG_IGN)) == SIG_DFL)
            signal(SIGTERM, onintr);

}

/*
**    alarm_event(sig)
**
**    Come here for an alarm event
*/
static void
alarm_event(
      int sig GCC_UNUSED)
{
      no_alarm_event = 0;
}

/*
**    set_alarm_clock(seconds)
**
**    Set the alarm clock to fire in <seconds>
*/
void
set_alarm_clock(
      int seconds)
{
      signal(SIGALRM, alarm_event);
      no_alarm_event = 1;
      (void) alarm((unsigned) seconds);
}

Generated by  Doxygen 1.6.0   Back to index