]> mj.ucw.cz Git - libucw.git/blob - lib/ff-string.c
Some optimizations and fixes in bgets*().
[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           if (*src == '\n')
97             {
98               bdirect_read_commit(f, src);
99               goto exit;
100             }
101           *buf++ = *src++;
102         }
103       len += cnt;
104       if (cnt == src_len)
105         {
106           bdirect_read_commit(f, src);
107           src_len = bdirect_read_prepare(f, &src);
108         }
109       else
110         src_len -= cnt;
111       if (cnt == buf_len)
112         {
113           bb_do_grow(bb, len + 1);
114           buf = bb->ptr + len;
115           buf_len = bb->len - len;
116         }
117       else
118         buf_len -= cnt;
119     }
120   while (src_len);
121 exit:
122   *buf++ = 0;
123   return buf - bb->ptr;
124 }
125
126 byte *
127 bgets_mp(struct mempool *mp, struct fastbuf *f)
128 {
129   byte *src;
130   uns src_len = bdirect_read_prepare(f, &src);
131   if (!src_len)
132     return NULL;
133 #define BLOCK_SIZE 4096
134   struct block {
135     struct block *prev;
136     byte data[BLOCK_SIZE];
137   } *blocks = NULL;
138   uns sum = 0, buf_len = BLOCK_SIZE;
139   struct block *new_block = alloca(sizeof(struct block));
140   byte *buf = new_block->data;
141   do
142     {
143       uns cnt = MIN(src_len, buf_len);
144       for (uns i = cnt; i--;)
145         {
146           if (*src == '\n')
147             {
148               bdirect_read_commit(f, src);
149               goto exit;
150             }
151           *buf++ = *src++;
152         }
153       if (cnt == src_len)
154         {
155           bdirect_read_commit(f, src);
156           src_len = bdirect_read_prepare(f, &src);
157         }
158       else
159         src_len -= cnt;
160       if (cnt == buf_len)
161         {
162           new_block->prev = blocks;
163           blocks = new_block;
164           sum += buf_len = BLOCK_SIZE;
165           buf = new_block->data;
166         }
167       else
168         buf_len -= cnt;
169     }
170   while (src_len);
171 exit: ; 
172   uns len = buf - new_block->data;
173   byte *result = mp_alloc(mp, sum + len + 1) + sum;
174   result[len] = 0;
175   memcpy(result, new_block->data, len);
176   while (blocks)
177     {
178       result -= BLOCK_SIZE;
179       memcpy(result, blocks->data, BLOCK_SIZE);
180       blocks = blocks->prev;
181     }
182   return result;
183 #undef BLOCK_SIZE
184 }
185
186 int
187 bgets_stk_step(struct fastbuf *f, byte *old_buf, byte *buf, uns len)
188 {
189   if (old_buf)
190     {
191       len = len >> 1;
192       memcpy(buf, old_buf, len);
193       buf += len;
194     }
195   while (len--)
196     {
197       int k = bgetc(f);
198       if (k == '\n' || k < 0)
199         return *buf = 0;
200       *buf++ = k;
201     }
202   return 1;
203 }
204
205 byte *
206 bgets0(struct fastbuf *f, byte *b, uns l)
207 {
208   ASSERT(l);
209   byte *src;
210   uns src_len = bdirect_read_prepare(f, &src);
211   if (!src_len)
212     return NULL;
213   do
214     {
215       uns cnt = MIN(l, src_len);
216       for (uns i = cnt; i--;)
217         {
218           *b = *src++;
219           if (!*b)
220             {
221               bdirect_read_commit(f, src);
222               return b;
223             }
224           b++;
225         }
226       if (unlikely(cnt == l))
227         die("%s: Line too long", f->name);
228       l -= cnt;
229       bdirect_read_commit(f, src);
230       src_len = bdirect_read_prepare(f, &src);
231     }
232   while (src_len);
233   *b = 0;
234   return b;
235 }