Branch data Line data Source code
1 : : // This file is a part of Julia. License is MIT: https://julialang.org/license
2 : :
3 : : #include <stdlib.h>
4 : : #include <stdarg.h>
5 : : #include <string.h>
6 : : #include <assert.h>
7 : : #include <limits.h>
8 : : #include <errno.h>
9 : : #include <wchar.h>
10 : : #include <stdio.h> // for printf
11 : :
12 : : #include "dtypes.h"
13 : :
14 : : #ifdef _OS_WINDOWS_
15 : : #include <malloc.h>
16 : : #include <io.h>
17 : : #include <fcntl.h>
18 : : #define fileno _fileno
19 : : //#define lseek _lseek
20 : : #else
21 : : #include <unistd.h>
22 : : #include <sys/time.h>
23 : : #include <sys/select.h>
24 : : #include <sys/stat.h>
25 : : #include <fcntl.h>
26 : : #endif
27 : :
28 : : #include "utils.h"
29 : : #include "utf8.h"
30 : : #include "utf8proc.h"
31 : : #include "ios.h"
32 : : #include "timefuncs.h"
33 : :
34 : : #define MOST_OF(x) ((x) - ((x)>>4))
35 : :
36 : : #ifdef __cplusplus
37 : : extern "C" {
38 : : #endif
39 : :
40 : : void (*ios_set_io_wait_func)(int) = NULL;
41 : 18268 : static void set_io_wait_begin(int v)
42 : : {
43 [ + - ]: 18268 : if (__likely(ios_set_io_wait_func)) {
44 : 18268 : ios_set_io_wait_func(v);
45 : : }
46 : 18268 : }
47 : :
48 : : /* OS-level primitive wrappers */
49 : :
50 : : #if defined(__APPLE__) || defined(_OS_WINDOWS_)
51 : : JL_DLLEXPORT void *memrchr(const void *s, int c, size_t n)
52 : : {
53 : : const unsigned char *src = (unsigned char*)s + n;
54 : : unsigned char uc = c;
55 : : while (--src >= (unsigned char*)s)
56 : : if (*src == uc)
57 : : return (void*)src;
58 : : return NULL;
59 : : }
60 : : #else
61 : : extern void *memrchr(const void *s, int c, size_t n);
62 : : #endif
63 : :
64 : : /*
65 : : static int _fd_available(long fd)
66 : : {
67 : : #ifndef _OS_WINDOWS_
68 : : fd_set set;
69 : : struct timeval tv = {0, 0};
70 : :
71 : : FD_ZERO(&set);
72 : : FD_SET(fd, &set);
73 : : return (select(fd+1, &set, NULL, NULL, &tv)!=0);
74 : : #else
75 : : return 1;
76 : : #endif
77 : : }
78 : : */
79 : :
80 : 4 : static int _enonfatal(int err)
81 : : {
82 [ + - - + ]: 4 : return (err == EAGAIN ||/* err == EINPROGRESS ||*/ err == EINTR /*|| err == EWOULDBLOCK*/); //jwn
83 : : }
84 : :
85 : : #define SLEEP_TIME 5//ms
86 : :
87 : : #if defined(__APPLE__)
88 : : #define MAXSIZE ((1l << 31) - 1) // OSX cannot handle blocks larger than this
89 : : #define LIMIT_IO_SIZE(n) ((n) < MAXSIZE ? (n) : MAXSIZE)
90 : : #elif defined(_OS_WINDOWS_)
91 : : #define MAXSIZE (0x7fffffff) // Windows read() takes a uint
92 : : #define LIMIT_IO_SIZE(n) ((n) < (size_t)MAXSIZE ? (unsigned int)(n) : MAXSIZE)
93 : : #else
94 : : #define LIMIT_IO_SIZE(n) (n)
95 : : #endif
96 : :
97 : : // return error code, #bytes read in *nread
98 : : // these wrappers retry operations until success or a fatal error
99 : 4534 : static int _os_read(long fd, void *buf, size_t n, size_t *nread)
100 : : {
101 : : ssize_t r;
102 : :
103 : 4534 : n = LIMIT_IO_SIZE(n);
104 : : while (1) {
105 : 4534 : set_io_wait_begin(1);
106 : 4534 : r = read((int)fd, buf, n);
107 : 4534 : set_io_wait_begin(0);
108 [ + - ]: 4534 : if (r > -1) {
109 : 4534 : *nread = (size_t)r;
110 : 4534 : return 0;
111 : : }
112 : : // This test is a hack to fix #11481 for Windows 7. Unnecessary for Windows 10.
113 [ # # # # ]: 0 : if (errno == ENOMEM && n > 80) {
114 : 0 : n >>= 3;
115 : 0 : continue;
116 : : }
117 [ # # ]: 0 : if (!_enonfatal(errno)) {
118 : 0 : *nread = 0;
119 : 0 : return errno;
120 : : }
121 : 0 : sleep_ms(SLEEP_TIME);
122 : : }
123 : : return 0;
124 : : }
125 : :
126 : 272 : static int _os_read_all(long fd, void *buf, size_t n, size_t *nread)
127 : : {
128 : : size_t got;
129 : :
130 : 272 : *nread = 0;
131 : :
132 [ + + ]: 544 : while (n>0) {
133 : 272 : set_io_wait_begin(1);
134 : 272 : int err = _os_read(fd, buf, n, &got);
135 : 272 : set_io_wait_begin(0);
136 : 272 : n -= got;
137 : 272 : *nread += got;
138 : 272 : buf = (char *)buf + got;
139 [ + - - + ]: 272 : if (err || got==0)
140 : 0 : return err;
141 : : }
142 : 272 : return 0;
143 : : }
144 : :
145 : 11570 : static int _os_write(long fd, const void *buf, size_t n, size_t *nwritten)
146 : : {
147 : : ssize_t r;
148 : :
149 : : while (1) {
150 : 11570 : r = write((int)fd, buf, LIMIT_IO_SIZE(n));
151 [ + - ]: 11570 : if (r > -1) {
152 : 11570 : *nwritten = (size_t)r;
153 : 11570 : return 0;
154 : : }
155 [ # # ]: 0 : if (!_enonfatal(errno)) {
156 : 0 : *nwritten = 0;
157 : 0 : return errno;
158 : : }
159 : 0 : sleep_ms(SLEEP_TIME);
160 : : }
161 : : return 0;
162 : : }
163 : :
164 : 11570 : int _os_write_all(long fd, const void *buf, size_t n, size_t *nwritten)
165 : : {
166 : : size_t wrote;
167 : :
168 : 11570 : *nwritten = 0;
169 : :
170 [ + + ]: 23140 : while (n>0) {
171 : 11570 : int err = _os_write(fd, buf, n, &wrote);
172 : 11570 : n -= wrote;
173 : 11570 : *nwritten += wrote;
174 : 11570 : buf = (char *)buf + wrote;
175 [ - + ]: 11570 : if (err)
176 : 0 : return err;
177 : : }
178 : 11570 : return 0;
179 : : }
180 : :
181 : :
182 : : /* internal utility functions */
183 : :
184 : 8528820 : static char *_buf_realloc(ios_t *s, size_t sz)
185 : : {
186 : : char *temp;
187 : :
188 [ + + + + : 8528820 : if ((s->buf==NULL || s->buf==&s->local[0]) && (sz <= IOS_INLSIZE)) {
+ + ]
189 : : /* TODO: if we want to allow shrinking, see if the buffer shrank
190 : : down to this size, in which case we need to copy. */
191 : 7162580 : s->buf = &s->local[0];
192 : 7162580 : s->maxsize = IOS_INLSIZE;
193 : 7162580 : s->ownbuf = 1;
194 : 7162580 : return s->buf;
195 : : }
196 : :
197 [ + + ]: 1366240 : if (sz <= s->maxsize) return s->buf;
198 : :
199 [ + - + + ]: 1366170 : if (s->ownbuf && s->buf != &s->local[0]) {
200 : : // if we own the buffer we're free to resize it
201 : 824748 : temp = (char*)LLT_REALLOC(s->buf, sz);
202 [ - + ]: 824748 : if (temp == NULL)
203 : 0 : return NULL;
204 : : }
205 : : else {
206 : 541422 : temp = (char*)LLT_ALLOC(sz);
207 [ - + ]: 541422 : if (temp == NULL)
208 : 0 : return NULL;
209 : 541422 : s->ownbuf = 1;
210 [ + + ]: 541422 : if (s->size > 0)
211 : 488634 : memcpy(temp, s->buf, (size_t)s->size);
212 : : }
213 : :
214 : 1366170 : s->buf = temp;
215 : 1366170 : s->maxsize = sz;
216 : 1366170 : return s->buf;
217 : : }
218 : :
219 : : // write a block of data into the buffer at the current position, resizing
220 : : // if necessary. returns # written.
221 : 179008800 : static size_t _write_grow(ios_t *s, const char *data, size_t n)
222 : : {
223 : : size_t amt;
224 : : size_t newsize;
225 : :
226 [ - + ]: 179008800 : if (n == 0)
227 : 0 : return 0;
228 : :
229 [ + + ]: 179008800 : if (s->bpos + n > s->size) {
230 [ + + ]: 178722600 : if (s->bpos + n > s->maxsize) {
231 : : /* TODO: here you might want to add a mechanism for limiting
232 : : the growth of the stream. */
233 [ + - ]: 1361582 : newsize = (size_t)(s->maxsize ? s->maxsize * 2 : 8);
234 [ + + ]: 1487614 : while (s->bpos + n > newsize)
235 : 126032 : newsize *= 2;
236 [ - + ]: 1361582 : if (_buf_realloc(s, newsize) == NULL) {
237 : : /* no more space; write as much as we can */
238 : 0 : amt = (size_t)(s->maxsize - s->bpos);
239 [ # # ]: 0 : if (amt > 0) {
240 : 0 : memcpy(&s->buf[s->bpos], data, amt);
241 : : }
242 : 0 : s->bpos += amt;
243 : 0 : s->size = s->maxsize;
244 : 0 : return amt;
245 : : }
246 : : }
247 : 178722600 : s->size = s->bpos + n;
248 : : }
249 : 179008800 : memcpy(s->buf + s->bpos, data, n);
250 : 179008800 : s->bpos += n;
251 : :
252 : 179008800 : return n;
253 : : }
254 : :
255 : :
256 : : /* interface functions, low level */
257 : :
258 : 95586200 : static size_t _ios_read(ios_t *s, char *dest, size_t n, int all)
259 : : {
260 : 95586200 : size_t tot = 0;
261 : : size_t got, avail;
262 : 95586200 : int didread = 0;
263 : :
264 [ + + ]: 95586200 : if (s->state == bst_wr) {
265 : 215136 : ios_seek(s, ios_pos(s));
266 : : }
267 : 95586200 : s->state = bst_rd;
268 : :
269 [ + - ]: 95587000 : while (n > 0) {
270 : 95587000 : avail = (size_t)(s->size - s->bpos);
271 : :
272 [ + + ]: 95587000 : if (avail > 0) {
273 : 93131400 : size_t ncopy = (avail >= n) ? n : avail;
274 : 93131400 : memcpy(dest, s->buf + s->bpos, ncopy);
275 : 93131400 : s->bpos += ncopy;
276 [ + + ]: 93131400 : if (ncopy >= n)
277 : 93131000 : return tot+ncopy;
278 : : }
279 [ + + - + ]: 2455980 : if (s->bm == bm_mem || s->fd == -1) {
280 : : // can't get any more data
281 [ + - ]: 2454780 : if (avail == 0)
282 : 2454780 : s->_eof = 1;
283 : 2454780 : return avail;
284 : : }
285 : :
286 : 1198 : dest += avail;
287 : 1198 : n -= avail;
288 : 1198 : tot += avail;
289 : :
290 [ - + - - ]: 1198 : if (didread && !all) return tot;
291 : :
292 : 1198 : ios_flush(s);
293 : 1198 : s->bpos = s->size = 0;
294 : 1198 : s->fpos = -1;
295 [ + + ]: 1198 : if (n > MOST_OF(s->maxsize)) {
296 : : // doesn't fit comfortably in buffer; go direct
297 [ + - ]: 272 : if (all) {
298 : : //result = _os_read_all(s->fd, dest, n, &got);
299 : 272 : _os_read_all(s->fd, dest, n, &got);
300 : : }
301 : : else {
302 : : //result = _os_read(s->fd, dest, n, &got);
303 : 0 : _os_read(s->fd, dest, n, &got);
304 : : }
305 : 272 : tot += got;
306 [ - + ]: 272 : if (got == 0)
307 : 0 : s->_eof = 1;
308 : 272 : return tot;
309 : : }
310 : : else {
311 : : // refill buffer
312 [ - + ]: 926 : if (_os_read(s->fd, s->buf, (size_t)s->maxsize, &got)) {
313 : 0 : s->_eof = 1;
314 : 0 : return tot;
315 : : }
316 [ - + ]: 926 : if (got == 0) {
317 : 0 : s->_eof = 1;
318 : 0 : return tot;
319 : : }
320 : 926 : s->size = got;
321 : : }
322 : 926 : didread = 1;
323 : : }
324 : :
325 : 0 : return tot;
326 : : }
327 : :
328 : 90241800 : size_t ios_read(ios_t *s, char *dest, size_t n)
329 : : {
330 : 90241800 : return _ios_read(s, dest, n, 0);
331 : : }
332 : :
333 : 5344280 : size_t ios_readall(ios_t *s, char *dest, size_t n)
334 : : {
335 : 5344280 : return _ios_read(s, dest, n, 1);
336 : : }
337 : :
338 : 526062 : size_t ios_readprep(ios_t *s, size_t n)
339 : : {
340 [ + + - + ]: 526062 : if (s->state == bst_wr && s->bm != bm_mem) {
341 : 0 : ios_flush(s);
342 : 0 : s->bpos = s->size = 0;
343 : : }
344 : 526062 : size_t space = (size_t)(s->size - s->bpos);
345 : 526062 : s->state = bst_rd;
346 [ + + + + : 526062 : if (space >= n || s->bm == bm_mem || s->fd == -1)
- + ]
347 : 522726 : return space;
348 [ + + ]: 3336 : if (s->maxsize < s->bpos+n) {
349 : : // it won't fit. grow buffer or move data back.
350 [ + - + - ]: 20 : if (n <= s->maxsize && space <= ((s->maxsize)>>2)) {
351 [ - + ]: 20 : if (space)
352 : 0 : memmove(s->buf, s->buf+s->bpos, space);
353 : 20 : s->size -= s->bpos;
354 : 20 : s->bpos = 0;
355 : : }
356 : : else {
357 [ # # ]: 0 : if (_buf_realloc(s, (size_t)(s->bpos + n))==NULL)
358 : 0 : return space;
359 : : }
360 : : }
361 : : size_t got;
362 : 3336 : s->fpos = -1;
363 : 3336 : int result = _os_read(s->fd, s->buf+s->size, (size_t)(s->maxsize - s->size), &got);
364 [ - + ]: 3336 : if (result)
365 : 0 : return space;
366 : 3336 : s->size += got;
367 : 3336 : return (size_t)(s->size - s->bpos);
368 : : }
369 : :
370 : : // attempt to fill the buffer. returns the number of bytes available if we
371 : : // have read the whole file, or -1 if there might be more data.
372 : 3248 : ssize_t ios_fillbuf(ios_t *s)
373 : : {
374 : 3248 : size_t nb = s->maxsize - s->bpos;
375 : 3248 : size_t got = ios_readprep(s, nb);
376 [ + + ]: 3248 : if (got < nb)
377 : 2924 : return (ssize_t)got;
378 : 324 : return -1;
379 : : }
380 : :
381 : 496010000 : static void _write_update_pos(ios_t *s)
382 : : {
383 [ + + ]: 496010000 : if (s->bpos > s->ndirty) s->ndirty = s->bpos;
384 [ + + ]: 496010000 : if (s->bpos > s->size) s->size = s->bpos;
385 : 496010000 : }
386 : :
387 : : // directly copy a buffer to a descriptor
388 : 0 : JL_DLLEXPORT size_t ios_write_direct(ios_t *dest, ios_t *src)
389 : : {
390 : 0 : char *data = src->buf;
391 : 0 : size_t n = (size_t)src->size;
392 : : size_t nwr;
393 : 0 : dest->fpos = -1;
394 : 0 : _os_write_all(dest->fd, data, n, &nwr);
395 : 0 : return nwr;
396 : : }
397 : :
398 : 179299400 : size_t ios_write(ios_t *s, const char *data, size_t n)
399 : : {
400 [ - + ]: 179299400 : if (!s->writable) return 0;
401 [ + + ]: 179299400 : if (n == 0) return 0;
402 : : size_t space;
403 : 179280400 : size_t wrote = 0;
404 : :
405 [ + + ]: 179280400 : if (s->state == bst_rd) {
406 : 8 : ios_seek(s, ios_pos(s));
407 : : }
408 : 179280400 : s->state = bst_wr;
409 : 179280400 : space = (size_t)(s->maxsize - s->bpos);
410 : :
411 [ + + ]: 179280400 : if (s->bm == bm_mem) {
412 : 179008800 : wrote = _write_grow(s, data, n);
413 : : }
414 [ - + ]: 271594 : else if (s->bm == bm_none) {
415 : 0 : s->fpos = -1;
416 : 0 : _os_write_all(s->fd, data, n, &wrote);
417 : 0 : return wrote;
418 : : }
419 [ + + ]: 271594 : else if (n <= space) {
420 [ - + ]: 270914 : if (s->bm == bm_line) {
421 : : char *nl;
422 [ # # ]: 0 : if ((nl=(char*)memrchr(data, '\n', n)) != NULL) {
423 : 0 : size_t linesz = nl-data+1;
424 : 0 : s->bm = bm_block;
425 : 0 : wrote += ios_write(s, data, linesz);
426 : 0 : ios_flush(s);
427 : 0 : s->bm = bm_line;
428 : 0 : n -= linesz;
429 : 0 : data += linesz;
430 : : }
431 : : }
432 : 270914 : memcpy(s->buf + s->bpos, data, n);
433 : 270914 : s->bpos += n;
434 : 270914 : wrote += n;
435 : : }
436 : : else {
437 : 680 : ios_flush(s);
438 [ + + ]: 680 : if (n > MOST_OF(s->maxsize)) {
439 : 256 : s->fpos = -1;
440 : 256 : _os_write_all(s->fd, data, n, &wrote);
441 : 256 : return wrote;
442 : : }
443 : 424 : return ios_write(s, data, n);
444 : : }
445 : 179279800 : _write_update_pos(s);
446 : 179279800 : return wrote;
447 : : }
448 : :
449 : : // Returns 0 on success,
450 : : // -1 on error which set errno, and
451 : : // -2 on error which doesn't set errno.
452 : 874580 : int64_t ios_seek(ios_t *s, int64_t pos)
453 : : {
454 : 874580 : s->_eof = 0;
455 [ + + ]: 874580 : if (s->bm == bm_mem) {
456 [ + - - + ]: 873686 : if (pos < 0 || pos > s->size)
457 : 0 : return -2;
458 : 873686 : s->bpos = pos;
459 : : }
460 : : else {
461 : 894 : ios_flush(s);
462 : 894 : int64_t fdpos = lseek(s->fd, (off_t)pos, SEEK_SET);
463 [ - + ]: 894 : if (fdpos == (int64_t)-1)
464 : 0 : return fdpos;
465 : 894 : s->fpos = fdpos;
466 : 894 : s->bpos = s->size = 0;
467 : : }
468 : 874580 : return 0;
469 : : }
470 : :
471 : 994 : int64_t ios_seek_end(ios_t *s)
472 : : {
473 : 994 : s->_eof = 1;
474 [ - + ]: 994 : if (s->bm == bm_mem) {
475 : 0 : s->bpos = s->size;
476 : : }
477 : : else {
478 : 994 : ios_flush(s);
479 : 994 : int64_t fdpos = lseek(s->fd, 0, SEEK_END);
480 [ - + ]: 994 : if (fdpos == (int64_t)-1)
481 : 0 : return fdpos;
482 : 994 : s->fpos = fdpos;
483 : 994 : s->bpos = s->size = 0;
484 : : }
485 : 994 : return 0;
486 : : }
487 : :
488 : : // Returns 0 on success,
489 : : // -1 on error which set errno, and
490 : : // -2 on error which doesn't set errno.
491 : 230 : int64_t ios_skip(ios_t *s, int64_t offs)
492 : : {
493 [ + + ]: 230 : if (offs != 0) {
494 [ + + ]: 182 : if (offs > 0) {
495 [ + - ]: 120 : if (offs <= (s->size - s->bpos)) {
496 : 120 : s->bpos += offs;
497 : 120 : return 0;
498 : : }
499 [ # # ]: 0 : else if (s->bm == bm_mem) {
500 : : // TODO: maybe grow buffer
501 : 0 : return -2;
502 : : }
503 : : }
504 [ + - ]: 62 : else if (offs < 0) {
505 [ + - ]: 62 : if (-offs <= (int64_t)s->bpos) {
506 : 62 : s->bpos += offs;
507 : 62 : s->_eof = 0;
508 : 62 : return 0;
509 : : }
510 [ # # ]: 0 : else if (s->bm == bm_mem) {
511 : 0 : return -2;
512 : : }
513 : : }
514 : 0 : ios_flush(s);
515 [ # # ]: 0 : if (s->state == bst_wr)
516 : 0 : offs += s->bpos;
517 [ # # ]: 0 : else if (s->state == bst_rd)
518 : 0 : offs -= (s->size - s->bpos);
519 : 0 : int64_t fdpos = lseek(s->fd, (off_t)offs, SEEK_CUR);
520 [ # # ]: 0 : if (fdpos == (int64_t)-1)
521 : 0 : return fdpos;
522 : 0 : s->fpos = fdpos;
523 : 0 : s->bpos = s->size = 0;
524 : 0 : s->_eof = 0;
525 : : }
526 : 48 : return 0;
527 : : }
528 : :
529 : 64703000 : int64_t ios_pos(ios_t *s)
530 : : {
531 [ + + ]: 64703000 : if (s->bm == bm_mem)
532 : 64701800 : return s->bpos;
533 : :
534 : 1230 : int64_t fdpos = s->fpos;
535 [ + + ]: 1230 : if (fdpos == (int64_t)-1) {
536 : 14 : fdpos = lseek(s->fd, 0, SEEK_CUR);
537 [ - + ]: 14 : if (fdpos == (int64_t)-1)
538 : 0 : return fdpos;
539 : 14 : s->fpos = fdpos;
540 : : }
541 : :
542 [ + + ]: 1230 : if (s->state == bst_wr)
543 : 44 : fdpos += s->bpos;
544 [ + + ]: 1186 : else if (s->state == bst_rd)
545 : 332 : fdpos -= (s->size - s->bpos);
546 : 1230 : return fdpos;
547 : : }
548 : :
549 : 332 : int64_t ios_filesize(ios_t *s)
550 : : {
551 : 332 : int64_t fdpos = s->fpos;
552 [ + + ]: 332 : if (fdpos == (int64_t)-1) {
553 : 324 : fdpos = lseek(s->fd, 0, SEEK_CUR);
554 [ - + ]: 324 : if (fdpos == (int64_t)-1)
555 : 0 : return fdpos;
556 : 324 : s->fpos = fdpos;
557 : : }
558 : 332 : off_t sz = lseek(s->fd, 0, SEEK_END);
559 : 332 : lseek(s->fd, (off_t)fdpos, SEEK_SET);
560 : 332 : return sz;
561 : : }
562 : :
563 : 1699768 : int ios_trunc(ios_t *s, size_t size)
564 : : {
565 [ + - ]: 1699768 : if (s->bm == bm_mem) {
566 [ + + ]: 1699768 : if (size == s->size)
567 : 28548 : return 0;
568 [ + + ]: 1671220 : if (size < s->size) {
569 [ + - ]: 1671056 : if (s->bpos > size)
570 : 1671056 : s->bpos = size;
571 : : }
572 : : else {
573 [ - + ]: 164 : if (_buf_realloc(s, size)==NULL)
574 : 0 : return 0;
575 : : }
576 : 1671220 : s->size = size;
577 : 1671220 : return 0;
578 : : }
579 : : else {
580 : 0 : ios_flush(s);
581 [ # # ]: 0 : if (s->state == bst_rd) {
582 : 0 : int64_t p = ios_pos(s);
583 [ # # ]: 0 : if (size < p + (s->size - s->bpos))
584 : 0 : s->size -= (p + (s->size - s->bpos) - size);
585 : : }
586 : : #if !defined(_OS_WINDOWS_)
587 [ # # ]: 0 : if (ftruncate(s->fd, size) == 0)
588 : : #else
589 : : if (_chsize_s(s->fd, size) == 0)
590 : : #endif
591 : 0 : return 0;
592 : : }
593 : 0 : return 1;
594 : : }
595 : :
596 : 443338000 : int ios_eof(ios_t *s)
597 : : {
598 [ + + + + ]: 443338000 : if (s->state == bst_rd && s->bpos < s->size)
599 : 442850000 : return 0;
600 [ + + ]: 487452 : if (s->bm == bm_mem)
601 : 487416 : return (s->_eof ? 1 : 0);
602 [ - + ]: 36 : if (s->fd == -1)
603 : 0 : return 1;
604 [ - + ]: 36 : if (s->_eof)
605 : 0 : return 1;
606 : 36 : return 0;
607 : : /*
608 : : if (_fd_available(s->fd))
609 : : return 0;
610 : : s->_eof = 1;
611 : : return 1;
612 : : */
613 : : }
614 : :
615 : 12900 : int ios_eof_blocking(ios_t *s)
616 : : {
617 [ + + + + ]: 12900 : if (s->state == bst_rd && s->bpos < s->size)
618 : 12848 : return 0;
619 [ - + ]: 52 : if (s->bm == bm_mem)
620 : 0 : return (s->_eof ? 1 : 0);
621 [ - + ]: 52 : if (s->fd == -1)
622 : 0 : return 1;
623 : :
624 [ + + ]: 52 : if (ios_readprep(s, 1) < 1)
625 : 36 : return 1;
626 : 16 : return 0;
627 : : }
628 : :
629 : 8462240 : int ios_flush(ios_t *s)
630 : : {
631 [ + + + + : 8462240 : if (s->ndirty == 0 || s->bm == bm_mem || s->buf == NULL)
- + ]
632 : 8450920 : return 0;
633 [ - + ]: 11314 : if (s->fd == -1)
634 : 0 : return -1;
635 : :
636 [ - + ]: 11314 : if (s->state == bst_rd) {
637 : 0 : if (lseek(s->fd, -(off_t)s->size, SEEK_CUR) == (off_t)-1) {
638 : : }
639 : : }
640 : :
641 : 11314 : size_t nw, ntowrite=s->ndirty;
642 : 11314 : s->fpos = -1;
643 : 11314 : int err = _os_write_all(s->fd, s->buf, ntowrite, &nw);
644 : : // todo: try recovering from some kinds of errors (e.g. retry)
645 : :
646 [ - + ]: 11314 : if (s->state == bst_rd) {
647 : 0 : if (lseek(s->fd, (off_t)(s->size - nw), SEEK_CUR) == (off_t)-1) {
648 : : }
649 : : }
650 [ + - ]: 11314 : else if (s->state == bst_wr) {
651 [ - + ]: 11314 : if (s->bpos != nw &&
652 : 0 : lseek(s->fd, (off_t)(s->bpos - nw), SEEK_CUR) == (off_t)-1) {
653 : : }
654 : : // now preserve the invariant that data to write
655 : : // begins at the beginning of the buffer, and s->size refers
656 : : // to how much valid file data is stored in the buffer.
657 [ - + ]: 11314 : if (s->size > s->ndirty) {
658 : 0 : size_t delta = (size_t)(s->size - s->ndirty);
659 : 0 : memmove(s->buf, s->buf + s->ndirty, delta);
660 : : }
661 : 11314 : s->size -= s->ndirty;
662 : 11314 : s->bpos = 0;
663 : : }
664 : :
665 : 11314 : s->ndirty = 0;
666 : :
667 [ - + ]: 11314 : if (err)
668 : 0 : return err;
669 [ - + ]: 11314 : if (nw < ntowrite)
670 : 0 : return -1;
671 : 11314 : return 0;
672 : : }
673 : :
674 : 5003580 : int ios_close(ios_t *s)
675 : : {
676 : 5003580 : int err = ios_flush(s);
677 [ + + + + ]: 5003580 : if (s->fd != -1 && s->ownfd) {
678 : 4328 : int err2 = close(s->fd);
679 [ - + ]: 4328 : if (err2 != 0)
680 : 0 : err = err2;
681 : : }
682 : 5003580 : s->fd = -1;
683 [ + + + + : 5003580 : if (s->buf!=NULL && s->ownbuf && s->buf!=&s->local[0]) {
+ + ]
684 : 56908 : LLT_FREE(s->buf);
685 : : }
686 : 5003580 : s->buf = NULL;
687 : 5003580 : s->size = s->maxsize = s->bpos = 0;
688 : 5003580 : return err;
689 : : }
690 : :
691 : 0 : int ios_isopen(ios_t *s)
692 : : {
693 : 0 : return s->fd != -1;
694 : : }
695 : :
696 : 493100 : static void _buf_init(ios_t *s, bufmode_t bm)
697 : : {
698 : 493100 : s->bm = bm;
699 [ + + - + ]: 493100 : if (s->bm == bm_mem || s->bm == bm_none) {
700 : 488666 : s->buf = &s->local[0];
701 : 488666 : s->maxsize = IOS_INLSIZE;
702 : : }
703 : : else {
704 : 4434 : s->buf = NULL;
705 : 4434 : s->maxsize = 0;
706 : 4434 : _buf_realloc(s, IOS_BUFSIZE);
707 : : }
708 : 493100 : s->size = s->bpos = 0;
709 : 493100 : }
710 : :
711 : 488666 : char *ios_take_buffer(ios_t *s, size_t *psize)
712 : : {
713 : : char *buf;
714 : :
715 : 488666 : ios_flush(s);
716 : :
717 [ + - + - : 488666 : if (s->buf == &s->local[0] || s->buf == NULL || (!s->ownbuf && s->size == s->maxsize)) {
- + - - ]
718 : 0 : buf = (char*)LLT_ALLOC((size_t)s->size + 1);
719 [ # # ]: 0 : if (buf == NULL)
720 : 0 : return NULL;
721 [ # # ]: 0 : if (s->size)
722 : 0 : memcpy(buf, s->buf, (size_t)s->size);
723 : : }
724 [ + + ]: 488666 : else if (s->size == s->maxsize) {
725 : 2250 : buf = (char*)LLT_REALLOC(s->buf, (size_t)s->size + 1);
726 [ - + ]: 2250 : if (buf == NULL)
727 : 0 : return NULL;
728 : : }
729 : : else {
730 : 486416 : buf = s->buf;
731 : : }
732 : 488666 : buf[s->size] = '\0';
733 : :
734 : 488666 : *psize = s->size + 1;
735 : :
736 : : /* empty stream and reinitialize */
737 : 488666 : _buf_init(s, s->bm);
738 : :
739 : 488666 : return buf;
740 : : }
741 : :
742 : 2455040 : int ios_setbuf(ios_t *s, char *buf, size_t size, int own)
743 : : {
744 : 2455040 : ios_flush(s);
745 : 2455040 : size_t nvalid=0;
746 : :
747 : 2455040 : nvalid = (size_t)((size < s->size) ? size : s->size);
748 [ - + ]: 2455040 : if (nvalid > 0)
749 : 0 : memcpy(buf, s->buf, nvalid);
750 [ - + ]: 2455040 : if (s->bpos > nvalid) {
751 : : // truncated
752 : 0 : s->bpos = nvalid;
753 : : }
754 : 2455040 : s->size = nvalid;
755 : :
756 [ + - + - : 2455040 : if (s->buf!=NULL && s->ownbuf && s->buf!=&s->local[0]) {
- + ]
757 : 0 : LLT_FREE(s->buf);
758 : : }
759 : 2455040 : s->buf = buf;
760 : 2455040 : s->maxsize = size;
761 : 2455040 : s->ownbuf = own;
762 : 2455040 : return 0;
763 : : }
764 : :
765 : 846 : int ios_bufmode(ios_t *s, bufmode_t mode)
766 : : {
767 : : // no fd; can only do mem-only buffering
768 [ - + - - ]: 846 : if (s->fd == -1 && mode != bm_mem)
769 : 0 : return -1;
770 : 846 : s->bm = mode;
771 : 846 : return 0;
772 : : }
773 : :
774 : 0 : int ios_get_readable(ios_t *s)
775 : : {
776 : 0 : return s->readable;
777 : : }
778 : :
779 : 10288 : int ios_get_writable(ios_t *s)
780 : : {
781 : 10288 : return s->writable;
782 : : }
783 : :
784 : 226 : void ios_set_readonly(ios_t *s)
785 : : {
786 [ - + ]: 226 : if (!s->writable) return;
787 : 226 : ios_flush(s);
788 : 226 : s->state = bst_none;
789 : 226 : s->writable = 0;
790 : : }
791 : :
792 : 120340 : static size_t ios_copy_(ios_t *to, ios_t *from, size_t nbytes, bool_t all)
793 : : {
794 : 120340 : size_t total = 0, avail;
795 [ + - ]: 120340 : if (!ios_eof(from)) {
796 : : do {
797 : 240668 : avail = ios_readprep(from, IOS_BUFSIZE/2);
798 [ + + ]: 240668 : if (avail == 0) {
799 : 120340 : from->_eof = 1;
800 : 120340 : break;
801 : : }
802 : : size_t written, ntowrite;
803 [ + - + - ]: 120328 : ntowrite = (avail <= nbytes || all) ? avail : nbytes;
804 : 120328 : written = ios_write(to, from->buf+from->bpos, ntowrite);
805 : : // TODO: should this be +=written instead?
806 : 120328 : from->bpos += ntowrite;
807 : 120328 : total += written;
808 [ - + ]: 120328 : if (!all) {
809 : 0 : nbytes -= written;
810 [ # # ]: 0 : if (nbytes == 0)
811 : 0 : break;
812 : : }
813 [ - + ]: 120328 : if (written < ntowrite)
814 : 0 : break;
815 [ + - ]: 120328 : } while (!ios_eof(from));
816 : : }
817 : 120340 : return total;
818 : : }
819 : :
820 : 0 : size_t ios_copy(ios_t *to, ios_t *from, size_t nbytes)
821 : : {
822 : 0 : return ios_copy_(to, from, nbytes, 0);
823 : : }
824 : :
825 : 120340 : size_t ios_copyall(ios_t *to, ios_t *from)
826 : : {
827 : 120340 : return ios_copy_(to, from, 0, 1);
828 : : }
829 : :
830 : : #define LINE_CHUNK_SIZE 160
831 : :
832 : 20 : size_t ios_copyuntil(ios_t *to, ios_t *from, char delim)
833 : : {
834 : 20 : size_t total = 0, avail = (size_t)(from->size - from->bpos);
835 [ + - ]: 40 : while (!ios_eof(from)) {
836 [ + + ]: 40 : if (avail == 0) {
837 : 20 : avail = ios_readprep(from, LINE_CHUNK_SIZE);
838 [ - + ]: 20 : if (avail == 0)
839 : 0 : break;
840 : : }
841 : : size_t written;
842 : 40 : char *pd = (char*)memchr(from->buf+from->bpos, delim, avail);
843 [ + + ]: 40 : if (pd == NULL) {
844 : 20 : written = ios_write(to, from->buf+from->bpos, avail);
845 : 20 : from->bpos += avail;
846 : 20 : total += written;
847 : 20 : avail = 0;
848 : : }
849 : : else {
850 : 20 : size_t ntowrite = pd - (from->buf+from->bpos) + 1;
851 : 20 : written = ios_write(to, from->buf+from->bpos, ntowrite);
852 : 20 : from->bpos += ntowrite;
853 : 20 : total += written;
854 : 20 : return total;
855 : : }
856 : : }
857 : 0 : from->_eof = 1;
858 : 0 : return total;
859 : : }
860 : :
861 : 12836 : size_t ios_nchomp(ios_t *from, size_t ntowrite)
862 : : {
863 [ - + ]: 12836 : assert(ntowrite > 0);
864 : : size_t nchomp;
865 [ + - - + ]: 12836 : if (ntowrite > 1 && from->buf[from->bpos+ntowrite - 2] == '\r') {
866 : 0 : nchomp = 2;
867 : : }
868 : : else {
869 : 12836 : nchomp = 1;
870 : : }
871 : 12836 : return nchomp;
872 : : }
873 : :
874 : 7167080 : static void _ios_init(ios_t *s)
875 : : {
876 : : // put all fields in a sane initial state
877 : 7167080 : s->bm = bm_block;
878 : 7167080 : s->state = bst_none;
879 : 7167080 : s->errcode = 0;
880 : 7167080 : s->buf = NULL;
881 : 7167080 : s->maxsize = 0;
882 : 7167080 : s->size = 0;
883 : 7167080 : s->bpos = 0;
884 : 7167080 : s->ndirty = 0;
885 : 7167080 : s->fpos = -1;
886 : 7167080 : s->lineno = 1;
887 : 7167080 : s->u_colno = 0;
888 : 7167080 : s->fd = -1;
889 : 7167080 : s->ownbuf = 1;
890 : 7167080 : s->ownfd = 0;
891 : 7167080 : s->_eof = 0;
892 : 7167080 : s->readable = 1;
893 : 7167080 : s->writable = 1;
894 : 7167080 : s->rereadable = 0;
895 : 7167080 : }
896 : :
897 : : /* stream object initializers. we do no allocation. */
898 : :
899 : : #if !defined(_OS_WINDOWS_)
900 : : /*
901 : : * NOTE: we do not handle system call restart in this function,
902 : : * please do it manually:
903 : : *
904 : : * do
905 : : * open_cloexec(...)
906 : : * while (-1 == fd && _enonfatal(errno))
907 : : */
908 : 4328 : static int open_cloexec(const char *path, int flags, mode_t mode)
909 : : {
910 : : #ifdef O_CLOEXEC
911 : : static int no_cloexec = 0;
912 : :
913 [ + - ]: 4328 : if (!no_cloexec) {
914 : 4328 : set_io_wait_begin(1);
915 : 4328 : int fd = open(path, flags | O_CLOEXEC, mode);
916 : 4328 : set_io_wait_begin(0);
917 : :
918 [ + + ]: 4328 : if (fd != -1)
919 : 4324 : return fd;
920 [ + - ]: 4 : if (errno != EINVAL)
921 : 4 : return -1;
922 : :
923 : : /* O_CLOEXEC not supported. */
924 : 0 : no_cloexec = 1;
925 : : }
926 : : #endif
927 : 0 : set_io_wait_begin(1);
928 : 0 : int fd = open(path, flags, mode);
929 : 0 : set_io_wait_begin(0);
930 : 0 : return fd;
931 : : }
932 : : #endif
933 : :
934 : 4328 : ios_t *ios_file(ios_t *s, const char *fname, int rd, int wr, int create, int trunc)
935 : : {
936 : : int flags;
937 : : int fd;
938 [ + + - + ]: 4328 : if (!(rd || wr))
939 : : // must specify read and/or write
940 : 0 : goto open_file_err;
941 [ + + + + ]: 4328 : flags = wr ? (rd ? O_RDWR : O_WRONLY) : O_RDONLY;
942 [ + + ]: 4328 : if (create) flags |= O_CREAT;
943 [ + + ]: 4328 : if (trunc) flags |= O_TRUNC;
944 : : #if defined(_OS_WINDOWS_)
945 : : size_t wlen = MultiByteToWideChar(CP_UTF8, 0, fname, -1, NULL, 0);
946 : : if (!wlen) goto open_file_err;
947 : : wchar_t *fname_w = (wchar_t*)alloca(wlen*sizeof(wchar_t));
948 : : if (!MultiByteToWideChar(CP_UTF8, 0, fname, -1, fname_w, wlen)) goto open_file_err;
949 : : set_io_wait_begin(1);
950 : : fd = _wopen(fname_w, flags | O_BINARY | O_NOINHERIT, _S_IREAD | _S_IWRITE);
951 : : set_io_wait_begin(0);
952 : : #else
953 : : // The mode of the created file is (mode & ~umask), which resolves with
954 : : // default umask to u=rw,g=r,o=r
955 : : do
956 : 4328 : fd = open_cloexec(fname, flags,
957 : : S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
958 [ + + - + ]: 4328 : while (-1 == fd && _enonfatal(errno));
959 : : #endif
960 [ + + ]: 4328 : if (fd == -1)
961 : 4 : goto open_file_err;
962 : :
963 : 4324 : s = ios_fd(s, fd, 1, 1);
964 : 4324 : s->fpos = 0;
965 [ + + ]: 4324 : if (!rd)
966 : 140 : s->readable = 0;
967 [ + + ]: 4324 : if (!wr)
968 : 4146 : s->writable = 0;
969 : 4324 : return s;
970 : 4 : open_file_err:
971 : 4 : s->fd = -1;
972 : 4 : return NULL;
973 : : }
974 : :
975 : : // Portable ios analogue of mkstemp: modifies fname to replace
976 : : // trailing XXXX's with unique ID and returns the file handle s
977 : : // for writing and reading.
978 : 0 : ios_t *ios_mkstemp(ios_t *s, char *fname)
979 : : {
980 : : int fd;
981 : : // would be better to use a libuv function once it exists (see libuv/libuv#322)
982 : : #ifdef _OS_WINDOWS_
983 : : size_t wlen = MultiByteToWideChar(CP_UTF8, 0, fname, -1, NULL, 0);
984 : : if (!wlen) goto open_file_err;
985 : : wchar_t *fname_w = (wchar_t*)alloca(wlen*sizeof(wchar_t));
986 : : if (!MultiByteToWideChar(CP_UTF8, 0, fname, -1, fname_w, wlen) ||
987 : : !_wmktemp(fname_w) ||
988 : : !WideCharToMultiByte(CP_UTF8, 0, fname_w, -1, fname, strlen(fname)+1,
989 : : NULL, NULL))
990 : : goto open_file_err;
991 : : fd = _wopen(fname_w, O_CREAT|O_TRUNC|O_RDWR | O_BINARY | O_NOINHERIT, _S_IREAD | _S_IWRITE);
992 : : #else
993 : 0 : fd = mkstemp(fname);
994 : : #endif
995 : 0 : ios_fd(s, fd, 1, 1);
996 [ # # ]: 0 : if (fd == -1)
997 : 0 : goto open_file_err;
998 : 0 : return s;
999 : 0 : open_file_err:
1000 : 0 : s->fd = -1;
1001 : 0 : return NULL;
1002 : : }
1003 : :
1004 : 7162640 : ios_t *ios_mem(ios_t *s, size_t initsize)
1005 : : {
1006 : 7162640 : _ios_init(s);
1007 : 7162640 : s->bm = bm_mem;
1008 : 7162640 : s->rereadable = 1;
1009 : 7162640 : _buf_realloc(s, initsize);
1010 : 7162640 : return s;
1011 : : }
1012 : :
1013 : 0 : ios_t *ios_str(ios_t *s, char *str)
1014 : : {
1015 : 0 : size_t n = strlen(str);
1016 [ # # ]: 0 : if (ios_mem(s, n+1)==NULL) return NULL;
1017 : 0 : ios_write(s, str, n+1);
1018 : 0 : ios_seek(s, 0);
1019 : 0 : return s;
1020 : : }
1021 : :
1022 : 226 : ios_t *ios_static_buffer(ios_t *s, char *buf, size_t sz)
1023 : : {
1024 : 226 : ios_mem(s, 0);
1025 : 226 : ios_setbuf(s, buf, sz, 0);
1026 : 226 : s->size = sz;
1027 : 226 : ios_set_readonly(s);
1028 : 226 : return s;
1029 : : }
1030 : :
1031 : 4434 : ios_t *ios_fd(ios_t *s, long fd, int isfile, int own)
1032 : : {
1033 : 4434 : _ios_init(s);
1034 : 4434 : s->fd = fd;
1035 [ + + ]: 4434 : if (isfile) s->rereadable = 1;
1036 : 4434 : _buf_init(s, bm_block);
1037 : 4434 : s->ownfd = own;
1038 [ + + ]: 4434 : if (fd == STDERR_FILENO)
1039 : 30 : s->bm = bm_none;
1040 [ + + ]: 4434 : if (fd == STDOUT_FILENO)
1041 : 30 : s->bm = bm_line;
1042 : 4434 : return s;
1043 : : }
1044 : :
1045 : : ios_t *ios_stdin = NULL;
1046 : : ios_t *ios_stdout = NULL;
1047 : : ios_t *ios_stderr = NULL;
1048 : :
1049 : 30 : void ios_init_stdstreams(void)
1050 : : {
1051 : 30 : ios_stdin = (ios_t*)malloc_s(sizeof(ios_t));
1052 : 30 : ios_fd(ios_stdin, STDIN_FILENO, 0, 0);
1053 : :
1054 : 30 : ios_stdout = (ios_t*)malloc_s(sizeof(ios_t));
1055 : 30 : ios_fd(ios_stdout, STDOUT_FILENO, 0, 0);
1056 : 30 : ios_stdout->bm = bm_line;
1057 : :
1058 : 30 : ios_stderr = (ios_t*)malloc_s(sizeof(ios_t));
1059 : 30 : ios_fd(ios_stderr, STDERR_FILENO, 0, 0);
1060 : 30 : ios_stderr->bm = bm_none;
1061 : 30 : }
1062 : :
1063 : : /* higher level interface */
1064 : :
1065 : 320688000 : int ios_putc(int c, ios_t *s)
1066 : : {
1067 : 320688000 : char ch = (char)c;
1068 : :
1069 [ + + + + : 320688000 : if (s->state == bst_wr && s->bpos < s->maxsize && s->bm != bm_none) {
+ - ]
1070 : 316730000 : s->buf[s->bpos++] = ch;
1071 : 316730000 : _write_update_pos(s);
1072 [ - + - - ]: 316730000 : if (s->bm == bm_line && ch == '\n')
1073 : 0 : ios_flush(s);
1074 : 316730000 : return 1;
1075 : : }
1076 : 3957100 : return (int)ios_write(s, &ch, 1);
1077 : : }
1078 : :
1079 : 610910000 : int ios_getc(ios_t *s)
1080 : : {
1081 : : char ch;
1082 [ + + + + ]: 610910000 : if (s->state == bst_rd && s->bpos < s->size) {
1083 : 605786000 : ch = s->buf[s->bpos++];
1084 : : }
1085 : : else {
1086 [ - + ]: 5124760 : if (s->_eof) return IOS_EOF;
1087 [ + + ]: 5124760 : if (ios_read(s, &ch, 1) < 1)
1088 : 2454780 : return IOS_EOF;
1089 : : }
1090 [ + + ]: 608456000 : if (ch == '\n') s->lineno++;
1091 : 608456000 : return (unsigned char)ch;
1092 : : }
1093 : :
1094 : 83673000 : int ios_peekc(ios_t *s)
1095 : : {
1096 [ + + ]: 83673000 : if (s->bpos < s->size)
1097 : 83490800 : return (unsigned char)s->buf[s->bpos];
1098 [ + + ]: 182054 : if (s->_eof) return IOS_EOF;
1099 : 136872 : size_t n = ios_readprep(s, 1);
1100 [ + - ]: 136872 : if (n == 0) return IOS_EOF;
1101 : 0 : return (unsigned char)s->buf[s->bpos];
1102 : : }
1103 : :
1104 : 0 : int ios_ungetc(int c, ios_t *s)
1105 : : {
1106 [ # # ]: 0 : if (s->state == bst_wr)
1107 : 0 : return IOS_EOF;
1108 [ # # ]: 0 : if (c == '\n') s->lineno--;
1109 [ # # ]: 0 : if (s->u_colno > 0) s->u_colno--;
1110 [ # # ]: 0 : if (s->bpos > 0) {
1111 : 0 : s->bpos--;
1112 [ # # ]: 0 : if (s->buf[s->bpos] != (char)c)
1113 : 0 : s->buf[s->bpos] = (char)c;
1114 : 0 : s->_eof = 0;
1115 : 0 : return c;
1116 : : }
1117 [ # # ]: 0 : if (s->size == s->maxsize) {
1118 [ # # ]: 0 : if (_buf_realloc(s, s->maxsize*2) == NULL)
1119 : 0 : return IOS_EOF;
1120 : : }
1121 : 0 : memmove(s->buf + 1, s->buf, s->size);
1122 : 0 : s->buf[0] = (char)c;
1123 : 0 : s->size++;
1124 : 0 : s->_eof = 0;
1125 : 0 : return c;
1126 : : }
1127 : :
1128 : 44776800 : int ios_getutf8(ios_t *s, uint32_t *pwc)
1129 : : {
1130 : : int c;
1131 : : size_t sz;
1132 : : char c0;
1133 : : char buf[8];
1134 : :
1135 : 44776800 : c = ios_peekc(s);
1136 [ + + ]: 44776800 : if (c == IOS_EOF) {
1137 : 154070 : s->_eof = 1;
1138 : 154070 : return IOS_EOF;
1139 : : }
1140 : 44622800 : c0 = (char)c;
1141 [ + + ]: 44622800 : if ((unsigned char)c0 < 0x80) {
1142 : 44519200 : (void)ios_getc(s); // consume peeked char, increment lineno
1143 : 44519200 : *pwc = (uint32_t)(unsigned char)c0;
1144 [ + + ]: 44519200 : if (c == '\n')
1145 : 1307384 : s->u_colno = 0;
1146 : : else
1147 : 43211800 : s->u_colno += utf8proc_charwidth(*pwc);
1148 : 44519200 : return 1;
1149 : : }
1150 : 103524 : sz = u8_seqlen(&c0);
1151 [ + - - + ]: 103524 : if (!isutf(c0) || sz > 4)
1152 : 0 : return 0;
1153 [ - + ]: 103524 : if (ios_readprep(s, sz) < sz)
1154 : : // NOTE: this returns EOF even though some bytes are available,
1155 : : // so we do not set s->_eof on this code path
1156 : 0 : return IOS_EOF;
1157 : 103524 : int valid = u8_isvalid(&s->buf[s->bpos], sz);
1158 [ + - ]: 103524 : if (valid) {
1159 : 103524 : size_t i = s->bpos;
1160 : 103524 : *pwc = u8_nextchar(s->buf, &i);
1161 : 103524 : s->u_colno += utf8proc_charwidth(*pwc);
1162 : 103524 : ios_read(s, buf, sz);
1163 : : }
1164 : 103524 : return valid;
1165 : : }
1166 : :
1167 : 34415200 : int ios_peekutf8(ios_t *s, uint32_t *pwc)
1168 : : {
1169 : : int c;
1170 : : size_t sz;
1171 : : char c0;
1172 : :
1173 : 34415200 : c = ios_peekc(s);
1174 [ + + ]: 34415200 : if (c == IOS_EOF)
1175 : 27984 : return IOS_EOF;
1176 : 34387200 : c0 = (char)c;
1177 [ + + ]: 34387200 : if ((unsigned char)c0 < 0x80) {
1178 : 34347000 : *pwc = (uint32_t)(unsigned char)c0;
1179 : 34347000 : return 1;
1180 : : }
1181 : 40190 : sz = u8_seqlen(&c0);
1182 [ + - - + ]: 40190 : if (!isutf(c0) || sz > 4)
1183 : 0 : return 0;
1184 [ - + ]: 40190 : if (ios_readprep(s, sz) < sz)
1185 : 0 : return IOS_EOF;
1186 : 40190 : int valid = u8_isvalid(&s->buf[s->bpos], sz);
1187 [ + - ]: 40190 : if (valid) {
1188 : 40190 : size_t i = s->bpos;
1189 : 40190 : *pwc = u8_nextchar(s->buf, &i);
1190 : : }
1191 : 40190 : return valid;
1192 : : }
1193 : :
1194 : 28238000 : int ios_pututf8(ios_t *s, uint32_t wc)
1195 : : {
1196 : : char buf[8];
1197 [ + + ]: 28238000 : if (wc < 0x80)
1198 : 28186400 : return ios_putc((int)wc, s);
1199 : 51518 : size_t n = u8_toutf8(buf, 8, &wc, 1);
1200 : 51518 : return ios_write(s, buf, n);
1201 : : }
1202 : :
1203 : 0 : void ios_purge(ios_t *s)
1204 : : {
1205 [ # # ]: 0 : if (s->state == bst_rd) {
1206 : 0 : s->bpos = s->size;
1207 : : }
1208 : 0 : }
1209 : :
1210 : 0 : char *ios_readline(ios_t *s)
1211 : : {
1212 : : ios_t dest;
1213 : 0 : ios_mem(&dest, 0);
1214 : 0 : ios_copyuntil(&dest, s, '\n');
1215 : : size_t n;
1216 : 0 : return ios_take_buffer(&dest, &n);
1217 : : }
1218 : :
1219 : : extern int vasprintf(char **strp, const char *fmt, va_list ap);
1220 : :
1221 : 48 : int ios_vprintf(ios_t *s, const char *format, va_list args)
1222 : : {
1223 : 48 : char *str=NULL;
1224 : : int c;
1225 : : va_list al;
1226 : : #if defined(_OS_WINDOWS_)
1227 : : al = args;
1228 : : #else
1229 : 48 : va_copy(al, args);
1230 : : #endif /* _OS_WINDOWS_ */
1231 : :
1232 [ + - + - : 48 : if (s->state == bst_wr && s->bpos < s->maxsize && s->bm != bm_none) {
+ - ]
1233 : 48 : size_t avail = (size_t)(s->maxsize - s->bpos);
1234 : 48 : char *start = s->buf + s->bpos;
1235 : 48 : c = vsnprintf(start, avail, format, args);
1236 [ - + ]: 48 : if (c < 0) {
1237 : : #if defined(_OS_WINDOWS_)
1238 : : // on windows this can mean not enough space was available
1239 : : #else
1240 : 0 : va_end(al);
1241 : 0 : return c;
1242 : : #endif
1243 : : }
1244 [ + - ]: 48 : else if (c < avail) {
1245 : 48 : s->bpos += (size_t)c;
1246 : 48 : _write_update_pos(s);
1247 : : // TODO: only works right if newline is at end
1248 [ - + - - ]: 48 : if (s->bm == bm_line && memrchr(start, '\n', (size_t)c))
1249 : 0 : ios_flush(s);
1250 : 48 : va_end(al);
1251 : 48 : return c;
1252 : : }
1253 : : }
1254 : 0 : c = vasprintf(&str, format, al);
1255 : :
1256 [ # # ]: 0 : if (c >= 0) {
1257 : 0 : ios_write(s, str, c);
1258 : :
1259 : 0 : LLT_FREE(str);
1260 : : }
1261 : 0 : va_end(al);
1262 : 0 : return c;
1263 : : }
1264 : :
1265 : 48 : int ios_printf(ios_t *s, const char *format, ...)
1266 : : {
1267 : : va_list args;
1268 : : int c;
1269 : :
1270 : 48 : va_start(args, format);
1271 : 48 : c = ios_vprintf(s, format, args);
1272 : 48 : va_end(args);
1273 : 48 : return c;
1274 : : }
1275 : :
1276 : : #ifdef __cplusplus
1277 : : }
1278 : : #endif
|