|  | #include <ctype.h> | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  | #include <sys/mman.h> | 
|  | #include <fcntl.h> | 
|  | #include <string.h> | 
|  | #include <termios.h> | 
|  | #include <unistd.h> | 
|  |  | 
|  | struct { | 
|  | char key; | 
|  | char *chars; | 
|  | } map[] = { | 
|  | { '1', "_ -1?!,.:;\"'<=>()_" }, | 
|  | { '2', "Cabc2ABC" }, | 
|  | { '3', "Fdef3DEF" }, | 
|  | { '4', "Ighi4GHI" }, | 
|  | { '5', "Ljkl5JKL" }, | 
|  | { '6', "Omno6MNO" }, | 
|  | { '7', "Spqrs7PQRS" }, | 
|  | { '8', "Vtuv8TUV" }, | 
|  | { '9', "Zwxyz9WXYZ" }, | 
|  | { '0', "*+&0@/#*" }, | 
|  | }; | 
|  |  | 
|  | char next_char(char key, char current) | 
|  | { | 
|  | int i; | 
|  | char *next; | 
|  | for(i = 0; i < sizeof(map) / sizeof(map[0]); i++) { | 
|  | if(key == map[i].key) { | 
|  | next = strchr(map[i].chars, current); | 
|  | if(next && next[1]) | 
|  | return next[1]; | 
|  | return map[i].chars[1]; | 
|  | } | 
|  | } | 
|  | return key; | 
|  | } | 
|  |  | 
|  | char prev_char(char key, char current) | 
|  | { | 
|  | int i; | 
|  | char *next; | 
|  | for(i = 0; i < sizeof(map) / sizeof(map[0]); i++) { | 
|  | if(key == map[i].key) { | 
|  | next = strchr(map[i].chars+1, current); | 
|  | if(next && next[-1]) | 
|  | return next[-1]; | 
|  | return map[i].chars[1]; | 
|  | } | 
|  | } | 
|  | return key; | 
|  | } | 
|  |  | 
|  | int readtty_main(int argc, char *argv[]) | 
|  | { | 
|  | int c; | 
|  | //int flags; | 
|  | char buf[1]; | 
|  | int res; | 
|  | struct termios ttyarg; | 
|  | struct termios savedttyarg; | 
|  | int nonblock = 0; | 
|  | int timeout = 0; | 
|  | int flush = 0; | 
|  | int phone = 0; | 
|  | char *accept = NULL; | 
|  | char *rejectstring = NULL; | 
|  | char last_char_in = 0; | 
|  | char current_char = 0; | 
|  | char *exit_string = NULL; | 
|  | int exit_match = 0; | 
|  |  | 
|  | do { | 
|  | c = getopt(argc, argv, "nt:fa:r:pe:"); | 
|  | if (c == EOF) | 
|  | break; | 
|  | switch (c) { | 
|  | case 't': | 
|  | timeout = atoi(optarg); | 
|  | break; | 
|  | case 'n': | 
|  | nonblock = 1; | 
|  | break; | 
|  | case 'f': | 
|  | flush = 1; | 
|  | break; | 
|  | case 'a': | 
|  | accept = optarg; | 
|  | break; | 
|  | case 'r': | 
|  | rejectstring = optarg; | 
|  | break; | 
|  | case 'p': | 
|  | phone = 1; | 
|  | break; | 
|  | case 'e': | 
|  | exit_string = optarg; | 
|  | break; | 
|  | case '?': | 
|  | fprintf(stderr, "%s: invalid option -%c\n", | 
|  | argv[0], optopt); | 
|  | exit(1); | 
|  | } | 
|  | } while (1); | 
|  |  | 
|  | if(flush) | 
|  | tcflush(STDIN_FILENO, TCIFLUSH); | 
|  | ioctl(STDIN_FILENO, TCGETS , &savedttyarg) ;       /* set changed tty arguments */ | 
|  | ttyarg = savedttyarg; | 
|  | ttyarg.c_cc[VMIN] = (timeout > 0 || nonblock) ? 0 : 1;                /* minimum of 0 chars */ | 
|  | ttyarg.c_cc[VTIME] = timeout;              /* wait max 15/10 sec */ | 
|  | ttyarg.c_iflag = BRKINT | ICRNL; | 
|  | ttyarg.c_lflag &= ~(ECHO | ICANON); | 
|  | ioctl(STDIN_FILENO, TCSETS , &ttyarg); | 
|  |  | 
|  | while (1) { | 
|  | res = read(STDIN_FILENO, buf, 1); | 
|  | if(res <= 0) { | 
|  | if(phone) { | 
|  | if(current_char) { | 
|  | write(STDERR_FILENO, ¤t_char, 1); | 
|  | write(STDOUT_FILENO, ¤t_char, 1); | 
|  | if(exit_string && current_char == exit_string[exit_match]) { | 
|  | exit_match++; | 
|  | if(exit_string[exit_match] == '\0') | 
|  | break; | 
|  | } | 
|  | else | 
|  | exit_match = 0; | 
|  | current_char = 0; | 
|  | } | 
|  | continue; | 
|  | } | 
|  | break; | 
|  | } | 
|  | if(accept && strchr(accept, buf[0]) == NULL) { | 
|  | if(rejectstring) { | 
|  | write(STDOUT_FILENO, rejectstring, strlen(rejectstring)); | 
|  | break; | 
|  | } | 
|  | if(flush) | 
|  | tcflush(STDIN_FILENO, TCIFLUSH); | 
|  | continue; | 
|  | } | 
|  | if(phone) { | 
|  | //if(!isprint(buf[0])) { | 
|  | //  fprintf(stderr, "got unprintable character 0x%x\n", buf[0]); | 
|  | //} | 
|  | if(buf[0] == '\0') { | 
|  | if(current_char) { | 
|  | current_char = prev_char(last_char_in, current_char); | 
|  | write(STDERR_FILENO, ¤t_char, 1); | 
|  | write(STDERR_FILENO, "\b", 1); | 
|  | } | 
|  | continue; | 
|  | } | 
|  | if(current_char && buf[0] != last_char_in) { | 
|  | write(STDERR_FILENO, ¤t_char, 1); | 
|  | write(STDOUT_FILENO, ¤t_char, 1); | 
|  | if(exit_string && current_char == exit_string[exit_match]) { | 
|  | exit_match++; | 
|  | if(exit_string[exit_match] == '\0') | 
|  | break; | 
|  | } | 
|  | else | 
|  | exit_match = 0; | 
|  | current_char = 0; | 
|  | } | 
|  | last_char_in = buf[0]; | 
|  | current_char = next_char(last_char_in, current_char); | 
|  | write(STDERR_FILENO, ¤t_char, 1); | 
|  | write(STDERR_FILENO, "\b", 1); | 
|  | continue; | 
|  | } | 
|  | write(STDOUT_FILENO, buf, 1); | 
|  | break; | 
|  | } | 
|  | ioctl(STDIN_FILENO, TCSETS , &savedttyarg) ;       /* set changed tty arguments */ | 
|  |  | 
|  | return 0; | 
|  | } |