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
68int
69cirbuf_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
83int
84cirbuf_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
114int
115cirbuf_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
146static 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
157int
158cirbuf_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
167void
168cirbuf_add_head(struct cirbuf * cbuf, char c)
169{
170	__cirbuf_add_head(cbuf, c);
171}
172
173/* add at tail */
174
175static 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
186int
187cirbuf_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
196void
197cirbuf_add_tail(struct cirbuf * cbuf, char c)
198{
199	__cirbuf_add_tail(cbuf, c);
200}
201
202
203static 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
220static 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... */
238int
239cirbuf_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... */
259int
260cirbuf_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
281int
282cirbuf_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
301int
302cirbuf_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
321static 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
331int
332cirbuf_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
341void
342cirbuf_del_head(struct cirbuf * cbuf)
343{
344	__cirbuf_del_head(cbuf);
345}
346
347/* del at tail */
348
349static 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
359int
360cirbuf_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
369void
370cirbuf_del_tail(struct cirbuf * cbuf)
371{
372	__cirbuf_del_tail(cbuf);
373}
374
375/* convert to buffer */
376
377int
378cirbuf_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
415int
416cirbuf_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
454char
455cirbuf_get_head(struct cirbuf * cbuf)
456{
457	return cbuf->buf[cbuf->start];
458}
459
460/* get head or get tail */
461
462char
463cirbuf_get_tail(struct cirbuf * cbuf)
464{
465	return cbuf->buf[cbuf->end];
466}
467