1 // SPDX-License-Identifier: GPL-2.0
5 #include <linux/kernel.h>
6 #include <linux/string.h>
7 #include <linux/zalloc.h>
14 * Used as the default ->buf value, so that people can always assume
15 * buf is non NULL and ->buf is NUL terminated even for a freshly
18 char strbuf_slopbuf
[1];
20 int strbuf_init(struct strbuf
*sb
, ssize_t hint
)
22 sb
->alloc
= sb
->len
= 0;
23 sb
->buf
= strbuf_slopbuf
;
25 return strbuf_grow(sb
, hint
);
29 void strbuf_release(struct strbuf
*sb
)
37 char *strbuf_detach(struct strbuf
*sb
, size_t *sz
)
39 char *res
= sb
->alloc
? sb
->buf
: NULL
;
46 int strbuf_grow(struct strbuf
*sb
, size_t extra
)
49 size_t nr
= sb
->len
+ extra
+ 1;
57 if (alloc_nr(sb
->alloc
) > nr
)
58 nr
= alloc_nr(sb
->alloc
);
61 * Note that sb->buf == strbuf_slopbuf if sb->alloc == 0, and it is
62 * a static variable. Thus we have to avoid passing it to realloc.
64 buf
= realloc(sb
->alloc
? sb
->buf
: NULL
, nr
* sizeof(*buf
));
73 int strbuf_addch(struct strbuf
*sb
, int c
)
75 int ret
= strbuf_grow(sb
, 1);
79 sb
->buf
[sb
->len
++] = c
;
80 sb
->buf
[sb
->len
] = '\0';
84 int strbuf_add(struct strbuf
*sb
, const void *data
, size_t len
)
86 int ret
= strbuf_grow(sb
, len
);
90 memcpy(sb
->buf
+ sb
->len
, data
, len
);
91 return strbuf_setlen(sb
, sb
->len
+ len
);
94 static int strbuf_addv(struct strbuf
*sb
, const char *fmt
, va_list ap
)
99 if (!strbuf_avail(sb
)) {
100 ret
= strbuf_grow(sb
, 64);
105 va_copy(ap_saved
, ap
);
106 len
= vsnprintf(sb
->buf
+ sb
->len
, sb
->alloc
- sb
->len
, fmt
, ap
);
111 if (len
> strbuf_avail(sb
)) {
112 ret
= strbuf_grow(sb
, len
);
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");
125 return strbuf_setlen(sb
, sb
->len
+ len
);
128 int strbuf_addf(struct strbuf
*sb
, const char *fmt
, ...)
134 ret
= strbuf_addv(sb
, fmt
, ap
);
139 ssize_t
strbuf_read(struct strbuf
*sb
, int fd
, ssize_t hint
)
141 size_t oldlen
= sb
->len
;
142 size_t oldalloc
= sb
->alloc
;
145 ret
= strbuf_grow(sb
, hint
? hint
: 8192);
152 cnt
= read(fd
, sb
->buf
+ sb
->len
, sb
->alloc
- sb
->len
- 1);
157 strbuf_setlen(sb
, oldlen
);
163 ret
= strbuf_grow(sb
, 8192);
168 sb
->buf
[sb
->len
] = '\0';
169 return sb
->len
- oldlen
;