162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef __PERF_STRBUF_H
362306a36Sopenharmony_ci#define __PERF_STRBUF_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci * Strbuf's can be use in many ways: as a byte array, or to store arbitrary
762306a36Sopenharmony_ci * long, overflow safe strings.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Strbufs has some invariants that are very important to keep in mind:
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * 1. the ->buf member is always malloc-ed, hence strbuf's can be used to
1262306a36Sopenharmony_ci *    build complex strings/buffers whose final size isn't easily known.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *    It is NOT legal to copy the ->buf pointer away.
1562306a36Sopenharmony_ci *    `strbuf_detach' is the operation that detaches a buffer from its shell
1662306a36Sopenharmony_ci *    while keeping the shell valid wrt its invariants.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * 2. the ->buf member is a byte array that has at least ->len + 1 bytes
1962306a36Sopenharmony_ci *    allocated. The extra byte is used to store a '\0', allowing the ->buf
2062306a36Sopenharmony_ci *    member to be a valid C-string. Every strbuf function ensure this
2162306a36Sopenharmony_ci *    invariant is preserved.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci *    Note that it is OK to "play" with the buffer directly if you work it
2462306a36Sopenharmony_ci *    that way:
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci *    strbuf_grow(sb, SOME_SIZE);
2762306a36Sopenharmony_ci *       ... Here, the memory array starting at sb->buf, and of length
2862306a36Sopenharmony_ci *       ... strbuf_avail(sb) is all yours, and you are sure that
2962306a36Sopenharmony_ci *       ... strbuf_avail(sb) is at least SOME_SIZE.
3062306a36Sopenharmony_ci *    strbuf_setlen(sb, sb->len + SOME_OTHER_SIZE);
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci *    Of course, SOME_OTHER_SIZE must be smaller or equal to strbuf_avail(sb).
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci *    Doing so is safe, though if it has to be done in many places, adding the
3562306a36Sopenharmony_ci *    missing API to the strbuf module is the way to go.
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci *    XXX: do _not_ assume that the area that is yours is of size ->alloc - 1
3862306a36Sopenharmony_ci *         even if it's true in the current implementation. Alloc is somehow a
3962306a36Sopenharmony_ci *         "private" member that should not be messed with.
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#include <assert.h>
4362306a36Sopenharmony_ci#include <stdarg.h>
4462306a36Sopenharmony_ci#include <stddef.h>
4562306a36Sopenharmony_ci#include <string.h>
4662306a36Sopenharmony_ci#include <linux/compiler.h>
4762306a36Sopenharmony_ci#include <sys/types.h>
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ciextern char strbuf_slopbuf[];
5062306a36Sopenharmony_cistruct strbuf {
5162306a36Sopenharmony_ci	size_t alloc;
5262306a36Sopenharmony_ci	size_t len;
5362306a36Sopenharmony_ci	char *buf;
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#define STRBUF_INIT  { 0, 0, strbuf_slopbuf }
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/*----- strbuf life cycle -----*/
5962306a36Sopenharmony_ciint strbuf_init(struct strbuf *buf, ssize_t hint);
6062306a36Sopenharmony_civoid strbuf_release(struct strbuf *buf);
6162306a36Sopenharmony_cichar *strbuf_detach(struct strbuf *buf, size_t *);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/*----- strbuf size related -----*/
6462306a36Sopenharmony_cistatic inline ssize_t strbuf_avail(const struct strbuf *sb) {
6562306a36Sopenharmony_ci	return sb->alloc ? sb->alloc - sb->len - 1 : 0;
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ciint strbuf_grow(struct strbuf *buf, size_t);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic inline int strbuf_setlen(struct strbuf *sb, size_t len) {
7162306a36Sopenharmony_ci	if (!sb->alloc) {
7262306a36Sopenharmony_ci		int ret = strbuf_grow(sb, 0);
7362306a36Sopenharmony_ci		if (ret)
7462306a36Sopenharmony_ci			return ret;
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci	assert(len < sb->alloc);
7762306a36Sopenharmony_ci	sb->len = len;
7862306a36Sopenharmony_ci	sb->buf[len] = '\0';
7962306a36Sopenharmony_ci	return 0;
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/*----- add data in your buffer -----*/
8362306a36Sopenharmony_ciint strbuf_addch(struct strbuf *sb, int c);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ciint strbuf_add(struct strbuf *buf, const void *, size_t);
8662306a36Sopenharmony_cistatic inline int strbuf_addstr(struct strbuf *sb, const char *s) {
8762306a36Sopenharmony_ci	return strbuf_add(sb, s, strlen(s));
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ciint strbuf_addf(struct strbuf *sb, const char *fmt, ...) __printf(2, 3);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/* XXX: if read fails, any partial read is undone */
9362306a36Sopenharmony_cissize_t strbuf_read(struct strbuf *, int fd, ssize_t hint);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#endif /* __PERF_STRBUF_H */
96