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