strbuf.c 11.6 KB
Newer Older
1
#include "cache.h"
2
#include "refs.h"
3

4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
int starts_with(const char *str, const char *prefix)
{
	for (; ; str++, prefix++)
		if (!*prefix)
			return 1;
		else if (*str != *prefix)
			return 0;
}

int ends_with(const char *str, const char *suffix)
{
	int len = strlen(str), suflen = strlen(suffix);
	if (len < suflen)
		return 0;
	else
		return !strcmp(str + len - suflen, suffix);
}

22 23 24 25 26 27 28
/*
 * Used as the default ->buf value, so that people can always assume
 * buf is non NULL and ->buf is NUL terminated even for a freshly
 * initialized strbuf.
 */
char strbuf_slopbuf[1];

29 30
void strbuf_init(struct strbuf *sb, size_t hint)
{
31 32
	sb->alloc = sb->len = 0;
	sb->buf = strbuf_slopbuf;
33
	if (hint)
34
		strbuf_grow(sb, hint);
35 36
}

37 38
void strbuf_release(struct strbuf *sb)
{
39 40 41 42
	if (sb->alloc) {
		free(sb->buf);
		strbuf_init(sb, 0);
	}
43 44
}

45
char *strbuf_detach(struct strbuf *sb, size_t *sz)
46
{
47 48 49
	char *res;
	strbuf_grow(sb, 0);
	res = sb->buf;
50 51
	if (sz)
		*sz = sb->len;
52
	strbuf_init(sb, 0);
53 54 55
	return res;
}

56 57 58 59 60 61 62 63 64 65 66 67
void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)
{
	strbuf_release(sb);
	sb->buf   = buf;
	sb->len   = len;
	sb->alloc = alloc;
	strbuf_grow(sb, 0);
	sb->buf[sb->len] = '\0';
}

void strbuf_grow(struct strbuf *sb, size_t extra)
{
68
	int new_buf = !sb->alloc;
69 70
	if (unsigned_add_overflows(extra, 1) ||
	    unsigned_add_overflows(sb->len, extra + 1))
71
		die("you want to use way too much memory");
72
	if (new_buf)
73
		sb->buf = NULL;
74
	ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
75 76
	if (new_buf)
		sb->buf[0] = '\0';
77 78
}

79 80 81 82 83 84 85 86 87 88 89 90
void strbuf_trim(struct strbuf *sb)
{
	char *b = sb->buf;
	while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
		sb->len--;
	while (sb->len > 0 && isspace(*b)) {
		b++;
		sb->len--;
	}
	memmove(sb->buf, b, sb->len);
	sb->buf[sb->len] = '\0';
}
91 92 93 94 95 96 97
void strbuf_rtrim(struct strbuf *sb)
{
	while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
		sb->len--;
	sb->buf[sb->len] = '\0';
}

98 99 100 101 102 103 104 105 106 107 108
void strbuf_ltrim(struct strbuf *sb)
{
	char *b = sb->buf;
	while (sb->len > 0 && isspace(*b)) {
		b++;
		sb->len--;
	}
	memmove(sb->buf, b, sb->len);
	sb->buf[sb->len] = '\0';
}

109 110
struct strbuf **strbuf_split_buf(const char *str, size_t slen,
				 int terminator, int max)
111
{
112 113
	struct strbuf **ret = NULL;
	size_t nr = 0, alloc = 0;
114 115
	struct strbuf *t;

116 117 118
	while (slen) {
		int len = slen;
		if (max <= 0 || nr + 1 < max) {
119
			const char *end = memchr(str, terminator, slen);
120 121 122
			if (end)
				len = end - str + 1;
		}
123 124
		t = xmalloc(sizeof(struct strbuf));
		strbuf_init(t, len);
125
		strbuf_add(t, str, len);
126 127
		ALLOC_GROW(ret, nr + 2, alloc);
		ret[nr++] = t;
128 129
		str += len;
		slen -= len;
130
	}
131 132
	ALLOC_GROW(ret, nr + 1, alloc); /* In case string was empty */
	ret[nr] = NULL;
133 134 135 136 137 138 139 140 141 142 143 144 145 146
	return ret;
}

void strbuf_list_free(struct strbuf **sbs)
{
	struct strbuf **s = sbs;

	while (*s) {
		strbuf_release(*s);
		free(*s++);
	}
	free(sbs);
}

147
int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
P
Pierre Habouzit 已提交
148
{
A
Alex Riesen 已提交
149 150 151 152 153
	int len = a->len < b->len ? a->len: b->len;
	int cmp = memcmp(a->buf, b->buf, len);
	if (cmp)
		return cmp;
	return a->len < b->len ? -1: a->len != b->len;
P
Pierre Habouzit 已提交
154 155
}

156 157 158
void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
				   const void *data, size_t dlen)
{
159
	if (unsigned_add_overflows(pos, len))
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
		die("you want to use way too much memory");
	if (pos > sb->len)
		die("`pos' is too far after the end of the buffer");
	if (pos + len > sb->len)
		die("`pos + len' is too far after the end of the buffer");

	if (dlen >= len)
		strbuf_grow(sb, dlen - len);
	memmove(sb->buf + pos + dlen,
			sb->buf + pos + len,
			sb->len - pos - len);
	memcpy(sb->buf + pos, data, dlen);
	strbuf_setlen(sb, sb->len + dlen - len);
}

175 176 177 178 179 180 181 182 183 184
void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
{
	strbuf_splice(sb, pos, 0, data, len);
}

void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
{
	strbuf_splice(sb, pos, len, NULL, 0);
}

185 186
void strbuf_add(struct strbuf *sb, const void *data, size_t len)
{
187 188 189 190 191
	strbuf_grow(sb, len);
	memcpy(sb->buf + sb->len, data, len);
	strbuf_setlen(sb, sb->len + len);
}

R
René Scharfe 已提交
192 193 194 195 196 197 198
void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
{
	strbuf_grow(sb, len);
	memcpy(sb->buf + sb->len, sb->buf + pos, len);
	strbuf_setlen(sb, sb->len + len);
}

199 200
void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
{
201
	va_list ap;
J
Jeff King 已提交
202 203 204 205 206
	va_start(ap, fmt);
	strbuf_vaddf(sb, fmt, ap);
	va_end(ap);
}

J
Junio C Hamano 已提交
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
static void add_lines(struct strbuf *out,
			const char *prefix1,
			const char *prefix2,
			const char *buf, size_t size)
{
	while (size) {
		const char *prefix;
		const char *next = memchr(buf, '\n', size);
		next = next ? (next + 1) : (buf + size);

		prefix = (prefix2 && buf[0] == '\n') ? prefix2 : prefix1;
		strbuf_addstr(out, prefix);
		strbuf_add(out, buf, next - buf);
		size -= next - buf;
		buf = next;
	}
	strbuf_complete_line(out);
}

void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size)
{
	static char prefix1[3];
	static char prefix2[2];

	if (prefix1[0] != comment_line_char) {
		sprintf(prefix1, "%c ", comment_line_char);
		sprintf(prefix2, "%c", comment_line_char);
	}
	add_lines(out, prefix1, prefix2, buf, size);
}

void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)
{
	va_list params;
	struct strbuf buf = STRBUF_INIT;
	int incomplete_line = sb->len && sb->buf[sb->len - 1] != '\n';

	va_start(params, fmt);
	strbuf_vaddf(&buf, fmt, params);
	va_end(params);

	strbuf_add_commented_lines(sb, buf.buf, buf.len);
	if (incomplete_line)
		sb->buf[--sb->len] = '\0';

	strbuf_release(&buf);
}

J
Jeff King 已提交
255 256 257 258
void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap)
{
	int len;
	va_list cp;
259

260 261
	if (!strbuf_avail(sb))
		strbuf_grow(sb, 64);
J
Jeff King 已提交
262 263 264
	va_copy(cp, ap);
	len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, cp);
	va_end(cp);
265
	if (len < 0)
J
Jeff King 已提交
266
		die("BUG: your vsnprintf is broken (returned %d)", len);
267
	if (len > strbuf_avail(sb)) {
268 269
		strbuf_grow(sb, len);
		len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
J
Jeff King 已提交
270 271
		if (len > strbuf_avail(sb))
			die("BUG: your vsnprintf is broken (insatiable)");
272 273
	}
	strbuf_setlen(sb, sb->len + len);
274 275
}

276 277
void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
		   void *context)
278 279
{
	for (;;) {
280 281
		const char *percent;
		size_t consumed;
282 283 284 285 286 287 288

		percent = strchrnul(format, '%');
		strbuf_add(sb, format, percent - format);
		if (!*percent)
			break;
		format = percent + 1;

J
Jeff King 已提交
289 290 291 292 293 294
		if (*format == '%') {
			strbuf_addch(sb, '%');
			format++;
			continue;
		}

295 296 297 298
		consumed = fn(sb, format, context);
		if (consumed)
			format += consumed;
		else
299 300 301 302
			strbuf_addch(sb, '%');
	}
}

303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
		void *context)
{
	struct strbuf_expand_dict_entry *e = context;
	size_t len;

	for (; e->placeholder && (len = strlen(e->placeholder)); e++) {
		if (!strncmp(placeholder, e->placeholder, len)) {
			if (e->value)
				strbuf_addstr(sb, e->value);
			return len;
		}
	}
	return 0;
}

319 320 321 322 323 324 325 326 327 328 329
void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src)
{
	int i, len = src->len;

	for (i = 0; i < len; i++) {
		if (src->buf[i] == '%')
			strbuf_addch(dst, '%');
		strbuf_addch(dst, src->buf[i]);
	}
}

330 331
size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
{
332
	size_t res;
333
	size_t oldalloc = sb->alloc;
334 335 336

	strbuf_grow(sb, size);
	res = fread(sb->buf + sb->len, 1, size, f);
337
	if (res > 0)
338
		strbuf_setlen(sb, sb->len + res);
339
	else if (oldalloc == 0)
340
		strbuf_release(sb);
341
	return res;
342 343
}

344
ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
345 346
{
	size_t oldlen = sb->len;
347
	size_t oldalloc = sb->alloc;
348

349
	strbuf_grow(sb, hint ? hint : 8192);
350
	for (;;) {
351 352
		ssize_t want = sb->alloc - sb->len - 1;
		ssize_t got = read_in_full(fd, sb->buf + sb->len, want);
353

354
		if (got < 0) {
355 356 357 358
			if (oldalloc == 0)
				strbuf_release(sb);
			else
				strbuf_setlen(sb, oldlen);
359 360
			return -1;
		}
361 362
		sb->len += got;
		if (got < want)
363
			break;
364
		strbuf_grow(sb, 8192);
365 366 367 368
	}

	sb->buf[sb->len] = '\0';
	return sb->len - oldlen;
369 370
}

371 372 373 374
#define STRBUF_MAXLINK (2*PATH_MAX)

int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
{
375 376
	size_t oldalloc = sb->alloc;

377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
	if (hint < 32)
		hint = 32;

	while (hint < STRBUF_MAXLINK) {
		int len;

		strbuf_grow(sb, hint);
		len = readlink(path, sb->buf, hint);
		if (len < 0) {
			if (errno != ERANGE)
				break;
		} else if (len < hint) {
			strbuf_setlen(sb, len);
			return 0;
		}

		/* .. the buffer was too small - try again */
		hint *= 2;
	}
396 397
	if (oldalloc == 0)
		strbuf_release(sb);
398 399 400
	return -1;
}

401
int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
402
{
403
	int ch;
404 405 406

	if (feof(fp))
		return EOF;
407 408

	strbuf_reset(sb);
409
	while ((ch = fgetc(fp)) != EOF) {
410 411
		strbuf_grow(sb, 1);
		sb->buf[sb->len++] = ch;
412 413
		if (ch == term)
			break;
414
	}
415 416
	if (ch == EOF && sb->len == 0)
		return EOF;
417 418

	sb->buf[sb->len] = '\0';
419
	return 0;
420
}
K
Kristian Høgsberg 已提交
421

422 423 424 425 426 427 428 429 430
int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
{
	if (strbuf_getwholeline(sb, fp, term))
		return EOF;
	if (sb->buf[sb->len-1] == term)
		strbuf_setlen(sb, sb->len-1);
	return 0;
}

431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term)
{
	strbuf_reset(sb);

	while (1) {
		char ch;
		ssize_t len = xread(fd, &ch, 1);
		if (len <= 0)
			return EOF;
		strbuf_addch(sb, ch);
		if (ch == term)
			break;
	}
	return 0;
}

447
int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
K
Kristian Høgsberg 已提交
448 449 450 451 452 453
{
	int fd, len;

	fd = open(path, O_RDONLY);
	if (fd < 0)
		return -1;
454
	len = strbuf_read(sb, fd, hint);
K
Kristian Høgsberg 已提交
455 456 457 458 459 460
	close(fd);
	if (len < 0)
		return -1;

	return len;
}
461 462 463 464

void strbuf_add_lines(struct strbuf *out, const char *prefix,
		      const char *buf, size_t size)
{
J
Junio C Hamano 已提交
465
	add_lines(out, prefix, NULL, buf, size);
466
}
J
Junio C Hamano 已提交
467

468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s)
{
	while (*s) {
		size_t len = strcspn(s, "\"<>&");
		strbuf_add(buf, s, len);
		s += len;
		switch (*s) {
		case '"':
			strbuf_addstr(buf, "&quot;");
			break;
		case '<':
			strbuf_addstr(buf, "&lt;");
			break;
		case '>':
			strbuf_addstr(buf, "&gt;");
			break;
		case '&':
			strbuf_addstr(buf, "&amp;");
			break;
		case 0:
			return;
		}
		s++;
	}
}

J
Jeff King 已提交
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
static int is_rfc3986_reserved(char ch)
{
	switch (ch) {
		case '!': case '*': case '\'': case '(': case ')': case ';':
		case ':': case '@': case '&': case '=': case '+': case '$':
		case ',': case '/': case '?': case '#': case '[': case ']':
			return 1;
	}
	return 0;
}

static int is_rfc3986_unreserved(char ch)
{
	return isalnum(ch) ||
		ch == '-' || ch == '_' || ch == '.' || ch == '~';
}

511 512
static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,
				 int reserved)
J
Jeff King 已提交
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529
{
	strbuf_grow(sb, len);
	while (len--) {
		char ch = *s++;
		if (is_rfc3986_unreserved(ch) ||
		    (!reserved && is_rfc3986_reserved(ch)))
			strbuf_addch(sb, ch);
		else
			strbuf_addf(sb, "%%%02x", ch);
	}
}

void strbuf_addstr_urlencode(struct strbuf *sb, const char *s,
			     int reserved)
{
	strbuf_add_urlencode(sb, s, strlen(s), reserved);
}
530

531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes)
{
	if (bytes > 1 << 30) {
		strbuf_addf(buf, "%u.%2.2u GiB",
			    (int)(bytes >> 30),
			    (int)(bytes & ((1 << 30) - 1)) / 10737419);
	} else if (bytes > 1 << 20) {
		int x = bytes + 5243;  /* for rounding */
		strbuf_addf(buf, "%u.%2.2u MiB",
			    x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20);
	} else if (bytes > 1 << 10) {
		int x = bytes + 5;  /* for rounding */
		strbuf_addf(buf, "%u.%2.2u KiB",
			    x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10);
	} else {
		strbuf_addf(buf, "%u bytes", (int)bytes);
	}
}

550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
int printf_ln(const char *fmt, ...)
{
	int ret;
	va_list ap;
	va_start(ap, fmt);
	ret = vprintf(fmt, ap);
	va_end(ap);
	if (ret < 0 || putchar('\n') == EOF)
		return -1;
	return ret + 1;
}

int fprintf_ln(FILE *fp, const char *fmt, ...)
{
	int ret;
	va_list ap;
	va_start(ap, fmt);
	ret = vfprintf(fp, fmt, ap);
	va_end(ap);
	if (ret < 0 || putc('\n', fp) == EOF)
		return -1;
	return ret + 1;
}