| /* posix.c |
| * |
| * 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. |
| * |
| * 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 |
| |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <signal.h> |
| #include <stdio.h> |
| #include <termios.h> |
| #include <unistd.h> |
| |
| #include "estruct.h" |
| #include "edef.h" |
| #include "efunc.h" |
| |
| /* Since Mac OS X's termios.h doesn't have the following 2 macros, define them. |
| */ |
| #if defined(SYSV) && (defined(_DARWIN_C_SOURCE) || defined(_FREEBSD_C_SOURCE)) |
| #define OLCUC 0000002 |
| #define XCASE 0000004 |
| #endif |
| |
| static int kbdflgs; /* saved keyboard fd flags */ |
| static int kbdpoll; /* in O_NDELAY mode */ |
| |
| static struct termios otermios; /* original terminal characteristics */ |
| static struct termios ntermios; /* charactoristics to use inside */ |
| |
| #define TBUFSIZ 128 |
| static char tobuf[TBUFSIZ]; /* terminal output buffer */ |
| |
| |
| /* |
| * 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. |
| */ |
| void ttopen(void) |
| { |
| 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 |
| | INPCK | INLCR | IGNCR | ICRNL); |
| |
| /* raw CR/NR etc output handling */ |
| ntermios.c_oflag &= |
| ~(OPOST | ONLCR | OLCUC | OCRNL | ONOCR | ONLRET); |
| |
| /* No signal handling, no echo etc */ |
| ntermios.c_lflag &= ~(ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK |
| | ECHONL | NOFLSH | TOSTOP | ECHOCTL | |
| ECHOPRT | ECHOKE | FLUSHO | PENDIN | IEXTEN); |
| |
| /* 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); |
| |
| kbdflgs = fcntl(0, F_GETFL, 0); |
| kbdpoll = FALSE; |
| |
| /* on all screens we are not sure of the initial position |
| of the cursor */ |
| 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. |
| */ |
| void ttclose(void) |
| { |
| 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). |
| */ |
| int ttputc(int c) |
| { |
| unsigned char utf8[6], *p = utf8+5; |
| int bytes = 1; |
| |
| if (c < 0) |
| return 0; |
| *p = c; |
| if (c > 0x7f) { |
| int prefix = 0x40; |
| do { |
| *p = 0x80 + (c & 0x3f); |
| --p; |
| bytes++; |
| prefix >>= 1; |
| c >>= 6; |
| } while (c > prefix); |
| *p = c - 2*prefix; |
| } |
| fwrite(p, 1, bytes, stdout); |
| return 0; |
| } |
| |
| /* |
| * 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. |
| */ |
| void ttflush(void) |
| { |
| /* |
| * 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. |
| */ |
| int ttgetc(void) |
| { |
| static unsigned char buffer[32]; |
| static int pending; |
| unsigned char c, second; |
| int count; |
| |
| count = pending; |
| if (!count) { |
| count = read(0, buffer, sizeof(buffer)); |
| if (count <= 0) |
| return 0; |
| pending = count; |
| } |
| |
| c = buffer[0]; |
| if (c >= 32 && c < 128) |
| goto done; |
| |
| /* Special character - try to fill buffer */ |
| if (count == 1) { |
| 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); |
| |
| if (n <= 0) |
| goto done; |
| pending += n; |
| } |
| second = buffer[1]; |
| |
| /* Turn ESC+'[' into CSI */ |
| if (c == 27 && second == '[') { |
| pending -= 2; |
| memmove(buffer, buffer+2, pending); |
| return 128+27; |
| } |
| |
| /* Normal 7-bit? */ |
| if (!(c & 0x80)) |
| goto done; |
| |
| /* |
| * Unexpected UTF-8 continuation character? Maybe |
| * we're in non-UTF mode, or maybe it's a control |
| * character.. Regardless, just pass it on. |
| */ |
| if (!(c & 0x40)) |
| goto done; |
| |
| /* |
| * Multi-byte sequences.. Right now we only |
| * want to get characters that can be represented |
| * in a single byte, so we're not interested in |
| * anything else.. |
| */ |
| if (c & 0x3c) |
| goto done; |
| |
| if ((second & 0xc0) != 0x80) |
| goto done; |
| |
| /* |
| * Ok, it's a two-byte UTF-8 character that can be represented |
| * as a single-byte Latin1 character! |
| */ |
| c = (c << 6) | (second & 0x3f); |
| pending -= 2; |
| memmove(buffer, buffer+2, pending); |
| |
| return c; |
| |
| done: |
| pending--; |
| memmove(buffer, buffer+1, pending); |
| return c; |
| } |
| |
| /* typahead: Check to see if any characters are already in the |
| keyboard buffer |
| */ |
| |
| int typahead(void) |
| { |
| int x; /* holds # of pending chars */ |
| |
| #ifdef FIONREAD |
| if (ioctl(0, FIONREAD, &x) < 0) |
| x = 0; |
| #else |
| x = 0; |
| #endif |
| return x; |
| } |
| |
| #endif /* POSIX */ |