blob: aafe908b82b5720b4487c242370ed326ec520e2c [file] [log] [blame]
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +09001#include "debug.h"
Arnaldo Carvalho de Melo7ed09582016-07-07 11:06:58 -03002#include "util.h"
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003#include <linux/kernel.h>
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -03004#include <errno.h>
Ingo Molnar07800602009-04-20 15:00:56 +02005
Ingo Molnar07800602009-04-20 15:00:56 +02006/*
7 * Used as the default ->buf value, so that people can always assume
8 * buf is non NULL and ->buf is NUL terminated even for a freshly
9 * initialized strbuf.
10 */
11char strbuf_slopbuf[1];
12
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090013int strbuf_init(struct strbuf *sb, ssize_t hint)
Ingo Molnar07800602009-04-20 15:00:56 +020014{
15 sb->alloc = sb->len = 0;
16 sb->buf = strbuf_slopbuf;
17 if (hint)
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090018 return strbuf_grow(sb, hint);
19 return 0;
Ingo Molnar07800602009-04-20 15:00:56 +020020}
21
22void strbuf_release(struct strbuf *sb)
23{
24 if (sb->alloc) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -030025 zfree(&sb->buf);
Ingo Molnar07800602009-04-20 15:00:56 +020026 strbuf_init(sb, 0);
27 }
28}
29
30char *strbuf_detach(struct strbuf *sb, size_t *sz)
31{
32 char *res = sb->alloc ? sb->buf : NULL;
33 if (sz)
34 *sz = sb->len;
35 strbuf_init(sb, 0);
36 return res;
37}
38
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090039int strbuf_grow(struct strbuf *sb, size_t extra)
Ingo Molnar07800602009-04-20 15:00:56 +020040{
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090041 char *buf;
42 size_t nr = sb->len + extra + 1;
43
44 if (nr < sb->alloc)
45 return 0;
46
47 if (nr <= sb->len)
48 return -E2BIG;
49
50 if (alloc_nr(sb->alloc) > nr)
51 nr = alloc_nr(sb->alloc);
52
53 /*
54 * Note that sb->buf == strbuf_slopbuf if sb->alloc == 0, and it is
55 * a static variable. Thus we have to avoid passing it to realloc.
56 */
57 buf = realloc(sb->alloc ? sb->buf : NULL, nr * sizeof(*buf));
58 if (!buf)
59 return -ENOMEM;
60
61 sb->buf = buf;
62 sb->alloc = nr;
63 return 0;
Ingo Molnar07800602009-04-20 15:00:56 +020064}
65
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090066int strbuf_addch(struct strbuf *sb, int c)
Arnaldo Carvalho de Melo07412082016-03-23 16:56:56 -030067{
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090068 int ret = strbuf_grow(sb, 1);
69 if (ret)
70 return ret;
71
Arnaldo Carvalho de Melo07412082016-03-23 16:56:56 -030072 sb->buf[sb->len++] = c;
73 sb->buf[sb->len] = '\0';
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090074 return 0;
Arnaldo Carvalho de Melo07412082016-03-23 16:56:56 -030075}
76
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090077int strbuf_add(struct strbuf *sb, const void *data, size_t len)
Ingo Molnar07800602009-04-20 15:00:56 +020078{
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090079 int ret = strbuf_grow(sb, len);
80 if (ret)
81 return ret;
82
Ingo Molnar07800602009-04-20 15:00:56 +020083 memcpy(sb->buf + sb->len, data, len);
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090084 return strbuf_setlen(sb, sb->len + len);
Ingo Molnar07800602009-04-20 15:00:56 +020085}
86
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090087static int strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap)
Ingo Molnar07800602009-04-20 15:00:56 +020088{
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090089 int len, ret;
Namhyung Kimc7118362015-10-25 00:49:27 +090090 va_list ap_saved;
Ingo Molnar07800602009-04-20 15:00:56 +020091
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090092 if (!strbuf_avail(sb)) {
93 ret = strbuf_grow(sb, 64);
94 if (ret)
95 return ret;
96 }
Namhyung Kimc7118362015-10-25 00:49:27 +090097
98 va_copy(ap_saved, ap);
Namhyung Kimf787d952012-10-23 22:44:50 +090099 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
Ingo Molnar07800602009-04-20 15:00:56 +0200100 if (len < 0)
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900101 return len;
Ingo Molnar07800602009-04-20 15:00:56 +0200102 if (len > strbuf_avail(sb)) {
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900103 ret = strbuf_grow(sb, len);
104 if (ret)
105 return ret;
Namhyung Kimc7118362015-10-25 00:49:27 +0900106 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved);
107 va_end(ap_saved);
Ingo Molnar07800602009-04-20 15:00:56 +0200108 if (len > strbuf_avail(sb)) {
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900109 pr_debug("this should not happen, your vsnprintf is broken");
110 return -EINVAL;
Ingo Molnar07800602009-04-20 15:00:56 +0200111 }
112 }
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900113 return strbuf_setlen(sb, sb->len + len);
Ingo Molnar07800602009-04-20 15:00:56 +0200114}
115
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900116int strbuf_addf(struct strbuf *sb, const char *fmt, ...)
Namhyung Kimc7118362015-10-25 00:49:27 +0900117{
118 va_list ap;
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900119 int ret;
Namhyung Kimc7118362015-10-25 00:49:27 +0900120
121 va_start(ap, fmt);
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900122 ret = strbuf_addv(sb, fmt, ap);
Namhyung Kimc7118362015-10-25 00:49:27 +0900123 va_end(ap);
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900124 return ret;
Namhyung Kimc7118362015-10-25 00:49:27 +0900125}
126
Ingo Molnarf37a2912009-07-01 12:37:06 +0200127ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
Ingo Molnar07800602009-04-20 15:00:56 +0200128{
129 size_t oldlen = sb->len;
130 size_t oldalloc = sb->alloc;
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900131 int ret;
Ingo Molnar07800602009-04-20 15:00:56 +0200132
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900133 ret = strbuf_grow(sb, hint ? hint : 8192);
134 if (ret)
135 return ret;
136
Ingo Molnar07800602009-04-20 15:00:56 +0200137 for (;;) {
138 ssize_t cnt;
139
140 cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
141 if (cnt < 0) {
142 if (oldalloc == 0)
143 strbuf_release(sb);
144 else
145 strbuf_setlen(sb, oldlen);
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900146 return cnt;
Ingo Molnar07800602009-04-20 15:00:56 +0200147 }
148 if (!cnt)
149 break;
150 sb->len += cnt;
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900151 ret = strbuf_grow(sb, 8192);
152 if (ret)
153 return ret;
Ingo Molnar07800602009-04-20 15:00:56 +0200154 }
155
156 sb->buf[sb->len] = '\0';
157 return sb->len - oldlen;
158}