#ifndef LLSH_UTIL_H #define LLSH_UTIL_H #include #include #include #include /* ------------------------------------------------------------------ */ /* Growable byte buffer (NUL-terminated on steal) */ /* ------------------------------------------------------------------ */ typedef struct { char *data; size_t len; size_t cap; } xbuf; void xbuf_init(xbuf *b); void xbuf_free(xbuf *b); void xbuf_reset(xbuf *b); void xbuf_put(xbuf *b, const char *s); void xbuf_putn(xbuf *b, const char *s, size_t n); void xbuf_push(xbuf *b, char c); int xbuf_fmt(xbuf *b, const char *fmt, ...); char *xbuf_steal(xbuf *b); /* NUL-terminated string; buffer reset */ /* curl write callback that appends to an xbuf (pass `&buf` as the userdata). */ size_t xbuf_curl_write(char *data, size_t sz, size_t nm, void *ud); /* ------------------------------------------------------------------ */ /* Strings */ /* ------------------------------------------------------------------ */ char *xstrdup(const char *s); char *xstrndup(const char *s, size_t n); int xstreq(const char *a, const char *b); /* Trim ASCII whitespace from [s, s+n): returns a pointer into s and sets * *out_len (no copy). */ const char *xtrim_span(const char *s, size_t n, size_t *out_len); /* Rust str::trim whitespace set. */ bool utf8_is_ws(uint32_t cp); char *xstr_ltrim_dup(const char *s); char *xstr_rtrim_dup(const char *s); char *xstr_trim_dup(const char *s); char *xstrjoin2(const char *a, const char *b); #include char *xvsnprintf(const char *fmt, va_list ap); /* Variadic convenience wrapper: freshly allocated, printf-style. */ char *xstrfmt(const char *fmt, ...); /* UTF-8 aware helpers */ size_t utf8_len(const char *s); /* codepoint count */ size_t utf8_byte_len(const char *s, size_t max_points); const char *utf8_next(const char *p, const char *end, size_t *cp); size_t utf8_display_width(const char *s); /* CJK fullwidth aware */ bool utf8_is_valid(const char *s, size_t len); /* ------------------------------------------------------------------ */ /* String list */ /* ------------------------------------------------------------------ */ typedef struct { char **items; size_t len; size_t cap; } strlist; void sl_init(strlist *l); void sl_free(strlist *l); void sl_push(strlist *l, char *owned); /* takes ownership */ void sl_push_copy(strlist *l, const char *s); char *sl_pop_front(strlist *l); /* NULL when empty */ /* ------------------------------------------------------------------ */ /* Files */ /* ------------------------------------------------------------------ */ int read_file_to_buf(const char *path, char **out, size_t *out_len, char **err); int read_file_to_buf_limited(const char *path, size_t max_bytes, char **out, size_t *out_len, char **err); int write_file_from_buf(const char *path, const char *data, size_t len, char **err); bool path_exists(const char *path); /* Create `path` and any missing parent directories (0755). 0 on success. */ int mkdir_p(const char *path); /* Expand a leading `~` / `~/...` against $HOME (like a shell). * Returns a freshly allocated string. */ char *expand_tilde(const char *s); /* Resolve the system CA certificate bundle to pass as CURLOPT_CAINFO. * The statically linked vendored OpenSSL has no usable default cert path * (its --prefix points into the vendor tree, where no bundle is installed), * so without this libcurl cannot verify any TLS peer. Honors * $SSL_CERT_FILE / $CURL_CA_BUNDLE, then probes the usual distro locations. * Returns NULL when nothing readable is found. */ const char *llsh_ca_bundle(void); /* ------------------------------------------------------------------ */ /* Misc */ /* ------------------------------------------------------------------ */ double now_secs(void); void sleep_ms(unsigned long ms); void *xmalloc(size_t n); void *xrealloc(void *p, size_t n); char *itoa_dup(long long v); /* Format a double the way Rust's Display does for common values */ char *dtoa_dup(double v); #endif