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