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, ssize_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 unsigned int i; 96 97 for (i = 0; i < sb->len; i++) 98 sb->buf[i] = tolower(sb->buf[i]); 99 } 100 101 struct strbuf **strbuf_split(const struct strbuf *sb, int delim) 102 { 103 int alloc = 2, pos = 0; 104 char *n, *p; 105 struct strbuf **ret; 106 struct strbuf *t; 107 108 ret = calloc(alloc, sizeof(struct strbuf *)); 109 p = n = sb->buf; 110 while (n < sb->buf + sb->len) { 111 int len; 112 n = memchr(n, delim, sb->len - (n - sb->buf)); 113 if (pos + 1 >= alloc) { 114 alloc = alloc * 2; 115 ret = realloc(ret, sizeof(struct strbuf *) * alloc); 116 } 117 if (!n) 118 n = sb->buf + sb->len - 1; 119 len = n - p + 1; 120 t = malloc(sizeof(struct strbuf)); 121 strbuf_init(t, len); 122 strbuf_add(t, p, len); 123 ret[pos] = t; 124 ret[++pos] = NULL; 125 p = ++n; 126 } 127 return ret; 128 } 129 130 void strbuf_list_free(struct strbuf **sbs) 131 { 132 struct strbuf **s = sbs; 133 134 while (*s) { 135 strbuf_release(*s); 136 free(*s++); 137 } 138 free(sbs); 139 } 140 141 int strbuf_cmp(const struct strbuf *a, const struct strbuf *b) 142 { 143 int len = a->len < b->len ? a->len: b->len; 144 int cmp = memcmp(a->buf, b->buf, len); 145 if (cmp) 146 return cmp; 147 return a->len < b->len ? -1: a->len != b->len; 148 } 149 150 void strbuf_splice(struct strbuf *sb, size_t pos, size_t len, 151 const void *data, size_t dlen) 152 { 153 if (pos + len < pos) 154 die("you want to use way too much memory"); 155 if (pos > sb->len) 156 die("`pos' is too far after the end of the buffer"); 157 if (pos + len > sb->len) 158 die("`pos + len' is too far after the end of the buffer"); 159 160 if (dlen >= len) 161 strbuf_grow(sb, dlen - len); 162 memmove(sb->buf + pos + dlen, 163 sb->buf + pos + len, 164 sb->len - pos - len); 165 memcpy(sb->buf + pos, data, dlen); 166 strbuf_setlen(sb, sb->len + dlen - len); 167 } 168 169 void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len) 170 { 171 strbuf_splice(sb, pos, 0, data, len); 172 } 173 174 void strbuf_remove(struct strbuf *sb, size_t pos, size_t len) 175 { 176 strbuf_splice(sb, pos, len, NULL, 0); 177 } 178 179 void strbuf_add(struct strbuf *sb, const void *data, size_t len) 180 { 181 strbuf_grow(sb, len); 182 memcpy(sb->buf + sb->len, data, len); 183 strbuf_setlen(sb, sb->len + len); 184 } 185 186 void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len) 187 { 188 strbuf_grow(sb, len); 189 memcpy(sb->buf + sb->len, sb->buf + pos, len); 190 strbuf_setlen(sb, sb->len + len); 191 } 192 193 void strbuf_addf(struct strbuf *sb, const char *fmt, ...) 194 { 195 int len; 196 va_list ap; 197 198 if (!strbuf_avail(sb)) 199 strbuf_grow(sb, 64); 200 va_start(ap, fmt); 201 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); 202 va_end(ap); 203 if (len < 0) 204 die("your vsnprintf is broken"); 205 if (len > strbuf_avail(sb)) { 206 strbuf_grow(sb, len); 207 va_start(ap, fmt); 208 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); 209 va_end(ap); 210 if (len > strbuf_avail(sb)) { 211 die("this should not happen, your snprintf is broken"); 212 } 213 } 214 strbuf_setlen(sb, sb->len + len); 215 } 216 217 void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, 218 void *context) 219 { 220 for (;;) { 221 const char *percent; 222 size_t consumed; 223 224 percent = strchrnul(format, '%'); 225 strbuf_add(sb, format, percent - format); 226 if (!*percent) 227 break; 228 format = percent + 1; 229 230 consumed = fn(sb, format, context); 231 if (consumed) 232 format += consumed; 233 else 234 strbuf_addch(sb, '%'); 235 } 236 } 237 238 size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, 239 void *context) 240 { 241 struct strbuf_expand_dict_entry *e = context; 242 size_t len; 243 244 for (; e->placeholder && (len = strlen(e->placeholder)); e++) { 245 if (!strncmp(placeholder, e->placeholder, len)) { 246 if (e->value) 247 strbuf_addstr(sb, e->value); 248 return len; 249 } 250 } 251 return 0; 252 } 253 254 size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f) 255 { 256 size_t res; 257 size_t oldalloc = sb->alloc; 258 259 strbuf_grow(sb, size); 260 res = fread(sb->buf + sb->len, 1, size, f); 261 if (res > 0) 262 strbuf_setlen(sb, sb->len + res); 263 else if (oldalloc == 0) 264 strbuf_release(sb); 265 return res; 266 } 267 268 ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint) 269 { 270 size_t oldlen = sb->len; 271 size_t oldalloc = sb->alloc; 272 273 strbuf_grow(sb, hint ? hint : 8192); 274 for (;;) { 275 ssize_t cnt; 276 277 cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1); 278 if (cnt < 0) { 279 if (oldalloc == 0) 280 strbuf_release(sb); 281 else 282 strbuf_setlen(sb, oldlen); 283 return -1; 284 } 285 if (!cnt) 286 break; 287 sb->len += cnt; 288 strbuf_grow(sb, 8192); 289 } 290 291 sb->buf[sb->len] = '\0'; 292 return sb->len - oldlen; 293 } 294 295 #define STRBUF_MAXLINK (2*PATH_MAX) 296 297 int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint) 298 { 299 size_t oldalloc = sb->alloc; 300 301 if (hint < 32) 302 hint = 32; 303 304 while (hint < STRBUF_MAXLINK) { 305 ssize_t len; 306 307 strbuf_grow(sb, hint); 308 len = readlink(path, sb->buf, hint); 309 if (len < 0) { 310 if (errno != ERANGE) 311 break; 312 } else if (len < hint) { 313 strbuf_setlen(sb, len); 314 return 0; 315 } 316 317 /* .. the buffer was too small - try again */ 318 hint *= 2; 319 } 320 if (oldalloc == 0) 321 strbuf_release(sb); 322 return -1; 323 } 324 325 int strbuf_getline(struct strbuf *sb, FILE *fp, int term) 326 { 327 int ch; 328 329 strbuf_grow(sb, 0); 330 if (feof(fp)) 331 return EOF; 332 333 strbuf_reset(sb); 334 while ((ch = fgetc(fp)) != EOF) { 335 if (ch == term) 336 break; 337 strbuf_grow(sb, 1); 338 sb->buf[sb->len++] = ch; 339 } 340 if (ch == EOF && sb->len == 0) 341 return EOF; 342 343 sb->buf[sb->len] = '\0'; 344 return 0; 345 } 346 347 int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint) 348 { 349 int fd, len; 350 351 fd = open(path, O_RDONLY); 352 if (fd < 0) 353 return -1; 354 len = strbuf_read(sb, fd, hint); 355 close(fd); 356 if (len < 0) 357 return -1; 358 359 return len; 360 } 361