Changeset View
Changeset View
Standalone View
Standalone View
contrib/mg/ttyio.c
- This file was added.
/* $OpenBSD: ttyio.c,v 1.40 2021/03/20 09:00:49 lum Exp $ */ | |||||
/* This file is in the public domain. */ | |||||
/* | |||||
* POSIX terminal I/O. | |||||
* | |||||
* The functions in this file negotiate with the operating system for | |||||
* keyboard characters, and write characters to the display in a barely | |||||
* buffered fashion. | |||||
*/ | |||||
#include <sys/ioctl.h> | |||||
#include <sys/queue.h> | |||||
#include <sys/time.h> | |||||
#include <sys/types.h> | |||||
#include <errno.h> | |||||
#include <fcntl.h> | |||||
#include <poll.h> | |||||
#include <signal.h> | |||||
#include <stdio.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#include <term.h> | |||||
#include <termios.h> | |||||
#include <unistd.h> | |||||
#include "def.h" | |||||
#define NOBUF 512 /* Output buffer size. */ | |||||
int ttstarted; | |||||
char obuf[NOBUF]; /* Output buffer. */ | |||||
size_t nobuf; /* Buffer count. */ | |||||
struct termios oldtty; /* POSIX tty settings. */ | |||||
struct termios newtty; | |||||
int nrow; /* Terminal size, rows. */ | |||||
int ncol; /* Terminal size, columns. */ | |||||
/* | |||||
* This function gets called once, to set up the terminal. | |||||
* On systems w/o TCSASOFT we turn off off flow control, | |||||
* which isn't really the right thing to do. | |||||
*/ | |||||
void | |||||
ttopen(void) | |||||
{ | |||||
if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO)) | |||||
panic("standard input and output must be a terminal"); | |||||
if (ttraw() == FALSE) | |||||
panic("aborting due to terminal initialize failure"); | |||||
} | |||||
/* | |||||
* This function sets the terminal to RAW mode, as defined for the current | |||||
* shell. This is called both by ttopen() above and by spawncli() to | |||||
* get the current terminal settings and then change them to what | |||||
* mg expects. Thus, tty changes done while spawncli() is in effect | |||||
* will be reflected in mg. | |||||
*/ | |||||
int | |||||
ttraw(void) | |||||
{ | |||||
if (tcgetattr(0, &oldtty) == -1) { | |||||
dobeep(); | |||||
ewprintf("ttopen can't get terminal attributes"); | |||||
return (FALSE); | |||||
} | |||||
(void)memcpy(&newtty, &oldtty, sizeof(newtty)); | |||||
/* Set terminal to 'raw' mode and ignore a 'break' */ | |||||
newtty.c_cc[VMIN] = 1; | |||||
newtty.c_cc[VTIME] = 0; | |||||
newtty.c_iflag |= IGNBRK; | |||||
newtty.c_iflag &= ~(BRKINT | PARMRK | INLCR | IGNCR | ICRNL | IXON); | |||||
newtty.c_oflag &= ~OPOST; | |||||
newtty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); | |||||
if (tcsetattr(0, TCSASOFT | TCSADRAIN, &newtty) == -1) { | |||||
dobeep(); | |||||
ewprintf("ttopen can't tcsetattr"); | |||||
return (FALSE); | |||||
} | |||||
ttstarted = 1; | |||||
return (TRUE); | |||||
} | |||||
/* | |||||
* This function gets called just before we go back home to the shell. | |||||
* Put all of the terminal parameters back. | |||||
* Under UN*X this just calls ttcooked(), but the ttclose() hook is in | |||||
* because vttidy() in display.c expects it for portability reasons. | |||||
*/ | |||||
void | |||||
ttclose(void) | |||||
{ | |||||
if (ttstarted) { | |||||
if (ttcooked() == FALSE) | |||||
panic(""); /* ttcooked() already printf'd */ | |||||
ttstarted = 0; | |||||
} | |||||
} | |||||
/* | |||||
* This function restores all terminal settings to their default values, | |||||
* in anticipation of exiting or suspending the editor. | |||||
*/ | |||||
int | |||||
ttcooked(void) | |||||
{ | |||||
ttflush(); | |||||
if (tcsetattr(0, TCSASOFT | TCSADRAIN, &oldtty) == -1) { | |||||
dobeep(); | |||||
ewprintf("ttclose can't tcsetattr"); | |||||
return (FALSE); | |||||
} | |||||
return (TRUE); | |||||
} | |||||
/* | |||||
* Write character to the display. Characters are buffered up, | |||||
* to make things a little bit more efficient. | |||||
*/ | |||||
int | |||||
ttputc(int c) | |||||
{ | |||||
if (nobuf >= NOBUF) | |||||
ttflush(); | |||||
obuf[nobuf++] = c; | |||||
return (c); | |||||
} | |||||
/* | |||||
* Flush output. | |||||
*/ | |||||
void | |||||
ttflush(void) | |||||
{ | |||||
ssize_t written; | |||||
char *buf = obuf; | |||||
if (nobuf == 0 || batch == 1) | |||||
return; | |||||
while ((written = write(fileno(stdout), buf, nobuf)) != nobuf) { | |||||
if (written == -1) { | |||||
if (errno == EINTR) | |||||
continue; | |||||
panic("ttflush write failed"); | |||||
} | |||||
buf += written; | |||||
nobuf -= written; | |||||
} | |||||
nobuf = 0; | |||||
} | |||||
/* | |||||
* Read character from terminal. All 8 bits are returned, so that you | |||||
* can use a multi-national terminal. | |||||
*/ | |||||
int | |||||
ttgetc(void) | |||||
{ | |||||
char c; | |||||
ssize_t ret; | |||||
do { | |||||
ret = read(STDIN_FILENO, &c, 1); | |||||
if (ret == -1 && errno == EINTR) { | |||||
if (winch_flag) { | |||||
redraw(0, 0); | |||||
winch_flag = 0; | |||||
} | |||||
} else if (ret == -1 && errno == EIO) | |||||
panic("lost stdin"); | |||||
else if (ret == 1) | |||||
break; | |||||
} while (1); | |||||
return ((int) c) & 0xFF; | |||||
} | |||||
/* | |||||
* Returns TRUE if there are characters waiting to be read. | |||||
*/ | |||||
int | |||||
charswaiting(void) | |||||
{ | |||||
int x; | |||||
return ((ioctl(0, FIONREAD, &x) == -1) ? 0 : x); | |||||
} | |||||
/* | |||||
* panic - just exit, as quickly as we can. | |||||
*/ | |||||
void | |||||
panic(char *s) | |||||
{ | |||||
static int panicking = 0; | |||||
if (panicking) | |||||
return; | |||||
else | |||||
panicking = 1; | |||||
ttclose(); | |||||
(void) fputs("panic: ", stderr); | |||||
(void) fputs(s, stderr); | |||||
(void) fputc('\n', stderr); /* Use '\n' as no buffers now. */ | |||||
exit(1); | |||||
} | |||||
/* | |||||
* This function returns FALSE if any characters have showed up on the | |||||
* tty before 'msec' milliseconds. | |||||
*/ | |||||
int | |||||
ttwait(int msec) | |||||
{ | |||||
struct pollfd pfd[1]; | |||||
pfd[0].fd = 0; | |||||
pfd[0].events = POLLIN; | |||||
if ((poll(pfd, 1, msec)) == 0) | |||||
return (TRUE); | |||||
return (FALSE); | |||||
} |