VBUFPROTO int vbuf_peek(VBUF *v) { if (vbuf_is_empty(v)) return EOF; return (unsigned char)(*v->head); }
VBUFPROTO char * vbuf_cstr (VBUF *v) { size_t sz; if (vbuf_is_empty(v)) return NULL; // if the buffer is cstr safe, simply return if (v->tail > v->head) { *v->tail = 0; return v->head; } // wrapped ring buffer. now reverse 3 times to merge: // [buf head tail buf_end] sz = vbuf_size(v); vbuf_reverse(v->buf, v->tail); vbuf_reverse(v->head, v->buf_end); memmove(v->tail, v->head, v->buf_end - v->head); v->head = v->buf; v->tail = v->buf + sz; v->buf[sz] = 0; vbuf_reverse(v->head, v->tail); return v->buf; }
VBUFPROTO int vbuf_strchr(VBUF *v, char c) { const char *s = v->head, *d = v->tail; if (vbuf_is_empty(v)) return EOF; if (d < s) d = v->buf_end; while (s < d) if (*s++ == c) return s - v->head -1; if (v->tail > v->head) return EOF; s = v->buf; d = v->tail; while (s < d) if (*s++ == c) return (v->buf_end - v->head) + s - v->buf -1; return EOF; }
void vbuf_dbg_rpt(VBUF *v) { printf("v: [ cap: %u, size: %2lu, empty: %s, ptr=(%p,h=%p,t=%p,%p)]\n", (unsigned int)vbuf_capacity(v), vbuf_size(v), vbuf_is_empty(v) ? "YES" : "NO", v->buf, v->head, v->tail, v->buf_end); assert(v->buf_end == v->buf + v->capacity +1); }
VBUFPROTO char * vbuf_getstr (VBUF *v, char *s, size_t sz) { char *sbase = s; assert(sz > 0); if (vbuf_is_empty(v)) return NULL; while (sz-- > 0 && !vbuf_is_empty(v)) { if ('\0' == (*s++ = vbuf_pop(v))) return sbase; } // need to pad NUL. s[ sz == 0 ? 0 : -1] = '\0'; return sbase; }
VBUFPROTO int vbuf_peekat(VBUF *v, int i) { const char *s = v->head + i; if (vbuf_is_empty(v) || i >= vbuf_capacity(v)) return EOF; if (s < v->tail) return (unsigned char)*s; if (s >= v->buf_end) s -= v->buf_end - v->buf; if (s < v->tail) return (unsigned char)*s; return EOF; }
// TODO add API unit tests int main() { int i, r; const int szbuf = 40, szfrag = szbuf / 4 * 3; const char src[szbuf *2] = "hello, world"; const char *fragstring = "1234567890ABCDEFGHIJabcdefhijk"; const char *s; char dest[szbuf*2] = ""; VBUF vbuf, *v = &vbuf; vbuf_new(v, szbuf); // check basic structure assert(v->buf && v->capacity == szbuf -1); assert(v->head == v->tail && v->tail == v->buf); assert(v->buf_end == v->buf + v->capacity + 1); // fragmentize it! vbuf_dbg_fragmentize(v); assert(vbuf_is_empty(v) && !vbuf_is_full(v)); vbuf_putblk(v, src, szfrag); // check macro API assert(!vbuf_is_empty(v)); assert(!vbuf_is_full(v)); assert(vbuf_capacity(v) == szbuf-1); assert(vbuf_size(v) == szfrag); assert(vbuf_space(v) == vbuf_capacity(v) - szfrag); assert(vbuf_peek(v) == src[0]); // try filling buffer with putblk/getblk vbuf_dbg_fragmentize(v); for (i = 0; i < 10; i++) { r = vbuf_putblk(v, src, szbuf / 10); vbuf_dbg_rpt(v); assert( i == 9 ? !r : r); assert(!vbuf_is_full(v)); } r = vbuf_putblk(v, src, vbuf_capacity(v) - vbuf_size(v)); assert(r && vbuf_is_full(v) && !vbuf_is_empty(v)); for (i = 0; i < 10; i++) { r = vbuf_getblk(v, dest, szbuf / 10); dest[szbuf/10] = 0; printf("%2d. [got: %s] ", i+1, dest); vbuf_dbg_rpt(v); assert(i == 9 ? !r : r); assert(!vbuf_is_full(v) && !vbuf_is_empty(v)); } r = vbuf_getblk(v, dest, vbuf_size(v)); assert(r && vbuf_is_empty(v) && !vbuf_is_full(v)); // try unframgented vbuf_clear(v); r = vbuf_putblk(v, src, vbuf_capacity(v)); assert(r && vbuf_is_full(v)); r = vbuf_putblk(v, src, 1); assert(!r); r = vbuf_getblk(v, dest, szbuf-1); assert(r && vbuf_is_empty(v)); r = vbuf_getblk(v, dest, 1); assert(!r && vbuf_is_empty(v)); r = vbuf_putblk(v, src, szbuf); assert(!r && vbuf_is_empty(v)); // string operation vbuf_clear(v); vbuf_putstr(v, "str test(1)"); vbuf_putstr(v, "str test(2)"); vbuf_putstr(v, "str test(3)"); for (i = 0; i < 4; i++) { s = vbuf_getstr(v, dest, sizeof(dest)); printf("put/getstr(%d): %s\n", i+1, s ? s : "(NULL)"); assert(i < 3 ? s != NULL : s == NULL); } // cstr test vbuf_clear(v); vbuf_putstr(v, fragstring); vbuf_dbg_rpt(v); s = vbuf_cstr(v); printf("cstr test(simple): %s\n", s); assert(strcmp(s, fragstring) == 0); vbuf_dbg_fragmentize(v); vbuf_putstr(v, fragstring); vbuf_dbg_rpt(v); s = vbuf_cstr(v); printf("cstr test(unwrap): %s\n", s); assert(strcmp(s, fragstring) == 0); vbuf_dbg_fragmentize(v); vbuf_putblk(v, "*** peek test OK\n", sizeof("*** peek test OK\n")); while (EOF != (i = vbuf_pop(v))) putchar(i); // read/write test vbuf_dbg_fragmentize(v); printf("give me some input for finding location of 't': "); fflush(stdout); vbuf_read(v, 0, VBUF_RWSZ_MIN); printf("index of 't' = %d\n", vbuf_strchr(v, 't')); vbuf_dbg_rpt(v); printf("give me 4 chars: "); fflush(stdout); vbuf_read(v, 0, 4); vbuf_dbg_rpt(v); printf("\n flushing vbuf: ["); fflush(stdout); vbuf_write(v, 1, VBUF_RWSZ_ALL); printf("]\n"); return 0; }
/** * cin_is_buffer_empty(): quick check if input buffer is empty */ CIN_PROTO int cin_is_buffer_empty() { return vbuf_is_empty(cin); }