colla/strstream.c
snarmph 59b55c7f6c added:
dir -> directory walker similar to dirent
    dirwatch -> lets you watch a directory for changes in another thread
    vec -> generic vector
2021-10-25 01:32:31 +01:00

543 lines
No EOL
14 KiB
C

#include "strstream.h"
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <math.h> // HUGE_VALF
#include "tracelog.h"
/* == INPUT STREAM ============================================ */
str_istream_t istrInit(const char *str) {
return istrInitLen(str, strlen(str));
}
str_istream_t istrInitLen(const char *str, size_t len) {
str_istream_t res;
res.start = res.cur = str;
res.size = len;
return res;
}
char istrGet(str_istream_t *ctx) {
return *ctx->cur++;
}
void istrIgnore(str_istream_t *ctx, char delim) {
size_t position = ctx->cur - ctx->start;
size_t i;
for(i = position;
i < ctx->size && *ctx->cur != delim;
++i, ++ctx->cur);
}
char istrPeek(str_istream_t *ctx) {
return *ctx->cur;
}
void istrSkip(str_istream_t *ctx, size_t n) {
size_t remaining = ctx->size - (ctx->cur - ctx->start);
if(n > remaining) {
warn("skipping more then remaining: %zu -> %zu", n, remaining);
return;
}
ctx->cur += n;
}
void istrRead(str_istream_t *ctx, char *buf, size_t len) {
size_t remaining = ctx->size - (ctx->cur - ctx->start);
if(len > remaining) {
warn("istrRead: trying to read len %zu from remaining %zu", len, remaining);
return;
}
memcpy(buf, ctx->cur, len);
ctx->cur += len;
}
size_t istrReadMax(str_istream_t *ctx, char *buf, size_t len) {
size_t remaining = ctx->size - (ctx->cur - ctx->start);
len = remaining < len ? remaining : len;
memcpy(buf, ctx->cur, len);
ctx->cur += len;
return len;
}
void istrRewind(str_istream_t *ctx) {
ctx->cur = ctx->start;
}
size_t istrTell(str_istream_t *ctx) {
return ctx->cur - ctx->start;
}
bool istrIsFinished(str_istream_t *ctx) {
return ctx->cur == (ctx->start + ctx->size + 1);
}
bool istrGetbool(str_istream_t *ctx, bool *val) {
size_t remaining = ctx->size - (ctx->cur - ctx->start);
if(strncmp(ctx->cur, "true", remaining) == 0) {
*val = true;
return true;
}
if(strncmp(ctx->cur, "false", remaining) == 0) {
*val = false;
return true;
}
return false;
}
bool istrGetu8(str_istream_t *ctx, uint8_t *val) {
char *end = NULL;
*val = (uint8_t) strtoul(ctx->cur, &end, 0);
if(ctx->cur == end) {
warn("istrGetu8: no valid conversion could be performed");
return false;
}
else if(*val == UINT8_MAX) {
warn("istrGetu8: value read is out of the range of representable values");
return false;
}
ctx->cur = end;
return true;
}
bool istrGetu16(str_istream_t *ctx, uint16_t *val) {
char *end = NULL;
*val = (uint16_t) strtoul(ctx->cur, &end, 0);
if(ctx->cur == end) {
warn("istrGetu16: no valid conversion could be performed");
return false;
}
else if(*val == UINT16_MAX) {
warn("istrGetu16: value read is out of the range of representable values");
return false;
}
ctx->cur = end;
return true;
}
bool istrGetu32(str_istream_t *ctx, uint32_t *val) {
char *end = NULL;
*val = (uint32_t) strtoul(ctx->cur, &end, 0);
if(ctx->cur == end) {
warn("istrGetu32: no valid conversion could be performed");
return false;
}
else if(*val == UINT32_MAX) {
warn("istrGetu32: value read is out of the range of representable values");
return false;
}
ctx->cur = end;
return true;
}
bool istrGetu64(str_istream_t *ctx, uint64_t *val) {
char *end = NULL;
*val = strtoull(ctx->cur, &end, 0);
if(ctx->cur == end) {
warn("istrGetu64: no valid conversion could be performed");
return false;
}
else if(*val == ULLONG_MAX) {
warn("istrGetu64: value read is out of the range of representable values");
return false;
}
ctx->cur = end;
return true;
}
bool istrGeti8(str_istream_t *ctx, int8_t *val) {
char *end = NULL;
*val = (int8_t) strtol(ctx->cur, &end, 0);
if(ctx->cur == end) {
warn("istrGeti8: no valid conversion could be performed");
return false;
}
else if(*val == INT8_MAX || *val == INT8_MIN) {
warn("istrGeti8: value read is out of the range of representable values");
return false;
}
ctx->cur = end;
return true;
}
bool istrGeti16(str_istream_t *ctx, int16_t *val) {
char *end = NULL;
*val = (int16_t) strtol(ctx->cur, &end, 0);
if(ctx->cur == end) {
warn("istrGeti16: no valid conversion could be performed");
return false;
}
else if(*val == INT16_MAX || *val == INT16_MIN) {
warn("istrGeti16: value read is out of the range of representable values");
return false;
}
ctx->cur = end;
return true;
}
bool istrGeti32(str_istream_t *ctx, int32_t *val) {
char *end = NULL;
*val = (int32_t) strtol(ctx->cur, &end, 0);
if(ctx->cur == end) {
warn("istrGeti32: no valid conversion could be performed");
return false;
}
else if(*val == INT32_MAX || *val == INT32_MIN) {
warn("istrGeti32: value read is out of the range of representable values");
return false;
}
ctx->cur = end;
return true;
}
bool istrGeti64(str_istream_t *ctx, int64_t *val) {
char *end = NULL;
*val = strtoll(ctx->cur, &end, 0);
if(ctx->cur == end) {
warn("istrGeti64: no valid conversion could be performed");
return false;
}
else if(*val == INT64_MAX || *val == INT64_MIN) {
warn("istrGeti64: value read is out of the range of representable values");
return false;
}
ctx->cur = end;
return true;
}
bool istrGetfloat(str_istream_t *ctx, float *val) {
char *end = NULL;
*val = strtof(ctx->cur, &end);
if(ctx->cur == end) {
warn("istrGetfloat: no valid conversion could be performed");
return false;
}
else if(*val == HUGE_VALF || *val == -HUGE_VALF) {
warn("istrGetfloat: value read is out of the range of representable values");
return false;
}
ctx->cur = end;
return true;
}
bool istrGetdouble(str_istream_t *ctx, double *val) {
char *end = NULL;
*val = strtod(ctx->cur, &end);
if(ctx->cur == end) {
warn("istrGetdouble: no valid conversion could be performed");
return false;
}
else if(*val == HUGE_VAL || *val == -HUGE_VAL) {
warn("istrGetdouble: value read is out of the range of representable values");
return false;
}
ctx->cur = end;
return true;
}
size_t istrGetstring(str_istream_t *ctx, char **val, char delim) {
const char *from = ctx->cur;
istrIgnore(ctx, delim);
// if it didn't actually find it, it just reached the end of the string
if(*ctx->cur != delim) {
*val = NULL;
return 0;
}
size_t len = ctx->cur - from;
*val = malloc(len + 1);
memcpy(*val, from, len);
(*val)[len] = '\0';
return len;
}
size_t istrGetstringBuf(str_istream_t *ctx, char *val, size_t len) {
size_t remaining = ctx->size - (ctx->cur - ctx->start);
len -= 1;
len = remaining < len ? remaining : len;
memcpy(val, ctx->cur, len);
val[len] = '\0';
ctx->cur += len;
return len;
}
strview_t istrGetview(str_istream_t *ctx, char delim) {
const char *from = ctx->cur;
istrIgnore(ctx, delim);
// if it didn't actually find it, it just reached the end of the string
if(*ctx->cur != delim) {
return strvInitLen(NULL, 0);
}
size_t len = ctx->cur - from;
return strvInitLen(from, len);
}
strview_t istrGetviewLen(str_istream_t *ctx, size_t off, size_t len) {
size_t remaining = ctx->size - (ctx->cur - ctx->start) - off;
if(len > remaining) len = remaining;
return strvInitLen(ctx->cur + off, len);
}
/* == OUTPUT STREAM =========================================== */
static void _ostrRealloc(str_ostream_t *ctx, size_t needed) {
ctx->allocated = (ctx->allocated * 2) + needed;
ctx->buf = realloc(ctx->buf, ctx->allocated);
}
str_ostream_t ostrInit() {
return ostrInitLen(1);
}
str_ostream_t ostrInitLen(size_t initial_alloc) {
str_ostream_t stream;
stream.buf = calloc(initial_alloc, 1);
stream.size = 0;
stream.allocated = initial_alloc;
return stream;
}
str_ostream_t ostrInitStr(const char *cstr, size_t len) {
str_ostream_t stream;
stream.buf = malloc(len + 1);
memcpy(stream.buf, cstr, len);
stream.size = len;
stream.allocated = len + 1;
return stream;
}
void ostrFree(str_ostream_t *ctx) {
free(ctx->buf);
ctx->buf = NULL;
ctx->size = 0;
ctx->allocated = 0;
}
void ostrClear(str_ostream_t *ctx) {
ctx->size = 0;
}
str_t ostrMove(str_ostream_t *ctx) {
str_t str = ostrAsStr(ctx);
*ctx = (str_ostream_t){0};
return str;
}
char ostrBack(str_ostream_t *ctx) {
if(ctx->size == 0) return '\0';
return ctx->buf[ctx->size - 1];
}
str_t ostrAsStr(str_ostream_t *ctx) {
return (str_t) {
.buf = ctx->buf,
.len = ctx->size
};
}
strview_t ostrAsView(str_ostream_t *ctx) {
return (strview_t) {
.buf = ctx->buf,
.len = ctx->size
};
}
void ostrReplace(str_ostream_t *ctx, char from, char to) {
for(size_t i = 0; i < ctx->size; ++i) {
if(ctx->buf[i] == from) {
ctx->buf[i] = to;
}
}
}
void ostrPrintf(str_ostream_t *ctx, const char *fmt, ...) {
va_list va;
va_start(va, fmt);
// vsnprintf returns the length of the formatted string, even if truncated
// we use this to get the actual length of the formatted string
char buf[1];
va_list vtemp;
va_copy(vtemp, va);
int len = vsnprintf(buf, sizeof(buf), fmt, vtemp);
va_end(vtemp);
if(len < 0) {
err("couldn't format string \"%s\"", fmt);
goto error;
}
size_t remaining = ctx->allocated - ctx->size;
if(remaining < (size_t)len) {
_ostrRealloc(ctx, len + 1);
remaining = ctx->allocated - ctx->size;
}
// actual formatting here
len = vsnprintf(ctx->buf + ctx->size, remaining, fmt, va);
if(len < 0) {
err("couldn't format stringh \"%s\"", fmt);
goto error;
}
ctx->size += len;
error:
va_end(va);
}
#define APPEND_BUF_LEN 20
void ostrPutc(str_ostream_t *ctx, char c) {
ostrAppendchar(ctx, c);
}
void ostrAppendbool(str_ostream_t *ctx, bool val) {
ostrAppendview(ctx, strvInit(val ? "true" : "false"));
}
void ostrAppendchar(str_ostream_t *ctx, char val) {
if(ctx->size >= ctx->allocated) {
_ostrRealloc(ctx, 1);
}
ctx->buf[ctx->size++] = val;
ctx->buf[ctx->size] = '\0';
}
void ostrAppendu8(str_ostream_t *ctx, uint8_t val) {
char buf[APPEND_BUF_LEN];
int len = snprintf(buf, sizeof(buf), "%hhu", val);
if(len <= 0) {
err("ostrAppendu8: couldn't write %hhu", val);
return;
}
ostrAppendview(ctx, strvInitLen(buf, len));
}
void ostrAppendu16(str_ostream_t *ctx, uint16_t val) {
char buf[APPEND_BUF_LEN];
int len = snprintf(buf, sizeof(buf), "%hu", val);
if(len <= 0) {
err("ostrAppendu16: couldn't write %hu", val);
return;
}
ostrAppendview(ctx, strvInitLen(buf, len));
}
void ostrAppendu32(str_ostream_t *ctx, uint32_t val) {
char buf[APPEND_BUF_LEN];
int len = snprintf(buf, sizeof(buf), "%u", val);
if(len <= 0) {
err("ostrAppendu32: couldn't write %u", val);
return;
}
ostrAppendview(ctx, strvInitLen(buf, len));
}
void ostrAppendu64(str_ostream_t *ctx, uint64_t val) {
char buf[APPEND_BUF_LEN];
#if _WIN32
int len = snprintf(buf, sizeof(buf), "%llu", val);
#else
int len = snprintf(buf, sizeof(buf), "%lu", val);
#endif
if(len <= 0) {
err("ostrAppendu64: couldn't write %lu", val);
return;
}
ostrAppendview(ctx, strvInitLen(buf, len));
}
void ostrAppendi8(str_ostream_t *ctx, int8_t val) {
char buf[APPEND_BUF_LEN];
int len = snprintf(buf, sizeof(buf), "%hhi", val);
if(len <= 0) {
err("ostrAppendi8: couldn't write %hhi", val);
return;
}
ostrAppendview(ctx, strvInitLen(buf, len));
}
void ostrAppendi16(str_ostream_t *ctx, int16_t val) {
char buf[APPEND_BUF_LEN];
int len = snprintf(buf, sizeof(buf), "%hi", val);
if(len <= 0) {
err("ostrAppendi16: couldn't write %hi", val);
return;
}
ostrAppendview(ctx, strvInitLen(buf, len));
}
void ostrAppendi32(str_ostream_t *ctx, int32_t val) {
char buf[APPEND_BUF_LEN];
int len = snprintf(buf, sizeof(buf), "%i", val);
if(len <= 0) {
err("ostrAppendi32: couldn't write %i", val);
return;
}
ostrAppendview(ctx, strvInitLen(buf, len));
}
void ostrAppendi64(str_ostream_t *ctx, int64_t val) {
char buf[APPEND_BUF_LEN];
#if _WIN32
int len = snprintf(buf, sizeof(buf), "%lli", val);
#else
int len = snprintf(buf, sizeof(buf), "%li", val);
#endif
if(len <= 0) {
err("ostrAppendi64: couldn't write %li", val);
return;
}
ostrAppendview(ctx, strvInitLen(buf, len));
}
void ostrAppendfloat(str_ostream_t *ctx, float val) {
char buf[APPEND_BUF_LEN * 3];
int len = snprintf(buf, sizeof(buf), "%g", (double)val);
if(len <= 0) {
err("ostrAppendfloat: couldn't write %g", (double)val);
return;
}
ostrAppendview(ctx, strvInitLen(buf, len));
}
void ostrAppenddouble(str_ostream_t *ctx, double val) {
char buf[APPEND_BUF_LEN * 3];
int len = snprintf(buf, sizeof(buf), "%g", val);
if(len <= 0) {
err("ostrAppenddouble: couldn't write %g", val);
return;
}
ostrAppendview(ctx, strvInitLen(buf, len));
}
void ostrAppendview(str_ostream_t *ctx, strview_t view) {
if((ctx->allocated - ctx->size) < view.len) {
_ostrRealloc(ctx, view.len + 1);
}
memcpy(ctx->buf + ctx->size, view.buf, view.len);
ctx->size += view.len;
ctx->buf[ctx->size] = '\0';
}