Home | History | Annotate | Download | only in util
      1 #include "cache.h"
      2 #include <linux/kernel.h>
      3 
      4 int prefixcmp(const char *str, const char *prefix)
      5 {
      6 	for (; ; str++, prefix++)
      7 		if (!*prefix)
      8 			return 0;
      9 		else if (*str != *prefix)
     10 			return (unsigned char)*prefix - (unsigned char)*str;
     11 }
     12 
     13 /*
     14  * Used as the default ->buf value, so that people can always assume
     15  * buf is non NULL and ->buf is NUL terminated even for a freshly
     16  * initialized strbuf.
     17  */
     18 char strbuf_slopbuf[1];
     19 
     20 void strbuf_init(struct strbuf *sb, ssize_t hint)
     21 {
     22 	sb->alloc = sb->len = 0;
     23 	sb->buf = strbuf_slopbuf;
     24 	if (hint)
     25 		strbuf_grow(sb, hint);
     26 }
     27 
     28 void strbuf_release(struct strbuf *sb)
     29 {
     30 	if (sb->alloc) {
     31 		free(sb->buf);
     32 		strbuf_init(sb, 0);
     33 	}
     34 }
     35 
     36 char *strbuf_detach(struct strbuf *sb, size_t *sz)
     37 {
     38 	char *res = sb->alloc ? sb->buf : NULL;
     39 	if (sz)
     40 		*sz = sb->len;
     41 	strbuf_init(sb, 0);
     42 	return res;
     43 }
     44 
     45 void strbuf_grow(struct strbuf *sb, size_t extra)
     46 {
     47 	if (sb->len + extra + 1 <= sb->len)
     48 		die("you want to use way too much memory");
     49 	if (!sb->alloc)
     50 		sb->buf = NULL;
     51 	ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
     52 }
     53 
     54 static void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
     55 				   const void *data, size_t dlen)
     56 {
     57 	if (pos + len < pos)
     58 		die("you want to use way too much memory");
     59 	if (pos > sb->len)
     60 		die("`pos' is too far after the end of the buffer");
     61 	if (pos + len > sb->len)
     62 		die("`pos + len' is too far after the end of the buffer");
     63 
     64 	if (dlen >= len)
     65 		strbuf_grow(sb, dlen - len);
     66 	memmove(sb->buf + pos + dlen,
     67 			sb->buf + pos + len,
     68 			sb->len - pos - len);
     69 	memcpy(sb->buf + pos, data, dlen);
     70 	strbuf_setlen(sb, sb->len + dlen - len);
     71 }
     72 
     73 void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
     74 {
     75 	strbuf_splice(sb, pos, len, NULL, 0);
     76 }
     77 
     78 void strbuf_add(struct strbuf *sb, const void *data, size_t len)
     79 {
     80 	strbuf_grow(sb, len);
     81 	memcpy(sb->buf + sb->len, data, len);
     82 	strbuf_setlen(sb, sb->len + len);
     83 }
     84 
     85 void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
     86 {
     87 	int len;
     88 	va_list ap;
     89 
     90 	if (!strbuf_avail(sb))
     91 		strbuf_grow(sb, 64);
     92 	va_start(ap, fmt);
     93 	len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
     94 	va_end(ap);
     95 	if (len < 0)
     96 		die("your vsnprintf is broken");
     97 	if (len > strbuf_avail(sb)) {
     98 		strbuf_grow(sb, len);
     99 		va_start(ap, fmt);
    100 		len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
    101 		va_end(ap);
    102 		if (len > strbuf_avail(sb)) {
    103 			die("this should not happen, your vsnprintf is broken");
    104 		}
    105 	}
    106 	strbuf_setlen(sb, sb->len + len);
    107 }
    108 
    109 ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
    110 {
    111 	size_t oldlen = sb->len;
    112 	size_t oldalloc = sb->alloc;
    113 
    114 	strbuf_grow(sb, hint ? hint : 8192);
    115 	for (;;) {
    116 		ssize_t cnt;
    117 
    118 		cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
    119 		if (cnt < 0) {
    120 			if (oldalloc == 0)
    121 				strbuf_release(sb);
    122 			else
    123 				strbuf_setlen(sb, oldlen);
    124 			return -1;
    125 		}
    126 		if (!cnt)
    127 			break;
    128 		sb->len += cnt;
    129 		strbuf_grow(sb, 8192);
    130 	}
    131 
    132 	sb->buf[sb->len] = '\0';
    133 	return sb->len - oldlen;
    134 }
    135