xref: /openbmc/linux/tools/perf/util/strbuf.c (revision 976e3645923bdd2fe7893aae33fd7a21098bfb28)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2*8520a98dSArnaldo Carvalho de Melo #include "cache.h"
35cea57f3SMasami Hiramatsu #include "debug.h"
4*8520a98dSArnaldo Carvalho de Melo #include "strbuf.h"
5e7f01d1eSArnaldo Carvalho de Melo #include <linux/kernel.h>
6*8520a98dSArnaldo Carvalho de Melo #include <linux/string.h>
77f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
8a43783aeSArnaldo Carvalho de Melo #include <errno.h>
9*8520a98dSArnaldo Carvalho de Melo #include <stdio.h>
10215a0d30SArnaldo Carvalho de Melo #include <stdlib.h>
1191854f9aSArnaldo Carvalho de Melo #include <unistd.h>
1286470930SIngo Molnar 
1386470930SIngo Molnar /*
1486470930SIngo Molnar  * Used as the default ->buf value, so that people can always assume
1586470930SIngo Molnar  * buf is non NULL and ->buf is NUL terminated even for a freshly
1686470930SIngo Molnar  * initialized strbuf.
1786470930SIngo Molnar  */
1886470930SIngo Molnar char strbuf_slopbuf[1];
1986470930SIngo Molnar 
strbuf_init(struct strbuf * sb,ssize_t hint)205cea57f3SMasami Hiramatsu int strbuf_init(struct strbuf *sb, ssize_t hint)
2186470930SIngo Molnar {
2286470930SIngo Molnar 	sb->alloc = sb->len = 0;
2386470930SIngo Molnar 	sb->buf = strbuf_slopbuf;
2486470930SIngo Molnar 	if (hint)
255cea57f3SMasami Hiramatsu 		return strbuf_grow(sb, hint);
265cea57f3SMasami Hiramatsu 	return 0;
2786470930SIngo Molnar }
2886470930SIngo Molnar 
strbuf_release(struct strbuf * sb)2986470930SIngo Molnar void strbuf_release(struct strbuf *sb)
3086470930SIngo Molnar {
3186470930SIngo Molnar 	if (sb->alloc) {
3274cf249dSArnaldo Carvalho de Melo 		zfree(&sb->buf);
3386470930SIngo Molnar 		strbuf_init(sb, 0);
3486470930SIngo Molnar 	}
3586470930SIngo Molnar }
3686470930SIngo Molnar 
strbuf_detach(struct strbuf * sb,size_t * sz)3786470930SIngo Molnar char *strbuf_detach(struct strbuf *sb, size_t *sz)
3886470930SIngo Molnar {
3986470930SIngo Molnar 	char *res = sb->alloc ? sb->buf : NULL;
4086470930SIngo Molnar 	if (sz)
4186470930SIngo Molnar 		*sz = sb->len;
4286470930SIngo Molnar 	strbuf_init(sb, 0);
4386470930SIngo Molnar 	return res;
4486470930SIngo Molnar }
4586470930SIngo Molnar 
strbuf_grow(struct strbuf * sb,size_t extra)465cea57f3SMasami Hiramatsu int strbuf_grow(struct strbuf *sb, size_t extra)
4786470930SIngo Molnar {
485cea57f3SMasami Hiramatsu 	char *buf;
495cea57f3SMasami Hiramatsu 	size_t nr = sb->len + extra + 1;
505cea57f3SMasami Hiramatsu 
515cea57f3SMasami Hiramatsu 	if (nr < sb->alloc)
525cea57f3SMasami Hiramatsu 		return 0;
535cea57f3SMasami Hiramatsu 
545cea57f3SMasami Hiramatsu 	if (nr <= sb->len)
555cea57f3SMasami Hiramatsu 		return -E2BIG;
565cea57f3SMasami Hiramatsu 
575cea57f3SMasami Hiramatsu 	if (alloc_nr(sb->alloc) > nr)
585cea57f3SMasami Hiramatsu 		nr = alloc_nr(sb->alloc);
595cea57f3SMasami Hiramatsu 
605cea57f3SMasami Hiramatsu 	/*
615cea57f3SMasami Hiramatsu 	 * Note that sb->buf == strbuf_slopbuf if sb->alloc == 0, and it is
625cea57f3SMasami Hiramatsu 	 * a static variable. Thus we have to avoid passing it to realloc.
635cea57f3SMasami Hiramatsu 	 */
645cea57f3SMasami Hiramatsu 	buf = realloc(sb->alloc ? sb->buf : NULL, nr * sizeof(*buf));
655cea57f3SMasami Hiramatsu 	if (!buf)
665cea57f3SMasami Hiramatsu 		return -ENOMEM;
675cea57f3SMasami Hiramatsu 
685cea57f3SMasami Hiramatsu 	sb->buf = buf;
695cea57f3SMasami Hiramatsu 	sb->alloc = nr;
705cea57f3SMasami Hiramatsu 	return 0;
7186470930SIngo Molnar }
7286470930SIngo Molnar 
strbuf_addch(struct strbuf * sb,int c)735cea57f3SMasami Hiramatsu int strbuf_addch(struct strbuf *sb, int c)
740741208aSArnaldo Carvalho de Melo {
755cea57f3SMasami Hiramatsu 	int ret = strbuf_grow(sb, 1);
765cea57f3SMasami Hiramatsu 	if (ret)
775cea57f3SMasami Hiramatsu 		return ret;
785cea57f3SMasami Hiramatsu 
790741208aSArnaldo Carvalho de Melo 	sb->buf[sb->len++] = c;
800741208aSArnaldo Carvalho de Melo 	sb->buf[sb->len] = '\0';
815cea57f3SMasami Hiramatsu 	return 0;
820741208aSArnaldo Carvalho de Melo }
830741208aSArnaldo Carvalho de Melo 
strbuf_add(struct strbuf * sb,const void * data,size_t len)845cea57f3SMasami Hiramatsu int strbuf_add(struct strbuf *sb, const void *data, size_t len)
8586470930SIngo Molnar {
865cea57f3SMasami Hiramatsu 	int ret = strbuf_grow(sb, len);
875cea57f3SMasami Hiramatsu 	if (ret)
885cea57f3SMasami Hiramatsu 		return ret;
895cea57f3SMasami Hiramatsu 
9086470930SIngo Molnar 	memcpy(sb->buf + sb->len, data, len);
915cea57f3SMasami Hiramatsu 	return strbuf_setlen(sb, sb->len + len);
9286470930SIngo Molnar }
9386470930SIngo Molnar 
strbuf_addv(struct strbuf * sb,const char * fmt,va_list ap)945cea57f3SMasami Hiramatsu static int strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap)
9586470930SIngo Molnar {
965cea57f3SMasami Hiramatsu 	int len, ret;
97c7118369SNamhyung Kim 	va_list ap_saved;
9886470930SIngo Molnar 
995cea57f3SMasami Hiramatsu 	if (!strbuf_avail(sb)) {
1005cea57f3SMasami Hiramatsu 		ret = strbuf_grow(sb, 64);
1015cea57f3SMasami Hiramatsu 		if (ret)
1025cea57f3SMasami Hiramatsu 			return ret;
1035cea57f3SMasami Hiramatsu 	}
104c7118369SNamhyung Kim 
105c7118369SNamhyung Kim 	va_copy(ap_saved, ap);
106f787d951SNamhyung Kim 	len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
107ce49d843SSanskriti Sharma 	if (len < 0) {
108ce49d843SSanskriti Sharma 		va_end(ap_saved);
1095cea57f3SMasami Hiramatsu 		return len;
110ce49d843SSanskriti Sharma 	}
11186470930SIngo Molnar 	if (len > strbuf_avail(sb)) {
1125cea57f3SMasami Hiramatsu 		ret = strbuf_grow(sb, len);
113ce49d843SSanskriti Sharma 		if (ret) {
114ce49d843SSanskriti Sharma 			va_end(ap_saved);
1155cea57f3SMasami Hiramatsu 			return ret;
116ce49d843SSanskriti Sharma 		}
117c7118369SNamhyung Kim 		len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved);
11886470930SIngo Molnar 		if (len > strbuf_avail(sb)) {
1195cea57f3SMasami Hiramatsu 			pr_debug("this should not happen, your vsnprintf is broken");
120ce49d843SSanskriti Sharma 			va_end(ap_saved);
1215cea57f3SMasami Hiramatsu 			return -EINVAL;
12286470930SIngo Molnar 		}
12386470930SIngo Molnar 	}
124ce49d843SSanskriti Sharma 	va_end(ap_saved);
1255cea57f3SMasami Hiramatsu 	return strbuf_setlen(sb, sb->len + len);
12686470930SIngo Molnar }
12786470930SIngo Molnar 
strbuf_addf(struct strbuf * sb,const char * fmt,...)1285cea57f3SMasami Hiramatsu int strbuf_addf(struct strbuf *sb, const char *fmt, ...)
129c7118369SNamhyung Kim {
130c7118369SNamhyung Kim 	va_list ap;
1315cea57f3SMasami Hiramatsu 	int ret;
132c7118369SNamhyung Kim 
133c7118369SNamhyung Kim 	va_start(ap, fmt);
1345cea57f3SMasami Hiramatsu 	ret = strbuf_addv(sb, fmt, ap);
135c7118369SNamhyung Kim 	va_end(ap);
1365cea57f3SMasami Hiramatsu 	return ret;
137c7118369SNamhyung Kim }
138c7118369SNamhyung Kim 
strbuf_read(struct strbuf * sb,int fd,ssize_t hint)139f37a291cSIngo Molnar ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
14086470930SIngo Molnar {
14186470930SIngo Molnar 	size_t oldlen = sb->len;
14286470930SIngo Molnar 	size_t oldalloc = sb->alloc;
1435cea57f3SMasami Hiramatsu 	int ret;
14486470930SIngo Molnar 
1455cea57f3SMasami Hiramatsu 	ret = strbuf_grow(sb, hint ? hint : 8192);
1465cea57f3SMasami Hiramatsu 	if (ret)
1475cea57f3SMasami Hiramatsu 		return ret;
1485cea57f3SMasami Hiramatsu 
14986470930SIngo Molnar 	for (;;) {
15086470930SIngo Molnar 		ssize_t cnt;
15186470930SIngo Molnar 
15286470930SIngo Molnar 		cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
15386470930SIngo Molnar 		if (cnt < 0) {
15486470930SIngo Molnar 			if (oldalloc == 0)
15586470930SIngo Molnar 				strbuf_release(sb);
15686470930SIngo Molnar 			else
15786470930SIngo Molnar 				strbuf_setlen(sb, oldlen);
1585cea57f3SMasami Hiramatsu 			return cnt;
15986470930SIngo Molnar 		}
16086470930SIngo Molnar 		if (!cnt)
16186470930SIngo Molnar 			break;
16286470930SIngo Molnar 		sb->len += cnt;
1635cea57f3SMasami Hiramatsu 		ret = strbuf_grow(sb, 8192);
1645cea57f3SMasami Hiramatsu 		if (ret)
1655cea57f3SMasami Hiramatsu 			return ret;
16686470930SIngo Molnar 	}
16786470930SIngo Molnar 
16886470930SIngo Molnar 	sb->buf[sb->len] = '\0';
16986470930SIngo Molnar 	return sb->len - oldlen;
17086470930SIngo Molnar }
171