| #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; | 
 | } |