#ifndef CST_UTIL_H #define CST_UTIL_H #include #include #ifdef __cplusplus extern "C" { #endif typedef struct { char *buf; size_t len; size_t cap; } cst_buf_t; int cst_buf_append(cst_buf_t *b, const char *s, size_t n); int cst_buf_puts(cst_buf_t *b, const char *s); int cst_buf_printf(cst_buf_t *b, const char *fmt, ...); void cst_buf_free(cst_buf_t *b); /* Take ownership of the NUL-terminated buffer (never NULL on success). */ char *cst_buf_steal(cst_buf_t *b); /* Largest n' <= n that does not split a UTF-8 sequence of s. */ size_t cst_utf8_floor(const char *s, size_t n); /* Copy s[0..n) replacing invalid UTF-8 with '?'. malloc'd, NUL-terminated. */ char *cst_utf8_sanitize(const char *s, size_t n, size_t *out_len); int cst_utf8_valid(const char *s, size_t n); /* Re-chunks a byte stream so no piece ends inside a UTF-8 sequence: the * incomplete tail (at most 3 bytes) waits in the hold for the next feed. */ typedef struct { char b[4]; size_t n; } cst_utf8_hold_t; /* Returns the complete prefix of hold+s[0..n) (malloc'd, NUL-terminated, * *out_len may be 0), or NULL on OOM. */ char *cst_utf8_hold_feed(cst_utf8_hold_t *h, const char *s, size_t n, size_t *out_len); /* Text files may start with a UTF-8 BOM (Windows editors): its length (0/3), * and an in-place strip of the NUL-terminated s (*len updated when given). */ size_t cst_bom_len(const char *s, size_t n); void cst_strip_bom(char *s, size_t *len); /* Line endings: "\r\n" -> "\n" in place (returns the new length); whether * every line of s ends in "\r\n" (and at least one does); and a malloc'd * copy of s with bare "\n" turned into "\r\n" when crlf, its BOM dropped and * a BOM added when bom. Edits keep a Windows file's style with these. */ size_t cst_crlf_to_lf(char *s, size_t n); int cst_text_is_crlf(const char *s, size_t n); char *cst_text_restyle(const char *s, size_t n, int crlf, int bom, size_t *out_len); /* fnmatch(3) without FNM_PATHNAME ('*' also crosses '/'): * ? [..] [!..] * [[:class:]] and backslash escapes over UTF-8 code points. Returns 0 on a * match. Always case-insensitive on Windows. */ #define CST_FNM_PERIOD 1 /* a leading '.' must be matched literally */ #define CST_FNM_CASEFOLD 2 int cst_fnmatch(const char *pat, const char *str, int flags); uint64_t cst_fnv1a64(uint64_t h, const void *data, size_t n); #define CST_FNV_INIT 1469598103934665603ULL #ifdef __cplusplus } #endif #endif