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 114
	struct strbuf *t;

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

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

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

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

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

174 175 176 177 178 179 180 181 182 183
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);
}

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

R
René Scharfe 已提交
191 192 193 194 195 196 197
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);
}

198 199
void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
{
200
	va_list ap;
J
Jeff King 已提交
201 202 203 204 205 206 207 208 209
	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;
210

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

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

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

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

246 247 248 249
		consumed = fn(sb, format, context);
		if (consumed)
			format += consumed;
		else
250 251 252 253
			strbuf_addch(sb, '%');
	}
}

254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
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;
}

270 271 272 273 274 275 276 277 278 279 280
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]);
	}
}

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

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

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

300
	strbuf_grow(sb, hint ? hint : 8192);
301 302 303 304 305
	for (;;) {
		ssize_t cnt;

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

	sb->buf[sb->len] = '\0';
	return sb->len - oldlen;
320 321
}

322 323 324 325
#define STRBUF_MAXLINK (2*PATH_MAX)

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

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

352
int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
353
{
354
	int ch;
355 356 357

	if (feof(fp))
		return EOF;
358 359

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

	sb->buf[sb->len] = '\0';
370
	return 0;
371
}
K
Kristian Høgsberg 已提交
372

373 374 375 376 377 378 379 380 381
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;
}

382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
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;
}

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

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

	return len;
}
412 413 414 415 416 417 418 419 420 421 422 423 424 425

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 已提交
426

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

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

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