-
Notifications
You must be signed in to change notification settings - Fork 3
/
unixterm.c
201 lines (148 loc) · 3.58 KB
/
unixterm.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/*
* This file implement these functions for UNIX:
*
* 1. Terminal setup and tear down
* 2. Flushing the transmit and receive channels.
* 3. "Raw" transmit and receive on stdout and stdin.
* 4. Timeout handling when receiving.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <termios.h>
#include <unistd.h>
#include "zmdm.h"
#include "zmodem.h"
extern int last_sent;
/*
* routines to make the io channel raw and restore it
* to its normal state.
*/
struct termios old_termios;
void fd_init(void) {
struct termios t;
tcgetattr(0, &old_termios);
tcgetattr(0, &t);
t.c_iflag = 0;
t.c_oflag = 0;
t.c_lflag = 0;
t.c_cflag |= CS8;
tcsetattr(0, TCSANOW, &t);
}
void fd_exit(void) { tcsetattr(0, TCSANOW, &old_termios); }
/*
* read bytes as long as rdchk indicates that
* more data is available.
*/
void rx_purge(void) {
struct timeval t;
fd_set f;
unsigned char c;
t.tv_sec = 0;
t.tv_usec = 0;
FD_ZERO(&f);
FD_SET(0, &f);
while (select(1, &f, NULL, NULL, &t)) {
read(0, &c, 1);
}
}
/*
* send the bytes accumulated in the output buffer.
*/
void tx_flush(void) { fflush(stdout); }
/*
* transmit a character.
* this is the raw modem interface
*/
void tx_raw(int c) {
#ifdef DEBUG
if (raw_trace) {
fprintf(stderr, "%02x ", c);
}
#endif
last_sent = c & 0x7f;
putchar(c);
}
/*
* receive any style header within timeout milliseconds
*/
void alrm(int a) { signal(SIGALRM, SIG_IGN); }
int rx_poll(void) {
struct timeval t;
fd_set f;
t.tv_sec = 0;
t.tv_usec = 0;
FD_ZERO(&f);
FD_SET(0, &f);
if (select(1, &f, NULL, NULL, &t)) {
return 1;
}
return 0;
}
unsigned char inputbuffer[1024];
size_t n_in_inputbuffer = 0;
int inputbuffer_index;
/*
* rx_raw ; receive a single byte from the line.
* reads as many are available and then processes them one at a time
* check the data stream for 5 consecutive CAN characters;
* and if you see them abort. this saves a lot of clutter in
* the rest of the code; even though it is a very strange place
* for an exit. (but that was wat session abort was all about.)
*/
/* inline */
int rx_raw(int timeout) {
unsigned char c;
static int n_cans = 0;
if (n_in_inputbuffer == 0) {
/*
* change the timeout into seconds; minimum is 1
*/
timeout /= 1000;
if (timeout == 0) {
timeout++;
}
/*
* setup an alarm in case io takes too long
*/
signal(SIGALRM, alrm);
timeout /= 1000;
if (timeout == 0) {
timeout = 2;
}
alarm(timeout);
n_in_inputbuffer = read(0, inputbuffer, 1024);
if (n_in_inputbuffer <= 0) {
n_in_inputbuffer = 0;
}
/*
* cancel the alarm in case it did not go off yet
*/
signal(SIGALRM, SIG_IGN);
if (n_in_inputbuffer < 0 && (errno != 0 && errno != EINTR)) {
fprintf(stderr, "zmdm : fatal error reading device\n");
exit(1);
}
if (n_in_inputbuffer == 0) {
return TIMEOUT;
}
inputbuffer_index = 0;
}
c = inputbuffer[inputbuffer_index++];
n_in_inputbuffer--;
if (c == CAN) {
n_cans++;
if (n_cans == 5) {
/*
* the other side is serious about this. just shut up;
* clean up and exit.
*/
cleanup();
exit(CAN);
}
} else {
n_cans = 0;
}
return c;
}