futhark-0.26.3: rts/c/util.h
// Start of util.h.
//
// Various helper functions that are useful in all generated C code.
#include <errno.h>
#include <string.h>
static const char *fut_progname = "(embedded Futhark)";
static void futhark_panic(int eval, const char *fmt, ...) __attribute__((noreturn));
static char* msgprintf(const char *s, ...);
static void* slurp_file(const char *filename, size_t *size);
static int dump_file(const char *file, const void *buf, size_t n);
struct str_builder;
static void str_builder_init(struct str_builder *b);
static void str_builder(struct str_builder *b, const char *s, ...);
static char *strclone(const char *str);
static void futhark_panic(int eval, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s: ", fut_progname);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(eval);
}
// For generating arbitrary-sized error messages. It is the callers
// responsibility to free the buffer at some point.
static char* msgprintf(const char *s, ...) {
va_list vl;
va_start(vl, s);
size_t needed = 1 + (size_t)vsnprintf(NULL, 0, s, vl);
char *buffer = (char*) malloc(needed);
va_start(vl, s); // Must re-init.
vsnprintf(buffer, needed, s, vl);
return buffer;
}
static inline void check_err(int errval, int sets_errno, const char *fun, int line,
const char *msg, ...) {
if (errval) {
char errnum[10];
va_list vl;
va_start(vl, msg);
fprintf(stderr, "ERROR: ");
vfprintf(stderr, msg, vl);
fprintf(stderr, " in %s() at line %d with error code %s\n",
fun, line,
sets_errno ? strerror(errno) : errnum);
exit(errval);
}
}
#define CHECK_ERR(err, ...) check_err(err, 0, __func__, __LINE__, __VA_ARGS__)
#define CHECK_ERRNO(err, ...) check_err(err, 1, __func__, __LINE__, __VA_ARGS__)
// Read the rest of an open file into a NUL-terminated string; returns
// NULL on error.
static void* fslurp_file(FILE *f, size_t *size) {
off_t start = ftello(f);
fseeko(f, 0, SEEK_END);
off_t src_size = ftello(f)-start;
fseeko(f, start, SEEK_SET);
unsigned char *s = (unsigned char*) malloc((size_t)src_size + 1);
if (fread(s, 1, (size_t)src_size, f) != (size_t)src_size) {
free(s);
s = NULL;
} else {
s[src_size] = '\0';
}
if (size) {
*size = (size_t)src_size;
}
return s;
}
// Read a file into a NUL-terminated string; returns NULL on error.
static void* slurp_file(const char *filename, size_t *size) {
FILE *f = fopen(filename, "rb"); // To avoid Windows messing with linebreaks.
if (f == NULL) return NULL;
unsigned char *s = fslurp_file(f, size);
fclose(f);
return s;
}
// Dump 'n' bytes from 'buf' into the file at the designated location.
// Returns 0 on success.
static int dump_file(const char *file, const void *buf, size_t n) {
FILE *f = fopen(file, "w");
if (f == NULL) {
return 1;
}
if (fwrite(buf, sizeof(char), n, f) != n) {
return 1;
}
if (fclose(f) != 0) {
return 1;
}
return 0;
}
struct str_builder {
char *str;
size_t capacity; // Size of buffer.
size_t used; // Bytes used, *not* including final zero.
};
static void str_builder_init(struct str_builder *b) {
b->capacity = 10;
b->used = 0;
b->str = malloc(b->capacity);
b->str[0] = 0;
}
static void str_builder(struct str_builder *b, const char *s, ...) {
va_list vl;
va_start(vl, s);
size_t needed = (size_t)vsnprintf(NULL, 0, s, vl);
while (b->capacity < b->used + needed + 1) {
b->capacity *= 2;
b->str = realloc(b->str, b->capacity);
}
va_start(vl, s); // Must re-init.
vsnprintf(b->str+b->used, b->capacity-b->used, s, vl);
b->used += needed;
}
static void str_builder_str(struct str_builder *b, const char *s) {
size_t needed = strlen(s);
if (b->capacity < b->used + needed + 1) {
b->capacity *= 2;
b->str = realloc(b->str, b->capacity);
}
strcpy(b->str+b->used, s);
b->used += needed;
}
static void str_builder_char(struct str_builder *b, char c) {
size_t needed = 1;
if (b->capacity < b->used + needed + 1) {
b->capacity *= 2;
b->str = realloc(b->str, b->capacity);
}
b->str[b->used] = c;
b->str[b->used+1] = 0;
b->used += needed;
}
static void str_builder_json_str(struct str_builder* sb, const char* s) {
str_builder_char(sb, '"');
for (int j = 0; s[j]; j++) {
char c = s[j];
switch (c) {
case '\n':
str_builder_str(sb, "\\n");
break;
case '"':
str_builder_str(sb, "\\\"");
break;
default:
str_builder_char(sb, c);
}
}
str_builder_char(sb, '"');
}
static char *strclone(const char *str) {
size_t size = strlen(str) + 1;
char *copy = (char*) malloc(size);
if (copy == NULL) {
return NULL;
}
memcpy(copy, str, size);
return copy;
}
// Assumes NULL-terminated.
static char *strconcat(const char *src_fragments[]) {
size_t src_len = 0;
const char **p;
for (p = src_fragments; *p; p++) {
src_len += strlen(*p);
}
char *src = (char*) malloc(src_len + 1);
size_t n = 0;
for (p = src_fragments; *p; p++) {
strcpy(src + n, *p);
n += strlen(*p);
}
return src;
}
// End of util.h.