blob: e91b5e86f0274c0cb3d9e5c44df5d2513e2564f5 [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
6int prefixcmp(const char *str, const char *prefix)
7{
8 for (; ; str++, prefix++)
9 if (!*prefix)
10 return 0;
11 else if (*str != *prefix)
12 return (unsigned char)*prefix - (unsigned char)*str;
13}
14
15/*
16 * Used as the default ->buf value, so that people can always assume
17 * buf is non NULL and ->buf is NUL terminated even for a freshly
18 * initialized strbuf.
19 */
20char strbuf_slopbuf[1];
21
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090022int strbuf_init(struct strbuf *sb, ssize_t hint)
Ingo Molnar07800602009-04-20 15:00:56 +020023{
24 sb->alloc = sb->len = 0;
25 sb->buf = strbuf_slopbuf;
26 if (hint)
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090027 return strbuf_grow(sb, hint);
28 return 0;
Ingo Molnar07800602009-04-20 15:00:56 +020029}
30
31void strbuf_release(struct strbuf *sb)
32{
33 if (sb->alloc) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -030034 zfree(&sb->buf);
Ingo Molnar07800602009-04-20 15:00:56 +020035 strbuf_init(sb, 0);
36 }
37}
38
39char *strbuf_detach(struct strbuf *sb, size_t *sz)
40{
41 char *res = sb->alloc ? sb->buf : NULL;
42 if (sz)
43 *sz = sb->len;
44 strbuf_init(sb, 0);
45 return res;
46}
47
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090048int strbuf_grow(struct strbuf *sb, size_t extra)
Ingo Molnar07800602009-04-20 15:00:56 +020049{
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090050 char *buf;
51 size_t nr = sb->len + extra + 1;
52
53 if (nr < sb->alloc)
54 return 0;
55
56 if (nr <= sb->len)
57 return -E2BIG;
58
59 if (alloc_nr(sb->alloc) > nr)
60 nr = alloc_nr(sb->alloc);
61
62 /*
63 * Note that sb->buf == strbuf_slopbuf if sb->alloc == 0, and it is
64 * a static variable. Thus we have to avoid passing it to realloc.
65 */
66 buf = realloc(sb->alloc ? sb->buf : NULL, nr * sizeof(*buf));
67 if (!buf)
68 return -ENOMEM;
69
70 sb->buf = buf;
71 sb->alloc = nr;
72 return 0;
Ingo Molnar07800602009-04-20 15:00:56 +020073}
74
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090075int strbuf_addch(struct strbuf *sb, int c)
Arnaldo Carvalho de Melo07412082016-03-23 16:56:56 -030076{
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090077 int ret = strbuf_grow(sb, 1);
78 if (ret)
79 return ret;
80
Arnaldo Carvalho de Melo07412082016-03-23 16:56:56 -030081 sb->buf[sb->len++] = c;
82 sb->buf[sb->len] = '\0';
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090083 return 0;
Arnaldo Carvalho de Melo07412082016-03-23 16:56:56 -030084}
85
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090086int strbuf_add(struct strbuf *sb, const void *data, size_t len)
Ingo Molnar07800602009-04-20 15:00:56 +020087{
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090088 int ret = strbuf_grow(sb, len);
89 if (ret)
90 return ret;
91
Ingo Molnar07800602009-04-20 15:00:56 +020092 memcpy(sb->buf + sb->len, data, len);
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090093 return strbuf_setlen(sb, sb->len + len);
Ingo Molnar07800602009-04-20 15:00:56 +020094}
95
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090096static int strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap)
Ingo Molnar07800602009-04-20 15:00:56 +020097{
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090098 int len, ret;
Namhyung Kimc7118362015-10-25 00:49:27 +090099 va_list ap_saved;
Ingo Molnar07800602009-04-20 15:00:56 +0200100
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900101 if (!strbuf_avail(sb)) {
102 ret = strbuf_grow(sb, 64);
103 if (ret)
104 return ret;
105 }
Namhyung Kimc7118362015-10-25 00:49:27 +0900106
107 va_copy(ap_saved, ap);
Namhyung Kimf787d952012-10-23 22:44:50 +0900108 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
Ingo Molnar07800602009-04-20 15:00:56 +0200109 if (len < 0)
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900110 return len;
Ingo Molnar07800602009-04-20 15:00:56 +0200111 if (len > strbuf_avail(sb)) {
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900112 ret = strbuf_grow(sb, len);
113 if (ret)
114 return ret;
Namhyung Kimc7118362015-10-25 00:49:27 +0900115 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved);
116 va_end(ap_saved);
Ingo Molnar07800602009-04-20 15:00:56 +0200117 if (len > strbuf_avail(sb)) {
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900118 pr_debug("this should not happen, your vsnprintf is broken");
119 return -EINVAL;
Ingo Molnar07800602009-04-20 15:00:56 +0200120 }
121 }
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900122 return strbuf_setlen(sb, sb->len + len);
Ingo Molnar07800602009-04-20 15:00:56 +0200123}
124
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900125int strbuf_addf(struct strbuf *sb, const char *fmt, ...)
Namhyung Kimc7118362015-10-25 00:49:27 +0900126{
127 va_list ap;
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900128 int ret;
Namhyung Kimc7118362015-10-25 00:49:27 +0900129
130 va_start(ap, fmt);
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900131 ret = strbuf_addv(sb, fmt, ap);
Namhyung Kimc7118362015-10-25 00:49:27 +0900132 va_end(ap);
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900133 return ret;
Namhyung Kimc7118362015-10-25 00:49:27 +0900134}
135
Ingo Molnarf37a2912009-07-01 12:37:06 +0200136ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
Ingo Molnar07800602009-04-20 15:00:56 +0200137{
138 size_t oldlen = sb->len;
139 size_t oldalloc = sb->alloc;
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900140 int ret;
Ingo Molnar07800602009-04-20 15:00:56 +0200141
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900142 ret = strbuf_grow(sb, hint ? hint : 8192);
143 if (ret)
144 return ret;
145
Ingo Molnar07800602009-04-20 15:00:56 +0200146 for (;;) {
147 ssize_t cnt;
148
149 cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
150 if (cnt < 0) {
151 if (oldalloc == 0)
152 strbuf_release(sb);
153 else
154 strbuf_setlen(sb, oldlen);
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900155 return cnt;
Ingo Molnar07800602009-04-20 15:00:56 +0200156 }
157 if (!cnt)
158 break;
159 sb->len += cnt;
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900160 ret = strbuf_grow(sb, 8192);
161 if (ret)
162 return ret;
Ingo Molnar07800602009-04-20 15:00:56 +0200163 }
164
165 sb->buf[sb->len] = '\0';
166 return sb->len - oldlen;
167}