1 #include "cache.h" 2 3 int prefixcmp(const char *str, const char *prefix) 4 { 5 for (; ; str++, prefix++) 6 if (!*prefix) 7 return 0; 8 else if (*str != *prefix) 9 return (unsigned char)*prefix - (unsigned char)*str; 10 } 11 12 /* 13 * Used as the default ->buf value, so that people can always assume 14 * buf is non NULL and ->buf is NUL terminated even for a freshly 15 * initialized strbuf. 16 */ 17 char strbuf_slopbuf[1]; 18 19 void strbuf_init(struct strbuf *sb, size_t hint) 20 { 21 sb->alloc = sb->len = 0; 22 sb->buf = strbuf_slopbuf; 23 if (hint) 24 strbuf_grow(sb, hint); 25 } 26 27 void strbuf_release(struct strbuf *sb) 28 { 29 if (sb->alloc) { 30 free(sb->buf); 31 strbuf_init(sb, 0); 32 } 33 } 34 35 char *strbuf_detach(struct strbuf *sb, size_t *sz) 36 { 37 char *res = sb->alloc ? sb->buf : NULL; 38 if (sz) 39 *sz = sb->len; 40 strbuf_init(sb, 0); 41 return res; 42 } 43 44 void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc) 45 { 46 strbuf_release(sb); 47 sb->buf = buf; 48 sb->len = len; 49 sb->alloc = alloc; 50 strbuf_grow(sb, 0); 51 sb->buf[sb->len] = '\0'; 52 } 53 54 void strbuf_grow(struct strbuf *sb, size_t extra) 55 { 56 if (sb->len + extra + 1 <= sb->len) 57 die("you want to use way too much memory"); 58 if (!sb->alloc) 59 sb->buf = NULL; 60 ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc); 61 } 62 63 void strbuf_trim(struct strbuf *sb) 64 { 65 char *b = sb->buf; 66 while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1])) 67 sb->len--; 68 while (sb->len > 0 && isspace(*b)) { 69 b++; 70 sb->len--; 71 } 72 memmove(sb->buf, b, sb->len); 73 sb->buf[sb->len] = '\0'; 74 } 75 void strbuf_rtrim(struct strbuf *sb) 76 { 77 while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1])) 78 sb->len--; 79 sb->buf[sb->len] = '\0'; 80 } 81 82 void strbuf_ltrim(struct strbuf *sb) 83 { 84 char *b = sb->buf; 85 while (sb->len > 0 && isspace(*b)) { 86 b++; 87 sb->len--; 88 } 89 memmove(sb->buf, b, sb->len); 90 sb->buf[sb->len] = '\0'; 91 } 92 93 void strbuf_tolower(struct strbuf *sb) 94 { 95 int i; 96 for (i = 0; i < sb->len; i++) 97 sb->buf[i] = tolower(sb->buf[i]); 98 } 99 100 struct strbuf **strbuf_split(const struct strbuf *sb, int delim) 101 { 102 int alloc = 2, pos = 0; 103 char *n, *p; 104 struct strbuf **ret; 105 struct strbuf *t; 106 107 ret = calloc(alloc, sizeof(struct strbuf *)); 108 p = n = sb->buf; 109 while (n < sb->buf + sb->len) { 110 int len; 111 n = memchr(n, delim, sb->len - (n - sb->buf)); 112 if (pos + 1 >= alloc) { 113 alloc = alloc * 2; 114 ret = realloc(ret, sizeof(struct strbuf *) * alloc); 115 } 116 if (!n) 117 n = sb->buf + sb->len - 1; 118 len = n - p + 1; 119 t = malloc(sizeof(struct strbuf)); 120 strbuf_init(t, len); 121 strbuf_add(t, p, len); 122 ret[pos] = t; 123 ret[++pos] = NULL; 124 p = ++n; 125 } 126 return ret; 127 } 128 129 void strbuf_list_free(struct strbuf **sbs) 130 { 131 struct strbuf **s = sbs; 132 133 while (*s) { 134 strbuf_release(*s); 135 free(*s++); 136 } 137 free(sbs); 138 } 139 140 int strbuf_cmp(const struct strbuf *a, const struct strbuf *b) 141 { 142 int len = a->len < b->len ? a->len: b->len; 143 int cmp = memcmp(a->buf, b->buf, len); 144 if (cmp) 145 return cmp; 146 return a->len < b->len ? -1: a->len != b->len; 147 } 148 149 void strbuf_splice(struct strbuf *sb, size_t pos, size_t len, 150 const void *data, size_t dlen) 151 { 152 if (pos + len < pos) 153 die("you want to use way too much memory"); 154 if (pos > sb->len) 155 die("`pos' is too far after the end of the buffer"); 156 if (pos + len > sb->len) 157 die("`pos + len' is too far after the end of the buffer"); 158 159 if (dlen >= len) 160 strbuf_grow(sb, dlen - len); 161 memmove(sb->buf + pos + dlen, 162 sb->buf + pos + len, 163 sb->len - pos - len); 164 memcpy(sb->buf + pos, data, dlen); 165 strbuf_setlen(sb, sb->len + dlen - len); 166 } 167 168 void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len) 169 { 170 strbuf_splice(sb, pos, 0, data, len); 171 } 172 173 void strbuf_remove(struct strbuf *sb, size_t pos, size_t len) 174 { 175 strbuf_splice(sb, pos, len, NULL, 0); 176 } 177 178 void strbuf_add(struct strbuf *sb, const void *data, size_t len) 179 { 180 strbuf_grow(sb, len); 181 memcpy(sb->buf + sb->len, data, len); 182 strbuf_setlen(sb, sb->len + len); 183 } 184 185 void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len) 186 { 187 strbuf_grow(sb, len); 188 memcpy(sb->buf + sb->len, sb->buf + pos, len); 189 strbuf_setlen(sb, sb->len + len); 190 } 191 192 void strbuf_addf(struct strbuf *sb, const char *fmt, ...) 193 { 194 int len; 195 va_list ap; 196 197 if (!strbuf_avail(sb)) 198 strbuf_grow(sb, 64); 199 va_start(ap, fmt); 200 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); 201 va_end(ap); 202 if (len < 0) 203 die("your vsnprintf is broken"); 204 if (len > strbuf_avail(sb)) { 205 strbuf_grow(sb, len); 206 va_start(ap, fmt); 207 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); 208 va_end(ap); 209 if (len > strbuf_avail(sb)) { 210 die("this should not happen, your snprintf is broken"); 211 } 212 } 213 strbuf_setlen(sb, sb->len + len); 214 } 215 216 void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, 217 void *context) 218 { 219 for (;;) { 220 const char *percent; 221 size_t consumed; 222 223 percent = strchrnul(format, '%'); 224 strbuf_add(sb, format, percent - format); 225 if (!*percent) 226 break; 227 format = percent + 1; 228 229 consumed = fn(sb, format, context); 230 if (consumed) 231 format += consumed; 232 else 233 strbuf_addch(sb, '%'); 234 } 235 } 236 237 size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, 238 void *context) 239 { 240 struct strbuf_expand_dict_entry *e = context; 241 size_t len; 242 243 for (; e->placeholder && (len = strlen(e->placeholder)); e++) { 244 if (!strncmp(placeholder, e->placeholder, len)) { 245 if (e->value) 246 strbuf_addstr(sb, e->value); 247 return len; 248 } 249 } 250 return 0; 251 } 252 253 size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f) 254 { 255 size_t res; 256 size_t oldalloc = sb->alloc; 257 258 strbuf_grow(sb, size); 259 res = fread(sb->buf + sb->len, 1, size, f); 260 if (res > 0) 261 strbuf_setlen(sb, sb->len + res); 262 else if (res < 0 && oldalloc == 0) 263 strbuf_release(sb); 264 return res; 265 } 266 267 ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint) 268 { 269 size_t oldlen = sb->len; 270 size_t oldalloc = sb->alloc; 271 272 strbuf_grow(sb, hint ? hint : 8192); 273 for (;;) { 274 ssize_t cnt; 275 276 cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1); 277 if (cnt < 0) { 278 if (oldalloc == 0) 279 strbuf_release(sb); 280 else 281 strbuf_setlen(sb, oldlen); 282 return -1; 283 } 284 if (!cnt) 285 break; 286 sb->len += cnt; 287 strbuf_grow(sb, 8192); 288 } 289 290 sb->buf[sb->len] = '\0'; 291 return sb->len - oldlen; 292 } 293 294 #define STRBUF_MAXLINK (2*PATH_MAX) 295 296 int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint) 297 { 298 size_t oldalloc = sb->alloc; 299 300 if (hint < 32) 301 hint = 32; 302 303 while (hint < STRBUF_MAXLINK) { 304 int len; 305 306 strbuf_grow(sb, hint); 307 len = readlink(path, sb->buf, hint); 308 if (len < 0) { 309 if (errno != ERANGE) 310 break; 311 } else if (len < hint) { 312 strbuf_setlen(sb, len); 313 return 0; 314 } 315 316 /* .. the buffer was too small - try again */ 317 hint *= 2; 318 } 319 if (oldalloc == 0) 320 strbuf_release(sb); 321 return -1; 322 } 323 324 int strbuf_getline(struct strbuf *sb, FILE *fp, int term) 325 { 326 int ch; 327 328 strbuf_grow(sb, 0); 329 if (feof(fp)) 330 return EOF; 331 332 strbuf_reset(sb); 333 while ((ch = fgetc(fp)) != EOF) { 334 if (ch == term) 335 break; 336 strbuf_grow(sb, 1); 337 sb->buf[sb->len++] = ch; 338 } 339 if (ch == EOF && sb->len == 0) 340 return EOF; 341 342 sb->buf[sb->len] = '\0'; 343 return 0; 344 } 345 346 int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint) 347 { 348 int fd, len; 349 350 fd = open(path, O_RDONLY); 351 if (fd < 0) 352 return -1; 353 len = strbuf_read(sb, fd, hint); 354 close(fd); 355 if (len < 0) 356 return -1; 357 358 return len; 359 } 360