227 lines
5.5 KiB
C
227 lines
5.5 KiB
C
/* Support routines for terminal I/O. This module defines the following
|
|
Fortran-callable routines: GROTER, GRCTER, GRWTER, GRPTER. */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <termios.h>
|
|
|
|
#ifdef PG_PPU
|
|
#define GROTER groter_
|
|
#define GRWTER grwter_
|
|
#define GRCTER grcter_
|
|
#define GRPTER grpter_
|
|
#define GRKTER grkter_
|
|
#define GRETER greter_
|
|
#else
|
|
#define GROTER groter
|
|
#define GRWTER grwter
|
|
#define GRCTER grcter
|
|
#define GRPTER grpter
|
|
#define GRKTER grkter
|
|
#define GRETER greter
|
|
#endif
|
|
|
|
/* Open a channel to the device specified by 'cdev'.
|
|
*
|
|
* cdev I The name of the device to be opened
|
|
* ldev I Number of valid characters in cdev
|
|
* groter O The open channel number (-1 indicates an error)
|
|
*/
|
|
int GROTER(cdev, ldev, cdev_len)
|
|
char *cdev; int *ldev;
|
|
int cdev_len;
|
|
{
|
|
int fd; /* The returned file descriptor */
|
|
char name[64]; /* A copy of the given terminal device name */
|
|
/*
|
|
* Make a copy of the given file if there is sufficient room in name[].
|
|
*/
|
|
if(*ldev <= sizeof(name)-1) {
|
|
strncpy(name, cdev, *ldev);
|
|
name[*ldev] = '\0';
|
|
} else {
|
|
fprintf(stderr, "groter: Terminal file name too long.\n");
|
|
return -1;
|
|
};
|
|
/*
|
|
* Open the terminal.
|
|
*/
|
|
if((fd = open(name, 2)) == -1) {
|
|
perror(name);
|
|
return -1;
|
|
};
|
|
return fd;
|
|
}
|
|
|
|
|
|
/* Close a previously opened channel.
|
|
*
|
|
* fd I The channel number to be closed
|
|
*/
|
|
void GRCTER(fd)
|
|
int *fd;
|
|
{
|
|
close(*fd);
|
|
return;
|
|
}
|
|
|
|
/* Write lbuf bytes from cbuf to the channel fd. Data is written without
|
|
* any formating.
|
|
*
|
|
* fd I The channel number
|
|
* cbuf I Character array of data to be written
|
|
* lbuf I/O The number of bytes to write, set to zero on return
|
|
*/
|
|
void GRWTER(fd, cbuf, lbuf, cbuf_len)
|
|
int *fd; char *cbuf; int *lbuf; int cbuf_len;
|
|
{
|
|
int nwritten = write (*fd, cbuf, *lbuf);
|
|
if (nwritten != *lbuf)
|
|
perror("Error writing to graphics device");
|
|
*lbuf = 0;
|
|
return;
|
|
}
|
|
|
|
/* Write prompt string on terminal and then read response. This version
|
|
* will try to read lbuf characters.
|
|
*
|
|
* fd I The channel number
|
|
* cprom I An optional prompt string
|
|
* lprom I Number of valid characters in cprom
|
|
* cbuf O Character array of data read
|
|
* lbuf I/O The number of bytes to read, on return number read
|
|
*/
|
|
void GRPTER(fd, cprom, lprom, cbuf, lbuf, cprom_len, cbuf_len)
|
|
int *fd; char *cprom; int *lprom; char *cbuf; int *lbuf;
|
|
int cprom_len; int cbuf_len;
|
|
{
|
|
char *buff = cbuf; /* C pointer to FORTRAN string */
|
|
int ndone=0; /* The number of characters read */
|
|
struct termios term; /* Terminal mode flags */
|
|
/*
|
|
* Get the current set of terminal mode flags.
|
|
*/
|
|
if(tcgetattr(*fd, &term)==0) {
|
|
struct termios saveterm; /* Saved terminal attributes */
|
|
int ntry; /* The number of characters still to be read */
|
|
int nread; /* The number of characters read in one iteration */
|
|
/*
|
|
* Save the existing terminal mode flags to be restored later.
|
|
*/
|
|
saveterm = term;
|
|
/*
|
|
* Enable raw single character input.
|
|
*/
|
|
term.c_lflag &= ~ICANON;
|
|
term.c_cc[VMIN] = 1;
|
|
/*
|
|
* Install the new terminal flags after first waiting for all pending
|
|
* output to be delivered to the terminal and after discarding any
|
|
* lingering input.
|
|
*/
|
|
tcsetattr(*fd, TCSAFLUSH, &term);
|
|
/*
|
|
* Prompt for input.
|
|
*/
|
|
if(*lprom>0) write(*fd, cprom, *lprom);
|
|
/*
|
|
* Read up to 'ntry' characters from the terminal.
|
|
*/
|
|
ndone = 0;
|
|
ntry = *lbuf;
|
|
do {
|
|
nread = read(*fd, &buff[ndone], ntry);
|
|
ndone += nread;
|
|
ntry -= nread;
|
|
} while(nread>0 && ntry>0);
|
|
/*
|
|
* Restore the previous terminal mode flags.
|
|
*/
|
|
tcsetattr(*fd, TCSAFLUSH, &saveterm);
|
|
};
|
|
*lbuf=ndone;
|
|
return;
|
|
}
|
|
|
|
|
|
static struct termios saved_attr;
|
|
static struct termios term; /* Terminal mode flags */
|
|
static int saved_fd=-1;
|
|
static int exit_handler=1;
|
|
/*
|
|
* Restore the previous terminal mode.
|
|
*/
|
|
void GRETER(void) {
|
|
if (saved_fd >= 0) {
|
|
tcsetattr(saved_fd, TCSAFLUSH, &saved_attr);
|
|
saved_fd = -1;
|
|
};
|
|
return;
|
|
}
|
|
|
|
|
|
/* Read one character from the terminal (with timeout),
|
|
* and set terminal to no canonical, no echo mode.
|
|
*
|
|
* fd I The channel number
|
|
* tmo I Timeout in tenths of a second
|
|
* cbuf O Character array of data read
|
|
*/
|
|
void GRKTER(fd, tmo, cbuf, cbuf_len)
|
|
int *fd; int *tmo; char *cbuf; int cbuf_len;
|
|
{
|
|
int nread;
|
|
/*
|
|
* Get the current set of terminal mode flags.
|
|
*/
|
|
*cbuf='\0';
|
|
if (*fd != saved_fd) {
|
|
if (saved_fd >= 0) {
|
|
tcsetattr(saved_fd, TCSAFLUSH, &saved_attr);
|
|
saved_fd = -1;
|
|
}
|
|
if(tcgetattr(*fd, &term)!=0) return;
|
|
/*
|
|
* Save the existing terminal mode flags to be restored later.
|
|
*/
|
|
saved_attr = term;
|
|
/*
|
|
* Enable raw single character input.
|
|
*/
|
|
term.c_lflag &= ~(ICANON) & ~(ECHO);
|
|
term.c_cc[VMIN] = 1;
|
|
term.c_cc[VTIME] = 0;
|
|
/*
|
|
* Install the new terminal flags after first waiting for all pending
|
|
* output to be delivered to the terminal and after discarding any
|
|
* lingering input.
|
|
*/
|
|
tcsetattr(*fd, TCSAFLUSH, &term);
|
|
if (exit_handler) {
|
|
atexit(GRETER);
|
|
exit_handler=0;
|
|
}
|
|
saved_fd = *fd;
|
|
}
|
|
if (*tmo != 0) {
|
|
term.c_cc[VMIN] = (*tmo == 0);
|
|
term.c_cc[VTIME] = *tmo;
|
|
tcsetattr(*fd, TCSANOW, &term);
|
|
}
|
|
/*
|
|
* Read one character from the terminal.
|
|
*/
|
|
nread = read(*fd, cbuf, 1);
|
|
if (nread!=1) *cbuf='\0';
|
|
if (*tmo != 0) {
|
|
term.c_cc[VMIN] = 1;
|
|
term.c_cc[VTIME] = 0;
|
|
tcsetattr(*fd, TCSANOW, &term);
|
|
}
|
|
return;
|
|
}
|