joeylib2/tools/common/toolFile.c

120 lines
2.7 KiB
C

// Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License.
// See LICENSE.md for license information.
// SPDX-License-Identifier: MIT
//
// toolFile.c - whole-file reads and writes, numbers from the command line,
// and fatal errors for the JoeyLib host tools (toolFile.h).
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "toolFile.h"
#define FAIL_EXIT 1
static void failV(int code, const char *fmt, va_list args) __attribute__((noreturn, format(printf, 2, 0)));
static const char *gToolName = "tool";
// "<toolName>: <message>" to stderr, then exit with code.
static void failV(int code, const char *fmt, va_list args) {
fprintf(stderr, "%s: ", gToolName);
vfprintf(stderr, fmt, args);
fputc('\n', stderr);
exit(code);
}
void toolFail(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
failV(FAIL_EXIT, fmt, args);
}
void toolFailCode(int code, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
failV(code, fmt, args);
}
void toolFileName(const char *toolName) {
gToolName = toolName;
}
bool toolParseInt(const char *s, size_t len, long *out) {
char buf[32];
char *end;
size_t i;
while (len > 0u && isspace((unsigned char)*s)) {
s++;
len--;
}
while (len > 0u && isspace((unsigned char)s[len - 1u])) {
len--;
}
if (len == 0u || len >= sizeof(buf)) {
return false;
}
memcpy(buf, s, len);
buf[len] = '\0';
for (i = (buf[0] == '+' || buf[0] == '-') ? 1u : 0u; i < len; i++) {
if (!isdigit((unsigned char)buf[i])) {
return false;
}
}
errno = 0;
*out = strtol(buf, &end, 10);
return *end == '\0' && errno != ERANGE;
}
bool toolReadFile(const char *path, uint8_t **data, size_t *len) {
FILE *f;
uint8_t *buf;
long size;
f = fopen(path, "rb");
if (f == NULL) {
return false;
}
if (fseek(f, 0, SEEK_END) != 0 || (size = ftell(f)) < 0 || fseek(f, 0, SEEK_SET) != 0) {
fclose(f);
return false;
}
buf = (uint8_t *)malloc((size_t)size + 1u);
if (buf == NULL || fread(buf, 1, (size_t)size, f) != (size_t)size) {
free(buf);
fclose(f);
return false;
}
fclose(f);
buf[size] = 0u;
*data = buf;
*len = (size_t)size;
return true;
}
bool toolWriteFile(const char *path, const uint8_t *data, size_t len) {
FILE *f;
bool ok;
f = fopen(path, "wb");
if (f == NULL) {
return false;
}
ok = fwrite(data, 1, len, f) == len;
ok = fclose(f) == 0 && ok;
return ok;
}