blob: 817593908d47a3d1ea27eb73080b94852e88d990 [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>
Ingo Molnar07800602009-04-20 15:00:56 +02004
5int prefixcmp(const char *str, const char *prefix)
6{
7 for (; ; str++, prefix++)
8 if (!*prefix)
9 return 0;
10 else if (*str != *prefix)
11 return (unsigned char)*prefix - (unsigned char)*str;
12}
13
14/*
15 * Used as the default ->buf value, so that people can always assume
16 * buf is non NULL and ->buf is NUL terminated even for a freshly
17 * initialized strbuf.
18 */
19char strbuf_slopbuf[1];
20
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090021int strbuf_init(struct strbuf *sb, ssize_t hint)
Ingo Molnar07800602009-04-20 15:00:56 +020022{
23 sb->alloc = sb->len = 0;
24 sb->buf = strbuf_slopbuf;
25 if (hint)
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090026 return strbuf_grow(sb, hint);
27 return 0;
Ingo Molnar07800602009-04-20 15:00:56 +020028}
29
30void strbuf_release(struct strbuf *sb)
31{
32 if (sb->alloc) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -030033 zfree(&sb->buf);
Ingo Molnar07800602009-04-20 15:00:56 +020034 strbuf_init(sb, 0);
35 }
36}
37
38char *strbuf_detach(struct strbuf *sb, size_t *sz)
39{
40 char *res = sb->alloc ? sb->buf : NULL;
41 if (sz)
42 *sz = sb->len;
43 strbuf_init(sb, 0);
44 return res;
45}
46
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090047int strbuf_grow(struct strbuf *sb, size_t extra)
Ingo Molnar07800602009-04-20 15:00:56 +020048{
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090049 char *buf;
50 size_t nr = sb->len + extra + 1;
51
52 if (nr < sb->alloc)
53 return 0;
54
55 if (nr <= sb->len)
56 return -E2BIG;
57
58 if (alloc_nr(sb->alloc) > nr)
59 nr = alloc_nr(sb->alloc);
60
61 /*
62 * Note that sb->buf == strbuf_slopbuf if sb->alloc == 0, and it is
63 * a static variable. Thus we have to avoid passing it to realloc.
64 */
65 buf = realloc(sb->alloc ? sb->buf : NULL, nr * sizeof(*buf));
66 if (!buf)
67 return -ENOMEM;
68
69 sb->buf = buf;
70 sb->alloc = nr;
71 return 0;
Ingo Molnar07800602009-04-20 15:00:56 +020072}
73
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090074int strbuf_addch(struct strbuf *sb, int c)
Arnaldo Carvalho de Melo07412082016-03-23 16:56:56 -030075{
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090076 int ret = strbuf_grow(sb, 1);
77 if (ret)
78 return ret;
79
Arnaldo Carvalho de Melo07412082016-03-23 16:56:56 -030080 sb->buf[sb->len++] = c;
81 sb->buf[sb->len] = '\0';
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090082 return 0;
Arnaldo Carvalho de Melo07412082016-03-23 16:56:56 -030083}
84
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090085int strbuf_add(struct strbuf *sb, const void *data, size_t len)
Ingo Molnar07800602009-04-20 15:00:56 +020086{
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090087 int ret = strbuf_grow(sb, len);
88 if (ret)
89 return ret;
90
Ingo Molnar07800602009-04-20 15:00:56 +020091 memcpy(sb->buf + sb->len, data, len);
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090092 return strbuf_setlen(sb, sb->len + len);
Ingo Molnar07800602009-04-20 15:00:56 +020093}
94
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090095static int strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap)
Ingo Molnar07800602009-04-20 15:00:56 +020096{
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +090097 int len, ret;
Namhyung Kimc7118362015-10-25 00:49:27 +090098 va_list ap_saved;
Ingo Molnar07800602009-04-20 15:00:56 +020099
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900100 if (!strbuf_avail(sb)) {
101 ret = strbuf_grow(sb, 64);
102 if (ret)
103 return ret;
104 }
Namhyung Kimc7118362015-10-25 00:49:27 +0900105
106 va_copy(ap_saved, ap);
Namhyung Kimf787d952012-10-23 22:44:50 +0900107 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
Ingo Molnar07800602009-04-20 15:00:56 +0200108 if (len < 0)
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900109 return len;
Ingo Molnar07800602009-04-20 15:00:56 +0200110 if (len > strbuf_avail(sb)) {
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900111 ret = strbuf_grow(sb, len);
112 if (ret)
113 return ret;
Namhyung Kimc7118362015-10-25 00:49:27 +0900114 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved);
115 va_end(ap_saved);
Ingo Molnar07800602009-04-20 15:00:56 +0200116 if (len > strbuf_avail(sb)) {
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900117 pr_debug("this should not happen, your vsnprintf is broken");
118 return -EINVAL;
Ingo Molnar07800602009-04-20 15:00:56 +0200119 }
120 }
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900121 return strbuf_setlen(sb, sb->len + len);
Ingo Molnar07800602009-04-20 15:00:56 +0200122}
123
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900124int strbuf_addf(struct strbuf *sb, const char *fmt, ...)
Namhyung Kimc7118362015-10-25 00:49:27 +0900125{
126 va_list ap;
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900127 int ret;
Namhyung Kimc7118362015-10-25 00:49:27 +0900128
129 va_start(ap, fmt);
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900130 ret = strbuf_addv(sb, fmt, ap);
Namhyung Kimc7118362015-10-25 00:49:27 +0900131 va_end(ap);
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900132 return ret;
Namhyung Kimc7118362015-10-25 00:49:27 +0900133}
134
Ingo Molnarf37a2912009-07-01 12:37:06 +0200135ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
Ingo Molnar07800602009-04-20 15:00:56 +0200136{
137 size_t oldlen = sb->len;
138 size_t oldalloc = sb->alloc;
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900139 int ret;
Ingo Molnar07800602009-04-20 15:00:56 +0200140
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900141 ret = strbuf_grow(sb, hint ? hint : 8192);
142 if (ret)
143 return ret;
144
Ingo Molnar07800602009-04-20 15:00:56 +0200145 for (;;) {
146 ssize_t cnt;
147
148 cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
149 if (cnt < 0) {
150 if (oldalloc == 0)
151 strbuf_release(sb);
152 else
153 strbuf_setlen(sb, oldlen);
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900154 return cnt;
Ingo Molnar07800602009-04-20 15:00:56 +0200155 }
156 if (!cnt)
157 break;
158 sb->len += cnt;
Masami Hiramatsu5cea57f2016-05-10 14:46:58 +0900159 ret = strbuf_grow(sb, 8192);
160 if (ret)
161 return ret;
Ingo Molnar07800602009-04-20 15:00:56 +0200162 }
163
164 sb->buf[sb->len] = '\0';
165 return sb->len - oldlen;
166}