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