1 #include "debug.h" 2 #include "util.h" 3 #include <linux/kernel.h> 4 5 int 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 */ 19 char strbuf_slopbuf[1]; 20 21 int 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 30 void strbuf_release(struct strbuf *sb) 31 { 32 if (sb->alloc) { 33 zfree(&sb->buf); 34 strbuf_init(sb, 0); 35 } 36 } 37 38 char *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 47 int 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 74 int 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 85 int 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 95 static 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 124 int 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 135 ssize_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 } 167