#include #include #include #include #include #include #include #include #include #include #include #include #include struct termios saved_termios; int saved_flags = 0, odd_keyboard = 0, done_atexit = 0; #define kbb_sz 256 char kbbuff[kbb_sz]; int kbb_b = 0, kbb_e = 0, kbb_n = 0, kbb_l = 0; const char * signame[] = { "", "HUP", "INT", "QUIT", "ILL", "TRAP", "ABRT", "EMT", "FPE", "KILL", "BUS", "SEGV", "SYS", "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "INFO", "USR1", "USR2", "THR", "LIBRT" }; const int numsigs = sizeof(signame) / sizeof(signame[0]); void saysignal(int n) { printf("signal %d: ", n); if (n > 0 && n < numsigs) printf("SIG%s\n", signame[n]); else printf("incorrect\n"); } void ignore_signals() { signal(SIGHUP, saysignal); signal(SIGILL, saysignal); signal(SIGTRAP, saysignal); signal(SIGABRT, saysignal); signal(SIGEMT, saysignal); signal(SIGFPE, saysignal); signal(SIGSYS, saysignal); signal(SIGPIPE, saysignal); signal(SIGALRM, saysignal); signal(SIGURG, saysignal); signal(SIGSTOP, saysignal); signal(SIGTSTP, saysignal); signal(SIGCONT, saysignal); signal(SIGCHLD, saysignal); signal(SIGTTIN, saysignal); signal(SIGTTOU, saysignal); signal(SIGXCPU, saysignal); signal(SIGXFSZ, saysignal); signal(SIGVTALRM, saysignal); signal(SIGPROF, saysignal); signal(SIGWINCH, saysignal); signal(SIGINFO, saysignal); signal(SIGUSR1, saysignal); signal(SIGUSR2, saysignal); signal(SIGTHR, saysignal); signal(SIGLIBRT, saysignal); } int enqueue(char c) { if (kbb_n == kbb_sz) return 0; kbbuff[kbb_e] = c; kbb_e += 1; if (kbb_e == kbb_sz) kbb_e = 0; kbb_n += 1; if (c == '\n') kbb_l += 1; return 1; } int kb_line_ready(void) { return kbb_l > 0; } int kb_char_ready(void) { return kbb_n > 0; } char read_kb_char(void) { if (kbb_n == 0) return '\0'; char c = kbbuff[kbb_b]; kbb_b += 1; if (kbb_b == kbb_sz) kbb_b = 0; kbb_n -= 1; if (c == '\n') kbb_l -= 1; return c; } char * read_kb_line(char * s, int n) { int len = 0; if (kbb_l == 0) return NULL; while (1) { if (kbb_n == 0) break; if (len == n - 1) break; char c = read_kb_char(); if (c == '\n') break; s[len] = c; len += 1; } s[len] = '\0'; return s; } static void sigio(int x) { char c; int n = read(0, & c, 1); if (n > 0) { int ok = enqueue(c); } } int keyboard_back_to_normal(void) { if (! odd_keyboard) return 0; int r = tcsetattr(0, TCSAFLUSH, & saved_termios); if (r < 0) return r; odd_keyboard = 0; signal(SIGIO, SIG_IGN); fcntl(0, F_SETFL, saved_flags); return 0; } int keyboard_immediate(void) { struct termios temp; int r = tcgetattr(0, & saved_termios); if (r < 0) return r; temp = saved_termios; temp.c_lflag &= ~ ICANON; temp.c_lflag &= ~ ECHO; temp.c_cc[VMIN] = 1; temp.c_cc[VTIME] = 0; r = tcsetattr(0, TCSAFLUSH, & temp); if (r < 0) return r; odd_keyboard = 1; signal(SIGIO, sigio); int pid = getpid(); saved_flags = fcntl(0, F_GETFL, 0); fcntl(0, F_SETFL, saved_flags | O_ASYNC | O_NONBLOCK); fcntl(0, F_SETOWN, pid); if (! done_atexit) { atexit((void (*)(void)) keyboard_back_to_normal); ignore_signals(); done_atexit = 1; } return 0; } void safeprint(const char * s) { int i = 0; while (1) { char c = s[i]; if (c == '\0') break; else if (c == '\\') printf("\\\\"); else if (c >= ' ' && c <= '~') putchar(c); else printf("\\%03o", c); i += 1; } } int main() { int r = keyboard_immediate(); if (r < 0) { perror("keyboard_immediate"); exit(1); } const int linelen = 100; char line[linelen], * s; while (1) { printf("> "); fflush(stdout); while (1) { s = read_kb_line(line, linelen); if (s != NULL) break; putchar('.'); fflush(stdout); while (1) { int r = usleep(1000000); if (r < 0) { if (kb_line_ready()) break; else if (errno = EINTR) continue; else perror("usleep"); } else break; } } printf("received \""); safeprint(line); printf("\"\n"); } }