]> mj.ucw.cz Git - libucw.git/blob - lib/ff-string.c
* dev-threads merged to dev-img
[libucw.git] / lib / ff-string.c
1 /*
2  *      UCW Library -- Fast Buffered I/O: Strings
3  *
4  *      (c) 1997--2006 Martin Mares <mj@ucw.cz>
5  *      (c) 2006 Pavel Charvat <pchar@ucw.cz>
6  *
7  *      This software may be freely distributed and used according to the terms
8  *      of the GNU Lesser General Public License.
9  */
10
11 #include "lib/lib.h"
12 #include "lib/fastbuf.h"
13 #include "lib/mempool.h"
14 #include "lib/bbuf.h"
15
16 byte *                                  /* Non-standard */
17 bgets(struct fastbuf *f, byte *b, uns l)
18 {
19   ASSERT(l);
20   byte *src;
21   uns src_len = bdirect_read_prepare(f, &src);
22   if (!src_len)
23     return NULL;
24   do
25     {
26       uns cnt = MIN(l, src_len);
27       for (uns i = cnt; i--;)
28         {
29           byte v = *src++;
30           if (v == '\n')
31             {
32               bdirect_read_commit(f, src);
33               goto exit;
34             }
35           *b++ = v;
36         }
37       if (unlikely(cnt == l))
38         die("%s: Line too long", f->name);
39       l -= cnt;
40       bdirect_read_commit(f, src);
41       src_len = bdirect_read_prepare(f, &src);
42     }
43   while (src_len);
44 exit:
45   *b = 0;
46   return b;
47 }
48
49 int
50 bgets_nodie(struct fastbuf *f, byte *b, uns l)
51 {
52   ASSERT(l);
53   byte *src, *start = b;
54   uns src_len = bdirect_read_prepare(f, &src);
55   if (!src_len)
56     return 0;
57   do
58     {
59       uns cnt = MIN(l, src_len);
60       for (uns i = cnt; i--;)
61         {
62           byte v = *src++;
63           if (v == '\n')
64             {
65               bdirect_read_commit(f, src);
66               goto exit;
67             }
68           *b++ = v;
69         }
70       bdirect_read_commit(f, src);
71       if (cnt == l)
72         return -1;
73       l -= cnt;
74       src_len = bdirect_read_prepare(f, &src);
75     }
76   while (src_len);
77 exit:
78   *b++ = 0;
79   return b - start;
80 }
81
82 uns
83 bgets_bb(struct fastbuf *f, struct bb_t *bb, uns limit)
84 {
85   ASSERT(limit);
86   byte *src;
87   uns src_len = bdirect_read_prepare(f, &src);
88   if (!src_len)
89     return 0;
90   bb_grow(bb, 1);
91   byte *buf = bb->ptr;
92   uns len = 0, buf_len = MIN(bb->len, limit);
93   do
94     {
95       uns cnt = MIN(src_len, buf_len);
96       for (uns i = cnt; i--;)
97         {
98           byte v = *src++;
99           if (v == '\n')
100             {
101               bdirect_read_commit(f, src);
102               goto exit;
103             }
104           *buf++ = v;
105         }
106       len += cnt;
107       if (cnt == src_len)
108         {
109           bdirect_read_commit(f, src);
110           src_len = bdirect_read_prepare(f, &src);
111         }
112       else
113         src_len -= cnt;
114       if (cnt == buf_len)
115         {
116           if (unlikely(len == limit))
117             die("%s: Line too long", f->name);
118           bb_do_grow(bb, len + 1);
119           buf = bb->ptr + len;
120           buf_len = MIN(bb->len, limit) - len;
121         }
122       else
123         buf_len -= cnt;
124     }
125   while (src_len);
126 exit:
127   *buf++ = 0;
128   return buf - bb->ptr;
129 }
130
131 byte *
132 bgets_mp(struct fastbuf *f, struct mempool *mp)
133 {
134   byte *src;
135   uns src_len = bdirect_read_prepare(f, &src);
136   if (!src_len)
137     return NULL;
138 #define BLOCK_SIZE (4096 - sizeof(void *))
139   struct block {
140     struct block *prev;
141     byte data[BLOCK_SIZE];
142   } *blocks = NULL;
143   uns sum = 0, buf_len = BLOCK_SIZE, cnt;
144   struct block first_block, *new_block = &first_block;
145   byte *buf = new_block->data;
146   do
147     {
148       cnt = MIN(src_len, buf_len);
149       for (uns i = cnt; i--;)
150         {
151           byte v = *src++;
152           if (v == '\n')
153             {
154               bdirect_read_commit(f, src);
155               goto exit;
156             }
157           *buf++ = v;
158         }
159       if (cnt == src_len)
160         {
161           bdirect_read_commit(f, src);
162           src_len = bdirect_read_prepare(f, &src);
163         }
164       else
165         src_len -= cnt;
166       if (cnt == buf_len)
167         {
168           new_block->prev = blocks;
169           blocks = new_block;
170           sum += buf_len = BLOCK_SIZE;
171           new_block = alloca(sizeof(struct block));
172           buf = new_block->data;
173         }
174       else
175         buf_len -= cnt;
176     }
177   while (src_len);
178 exit: ;
179   uns len = buf - new_block->data;
180   byte *result = mp_alloc(mp, sum + len + 1) + sum;
181   result[len] = 0;
182   memcpy(result, new_block->data, len);
183   while (blocks)
184     {
185       result -= BLOCK_SIZE;
186       memcpy(result, blocks->data, BLOCK_SIZE);
187       blocks = blocks->prev;
188     }
189   return result;
190 #undef BLOCK_SIZE
191 }
192
193 void
194 bgets_stk_init(struct bgets_stk_struct *s)
195 {
196   s->src_len = bdirect_read_prepare(s->f, &s->src);
197   if (!s->src_len)
198     {
199       s->cur_buf = NULL;
200       s->cur_len = 0;
201     }
202   else
203     {
204       s->old_buf = NULL;
205       s->cur_len = 256;
206     }
207 }
208
209 void
210 bgets_stk_step(struct bgets_stk_struct *s)
211 {
212   byte *buf = s->cur_buf;
213   uns buf_len = s->cur_len;
214   if (s->old_buf)
215     {
216       memcpy( s->cur_buf, s->old_buf, s->old_len);
217       buf += s->old_len;
218       buf_len -= s->old_len;
219     }
220   do
221     {
222       uns cnt = MIN(s->src_len, buf_len);
223       for (uns i = cnt; i--;)
224         {
225           byte v = *s->src++;
226           if (v == '\n')
227             {
228               bdirect_read_commit(s->f, s->src);
229               goto exit;
230             }
231           *buf++ = v;
232         }
233       if (cnt == s->src_len)
234         {
235           bdirect_read_commit(s->f, s->src);
236           s->src_len = bdirect_read_prepare(s->f, &s->src);
237         }
238       else
239         s->src_len -= cnt;
240       if (cnt == buf_len)
241         {
242           s->old_len = s->cur_len;
243           s->old_buf = s->cur_buf;
244           s->cur_len *= 2;
245           return;
246         }
247       else
248         buf_len -= cnt;
249     }
250   while (s->src_len);
251 exit:
252   *buf = 0;
253   s->cur_len = 0;
254 }
255
256 byte *
257 bgets0(struct fastbuf *f, byte *b, uns l)
258 {
259   ASSERT(l);
260   byte *src;
261   uns src_len = bdirect_read_prepare(f, &src);
262   if (!src_len)
263     return NULL;
264   do
265     {
266       uns cnt = MIN(l, src_len);
267       for (uns i = cnt; i--;)
268         {
269           *b = *src++;
270           if (!*b)
271             {
272               bdirect_read_commit(f, src);
273               return b;
274             }
275           b++;
276         }
277       if (unlikely(cnt == l))
278         die("%s: Line too long", f->name);
279       l -= cnt;
280       bdirect_read_commit(f, src);
281       src_len = bdirect_read_prepare(f, &src);
282     }
283   while (src_len);
284   *b = 0;
285   return b;
286 }