8cd5374463ce4182383d92a0d202b349f481690d
[libcmdline.git] / src / lib / cmdline_cirbuf.c
1 /*
2  * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
3  * All rights reserved.
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the University of California, Berkeley nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <string.h>
29 #include <errno.h>
30
31 #include "cmdline_cirbuf.h"
32
33
34 void 
35 cirbuf_init(struct cirbuf *cbuf, char *buf, unsigned int start, unsigned int maxlen)
36 {
37         cbuf->maxlen = maxlen;
38         cbuf->len = 0;
39         cbuf->start = start;
40         cbuf->end = start;
41         cbuf->buf = buf;
42 }
43
44 /* multiple add */
45
46 int
47 cirbuf_add_buf_head(struct cirbuf *cbuf, const char *c, unsigned int n)
48 {
49         unsigned int e;
50
51         if (!n || n > CIRBUF_GET_FREELEN(cbuf))
52                 return -EINVAL;
53
54         e = CIRBUF_IS_EMPTY(cbuf) ? 1 : 0;
55         
56         if (n < cbuf->start + e) {
57                 dprintf("s[%d] -> d[%d] (%d)\n", 0, cbuf->start - n + e, n);
58                 memcpy(cbuf->buf + cbuf->start - n + e, c, n);
59         }
60         else {
61                 dprintf("s[%d] -> d[%d] (%d)\n", + n - (cbuf->start + e), 0, cbuf->start + e);
62                 dprintf("s[%d] -> d[%d] (%d)\n", cbuf->maxlen - n + (cbuf->start + e), 0, n - (cbuf->start + e));
63                 memcpy(cbuf->buf, c  + n - (cbuf->start + e) , cbuf->start + e);
64                 memcpy(cbuf->buf + cbuf->maxlen - n + (cbuf->start + e), c, n - (cbuf->start + e));
65         }
66         cbuf->len += n;
67         cbuf->start += (cbuf->maxlen - n + e);
68         cbuf->start %= cbuf->maxlen;
69         return n;
70 }
71
72 /* multiple add */
73
74 int
75 cirbuf_add_buf_tail(struct cirbuf *cbuf, const char *c, unsigned int n)
76 {
77         unsigned int e;
78
79         if (!n || n > CIRBUF_GET_FREELEN(cbuf))
80                 return -EINVAL;
81
82         e = CIRBUF_IS_EMPTY(cbuf) ? 1 : 0;
83         
84         if (n < cbuf->maxlen - cbuf->end - 1 + e) {
85                 dprintf("s[%d] -> d[%d] (%d)\n", 0, cbuf->end + !e, n);
86                 memcpy(cbuf->buf + cbuf->end + !e, c, n);
87         }
88         else {
89                 dprintf("s[%d] -> d[%d] (%d)\n", cbuf->end + !e, 0, cbuf->maxlen - cbuf->end - 1 + e);
90                 dprintf("s[%d] -> d[%d] (%d)\n", cbuf->maxlen - cbuf->end - 1 + e, 0, n - cbuf->maxlen + cbuf->end + 1 - e);
91                 memcpy(cbuf->buf + cbuf->end + !e, c, cbuf->maxlen - cbuf->end - 1 + e);
92                 memcpy(cbuf->buf, c + cbuf->maxlen - cbuf->end - 1 + e, n - cbuf->maxlen + cbuf->end + 1 - e);
93         }
94         cbuf->len += n;
95         cbuf->end += n - e;
96         cbuf->end %= cbuf->maxlen;
97         return n;
98 }
99
100 /* add at head */
101
102 static inline void 
103 __cirbuf_add_head(struct cirbuf * cbuf, char c)
104 {
105         if (!CIRBUF_IS_EMPTY(cbuf)) {
106                 cbuf->start += (cbuf->maxlen - 1);
107                 cbuf->start %= cbuf->maxlen;
108         }
109         cbuf->buf[cbuf->start] = c;
110         cbuf->len ++;
111 }
112
113 int 
114 cirbuf_add_head_safe(struct cirbuf * cbuf, char c)
115 {
116         if (cbuf && !CIRBUF_IS_FULL(cbuf)) {
117                 __cirbuf_add_head(cbuf, c);     
118                 return 0;
119         }
120         return -EINVAL;
121 }
122
123 void
124 cirbuf_add_head(struct cirbuf * cbuf, char c)
125 {
126         __cirbuf_add_head(cbuf, c);     
127 }
128
129 /* add at tail */
130
131 static inline void 
132 __cirbuf_add_tail(struct cirbuf * cbuf, char c)
133 {
134         if (!CIRBUF_IS_EMPTY(cbuf)) {
135                 cbuf->end ++;
136                 cbuf->end %= cbuf->maxlen;
137         }
138         cbuf->buf[cbuf->end] = c;
139         cbuf->len ++;
140 }
141
142 int 
143 cirbuf_add_tail_safe(struct cirbuf * cbuf, char c)
144 {
145         if (cbuf && !CIRBUF_IS_FULL(cbuf)) {
146                 __cirbuf_add_tail(cbuf, c);     
147                 return 0;
148         }
149         return -EINVAL;
150 }
151
152 void
153 cirbuf_add_tail(struct cirbuf * cbuf, char c)
154 {
155         __cirbuf_add_tail(cbuf, c);     
156 }
157
158
159 static inline void
160 __cirbuf_shift_left(struct cirbuf *cbuf)
161 {
162         unsigned int i;
163         char tmp = cbuf->buf[cbuf->start];
164
165         for (i=0 ; i<cbuf->len ; i++) {
166                 cbuf->buf[(cbuf->start+i)%cbuf->maxlen] = 
167                         cbuf->buf[(cbuf->start+i+1)%cbuf->maxlen];
168         }
169         cbuf->buf[(cbuf->start-1+cbuf->maxlen)%cbuf->maxlen] = tmp;
170         cbuf->start += (cbuf->maxlen - 1);
171         cbuf->start %= cbuf->maxlen;
172         cbuf->end += (cbuf->maxlen - 1);
173         cbuf->end %= cbuf->maxlen;
174 }
175
176 static inline void
177 __cirbuf_shift_right(struct cirbuf *cbuf)
178 {
179         unsigned int i;
180         char tmp = cbuf->buf[cbuf->end];
181
182         for (i=0 ; i<cbuf->len ; i++) {
183                 cbuf->buf[(cbuf->end+cbuf->maxlen-i)%cbuf->maxlen] = 
184                         cbuf->buf[(cbuf->end+cbuf->maxlen-i-1)%cbuf->maxlen];
185         }
186         cbuf->buf[(cbuf->end+1)%cbuf->maxlen] = tmp;
187         cbuf->start += 1;
188         cbuf->start %= cbuf->maxlen;
189         cbuf->end += 1;
190         cbuf->end %= cbuf->maxlen;
191 }
192
193 /* XXX we could do a better algorithm here... */
194 void cirbuf_align_left(struct cirbuf * cbuf)
195 {
196         if (cbuf->start < cbuf->maxlen/2) {
197                 while (cbuf->start != 0) {
198                         __cirbuf_shift_left(cbuf);
199                 }
200         }
201         else {
202                 while (cbuf->start != 0) {
203                         __cirbuf_shift_right(cbuf);
204                 }
205         }
206 }
207
208 /* XXX we could do a better algorithm here... */
209 void cirbuf_align_right(struct cirbuf * cbuf)
210 {
211         if (cbuf->start >= cbuf->maxlen/2) {
212                 while (cbuf->end != cbuf->maxlen-1) {
213                         __cirbuf_shift_left(cbuf);
214                 }
215         }
216         else {
217                 while (cbuf->start != cbuf->maxlen-1) {
218                         __cirbuf_shift_right(cbuf);
219                 }
220         }
221 }
222
223 /* buffer del */
224
225 int
226 cirbuf_del_buf_head(struct cirbuf *cbuf, unsigned int size)
227 {
228         if (!size || size > CIRBUF_GET_LEN(cbuf))
229                 return -EINVAL;
230
231         cbuf->len -= size;
232         if (CIRBUF_IS_EMPTY(cbuf)) {
233                 cbuf->start += size - 1;
234                 cbuf->start %= cbuf->maxlen;
235         }
236         else {
237                 cbuf->start += size;
238                 cbuf->start %= cbuf->maxlen;
239         }
240         return 0;
241 }
242
243 /* buffer del */
244
245 int
246 cirbuf_del_buf_tail(struct cirbuf *cbuf, unsigned int size)
247 {
248         if (!size || size > CIRBUF_GET_LEN(cbuf))
249                 return -EINVAL;
250
251         cbuf->len -= size;
252         if (CIRBUF_IS_EMPTY(cbuf)) {
253                 cbuf->end  += (cbuf->maxlen - size + 1);
254                 cbuf->end %= cbuf->maxlen;
255         }
256         else {
257                 cbuf->end  += (cbuf->maxlen - size);
258                 cbuf->end %= cbuf->maxlen;
259         }
260         return 0;
261 }
262
263 /* del at head */
264
265 static inline void
266 __cirbuf_del_head(struct cirbuf * cbuf)
267 {
268         cbuf->len --;
269         if (!CIRBUF_IS_EMPTY(cbuf)) {
270                 cbuf->start ++;
271                 cbuf->start %= cbuf->maxlen;
272         }
273 }
274
275 int
276 cirbuf_del_head_safe(struct cirbuf * cbuf)
277 {
278         if (cbuf && !CIRBUF_IS_EMPTY(cbuf)) {
279                 __cirbuf_del_head(cbuf);
280                 return 0;
281         }
282         return -EINVAL;
283 }
284
285 void
286 cirbuf_del_head(struct cirbuf * cbuf)
287 {
288         __cirbuf_del_head(cbuf);
289 }
290
291 /* del at tail */
292
293 static inline void
294 __cirbuf_del_tail(struct cirbuf * cbuf)
295 {
296         cbuf->len --;
297         if (!CIRBUF_IS_EMPTY(cbuf)) {
298                 cbuf->end  += (cbuf->maxlen - 1);
299                 cbuf->end %= cbuf->maxlen;
300         }
301 }
302
303 int
304 cirbuf_del_tail_safe(struct cirbuf * cbuf)
305 {
306         if (cbuf && !CIRBUF_IS_EMPTY(cbuf)) {
307                 __cirbuf_del_tail(cbuf);
308                 return 0;
309         }
310         return -EINVAL;
311 }
312
313 void
314 cirbuf_del_tail(struct cirbuf * cbuf)
315 {
316         __cirbuf_del_tail(cbuf);
317 }
318
319 /* convert to buffer */
320
321 int
322 cirbuf_get_buf_head(struct cirbuf *cbuf, char *c, unsigned int size)
323 {
324         unsigned int n = (size < CIRBUF_GET_LEN(cbuf)) ? size : CIRBUF_GET_LEN(cbuf);
325         
326         if (!n)
327                 return 0;
328
329         if (cbuf->start <= cbuf->end) {
330                 dprintf("s[%d] -> d[%d] (%d)\n", cbuf->start, 0, n);
331                 memcpy(c, cbuf->buf + cbuf->start , n);
332         }
333         else {
334                 dprintf("s[%d] -> d[%d] (%d)\n", cbuf->start, 0, cbuf->maxlen - cbuf->start);
335                 dprintf("s[%d] -> d[%d] (%d)\n", 0, cbuf->maxlen - cbuf->start, n - cbuf->maxlen + cbuf->start);
336                 memcpy(c, cbuf->buf + cbuf->start , cbuf->maxlen - cbuf->start);
337                 memcpy(c + cbuf->maxlen - cbuf->start, cbuf->buf, n - cbuf->maxlen + cbuf->start);
338         }
339         return n;
340 }
341
342 /* convert to buffer */
343
344 int
345 cirbuf_get_buf_tail(struct cirbuf *cbuf, char *c, unsigned int size)
346 {
347         unsigned int n = (size < CIRBUF_GET_LEN(cbuf)) ? size : CIRBUF_GET_LEN(cbuf);
348
349         if (!n)
350                 return 0;
351
352         if (cbuf->start <= cbuf->end) {
353                 dprintf("s[%d] -> d[%d] (%d)\n", cbuf->end - n + 1, 0, n);
354                 memcpy(c, cbuf->buf + cbuf->end - n + 1, n);
355         }
356         else {
357                 dprintf("s[%d] -> d[%d] (%d)\n", 0,  cbuf->maxlen - cbuf->start, cbuf->end + 1);
358                 dprintf("s[%d] -> d[%d] (%d)\n", cbuf->maxlen - n + cbuf->end + 1, 0, n - cbuf->end - 1);
359
360                 memcpy(c + cbuf->maxlen - cbuf->start, cbuf->buf, cbuf->end + 1);
361                 memcpy(c, cbuf->buf + cbuf->maxlen - n + cbuf->end +1, n - cbuf->end - 1);
362         }
363         return n;
364 }
365
366 /* get head or get tail */
367
368 char 
369 cirbuf_get_head(struct cirbuf * cbuf)
370 {
371         return cbuf->buf[cbuf->start];
372 }
373
374 /* get head or get tail */
375
376 char 
377 cirbuf_get_tail(struct cirbuf * cbuf)
378 {
379         return cbuf->buf[cbuf->end];
380 }
381