removed unused code
[k8sterm.git] / src / libk8sterm / ttyrw.c
blob639609a729df76d7d89977b73dd6cff724d4b2ed
1 #include "k8sterm.h"
4 ////////////////////////////////////////////////////////////////////////////////
5 // tty r/w
6 static int k8t_ttyCanReadEx (K8Term *term, int msecto) {
7 for (;;) {
8 fd_set rfd;
9 struct timeval timeout = {0};
11 if (term->dead || term->cmdfd < 0) return 0;
12 FD_ZERO(&rfd);
13 FD_SET(term->cmdfd, &rfd);
14 if (msecto > 0) timeout.tv_usec = msecto*1000;
15 if (select(term->cmdfd+1, &rfd, NULL, NULL, (msecto >= 0 ? &timeout : NULL)) < 0) {
16 if (errno == EINTR) continue;
17 k8t_die("select failed: %s", strerror(errno));
19 if (FD_ISSET(term->cmdfd, &rfd)) return 1;
20 break;
22 return 0;
26 K8TERM_API int k8t_ttyCanRead (K8Term *term) {
27 return k8t_ttyCanReadEx(term, 0);
31 K8TERM_API int k8t_ttyCanWrite (K8Term *term) {
32 for (;;) {
33 fd_set wfd;
34 struct timeval timeout = {0};
36 if (term->dead || term->cmdfd < 0) return 0;
37 FD_ZERO(&wfd);
38 FD_SET(term->cmdfd, &wfd);
39 if (select(term->cmdfd+1, NULL, &wfd, NULL, &timeout) < 0) {
40 if (errno == EINTR) continue;
41 k8t_die("select failed: %s", strerror(errno));
43 if (FD_ISSET(term->cmdfd, &wfd)) return 1;
44 break;
46 return 0;
50 K8TERM_API void k8t_tmFeed (K8Term *term, char *buffer, int bufLen) {
51 char *ptr;
52 int left;
53 int res = 0;
55 /* append read bytes to unprocessed bytes */
56 if (term == NULL || term->dead || term->cmdfd < 0) return;
57 while (bufLen>0) {
58 left = K8T_OBUFSIZ-term->obuflen;
59 while (left > 0) {
60 int ret;
62 //if ((ret = read(term->cmdfd, term->obuf+term->obuflen, 1)) < 0) k8t_die("Couldn't read from shell: %s", strerror(errno));
63 ret = (bufLen > left) ? left : bufLen;
64 memcpy(term->obuf+term->obuflen, buffer, ret);
65 buffer += ret;
66 bufLen -= ret;
67 //if ((ret = read(term->cmdfd, term->obuf+term->obuflen, left)) < 0) {
69 // //fprintf(stderr, "Warning: couldn't read from tty: %s\n", strerror(errno));
70 // if (errno == EINTR) continue;
71 // res = -1;
72 // break;
73 //}
75 if (ret == 0) break;
76 //fprintf(stderr, "k8t_ttyRead: got %d bytes\n", ret);
77 term->obuflen += ret;
78 left -= ret;
80 //fprintf(stderr, "1: k8t_ttyRead after: free=%d, used=%d\n", left, term->obuflen);
81 if (term->obuflen == 0) return;
82 /* process every complete utf8 char */
83 ptr = term->obuf;
84 if (term->needConv) {
85 // need conversion from locale to utf-8
86 //fprintf(stderr, "buf: %d bytes\n", term->obuflen);
87 while (term->obuflen > 0) {
88 char obuf[K8T_UTF_SIZ+1];
89 int len;
91 //fprintf(stderr, "'%c' (%d)\n", (*ptr >= ' ' && *ptr != 127 ? *ptr : '.'), *ptr);
92 len = term->loc2utf(term, obuf, ptr, 1);
93 if (len > 0) {
94 obuf[len] = 0;
95 k8t_tmPutC(term, obuf);
97 ++ptr;
98 --term->obuflen;
100 term->obuflen = 0;
101 } else {
102 // don't do any conversion
103 while (term->obuflen >= K8T_UTF_SIZ || k8t_UTF8IsFull(ptr, term->obuflen)) {
104 uint32_t utf8c;
105 char s[K8T_UTF_SIZ+1];
106 int charsize = k8t_UTF8Decode(&utf8c, ptr);
107 int len;
109 len = k8t_UTF8Encode(s, utf8c);
110 if (len > 0) {
111 s[len] = 0;
112 k8t_tmPutC(term, s);
114 ptr += charsize;
115 term->obuflen -= charsize;
117 if (res < 0) term->obuflen = 0; // there was read error, we should not expect more bytes
118 //dlogf("2: k8t_ttyRead afterproc: used=%d", term->obuflen);
120 /* keep any uncomplete utf8 char for the next call */
121 if (term->obuflen > 0) {
122 res = 0;
123 memmove(term->obuf, ptr, term->obuflen);
129 // return -1 if there was read error, 0 otherwise
130 K8TERM_API int k8t_ttyRead (K8Term *term) {
131 char *ptr;
132 int left;
133 int res = 0;
135 /* append read bytes to unprocessed bytes */
136 if (term == NULL || term->dead || term->cmdfd < 0) return -1;
137 left = K8T_OBUFSIZ-term->obuflen;
138 //fprintf(stderr, "0: k8t_ttyRead before: free=%d, used=%d\n", left, term->obuflen);
139 while (left > 0 && k8t_ttyCanRead(term)) {
140 int ret;
142 //if ((ret = read(term->cmdfd, term->obuf+term->obuflen, 1)) < 0) k8t_die("Couldn't read from shell: %s", strerror(errno));
143 if ((ret = read(term->cmdfd, term->obuf+term->obuflen, left)) < 0) {
144 //fprintf(stderr, "Warning: couldn't read from tty: %s\n", strerror(errno));
145 if (errno == EINTR) continue;
146 res = -1;
147 break;
150 if (ret == 0) break;
151 //fprintf(stderr, "k8t_ttyRead: got %d bytes\n", ret);
152 term->obuflen += ret;
153 left -= ret;
155 //fprintf(stderr, "1: k8t_ttyRead after: free=%d, used=%d\n", left, term->obuflen);
156 if (term->obuflen == 0) return res;
157 /* process every complete utf8 char */
158 ptr = term->obuf;
159 if (term->needConv) {
160 // need conversion from locale to utf-8
161 //fprintf(stderr, "buf: %d bytes\n", term->obuflen);
162 while (term->obuflen > 0) {
163 char obuf[K8T_UTF_SIZ+1];
164 int len;
166 //fprintf(stderr, "'%c' (%d)\n", (*ptr >= ' ' && *ptr != 127 ? *ptr : '.'), *ptr);
167 len = term->loc2utf(term, obuf, ptr, 1);
168 if (len > 0) {
169 obuf[len] = 0;
170 k8t_tmPutC(term, obuf);
172 ++ptr;
173 --term->obuflen;
175 term->obuflen = 0;
176 } else {
177 // don't do any conversion
178 while (term->obuflen >= K8T_UTF_SIZ || k8t_UTF8IsFull(ptr, term->obuflen)) {
179 uint32_t utf8c;
180 char s[K8T_UTF_SIZ+1];
181 int charsize = k8t_UTF8Decode(&utf8c, ptr);
182 int len;
184 len = k8t_UTF8Encode(s, utf8c);
185 if (len > 0) {
186 s[len] = 0;
187 k8t_tmPutC(term, s);
189 ptr += charsize;
190 term->obuflen -= charsize;
192 if (res < 0) term->obuflen = 0; // there was read error, we should not expect more bytes
193 //dlogf("2: k8t_ttyRead afterproc: used=%d", term->obuflen);
195 /* keep any uncomplete utf8 char for the next call */
196 if (term->obuflen > 0) {
197 res = 0;
198 memmove(term->obuf, ptr, term->obuflen);
201 return res;
205 //TODO: remove idiotic copypaste, merge k8t_ttySendWriteBuf() and k8t_ttyFlushWriteBuf()
206 K8TERM_API int k8t_ttySendWriteBuf (K8Term *term) {
207 int sent = 0;
209 if (term == NULL || term->dead || term->cmdfd < 0) return -1;
210 if (term->wrbufpos >= term->wrbufused) {
211 term->wrbufpos = term->wrbufused = 0;
212 return 0;
215 //dlogf("0: k8t_ttyFlushWriteBuf before: towrite=%d", term->wrbufused-term->wrbufpos);
216 while (term->wrbufpos < term->wrbufused && k8t_ttyCanWrite(term)) {
217 int ret;
219 if ((ret = write(term->cmdfd, term->wrbuf+term->wrbufpos, term->wrbufused-term->wrbufpos)) < 0) {
220 //fprintf(stderr, "Warning: write error on tty #%d: %s\n", termidx, strerror(errno));
221 if (errno == EINTR) continue;
222 break;
224 if (ret == 0) break;
225 sent += ret;
226 term->wrbufpos += ret;
229 if (term->wrbufpos > 0) {
230 int left = term->wrbufused-term->wrbufpos;
232 if (left < 1) {
233 // write buffer is empty
234 term->wrbufpos = term->wrbufused = 0;
235 } else {
236 memmove(term->wrbuf, term->wrbuf+term->wrbufpos, left);
237 term->wrbufpos = 0;
238 term->wrbufused = left;
241 //dlogf("1: k8t_ttyFlushWriteBuf after: towrite=%d", term->wrbufused-term->wrbufpos);
243 return sent;
247 K8TERM_API void k8t_ttyFlushWriteBuf (K8Term *term) {
248 if (term == NULL || term->dead || term->cmdfd < 0) return;
249 if (term->wrbufpos >= term->wrbufused) {
250 term->wrbufpos = term->wrbufused = 0;
251 return;
255 if (term->wrbufpos < term->wrbufused && term->doWriteBufferFlush != NULL) {
256 while (term->wrbufpos < term->wrbufused) {
257 int wrt = term->doWriteBufferFlush(term, term->wrbuf+term->wrbufpos, term->wrbufused-term->wrbufpos);
259 if (wrt < 0) goto done;
260 if (wrt == 0) break;
261 term->wrbufpos += ret;
265 //dlogf("0: k8t_ttyFlushWriteBuf before: towrite=%d", term->wrbufused-term->wrbufpos);
266 while (term->wrbufpos < term->wrbufused) {
267 int ret;
269 if (!k8t_ttyCanWrite(term)) {
270 if (term->wrbufused >= term->wrbufsize-8) ret = 0; else break;
271 } else {
272 if ((ret = write(term->cmdfd, term->wrbuf+term->wrbufpos, term->wrbufused-term->wrbufpos)) < 0) {
273 //fprintf(stderr, "Warning: write error on tty #%d: %s\n", termidx, strerror(errno));
274 if (errno == EINTR) continue;
275 break;
279 if (ret == 0) {
280 int cr = k8t_ttyCanReadEx(term, 100);
282 //fprintf(stderr, "k8t_ttyCanReadEx: %d\n", cr);
283 if (cr < 0) break;
284 if (cr > 0) k8t_ttyRead(term);
285 continue;
288 term->wrbufpos += ret;
291 //done:
292 if (term->wrbufpos > 0) {
293 int left = term->wrbufused-term->wrbufpos;
295 if (left < 1) {
296 // write buffer is empty
297 term->wrbufpos = term->wrbufused = 0;
298 } else {
299 memmove(term->wrbuf, term->wrbuf+term->wrbufpos, left);
300 term->wrbufpos = 0;
301 term->wrbufused = left;
304 //dlogf("1: k8t_ttyFlushWriteBuf after: towrite=%d", term->wrbufused-term->wrbufpos);
308 // convert char to locale and write it
309 // return<0: error; ==0: ok
310 K8TERM_API int k8t_ttyWriteRawChar (K8Term *term, const char *s, int len, int noenc) {
311 char loc[16];
312 int clen;
313 int rdtries = 100;
315 if (s == NULL || len < 1) return 0;
316 if (!noenc) {
317 if (term->needConv) {
318 if ((clen = term->utf2loc(term, loc, s, len)) < 1) return 0;
319 } else {
320 if ((clen = k8t_UTF8Size(s)) < 1) return 0;
321 memmove(loc, s, clen);
323 } else {
324 memmove(loc, s, (clen = len));
327 while (term->wrbufused+clen >= term->wrbufsize) {
328 //FIXME: make write buffer dynamic?
329 int res;
331 // force write at least one char
332 //dlogf("k8t_ttyWrite: forced write");
333 if ((res = write(term->cmdfd, term->wrbuf+term->wrbufpos, 1)) < 0) {
334 //fprintf(stderr, "Warning: write error on tty #%d: %s\n", termidx, strerror(errno));
335 if (errno == EINTR) continue;
336 return -1; //SHIT!
338 if (res == 0) {
339 if (--rdtries > 0) {
340 int cr = k8t_ttyCanReadEx(term, 100);
342 //fprintf(stderr, "(%d) k8t_ttyCanReadEx: %d\n", rdtries, cr);
343 if (cr > 0) k8t_ttyRead(term);
344 if (cr >= 0) continue;
347 return -1; //SHIT!
349 ++term->wrbufpos;
350 k8t_ttyFlushWriteBuf(term); // make room for char
352 memcpy(term->wrbuf+term->wrbufused, loc, clen);
353 term->wrbufused += clen;
355 return 0;
359 K8TERM_API void k8t_ttyWriteNoEnc (K8Term *term, const char *s, size_t n) {
360 if (n > 0) {
361 term->ubufpos = 0; // discard possible utf-8 char
362 while (n-- > 0) k8t_ttyWriteRawChar(term, s++, 1, 1);
364 k8t_ttyFlushWriteBuf(term);
368 K8TERM_API void k8t_ttyWrite (K8Term *term, const char *s, size_t n) {
369 if (term == NULL || term->dead || term->cmdfd < 0) return;
370 //k8t_ttyFlushWriteBuf();
371 if (s != NULL && n > 0) {
372 while (n > 0) {
373 unsigned char c = (unsigned char)(s[0]);
375 if (term->ubufpos > 0 && k8t_UTF8IsFull(term->ubuf, term->ubufpos)) {
376 // have complete char
377 k8t_ttyWriteRawChar(term, term->ubuf, term->ubufpos, 0);
378 term->ubufpos = 0;
379 continue;
382 if (term->ubufpos == 0) {
383 // new char
384 if (c < 128) {
385 k8t_ttyWriteRawChar(term, s, 1, 0);
386 } else if ((c&0xc0) == 0xc0) {
387 // new utf-8 char
388 term->ubuf[term->ubufpos++] = *s;
389 } else {
390 // ignore unsynced utf-8
392 ++s;
393 --n;
394 continue;
396 // char continues
397 if (c < 128 || term->ubufpos >= K8T_UTF_SIZ || (c&0xc0) == 0xc0) {
398 // discard previous utf-8, it's bad
399 term->ubufpos = 0;
400 continue;
402 // collect
403 term->ubuf[term->ubufpos++] = *s;
404 ++s;
405 --n;
406 if (k8t_UTF8IsFull(term->ubuf, term->ubufpos)) {
407 // have complete char
408 k8t_ttyWriteRawChar(term, term->ubuf, term->ubufpos, 0);
409 term->ubufpos = 0;
413 k8t_ttyFlushWriteBuf(term);