xref: /dpdk/lib/cmdline/cmdline_cirbuf.c (revision daa02b5cddbb8e11b31d41e2bf7bb1ae64dcae2f)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation.
3  * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
4  * All rights reserved.
5  */
6 
7 #include <string.h>
8 #include <errno.h>
9 #include <stdio.h>
10 
11 #include "cmdline_cirbuf.h"
12 
13 
14 int
15 cirbuf_init(struct cirbuf *cbuf, char *buf, unsigned int start, unsigned int maxlen)
16 {
17 	if (!cbuf || !buf)
18 		return -EINVAL;
19 	cbuf->maxlen = maxlen;
20 	cbuf->len = 0;
21 	cbuf->start = start;
22 	cbuf->end = start;
23 	cbuf->buf = buf;
24 	return 0;
25 }
26 
27 /* multiple add */
28 
29 int
30 cirbuf_add_buf_head(struct cirbuf *cbuf, const char *c, unsigned int n)
31 {
32 	unsigned int e;
33 
34 	if (!cbuf || !c || !n || n > CIRBUF_GET_FREELEN(cbuf))
35 		return -EINVAL;
36 
37 	e = CIRBUF_IS_EMPTY(cbuf) ? 1 : 0;
38 
39 	if (n < cbuf->start + e) {
40 		dprintf("s[%d] -> d[%d] (%d)\n", 0, cbuf->start - n + e, n);
41 		memcpy(cbuf->buf + cbuf->start - n + e, c, n);
42 	}
43 	else {
44 		dprintf("s[%d] -> d[%d] (%d)\n", + n - (cbuf->start + e), 0,
45 			cbuf->start + e);
46 		dprintf("s[%d] -> d[%d] (%d)\n", cbuf->maxlen - n +
47 			(cbuf->start + e), 0, n - (cbuf->start + e));
48 		memcpy(cbuf->buf, c  + n - (cbuf->start + e) , cbuf->start + e);
49 		memcpy(cbuf->buf + cbuf->maxlen - n + (cbuf->start + e), c,
50 		       n - (cbuf->start + e));
51 	}
52 	cbuf->len += n;
53 	cbuf->start += (cbuf->maxlen - n + e);
54 	cbuf->start %= cbuf->maxlen;
55 	return n;
56 }
57 
58 /* multiple add */
59 
60 int
61 cirbuf_add_buf_tail(struct cirbuf *cbuf, const char *c, unsigned int n)
62 {
63 	unsigned int e;
64 
65 	if (!cbuf || !c || !n || n > CIRBUF_GET_FREELEN(cbuf))
66 		return -EINVAL;
67 
68 	e = CIRBUF_IS_EMPTY(cbuf) ? 1 : 0;
69 
70 	if (n < cbuf->maxlen - cbuf->end - 1 + e) {
71 		dprintf("s[%d] -> d[%d] (%d)\n", 0, cbuf->end + !e, n);
72 		memcpy(cbuf->buf + cbuf->end + !e, c, n);
73 	}
74 	else {
75 		dprintf("s[%d] -> d[%d] (%d)\n", cbuf->end + !e, 0,
76 			cbuf->maxlen - cbuf->end - 1 + e);
77 		dprintf("s[%d] -> d[%d] (%d)\n", cbuf->maxlen - cbuf->end - 1 +
78 			e, 0, n - cbuf->maxlen + cbuf->end + 1 - e);
79 		memcpy(cbuf->buf + cbuf->end + !e, c, cbuf->maxlen -
80 		       cbuf->end - 1 + e);
81 		memcpy(cbuf->buf, c + cbuf->maxlen - cbuf->end - 1 + e,
82 		       n - cbuf->maxlen + cbuf->end + 1 - e);
83 	}
84 	cbuf->len += n;
85 	cbuf->end += n - e;
86 	cbuf->end %= cbuf->maxlen;
87 	return n;
88 }
89 
90 /* add at head */
91 
92 static inline void
93 __cirbuf_add_head(struct cirbuf * cbuf, char c)
94 {
95 	if (!CIRBUF_IS_EMPTY(cbuf)) {
96 		cbuf->start += (cbuf->maxlen - 1);
97 		cbuf->start %= cbuf->maxlen;
98 	}
99 	cbuf->buf[cbuf->start] = c;
100 	cbuf->len ++;
101 }
102 
103 int
104 cirbuf_add_head_safe(struct cirbuf * cbuf, char c)
105 {
106 	if (cbuf && !CIRBUF_IS_FULL(cbuf)) {
107 		__cirbuf_add_head(cbuf, c);
108 		return 0;
109 	}
110 	return -EINVAL;
111 }
112 
113 void
114 cirbuf_add_head(struct cirbuf * cbuf, char c)
115 {
116 	__cirbuf_add_head(cbuf, c);
117 }
118 
119 /* add at tail */
120 
121 static inline void
122 __cirbuf_add_tail(struct cirbuf * cbuf, char c)
123 {
124 	if (!CIRBUF_IS_EMPTY(cbuf)) {
125 		cbuf->end ++;
126 		cbuf->end %= cbuf->maxlen;
127 	}
128 	cbuf->buf[cbuf->end] = c;
129 	cbuf->len ++;
130 }
131 
132 int
133 cirbuf_add_tail_safe(struct cirbuf * cbuf, char c)
134 {
135 	if (cbuf && !CIRBUF_IS_FULL(cbuf)) {
136 		__cirbuf_add_tail(cbuf, c);
137 		return 0;
138 	}
139 	return -EINVAL;
140 }
141 
142 void
143 cirbuf_add_tail(struct cirbuf * cbuf, char c)
144 {
145 	__cirbuf_add_tail(cbuf, c);
146 }
147 
148 
149 static inline void
150 __cirbuf_shift_left(struct cirbuf *cbuf)
151 {
152 	unsigned int i;
153 	char tmp = cbuf->buf[cbuf->start];
154 
155 	for (i=0 ; i<cbuf->len ; i++) {
156 		cbuf->buf[(cbuf->start+i)%cbuf->maxlen] =
157 			cbuf->buf[(cbuf->start+i+1)%cbuf->maxlen];
158 	}
159 	cbuf->buf[(cbuf->start-1+cbuf->maxlen)%cbuf->maxlen] = tmp;
160 	cbuf->start += (cbuf->maxlen - 1);
161 	cbuf->start %= cbuf->maxlen;
162 	cbuf->end += (cbuf->maxlen - 1);
163 	cbuf->end %= cbuf->maxlen;
164 }
165 
166 static inline void
167 __cirbuf_shift_right(struct cirbuf *cbuf)
168 {
169 	unsigned int i;
170 	char tmp = cbuf->buf[cbuf->end];
171 
172 	for (i=0 ; i<cbuf->len ; i++) {
173 		cbuf->buf[(cbuf->end+cbuf->maxlen-i)%cbuf->maxlen] =
174 			cbuf->buf[(cbuf->end+cbuf->maxlen-i-1)%cbuf->maxlen];
175 	}
176 	cbuf->buf[(cbuf->end+1)%cbuf->maxlen] = tmp;
177 	cbuf->start += 1;
178 	cbuf->start %= cbuf->maxlen;
179 	cbuf->end += 1;
180 	cbuf->end %= cbuf->maxlen;
181 }
182 
183 /* XXX we could do a better algorithm here... */
184 int
185 cirbuf_align_left(struct cirbuf * cbuf)
186 {
187 	if (!cbuf)
188 		return -EINVAL;
189 
190 	if (cbuf->start < cbuf->maxlen/2) {
191 		while (cbuf->start != 0) {
192 			__cirbuf_shift_left(cbuf);
193 		}
194 	}
195 	else {
196 		while (cbuf->start != 0) {
197 			__cirbuf_shift_right(cbuf);
198 		}
199 	}
200 
201 	return 0;
202 }
203 
204 /* XXX we could do a better algorithm here... */
205 int
206 cirbuf_align_right(struct cirbuf * cbuf)
207 {
208 	if (!cbuf)
209 		return -EINVAL;
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 	return 0;
223 }
224 
225 /* buffer del */
226 
227 int
228 cirbuf_del_buf_head(struct cirbuf *cbuf, unsigned int size)
229 {
230 	if (!cbuf || !size || size > CIRBUF_GET_LEN(cbuf))
231 		return -EINVAL;
232 
233 	cbuf->len -= size;
234 	if (CIRBUF_IS_EMPTY(cbuf)) {
235 		cbuf->start += size - 1;
236 		cbuf->start %= cbuf->maxlen;
237 	}
238 	else {
239 		cbuf->start += size;
240 		cbuf->start %= cbuf->maxlen;
241 	}
242 	return 0;
243 }
244 
245 /* buffer del */
246 
247 int
248 cirbuf_del_buf_tail(struct cirbuf *cbuf, unsigned int size)
249 {
250 	if (!cbuf || !size || size > CIRBUF_GET_LEN(cbuf))
251 		return -EINVAL;
252 
253 	cbuf->len -= size;
254 	if (CIRBUF_IS_EMPTY(cbuf)) {
255 		cbuf->end  += (cbuf->maxlen - size + 1);
256 		cbuf->end %= cbuf->maxlen;
257 	}
258 	else {
259 		cbuf->end  += (cbuf->maxlen - size);
260 		cbuf->end %= cbuf->maxlen;
261 	}
262 	return 0;
263 }
264 
265 /* del at head */
266 
267 static inline void
268 __cirbuf_del_head(struct cirbuf * cbuf)
269 {
270 	cbuf->len --;
271 	if (!CIRBUF_IS_EMPTY(cbuf)) {
272 		cbuf->start ++;
273 		cbuf->start %= cbuf->maxlen;
274 	}
275 }
276 
277 int
278 cirbuf_del_head_safe(struct cirbuf * cbuf)
279 {
280 	if (cbuf && !CIRBUF_IS_EMPTY(cbuf)) {
281 		__cirbuf_del_head(cbuf);
282 		return 0;
283 	}
284 	return -EINVAL;
285 }
286 
287 void
288 cirbuf_del_head(struct cirbuf * cbuf)
289 {
290 	__cirbuf_del_head(cbuf);
291 }
292 
293 /* del at tail */
294 
295 static inline void
296 __cirbuf_del_tail(struct cirbuf * cbuf)
297 {
298 	cbuf->len --;
299 	if (!CIRBUF_IS_EMPTY(cbuf)) {
300 		cbuf->end  += (cbuf->maxlen - 1);
301 		cbuf->end %= cbuf->maxlen;
302 	}
303 }
304 
305 int
306 cirbuf_del_tail_safe(struct cirbuf * cbuf)
307 {
308 	if (cbuf && !CIRBUF_IS_EMPTY(cbuf)) {
309 		__cirbuf_del_tail(cbuf);
310 		return 0;
311 	}
312 	return -EINVAL;
313 }
314 
315 void
316 cirbuf_del_tail(struct cirbuf * cbuf)
317 {
318 	__cirbuf_del_tail(cbuf);
319 }
320 
321 /* convert to buffer */
322 
323 int
324 cirbuf_get_buf_head(struct cirbuf *cbuf, char *c, unsigned int size)
325 {
326 	unsigned int n;
327 
328 	if (!cbuf || !c)
329 		return -EINVAL;
330 
331 	n = (size < CIRBUF_GET_LEN(cbuf)) ? size : CIRBUF_GET_LEN(cbuf);
332 
333 	if (!n)
334 		return 0;
335 
336 	if (cbuf->start <= cbuf->end) {
337 		dprintf("s[%d] -> d[%d] (%d)\n", cbuf->start, 0, n);
338 		memcpy(c, cbuf->buf + cbuf->start , n);
339 	}
340 	else {
341 		/* check if we need to go from end to the beginning */
342 		if (n <= cbuf->maxlen - cbuf->start) {
343 			dprintf("s[%d] -> d[%d] (%d)\n", 0, cbuf->start, n);
344 			memcpy(c, cbuf->buf + cbuf->start , n);
345 		}
346 		else {
347 			dprintf("s[%d] -> d[%d] (%d)\n", cbuf->start, 0,
348 				cbuf->maxlen - cbuf->start);
349 			dprintf("s[%d] -> d[%d] (%d)\n", 0, cbuf->maxlen - cbuf->start,
350 				n - cbuf->maxlen + cbuf->start);
351 			memcpy(c, cbuf->buf + cbuf->start , cbuf->maxlen - cbuf->start);
352 			memcpy(c + cbuf->maxlen - cbuf->start, cbuf->buf,
353 				   n - cbuf->maxlen + cbuf->start);
354 		}
355 	}
356 	return n;
357 }
358 
359 /* convert to buffer */
360 
361 int
362 cirbuf_get_buf_tail(struct cirbuf *cbuf, char *c, unsigned int size)
363 {
364 	unsigned int n;
365 
366 	if (!cbuf || !c)
367 		return -EINVAL;
368 
369 	n = (size < CIRBUF_GET_LEN(cbuf)) ? size : CIRBUF_GET_LEN(cbuf);
370 
371 	if (!n)
372 		return 0;
373 
374 	if (cbuf->start <= cbuf->end) {
375 		dprintf("s[%d] -> d[%d] (%d)\n", cbuf->end - n + 1, 0, n);
376 		memcpy(c, cbuf->buf + cbuf->end - n + 1, n);
377 	}
378 	else {
379 		/* check if we need to go from end to the beginning */
380 		if (n <= cbuf->end + 1) {
381 			dprintf("s[%d] -> d[%d] (%d)\n", 0, cbuf->end - n + 1, n);
382 			memcpy(c, cbuf->buf + cbuf->end - n + 1, n);
383 		}
384 		else {
385 			dprintf("s[%d] -> d[%d] (%d)\n", 0,
386 				cbuf->maxlen - cbuf->start, cbuf->end + 1);
387 			dprintf("s[%d] -> d[%d] (%d)\n",
388 				cbuf->maxlen - n + cbuf->end + 1, 0, n - cbuf->end - 1);
389 			memcpy(c + cbuf->maxlen - cbuf->start,
390 					       cbuf->buf, cbuf->end + 1);
391 			memcpy(c, cbuf->buf + cbuf->maxlen - n + cbuf->end +1,
392 				   n - cbuf->end - 1);
393 		}
394 	}
395 	return n;
396 }
397 
398 /* get head or get tail */
399 
400 char
401 cirbuf_get_head(struct cirbuf * cbuf)
402 {
403 	return cbuf->buf[cbuf->start];
404 }
405 
406 /* get head or get tail */
407 
408 char
409 cirbuf_get_tail(struct cirbuf * cbuf)
410 {
411 	return cbuf->buf[cbuf->end];
412 }
413