4 ////////////////////////////////////////////////////////////////////////////////
6 static int k8t_ttyCanReadEx (K8Term
*term
, int msecto
) {
9 struct timeval timeout
= {0};
11 if (term
->dead
|| term
->cmdfd
< 0) return 0;
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;
26 K8TERM_API
int k8t_ttyCanRead (K8Term
*term
) {
27 return k8t_ttyCanReadEx(term
, 0);
31 K8TERM_API
int k8t_ttyCanWrite (K8Term
*term
) {
34 struct timeval timeout
= {0};
36 if (term
->dead
|| term
->cmdfd
< 0) return 0;
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;
50 K8TERM_API
void k8t_tmFeed (K8Term
*term
, char *buffer
, int bufLen
) {
55 /* append read bytes to unprocessed bytes */
56 if (term
== NULL
|| term
->dead
|| term
->cmdfd
< 0) return;
58 left
= K8T_OBUFSIZ
-term
->obuflen
;
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
);
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;
76 //fprintf(stderr, "k8t_ttyRead: got %d bytes\n", 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 */
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];
91 //fprintf(stderr, "'%c' (%d)\n", (*ptr >= ' ' && *ptr != 127 ? *ptr : '.'), *ptr);
92 len
= term
->loc2utf(term
, obuf
, ptr
, 1);
95 k8t_tmPutC(term
, obuf
);
102 // don't do any conversion
103 while (term
->obuflen
>= K8T_UTF_SIZ
|| k8t_UTF8IsFull(ptr
, term
->obuflen
)) {
105 char s
[K8T_UTF_SIZ
+1];
106 int charsize
= k8t_UTF8Decode(&utf8c
, ptr
);
109 len
= k8t_UTF8Encode(s
, utf8c
);
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) {
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
) {
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
)) {
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;
151 //fprintf(stderr, "k8t_ttyRead: got %d bytes\n", ret);
152 term
->obuflen
+= 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 */
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];
166 //fprintf(stderr, "'%c' (%d)\n", (*ptr >= ' ' && *ptr != 127 ? *ptr : '.'), *ptr);
167 len
= term
->loc2utf(term
, obuf
, ptr
, 1);
170 k8t_tmPutC(term
, obuf
);
177 // don't do any conversion
178 while (term
->obuflen
>= K8T_UTF_SIZ
|| k8t_UTF8IsFull(ptr
, term
->obuflen
)) {
180 char s
[K8T_UTF_SIZ
+1];
181 int charsize
= k8t_UTF8Decode(&utf8c
, ptr
);
184 len
= k8t_UTF8Encode(s
, utf8c
);
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) {
198 memmove(term
->obuf
, ptr
, term
->obuflen
);
205 //TODO: remove idiotic copypaste, merge k8t_ttySendWriteBuf() and k8t_ttyFlushWriteBuf()
206 K8TERM_API
int k8t_ttySendWriteBuf (K8Term
*term
) {
209 if (term
== NULL
|| term
->dead
|| term
->cmdfd
< 0) return -1;
210 if (term
->wrbufpos
>= term
->wrbufused
) {
211 term
->wrbufpos
= term
->wrbufused
= 0;
215 //dlogf("0: k8t_ttyFlushWriteBuf before: towrite=%d", term->wrbufused-term->wrbufpos);
216 while (term
->wrbufpos
< term
->wrbufused
&& k8t_ttyCanWrite(term
)) {
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;
226 term
->wrbufpos
+= ret
;
229 if (term
->wrbufpos
> 0) {
230 int left
= term
->wrbufused
-term
->wrbufpos
;
233 // write buffer is empty
234 term
->wrbufpos
= term
->wrbufused
= 0;
236 memmove(term
->wrbuf
, term
->wrbuf
+term
->wrbufpos
, left
);
238 term
->wrbufused
= left
;
241 //dlogf("1: k8t_ttyFlushWriteBuf after: towrite=%d", term->wrbufused-term->wrbufpos);
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;
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;
261 term->wrbufpos += ret;
265 //dlogf("0: k8t_ttyFlushWriteBuf before: towrite=%d", term->wrbufused-term->wrbufpos);
266 while (term
->wrbufpos
< term
->wrbufused
) {
269 if (!k8t_ttyCanWrite(term
)) {
270 if (term
->wrbufused
>= term
->wrbufsize
-8) ret
= 0; else break;
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;
280 int cr
= k8t_ttyCanReadEx(term
, 100);
282 //fprintf(stderr, "k8t_ttyCanReadEx: %d\n", cr);
284 if (cr
> 0) k8t_ttyRead(term
);
288 term
->wrbufpos
+= ret
;
292 if (term
->wrbufpos
> 0) {
293 int left
= term
->wrbufused
-term
->wrbufpos
;
296 // write buffer is empty
297 term
->wrbufpos
= term
->wrbufused
= 0;
299 memmove(term
->wrbuf
, term
->wrbuf
+term
->wrbufpos
, left
);
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
) {
315 if (s
== NULL
|| len
< 1) return 0;
317 if (term
->needConv
) {
318 if ((clen
= term
->utf2loc(term
, loc
, s
, len
)) < 1) return 0;
320 if ((clen
= k8t_UTF8Size(s
)) < 1) return 0;
321 memmove(loc
, s
, clen
);
324 memmove(loc
, s
, (clen
= len
));
327 while (term
->wrbufused
+clen
>= term
->wrbufsize
) {
328 //FIXME: make write buffer dynamic?
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;
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;
350 k8t_ttyFlushWriteBuf(term
); // make room for char
352 memcpy(term
->wrbuf
+term
->wrbufused
, loc
, clen
);
353 term
->wrbufused
+= clen
;
359 K8TERM_API
void k8t_ttyWriteNoEnc (K8Term
*term
, const char *s
, size_t n
) {
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) {
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);
382 if (term
->ubufpos
== 0) {
385 k8t_ttyWriteRawChar(term
, s
, 1, 0);
386 } else if ((c
&0xc0) == 0xc0) {
388 term
->ubuf
[term
->ubufpos
++] = *s
;
390 // ignore unsynced utf-8
397 if (c
< 128 || term
->ubufpos
>= K8T_UTF_SIZ
|| (c
&0xc0) == 0xc0) {
398 // discard previous utf-8, it's bad
403 term
->ubuf
[term
->ubufpos
++] = *s
;
406 if (k8t_UTF8IsFull(term
->ubuf
, term
->ubufpos
)) {
407 // have complete char
408 k8t_ttyWriteRawChar(term
, term
->ubuf
, term
->ubufpos
, 0);
413 k8t_ttyFlushWriteBuf(term
);