2013-05-20 03:16:19 -04:00
|
|
|
/* posix.c -- implements termio.h */
|
|
|
|
#include "termio.h"
|
2013-05-20 01:16:08 -04:00
|
|
|
|
2010-11-28 17:09:55 -05:00
|
|
|
/* posix.c
|
2005-05-31 11:50:56 -04:00
|
|
|
*
|
2010-11-28 17:09:55 -05:00
|
|
|
* The functions in this file negotiate with the operating system for
|
|
|
|
* characters, and write characters in a barely buffered fashion on the
|
|
|
|
* display. All operating systems.
|
2005-05-31 11:50:56 -04:00
|
|
|
*
|
|
|
|
* modified by Petri Kutvonen
|
|
|
|
*
|
|
|
|
* based on termio.c, with all the old cruft removed, and
|
|
|
|
* fixed for termios rather than the old termio.. Linus Torvalds
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef POSIX
|
|
|
|
|
2010-11-28 17:09:55 -05:00
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <signal.h>
|
2005-05-31 11:50:56 -04:00
|
|
|
#include <stdio.h>
|
2013-10-12 22:15:52 -04:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2010-11-28 17:09:55 -05:00
|
|
|
#include <termios.h>
|
2005-10-01 02:52:55 -04:00
|
|
|
#include <unistd.h>
|
2010-11-28 17:09:55 -05:00
|
|
|
|
2005-05-31 11:50:56 -04:00
|
|
|
#include "estruct.h"
|
2013-10-12 21:54:05 -04:00
|
|
|
#include "retcode.h"
|
2012-07-10 19:21:35 -04:00
|
|
|
#include "utf8.h"
|
2005-05-31 11:50:56 -04:00
|
|
|
|
2013-09-27 21:40:42 -04:00
|
|
|
int ttrow = HUGE ; /* Row location of HW cursor */
|
|
|
|
int ttcol = HUGE ; /* Column location of HW cursor */
|
|
|
|
|
2010-11-28 17:09:55 -05:00
|
|
|
/* Since Mac OS X's termios.h doesn't have the following 2 macros, define them.
|
|
|
|
*/
|
2012-05-26 10:06:28 -04:00
|
|
|
#if defined(SYSV) && (defined(_DARWIN_C_SOURCE) || defined(_FREEBSD_C_SOURCE))
|
2010-11-28 17:09:55 -05:00
|
|
|
#define OLCUC 0000002
|
|
|
|
#define XCASE 0000004
|
|
|
|
#endif
|
2005-05-31 11:50:56 -04:00
|
|
|
|
2013-05-01 01:03:04 -04:00
|
|
|
#ifdef CYGWIN
|
|
|
|
#define XCASE 0
|
|
|
|
#define ECHOPRT 0
|
|
|
|
#define PENDIN 0
|
|
|
|
#endif
|
|
|
|
|
2005-10-01 02:37:34 -04:00
|
|
|
static int kbdflgs; /* saved keyboard fd flags */
|
2005-10-01 02:52:55 -04:00
|
|
|
static int kbdpoll; /* in O_NDELAY mode */
|
2005-05-31 11:50:56 -04:00
|
|
|
|
2005-10-01 02:37:34 -04:00
|
|
|
static struct termios otermios; /* original terminal characteristics */
|
|
|
|
static struct termios ntermios; /* charactoristics to use inside */
|
2005-05-31 11:50:56 -04:00
|
|
|
|
|
|
|
#define TBUFSIZ 128
|
2005-10-01 02:37:34 -04:00
|
|
|
static char tobuf[TBUFSIZ]; /* terminal output buffer */
|
2005-05-31 11:50:56 -04:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function is called once to set up the terminal device streams.
|
|
|
|
* On VMS, it translates TT until it finds the terminal, then assigns
|
|
|
|
* a channel to it and sets it raw. On CPM it is a no-op.
|
|
|
|
*/
|
2005-09-30 20:08:36 -04:00
|
|
|
void ttopen(void)
|
2005-05-31 11:50:56 -04:00
|
|
|
{
|
|
|
|
tcgetattr(0, &otermios); /* save old settings */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* base new settings on old ones - don't change things
|
|
|
|
* we don't know about
|
|
|
|
*/
|
|
|
|
ntermios = otermios;
|
|
|
|
|
|
|
|
/* raw CR/NL etc input handling, but keep ISTRIP if we're on a 7-bit line */
|
|
|
|
ntermios.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK
|
2013-05-01 07:13:08 -04:00
|
|
|
| IXON | IXOFF | IXANY
|
2005-05-31 11:50:56 -04:00
|
|
|
| INPCK | INLCR | IGNCR | ICRNL);
|
|
|
|
|
|
|
|
/* raw CR/NR etc output handling */
|
2005-09-30 18:26:09 -04:00
|
|
|
ntermios.c_oflag &=
|
|
|
|
~(OPOST | ONLCR | OLCUC | OCRNL | ONOCR | ONLRET);
|
2005-05-31 11:50:56 -04:00
|
|
|
|
|
|
|
/* No signal handling, no echo etc */
|
|
|
|
ntermios.c_lflag &= ~(ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK
|
2005-09-30 18:26:09 -04:00
|
|
|
| ECHONL | NOFLSH | TOSTOP | ECHOCTL |
|
|
|
|
ECHOPRT | ECHOKE | FLUSHO | PENDIN | IEXTEN);
|
2005-05-31 11:50:56 -04:00
|
|
|
|
|
|
|
/* one character, no timeout */
|
|
|
|
ntermios.c_cc[VMIN] = 1;
|
|
|
|
ntermios.c_cc[VTIME] = 0;
|
|
|
|
tcsetattr(0, TCSADRAIN, &ntermios); /* and activate them */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* provide a smaller terminal output buffer so that
|
|
|
|
* the type ahead detection works better (more often)
|
|
|
|
*/
|
|
|
|
setbuffer(stdout, &tobuf[0], TBUFSIZ);
|
|
|
|
|
2005-09-30 18:26:09 -04:00
|
|
|
kbdflgs = fcntl(0, F_GETFL, 0);
|
2005-05-31 11:50:56 -04:00
|
|
|
kbdpoll = FALSE;
|
|
|
|
|
|
|
|
/* on all screens we are not sure of the initial position
|
2005-09-30 18:26:09 -04:00
|
|
|
of the cursor */
|
2005-05-31 11:50:56 -04:00
|
|
|
ttrow = 999;
|
|
|
|
ttcol = 999;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function gets called just before we go back home to the command
|
|
|
|
* interpreter. On VMS it puts the terminal back in a reasonable state.
|
|
|
|
* Another no-operation on CPM.
|
|
|
|
*/
|
2005-09-30 20:08:36 -04:00
|
|
|
void ttclose(void)
|
2005-05-31 11:50:56 -04:00
|
|
|
{
|
|
|
|
tcsetattr(0, TCSADRAIN, &otermios); /* restore terminal settings */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write a character to the display. On VMS, terminal output is buffered, and
|
|
|
|
* we just put the characters in the big array, after checking for overflow.
|
|
|
|
* On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
|
|
|
|
* MS-DOS (use the very very raw console output routine).
|
|
|
|
*/
|
2005-09-30 20:08:36 -04:00
|
|
|
int ttputc(int c)
|
2005-05-31 11:50:56 -04:00
|
|
|
{
|
2012-07-10 19:21:35 -04:00
|
|
|
char utf8[6];
|
|
|
|
int bytes;
|
|
|
|
|
|
|
|
bytes = unicode_to_utf8(c, utf8);
|
|
|
|
fwrite(utf8, 1, bytes, stdout);
|
2012-07-10 17:24:23 -04:00
|
|
|
return 0;
|
2005-05-31 11:50:56 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Flush terminal buffer. Does real work where the terminal output is buffered
|
|
|
|
* up. A no-operation on systems where byte at a time terminal I/O is done.
|
|
|
|
*/
|
2005-09-30 20:08:36 -04:00
|
|
|
void ttflush(void)
|
2005-05-31 11:50:56 -04:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Add some terminal output success checking, sometimes an orphaned
|
|
|
|
* process may be left looping on SunOS 4.1.
|
|
|
|
*
|
|
|
|
* How to recover here, or is it best just to exit and lose
|
|
|
|
* everything?
|
|
|
|
*
|
|
|
|
* jph, 8-Oct-1993
|
|
|
|
* Jani Jaakkola suggested using select after EAGAIN but let's just wait a bit
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int status;
|
|
|
|
|
|
|
|
status = fflush(stdout);
|
|
|
|
while (status < 0 && errno == EAGAIN) {
|
|
|
|
sleep(1);
|
|
|
|
status = fflush(stdout);
|
|
|
|
}
|
|
|
|
if (status < 0)
|
|
|
|
exit(15);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read a character from the terminal, performing no editing and doing no echo
|
|
|
|
* at all. More complex in VMS that almost anyplace else, which figures. Very
|
|
|
|
* simple on CPM, because the system can do exactly what you want.
|
|
|
|
*/
|
2005-09-30 20:08:36 -04:00
|
|
|
int ttgetc(void)
|
2005-05-31 11:50:56 -04:00
|
|
|
{
|
2012-07-10 20:36:30 -04:00
|
|
|
static char buffer[32];
|
2008-06-07 14:48:44 -04:00
|
|
|
static int pending;
|
2012-07-10 20:36:30 -04:00
|
|
|
unicode_t c;
|
2012-07-10 21:11:30 -04:00
|
|
|
int count, bytes = 1, expected;
|
2008-06-07 14:48:44 -04:00
|
|
|
|
|
|
|
count = pending;
|
|
|
|
if (!count) {
|
|
|
|
count = read(0, buffer, sizeof(buffer));
|
|
|
|
if (count <= 0)
|
|
|
|
return 0;
|
|
|
|
pending = count;
|
|
|
|
}
|
|
|
|
|
2012-07-10 20:36:30 -04:00
|
|
|
c = (unsigned char) buffer[0];
|
2008-06-07 14:48:44 -04:00
|
|
|
if (c >= 32 && c < 128)
|
|
|
|
goto done;
|
|
|
|
|
2012-07-10 21:11:30 -04:00
|
|
|
/*
|
|
|
|
* Lazy. We don't bother calculating the exact
|
|
|
|
* expected length. We want at least two characters
|
|
|
|
* for the special character case (ESC+[) and for
|
|
|
|
* the normal short UTF8 sequence that starts with
|
|
|
|
* the 110xxxxx pattern.
|
|
|
|
*
|
|
|
|
* But if we have any of the other patterns, just
|
|
|
|
* try to get more characters. At worst, that will
|
|
|
|
* just result in a barely perceptible 0.1 second
|
|
|
|
* delay for some *very* unusual utf8 character
|
|
|
|
* input.
|
|
|
|
*/
|
|
|
|
expected = 2;
|
|
|
|
if ((c & 0xe0) == 0xe0)
|
|
|
|
expected = 6;
|
|
|
|
|
2008-06-07 14:48:44 -04:00
|
|
|
/* Special character - try to fill buffer */
|
2012-07-10 21:11:30 -04:00
|
|
|
if (count < expected) {
|
2008-06-07 14:48:44 -04:00
|
|
|
int n;
|
|
|
|
ntermios.c_cc[VMIN] = 0;
|
|
|
|
ntermios.c_cc[VTIME] = 1; /* A .1 second lag */
|
|
|
|
tcsetattr(0, TCSANOW, &ntermios);
|
|
|
|
|
|
|
|
n = read(0, buffer + count, sizeof(buffer) - count);
|
|
|
|
|
|
|
|
/* Undo timeout */
|
|
|
|
ntermios.c_cc[VMIN] = 1;
|
|
|
|
ntermios.c_cc[VTIME] = 0;
|
|
|
|
tcsetattr(0, TCSANOW, &ntermios);
|
2005-10-02 20:47:28 -04:00
|
|
|
|
2012-07-10 20:36:30 -04:00
|
|
|
if (n > 0)
|
|
|
|
pending += n;
|
2005-10-02 20:47:28 -04:00
|
|
|
}
|
2012-07-10 20:36:30 -04:00
|
|
|
if (pending > 1) {
|
|
|
|
unsigned char second = buffer[1];
|
2005-10-02 20:47:28 -04:00
|
|
|
|
2012-07-10 20:36:30 -04:00
|
|
|
/* Turn ESC+'[' into CSI */
|
|
|
|
if (c == 27 && second == '[') {
|
|
|
|
bytes = 2;
|
|
|
|
c = 128+27;
|
|
|
|
goto done;
|
|
|
|
}
|
2008-06-07 14:48:44 -04:00
|
|
|
}
|
2012-07-10 20:36:30 -04:00
|
|
|
bytes = utf8_to_unicode(buffer, 0, pending, &c);
|
2005-10-02 20:47:28 -04:00
|
|
|
|
2008-06-07 14:48:44 -04:00
|
|
|
done:
|
2012-07-10 20:36:30 -04:00
|
|
|
pending -= bytes;
|
|
|
|
memmove(buffer, buffer+bytes, pending);
|
2005-10-02 20:47:28 -04:00
|
|
|
return c;
|
2005-05-31 11:50:56 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* typahead: Check to see if any characters are already in the
|
|
|
|
keyboard buffer
|
|
|
|
*/
|
|
|
|
|
2005-09-30 20:08:36 -04:00
|
|
|
int typahead(void)
|
2005-05-31 11:50:56 -04:00
|
|
|
{
|
2005-09-30 18:26:09 -04:00
|
|
|
int x; /* holds # of pending chars */
|
2005-05-31 11:50:56 -04:00
|
|
|
|
|
|
|
#ifdef FIONREAD
|
2005-09-30 18:26:09 -04:00
|
|
|
if (ioctl(0, FIONREAD, &x) < 0)
|
2005-05-31 11:50:56 -04:00
|
|
|
x = 0;
|
|
|
|
#else
|
|
|
|
x = 0;
|
|
|
|
#endif
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2005-09-30 18:26:09 -04:00
|
|
|
#endif /* POSIX */
|