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