1 // SPDX-License-Identifier: GPL-2.0
4 #include <linux/kernel.h>
8 * Used as the default ->buf value, so that people can always assume
9 * buf is non NULL and ->buf is NUL terminated even for a freshly
12 char strbuf_slopbuf
[1];
14 int strbuf_init(struct strbuf
*sb
, ssize_t hint
)
16 sb
->alloc
= sb
->len
= 0;
17 sb
->buf
= strbuf_slopbuf
;
19 return strbuf_grow(sb
, hint
);
23 void strbuf_release(struct strbuf
*sb
)
31 char *strbuf_detach(struct strbuf
*sb
, size_t *sz
)
33 char *res
= sb
->alloc
? sb
->buf
: NULL
;
40 int strbuf_grow(struct strbuf
*sb
, size_t extra
)
43 size_t nr
= sb
->len
+ extra
+ 1;
51 if (alloc_nr(sb
->alloc
) > nr
)
52 nr
= alloc_nr(sb
->alloc
);
55 * Note that sb->buf == strbuf_slopbuf if sb->alloc == 0, and it is
56 * a static variable. Thus we have to avoid passing it to realloc.
58 buf
= realloc(sb
->alloc
? sb
->buf
: NULL
, nr
* sizeof(*buf
));
67 int strbuf_addch(struct strbuf
*sb
, int c
)
69 int ret
= strbuf_grow(sb
, 1);
73 sb
->buf
[sb
->len
++] = c
;
74 sb
->buf
[sb
->len
] = '\0';
78 int strbuf_add(struct strbuf
*sb
, const void *data
, size_t len
)
80 int ret
= strbuf_grow(sb
, len
);
84 memcpy(sb
->buf
+ sb
->len
, data
, len
);
85 return strbuf_setlen(sb
, sb
->len
+ len
);
88 static int strbuf_addv(struct strbuf
*sb
, const char *fmt
, va_list ap
)
93 if (!strbuf_avail(sb
)) {
94 ret
= strbuf_grow(sb
, 64);
99 va_copy(ap_saved
, ap
);
100 len
= vsnprintf(sb
->buf
+ sb
->len
, sb
->alloc
- sb
->len
, fmt
, ap
);
105 if (len
> strbuf_avail(sb
)) {
106 ret
= strbuf_grow(sb
, len
);
111 len
= vsnprintf(sb
->buf
+ sb
->len
, sb
->alloc
- sb
->len
, fmt
, ap_saved
);
113 if (len
> strbuf_avail(sb
)) {
114 pr_debug("this should not happen, your vsnprintf is broken");
120 return strbuf_setlen(sb
, sb
->len
+ len
);
123 int strbuf_addf(struct strbuf
*sb
, const char *fmt
, ...)
129 ret
= strbuf_addv(sb
, fmt
, ap
);
134 ssize_t
strbuf_read(struct strbuf
*sb
, int fd
, ssize_t hint
)
136 size_t oldlen
= sb
->len
;
137 size_t oldalloc
= sb
->alloc
;
140 ret
= strbuf_grow(sb
, hint
? hint
: 8192);
147 cnt
= read(fd
, sb
->buf
+ sb
->len
, sb
->alloc
- sb
->len
- 1);
152 strbuf_setlen(sb
, oldlen
);
158 ret
= strbuf_grow(sb
, 8192);
163 sb
->buf
[sb
->len
] = '\0';
164 return sb
->len
- oldlen
;