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

J
Junio C Hamano 已提交
4 5 6 7 8 9 10 11 12
int prefixcmp(const char *str, const char *prefix)
{
	for (; ; str++, prefix++)
		if (!*prefix)
			return 0;
		else if (*str != *prefix)
			return (unsigned char)*prefix - (unsigned char)*str;
}

A
Avery Pennarun 已提交
13 14 15 16 17 18 19 20 21
int suffixcmp(const char *str, const char *suffix)
{
	int len = strlen(str), suflen = strlen(suffix);
	if (len < suflen)
		return -1;
	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
struct strbuf **strbuf_split_buf(const char *str, size_t slen, int delim, int max)
110
{
111 112
	struct strbuf **ret = NULL;
	size_t nr = 0, alloc = 0;
113
	const char *n, *p;
114 115
	struct strbuf *t;

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

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

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

149
int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
P
Pierre Habouzit 已提交
150
{
A
Alex Riesen 已提交
151 152 153 154 155
	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 已提交
156 157
}

158 159 160
void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
				   const void *data, size_t dlen)
{
161
	if (unsigned_add_overflows(pos, len))
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
		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);
}

177 178 179 180 181 182 183 184 185 186
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);
}

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

R
René Scharfe 已提交
194 195 196 197 198 199 200
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);
}

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

void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap)
{
	int len;
	va_list cp;
213

214 215
	if (!strbuf_avail(sb))
		strbuf_grow(sb, 64);
J
Jeff King 已提交
216 217 218
	va_copy(cp, ap);
	len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, cp);
	va_end(cp);
219
	if (len < 0)
J
Jeff King 已提交
220
		die("BUG: your vsnprintf is broken (returned %d)", len);
221
	if (len > strbuf_avail(sb)) {
222 223
		strbuf_grow(sb, len);
		len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
J
Jeff King 已提交
224 225
		if (len > strbuf_avail(sb))
			die("BUG: your vsnprintf is broken (insatiable)");
226 227
	}
	strbuf_setlen(sb, sb->len + len);
228 229
}

230 231
void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
		   void *context)
232 233
{
	for (;;) {
234 235
		const char *percent;
		size_t consumed;
236 237 238 239 240 241 242

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

J
Jeff King 已提交
243 244 245 246 247 248
		if (*format == '%') {
			strbuf_addch(sb, '%');
			format++;
			continue;
		}

249 250 251 252
		consumed = fn(sb, format, context);
		if (consumed)
			format += consumed;
		else
253 254 255 256
			strbuf_addch(sb, '%');
	}
}

257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
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;
}

273 274 275 276 277 278 279 280 281 282 283
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]);
	}
}

284 285
size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
{
286
	size_t res;
287
	size_t oldalloc = sb->alloc;
288 289 290

	strbuf_grow(sb, size);
	res = fread(sb->buf + sb->len, 1, size, f);
291
	if (res > 0)
292
		strbuf_setlen(sb, sb->len + res);
293
	else if (oldalloc == 0)
294
		strbuf_release(sb);
295
	return res;
296 297
}

298
ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
299 300
{
	size_t oldlen = sb->len;
301
	size_t oldalloc = sb->alloc;
302

303
	strbuf_grow(sb, hint ? hint : 8192);
304 305 306 307 308
	for (;;) {
		ssize_t cnt;

		cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
		if (cnt < 0) {
309 310 311 312
			if (oldalloc == 0)
				strbuf_release(sb);
			else
				strbuf_setlen(sb, oldlen);
313 314 315 316 317
			return -1;
		}
		if (!cnt)
			break;
		sb->len += cnt;
318
		strbuf_grow(sb, 8192);
319 320 321 322
	}

	sb->buf[sb->len] = '\0';
	return sb->len - oldlen;
323 324
}

325 326 327 328
#define STRBUF_MAXLINK (2*PATH_MAX)

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

331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
	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;
	}
350 351
	if (oldalloc == 0)
		strbuf_release(sb);
352 353 354
	return -1;
}

355
int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
356
{
357
	int ch;
358 359 360

	if (feof(fp))
		return EOF;
361 362

	strbuf_reset(sb);
363
	while ((ch = fgetc(fp)) != EOF) {
364 365
		strbuf_grow(sb, 1);
		sb->buf[sb->len++] = ch;
366 367
		if (ch == term)
			break;
368
	}
369 370
	if (ch == EOF && sb->len == 0)
		return EOF;
371 372

	sb->buf[sb->len] = '\0';
373
	return 0;
374
}
K
Kristian Høgsberg 已提交
375

376 377 378 379 380 381 382 383 384
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;
}

385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
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;
}

401
int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
K
Kristian Høgsberg 已提交
402 403 404 405 406 407
{
	int fd, len;

	fd = open(path, O_RDONLY);
	if (fd < 0)
		return -1;
408
	len = strbuf_read(sb, fd, hint);
K
Kristian Høgsberg 已提交
409 410 411 412 413 414
	close(fd);
	if (len < 0)
		return -1;

	return len;
}
415 416 417 418 419 420 421 422 423 424 425 426 427 428

void strbuf_add_lines(struct strbuf *out, const char *prefix,
		      const char *buf, size_t size)
{
	while (size) {
		const char *next = memchr(buf, '\n', size);
		next = next ? (next + 1) : (buf + size);
		strbuf_addstr(out, prefix);
		strbuf_add(out, buf, next - buf);
		size -= next - buf;
		buf = next;
	}
	strbuf_complete_line(out);
}
J
Junio C Hamano 已提交
429

J
Jeff King 已提交
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
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 == '~';
}

447 448
static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,
				 int reserved)
J
Jeff King 已提交
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
{
	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);
}
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489

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;
}