readtty.c revision dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0
1dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <ctype.h>
2dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdio.h>
3dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdlib.h>
4dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/mman.h>
5dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <fcntl.h>
6dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <string.h>
7dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <termios.h>
8dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <unistd.h>
9dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
10dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstruct {
11dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char key;
12dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char *chars;
13dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} map[] = {
14dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    { '1', "_ -1?!,.:;\"'<=>()_" },
15dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    { '2', "Cabc2ABC" },
16dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    { '3', "Fdef3DEF" },
17dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    { '4', "Ighi4GHI" },
18dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    { '5', "Ljkl5JKL" },
19dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    { '6', "Omno6MNO" },
20dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    { '7', "Spqrs7PQRS" },
21dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    { '8', "Vtuv8TUV" },
22dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    { '9', "Zwxyz9WXYZ" },
23dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    { '0', "*+&0@/#*" },
24dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project};
25dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
26dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectchar next_char(char key, char current)
27dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
28dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int i;
29dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char *next;
30dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    for(i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
31dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if(key == map[i].key) {
32dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            next = strchr(map[i].chars, current);
33dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if(next && next[1])
34dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                return next[1];
35dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            return map[i].chars[1];
36dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
37dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
38dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return key;
39dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
40dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
41dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectchar prev_char(char key, char current)
42dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
43dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int i;
44dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char *next;
45dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    for(i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
46dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if(key == map[i].key) {
47dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            next = strchr(map[i].chars+1, current);
48dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if(next && next[-1])
49dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                return next[-1];
50dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            return map[i].chars[1];
51dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
52dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
53dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return key;
54dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
55dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
56dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint readtty_main(int argc, char *argv[])
57dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
58dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int c;
59dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    //int flags;
60dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char buf[1];
61dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int res;
62dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct termios ttyarg;
63dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct termios savedttyarg;
64dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int nonblock = 0;
65dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int timeout = 0;
66dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int flush = 0;
67dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int phone = 0;
68dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char *accept = NULL;
69dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char *rejectstring = NULL;
70dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char last_char_in = 0;
71dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char current_char = 0;
72dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char *exit_string = NULL;
73dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int exit_match = 0;
74dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
75dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    do {
76dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        c = getopt(argc, argv, "nt:fa:r:pe:");
77dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (c == EOF)
78dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
79dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        switch (c) {
80dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case 't':
81dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            timeout = atoi(optarg);
82dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
83dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case 'n':
84dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            nonblock = 1;
85dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
86dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case 'f':
87dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            flush = 1;
88dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
89dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case 'a':
90dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            accept = optarg;
91dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
92dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case 'r':
93dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            rejectstring = optarg;
94dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
95dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case 'p':
96dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            phone = 1;
97dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
98dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case 'e':
99dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            exit_string = optarg;
100dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
101dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case '?':
102dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            fprintf(stderr, "%s: invalid option -%c\n",
103dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                argv[0], optopt);
104dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            exit(1);
105dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
106dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } while (1);
107dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
108dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if(flush)
109dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        tcflush(STDIN_FILENO, TCIFLUSH);
110dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ioctl(STDIN_FILENO, TCGETS , &savedttyarg) ;       /* set changed tty arguments */
111dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ttyarg = savedttyarg;
112dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ttyarg.c_cc[VMIN] = (timeout > 0 || nonblock) ? 0 : 1;                /* minimum of 0 chars */
113dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ttyarg.c_cc[VTIME] = timeout;              /* wait max 15/10 sec */
114dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ttyarg.c_iflag = BRKINT | ICRNL;
115dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ttyarg.c_lflag &= ~(ECHO | ICANON);
116dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ioctl(STDIN_FILENO, TCSETS , &ttyarg);
117dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
118dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    while (1) {
119dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        res = read(STDIN_FILENO, buf, 1);
120dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if(res <= 0) {
121dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if(phone) {
122dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                if(current_char) {
123dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    write(STDERR_FILENO, &current_char, 1);
124dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    write(STDOUT_FILENO, &current_char, 1);
125dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    if(exit_string && current_char == exit_string[exit_match]) {
126dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                        exit_match++;
127dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                        if(exit_string[exit_match] == '\0')
128dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                            break;
129dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    }
130dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    else
131dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                        exit_match = 0;
132dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    current_char = 0;
133dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                }
134dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                continue;
135dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
136dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
137dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
138dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if(accept && strchr(accept, buf[0]) == NULL) {
139dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if(rejectstring) {
140dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                write(STDOUT_FILENO, rejectstring, strlen(rejectstring));
141dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                break;
142dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
143dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if(flush)
144dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                tcflush(STDIN_FILENO, TCIFLUSH);
145dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            continue;
146dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
147dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if(phone) {
148dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            //if(!isprint(buf[0])) {
149dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            //  fprintf(stderr, "got unprintable character 0x%x\n", buf[0]);
150dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            //}
151dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if(buf[0] == '\0') {
152dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                if(current_char) {
153dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    current_char = prev_char(last_char_in, current_char);
154dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    write(STDERR_FILENO, &current_char, 1);
155dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    write(STDERR_FILENO, "\b", 1);
156dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                }
157dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                continue;
158dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
159dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if(current_char && buf[0] != last_char_in) {
160dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                write(STDERR_FILENO, &current_char, 1);
161dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                write(STDOUT_FILENO, &current_char, 1);
162dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                if(exit_string && current_char == exit_string[exit_match]) {
163dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    exit_match++;
164dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    if(exit_string[exit_match] == '\0')
165dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                        break;
166dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                }
167dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                else
168dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    exit_match = 0;
169dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                current_char = 0;
170dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
171dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            last_char_in = buf[0];
172dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            current_char = next_char(last_char_in, current_char);
173dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            write(STDERR_FILENO, &current_char, 1);
174dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            write(STDERR_FILENO, "\b", 1);
175dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            continue;
176dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
177dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        write(STDOUT_FILENO, buf, 1);
178dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        break;
179dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
180dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ioctl(STDIN_FILENO, TCSETS , &savedttyarg) ;       /* set changed tty arguments */
181dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
182dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 0;
183dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
184