skip to content
==> include/mesh/text.h <==
1/* @ajax/mesh-text: growable strings, printf into them, and the Rust
2 * formatting the Rust implementation's messages use ({:?} of strings and
3 * floats, trim), so ported error messages are byte-for-byte the same.
4 *
5 * Allocation never fails visibly: out of memory aborts. */
6#ifndef MESH_TEXT_H
7#define MESH_TEXT_H
8
9#include <stdarg.h>
10#include <stdbool.h>
11#include <stddef.h>
12#include <stdint.h>
13
14typedef struct {
15    char *data; /* NUL-terminated once anything was written; NULL when empty */
16    size_t len, cap;
17} mesh_text;
18
19void *mesh_alloc(size_t n);             /* zeroed */
20void *mesh_realloc(void *p, size_t n);
21char *mesh_strdup(const char *s);
22char *mesh_strndup(const char *s, size_t n);
23char *mesh_fmt(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
24char *mesh_vfmt(const char *fmt, va_list ap);
25
26void mesh_text_putn(mesh_text *t, const char *s, size_t n);
27void mesh_text_puts(mesh_text *t, const char *s);
28void mesh_text_putc(mesh_text *t, char c);
29void mesh_text_printf(mesh_text *t, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
30void mesh_text_vprintf(mesh_text *t, const char *fmt, va_list ap);
31const char *mesh_text_str(mesh_text *t); /* "" when empty */
32char *mesh_text_take(mesh_text *t);      /* the string (caller frees); t is empty after */
33void mesh_text_clear(mesh_text *t);
34void mesh_text_free(mesh_text *t);
35
36/* Sets *err (when err is not NULL) to a new formatted message, freeing any
37 * old one. Returns false, so `return mesh_errf(err, ...)` reads naturally. */
38bool mesh_errf(char **err, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
39/* Replaces *err with prefix + *err (e.g. "manifest: " + why). */
40void mesh_err_prefix(char **err, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
41
42/* Rust's `{:?}` of a str: quoted, with \" \\ \n \r \t \0 and \u{..} escapes. */
43void mesh_text_debug_str(mesh_text *t, const char *s, size_t n);
44char *mesh_debug_str(const char *s); /* NUL-terminated input */
45/* Rust's `{:?}` of an f64 (shortest round-trip digits; "2.0", "1e16", "1.5e-7", "NaN", "inf"). */
46void mesh_text_debug_f64(mesh_text *t, double v);
47/* Rust's `{:?}` of an f32. */
48void mesh_text_debug_f32(mesh_text *t, float v);
49
50/* Rust's char::is_whitespace on UTF-8, and str::trim / trim_start / trim_end:
51 * the result is a (pointer, length) window into s. */
52size_t mesh_utf8_ws_len(const char *s, size_t n); /* bytes of one leading whitespace char, 0 if none */
53void mesh_trim(const char **s, size_t *n);
54void mesh_trim_start(const char **s, size_t *n);
55void mesh_trim_end(const char **s, size_t *n);
56
57/* Rust's u32::from_str (and from_str_radix 16): an optional '+', digits only,
58 * no overflow. */
59bool mesh_parse_u32(const char *s, size_t n, unsigned radix, uint32_t *out);
60bool mesh_parse_u64(const char *s, size_t n, unsigned radix, uint64_t *out);
61/* Rust's f64::from_str: [+-]? (inf|infinity|nan, any case | digits[.digits][e[+-]digits] | .digits[...]). */
62bool mesh_parse_f64(const char *s, size_t n, double *out);
63
64#endif