rutile/compiler/nstr.c
2025-01-30 17:59:26 -03:00

76 lines
1.7 KiB
C

#include <string.h>
#include <stdlib.h>
#include "pre.h"
int
vsnprintf(char *, unsigned long, const char *, va_list);
/* Creates a `Str` from a buffer of size `len` */
Str
Str_from_buf(u8 *buf, isize len)
{
/* If this triggers an OOB, its because the code that created the string was
* broken anyways. ASan will catch it. */
Assert(buf[len] == '\0');
return (Str){ buf, len };
}
/* "Converts" a `Str` into a C string. Since `Str` are meant to be
* null-terminated already, no conversion is made, but ensures that the
* null terminator is present. */
char *
Str_to_c(Str s)
{
if (s.len == 0 || s.s == nil)
return nil;
Assert(s.s[s.len] == '\0');
return (char *)s.s;
}
/* Returns `true` if both strings are equal. */
bool
Str_equal(Str s1, Str s2)
{
/* because passing nil to mem* is UB even if size == 0... */
return (s1.len == s2.len) && (s1.len == 0 || memcmp(s1.s, s2.s, s1.len) == 0);
}
/* Heaps allocates a new `Str` of size `len`, with contents from `data` if it is
* not `nil`.*/
Str
Str_new(const u8 *data, isize len)
{
Assert(len >= 0);
Str s;
s.s = calloc(len + 1, sizeof(*s.s));
s.len = len;
if (data != nil) {
memcpy(s.s, data, len);
s.s[len + 1] = '\0'; /* ensure */
}
return s;
}
/* Returns a formatted string (heap allocated) of the exact required size. */
Str
Strafmt(const char *fmt, ...)
{
Str s = {0};
va_list args;
va_start(args, fmt);
/* Calculate buffer size required to hold the formatted string */
int reqs = vsnprintf(nil, 0, fmt, args);
va_end(args);
if (reqs < 0)
return s;
s = Str_new(nil, reqs);
va_start(args, fmt); /* `vsnprintf` touched the arg list, reinitialize it */
/* the nil terminator is guaranteed by `Str_new` */
vsnprintf((char *)s.s, s.len + 1, fmt, args);
va_end(args);
return s;
}