18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef __PERF_STRBUF_H
38c2ecf20Sopenharmony_ci#define __PERF_STRBUF_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci/*
68c2ecf20Sopenharmony_ci * Strbuf's can be use in many ways: as a byte array, or to store arbitrary
78c2ecf20Sopenharmony_ci * long, overflow safe strings.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Strbufs has some invariants that are very important to keep in mind:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * 1. the ->buf member is always malloc-ed, hence strbuf's can be used to
128c2ecf20Sopenharmony_ci *    build complex strings/buffers whose final size isn't easily known.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *    It is NOT legal to copy the ->buf pointer away.
158c2ecf20Sopenharmony_ci *    `strbuf_detach' is the operation that detachs a buffer from its shell
168c2ecf20Sopenharmony_ci *    while keeping the shell valid wrt its invariants.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * 2. the ->buf member is a byte array that has at least ->len + 1 bytes
198c2ecf20Sopenharmony_ci *    allocated. The extra byte is used to store a '\0', allowing the ->buf
208c2ecf20Sopenharmony_ci *    member to be a valid C-string. Every strbuf function ensure this
218c2ecf20Sopenharmony_ci *    invariant is preserved.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci *    Note that it is OK to "play" with the buffer directly if you work it
248c2ecf20Sopenharmony_ci *    that way:
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci *    strbuf_grow(sb, SOME_SIZE);
278c2ecf20Sopenharmony_ci *       ... Here, the memory array starting at sb->buf, and of length
288c2ecf20Sopenharmony_ci *       ... strbuf_avail(sb) is all yours, and you are sure that
298c2ecf20Sopenharmony_ci *       ... strbuf_avail(sb) is at least SOME_SIZE.
308c2ecf20Sopenharmony_ci *    strbuf_setlen(sb, sb->len + SOME_OTHER_SIZE);
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci *    Of course, SOME_OTHER_SIZE must be smaller or equal to strbuf_avail(sb).
338c2ecf20Sopenharmony_ci *
348c2ecf20Sopenharmony_ci *    Doing so is safe, though if it has to be done in many places, adding the
358c2ecf20Sopenharmony_ci *    missing API to the strbuf module is the way to go.
368c2ecf20Sopenharmony_ci *
378c2ecf20Sopenharmony_ci *    XXX: do _not_ assume that the area that is yours is of size ->alloc - 1
388c2ecf20Sopenharmony_ci *         even if it's true in the current implementation. Alloc is somehow a
398c2ecf20Sopenharmony_ci *         "private" member that should not be messed with.
408c2ecf20Sopenharmony_ci */
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#include <assert.h>
438c2ecf20Sopenharmony_ci#include <stdarg.h>
448c2ecf20Sopenharmony_ci#include <stddef.h>
458c2ecf20Sopenharmony_ci#include <string.h>
468c2ecf20Sopenharmony_ci#include <linux/compiler.h>
478c2ecf20Sopenharmony_ci#include <sys/types.h>
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ciextern char strbuf_slopbuf[];
508c2ecf20Sopenharmony_cistruct strbuf {
518c2ecf20Sopenharmony_ci	size_t alloc;
528c2ecf20Sopenharmony_ci	size_t len;
538c2ecf20Sopenharmony_ci	char *buf;
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define STRBUF_INIT  { 0, 0, strbuf_slopbuf }
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/*----- strbuf life cycle -----*/
598c2ecf20Sopenharmony_ciint strbuf_init(struct strbuf *buf, ssize_t hint);
608c2ecf20Sopenharmony_civoid strbuf_release(struct strbuf *buf);
618c2ecf20Sopenharmony_cichar *strbuf_detach(struct strbuf *buf, size_t *);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/*----- strbuf size related -----*/
648c2ecf20Sopenharmony_cistatic inline ssize_t strbuf_avail(const struct strbuf *sb) {
658c2ecf20Sopenharmony_ci	return sb->alloc ? sb->alloc - sb->len - 1 : 0;
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ciint strbuf_grow(struct strbuf *buf, size_t);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic inline int strbuf_setlen(struct strbuf *sb, size_t len) {
718c2ecf20Sopenharmony_ci	if (!sb->alloc) {
728c2ecf20Sopenharmony_ci		int ret = strbuf_grow(sb, 0);
738c2ecf20Sopenharmony_ci		if (ret)
748c2ecf20Sopenharmony_ci			return ret;
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci	assert(len < sb->alloc);
778c2ecf20Sopenharmony_ci	sb->len = len;
788c2ecf20Sopenharmony_ci	sb->buf[len] = '\0';
798c2ecf20Sopenharmony_ci	return 0;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci/*----- add data in your buffer -----*/
838c2ecf20Sopenharmony_ciint strbuf_addch(struct strbuf *sb, int c);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ciint strbuf_add(struct strbuf *buf, const void *, size_t);
868c2ecf20Sopenharmony_cistatic inline int strbuf_addstr(struct strbuf *sb, const char *s) {
878c2ecf20Sopenharmony_ci	return strbuf_add(sb, s, strlen(s));
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ciint strbuf_addf(struct strbuf *sb, const char *fmt, ...) __printf(2, 3);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci/* XXX: if read fails, any partial read is undone */
938c2ecf20Sopenharmony_cissize_t strbuf_read(struct strbuf *, int fd, ssize_t hint);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci#endif /* __PERF_STRBUF_H */
96