rbuf: adapt to work on ccan/membuf.
[ccan] / ccan / rbuf / rbuf.c
1 /* Licensed under BSD-MIT - see LICENSE file for details */
2 #include <ccan/rbuf/rbuf.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6 #include <errno.h>
7 #include <string.h>
8 #include <fcntl.h>
9
10 bool rbuf_open(struct rbuf *rbuf, const char *name, char *buf, size_t buf_max,
11                void *(*expandfn)(struct membuf *, void *, size_t))
12 {
13         int fd = open(name, O_RDONLY);
14         if (fd >= 0) {
15                 rbuf_init(rbuf, fd, buf, buf_max, expandfn);
16                 return true;
17         }
18         return false;
19 }
20
21 size_t rbuf_good_size(int fd)
22 {
23         struct stat st;
24
25         if (fstat(fd, &st) == 0 && st.st_blksize >= 4096)
26                 return st.st_blksize;
27         return 4096;
28 }
29
30 static ssize_t get_more(struct rbuf *rbuf)
31 {
32         ssize_t r;
33
34         /* This is so we only call rbuf_good_size once. */
35         if (tcon_unwrap(&rbuf->m)->max_elems == 0)
36                 membuf_prepare_space(&rbuf->m, rbuf_good_size(rbuf->fd));
37         else /* membuf doubles internally, so just ask for anything. */
38                 membuf_prepare_space(&rbuf->m, 1);
39
40         /* This happens if realloc fails (errno already ENOMEM) */
41         if (!membuf_num_space(&rbuf->m))
42                 return -1;
43
44         r = read(rbuf->fd, membuf_space(&rbuf->m), membuf_num_space(&rbuf->m));
45         if (r <= 0)
46                 return r;
47
48         membuf_add(&rbuf->m, r);
49         return r;
50 }
51
52 void *rbuf_fill_all(struct rbuf *rbuf)
53 {
54         ssize_t r;
55
56         while ((r = get_more(rbuf)) != 0)
57                 if (r < 0)
58                         return NULL;
59         return rbuf_start(rbuf);
60 }
61
62 void *rbuf_fill(struct rbuf *rbuf)
63 {
64         if (!rbuf_len(rbuf)) {
65                 if (get_more(rbuf) < 0)
66                         return NULL;
67         }
68         return rbuf_start(rbuf);
69 }
70
71 char *rbuf_read_str(struct rbuf *rbuf, char term)
72 {
73         char *p;
74         ssize_t r = 0;
75         size_t prev = 0;
76
77         while (!(p = memchr(membuf_elems(&rbuf->m) + prev,
78                             term,
79                             membuf_num_elems(&rbuf->m) - prev))) {
80                 prev += r;
81                 r = get_more(rbuf);
82                 if (r < 0)
83                         return NULL;
84                 /* EOF with no term. */
85                 if (r == 0) {
86                         char *ret;
87                         size_t len = rbuf_len(rbuf);
88
89                         /* Nothing read at all? */
90                         if (!len && term) {
91                                 errno = 0;
92                                 return NULL;
93                         }
94
95                         /* Put term after input (get_more made room). */
96                         assert(membuf_num_space(&rbuf->m) > 0);
97                         ret = membuf_consume(&rbuf->m, len);
98                         ret[len] = '\0';
99                         return ret;
100                 }
101         }
102         *p = '\0';
103         return membuf_consume(&rbuf->m, p + 1 - (char *)rbuf_start(rbuf));
104 }