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