brintos

brintos / linux-shallow public Read only

0
0
Text · 3.1 KiB · a64a376 Raw
171 lines · c
1// SPDX-License-Identifier: GPL-2.02#include "cache.h"3#include "debug.h"4#include "strbuf.h"5#include <linux/kernel.h>6#include <linux/string.h>7#include <linux/zalloc.h>8#include <errno.h>9#include <stdio.h>10#include <stdlib.h>11#include <unistd.h>12 13/*14 * Used as the default ->buf value, so that people can always assume15 * buf is non NULL and ->buf is NUL terminated even for a freshly16 * initialized strbuf.17 */18char strbuf_slopbuf[1];19 20int strbuf_init(struct strbuf *sb, ssize_t hint)21{22	sb->alloc = sb->len = 0;23	sb->buf = strbuf_slopbuf;24	if (hint)25		return strbuf_grow(sb, hint);26	return 0;27}28 29void strbuf_release(struct strbuf *sb)30{31	if (sb->alloc) {32		zfree(&sb->buf);33		strbuf_init(sb, 0);34	}35}36 37char *strbuf_detach(struct strbuf *sb, size_t *sz)38{39	char *res = sb->alloc ? sb->buf : NULL;40	if (sz)41		*sz = sb->len;42	strbuf_init(sb, 0);43	return res;44}45 46int strbuf_grow(struct strbuf *sb, size_t extra)47{48	char *buf;49	size_t nr = sb->len + extra + 1;50 51	if (nr < sb->alloc)52		return 0;53 54	if (nr <= sb->len)55		return -E2BIG;56 57	if (alloc_nr(sb->alloc) > nr)58		nr = alloc_nr(sb->alloc);59 60	/*61	 * Note that sb->buf == strbuf_slopbuf if sb->alloc == 0, and it is62	 * a static variable. Thus we have to avoid passing it to realloc.63	 */64	buf = realloc(sb->alloc ? sb->buf : NULL, nr * sizeof(*buf));65	if (!buf)66		return -ENOMEM;67 68	sb->buf = buf;69	sb->alloc = nr;70	return 0;71}72 73int strbuf_addch(struct strbuf *sb, int c)74{75	int ret = strbuf_grow(sb, 1);76	if (ret)77		return ret;78 79	sb->buf[sb->len++] = c;80	sb->buf[sb->len] = '\0';81	return 0;82}83 84int strbuf_add(struct strbuf *sb, const void *data, size_t len)85{86	int ret = strbuf_grow(sb, len);87	if (ret)88		return ret;89 90	memcpy(sb->buf + sb->len, data, len);91	return strbuf_setlen(sb, sb->len + len);92}93 94static int strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap)95{96	int len, ret;97	va_list ap_saved;98 99	if (!strbuf_avail(sb)) {100		ret = strbuf_grow(sb, 64);101		if (ret)102			return ret;103	}104 105	va_copy(ap_saved, ap);106	len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);107	if (len < 0) {108		va_end(ap_saved);109		return len;110	}111	if (len > strbuf_avail(sb)) {112		ret = strbuf_grow(sb, len);113		if (ret) {114			va_end(ap_saved);115			return ret;116		}117		len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved);118		if (len > strbuf_avail(sb)) {119			pr_debug("this should not happen, your vsnprintf is broken");120			va_end(ap_saved);121			return -EINVAL;122		}123	}124	va_end(ap_saved);125	return strbuf_setlen(sb, sb->len + len);126}127 128int strbuf_addf(struct strbuf *sb, const char *fmt, ...)129{130	va_list ap;131	int ret;132 133	va_start(ap, fmt);134	ret = strbuf_addv(sb, fmt, ap);135	va_end(ap);136	return ret;137}138 139ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)140{141	size_t oldlen = sb->len;142	size_t oldalloc = sb->alloc;143	int ret;144 145	ret = strbuf_grow(sb, hint ? hint : 8192);146	if (ret)147		return ret;148 149	for (;;) {150		ssize_t cnt;151 152		cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);153		if (cnt < 0) {154			if (oldalloc == 0)155				strbuf_release(sb);156			else157				strbuf_setlen(sb, oldlen);158			return cnt;159		}160		if (!cnt)161			break;162		sb->len += cnt;163		ret = strbuf_grow(sb, 8192);164		if (ret)165			return ret;166	}167 168	sb->buf[sb->len] = '\0';169	return sb->len - oldlen;170}171