at v4.8-rc1 166 lines 3.2 kB view raw
1#include "debug.h" 2#include "util.h" 3#include <linux/kernel.h> 4 5int prefixcmp(const char *str, const char *prefix) 6{ 7 for (; ; str++, prefix++) 8 if (!*prefix) 9 return 0; 10 else if (*str != *prefix) 11 return (unsigned char)*prefix - (unsigned char)*str; 12} 13 14/* 15 * Used as the default ->buf value, so that people can always assume 16 * buf is non NULL and ->buf is NUL terminated even for a freshly 17 * initialized strbuf. 18 */ 19char strbuf_slopbuf[1]; 20 21int strbuf_init(struct strbuf *sb, ssize_t hint) 22{ 23 sb->alloc = sb->len = 0; 24 sb->buf = strbuf_slopbuf; 25 if (hint) 26 return strbuf_grow(sb, hint); 27 return 0; 28} 29 30void strbuf_release(struct strbuf *sb) 31{ 32 if (sb->alloc) { 33 zfree(&sb->buf); 34 strbuf_init(sb, 0); 35 } 36} 37 38char *strbuf_detach(struct strbuf *sb, size_t *sz) 39{ 40 char *res = sb->alloc ? sb->buf : NULL; 41 if (sz) 42 *sz = sb->len; 43 strbuf_init(sb, 0); 44 return res; 45} 46 47int strbuf_grow(struct strbuf *sb, size_t extra) 48{ 49 char *buf; 50 size_t nr = sb->len + extra + 1; 51 52 if (nr < sb->alloc) 53 return 0; 54 55 if (nr <= sb->len) 56 return -E2BIG; 57 58 if (alloc_nr(sb->alloc) > nr) 59 nr = alloc_nr(sb->alloc); 60 61 /* 62 * Note that sb->buf == strbuf_slopbuf if sb->alloc == 0, and it is 63 * a static variable. Thus we have to avoid passing it to realloc. 64 */ 65 buf = realloc(sb->alloc ? sb->buf : NULL, nr * sizeof(*buf)); 66 if (!buf) 67 return -ENOMEM; 68 69 sb->buf = buf; 70 sb->alloc = nr; 71 return 0; 72} 73 74int strbuf_addch(struct strbuf *sb, int c) 75{ 76 int ret = strbuf_grow(sb, 1); 77 if (ret) 78 return ret; 79 80 sb->buf[sb->len++] = c; 81 sb->buf[sb->len] = '\0'; 82 return 0; 83} 84 85int strbuf_add(struct strbuf *sb, const void *data, size_t len) 86{ 87 int ret = strbuf_grow(sb, len); 88 if (ret) 89 return ret; 90 91 memcpy(sb->buf + sb->len, data, len); 92 return strbuf_setlen(sb, sb->len + len); 93} 94 95static int strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap) 96{ 97 int len, ret; 98 va_list ap_saved; 99 100 if (!strbuf_avail(sb)) { 101 ret = strbuf_grow(sb, 64); 102 if (ret) 103 return ret; 104 } 105 106 va_copy(ap_saved, ap); 107 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); 108 if (len < 0) 109 return len; 110 if (len > strbuf_avail(sb)) { 111 ret = strbuf_grow(sb, len); 112 if (ret) 113 return ret; 114 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved); 115 va_end(ap_saved); 116 if (len > strbuf_avail(sb)) { 117 pr_debug("this should not happen, your vsnprintf is broken"); 118 return -EINVAL; 119 } 120 } 121 return strbuf_setlen(sb, sb->len + len); 122} 123 124int strbuf_addf(struct strbuf *sb, const char *fmt, ...) 125{ 126 va_list ap; 127 int ret; 128 129 va_start(ap, fmt); 130 ret = strbuf_addv(sb, fmt, ap); 131 va_end(ap); 132 return ret; 133} 134 135ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint) 136{ 137 size_t oldlen = sb->len; 138 size_t oldalloc = sb->alloc; 139 int ret; 140 141 ret = strbuf_grow(sb, hint ? hint : 8192); 142 if (ret) 143 return ret; 144 145 for (;;) { 146 ssize_t cnt; 147 148 cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1); 149 if (cnt < 0) { 150 if (oldalloc == 0) 151 strbuf_release(sb); 152 else 153 strbuf_setlen(sb, oldlen); 154 return cnt; 155 } 156 if (!cnt) 157 break; 158 sb->len += cnt; 159 ret = strbuf_grow(sb, 8192); 160 if (ret) 161 return ret; 162 } 163 164 sb->buf[sb->len] = '\0'; 165 return sb->len - oldlen; 166}