mirror of
https://github.com/zeldaret/oot.git
synced 2024-11-14 21:40:03 +00:00
d3b9ba17da
* [Audio 4/?] Build Samplebanks, match Audiotable * Fix some makefile formatting * Add missing scope in MARK chunk handling * Add comment to generate asm file when buffer bug data is emitted, remove duplicate CC4 definition * Adjust comment * SBCFLAGS * Remove unnecessary comments on notes_lut * Split build directories creation command into several to avoid it becoming too long * objcopy -j -> --only-section * Fix mkdir warning when extracted/VERSION/assets doesn't exist
144 lines
3.8 KiB
C
144 lines
3.8 KiB
C
/* SPDX-FileCopyrightText: Copyright (C) 2024 ZeldaRET */
|
|
/* SPDX-License-Identifier: CC0-1.0 */
|
|
#define _GNU_SOURCE
|
|
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
|
|
#include "util.h"
|
|
|
|
// TODO ideally we should be collecting all errors and displaying them all before exiting
|
|
|
|
NORETURN void
|
|
error(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
fprintf(stderr, "\x1b[91m"
|
|
"Error: "
|
|
"\x1b[97m");
|
|
vfprintf(stderr, fmt, ap);
|
|
fprintf(stderr, "\x1b[0m"
|
|
"\n");
|
|
va_end(ap);
|
|
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
void
|
|
warning(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
fprintf(stderr, "\x1b[95m"
|
|
"Warning: "
|
|
"\x1b[97m");
|
|
vfprintf(stderr, fmt, ap);
|
|
fprintf(stderr, "\x1b[0m"
|
|
"\n");
|
|
va_end(ap);
|
|
}
|
|
|
|
void *
|
|
util_read_whole_file(const char *filename, size_t *size_out)
|
|
{
|
|
FILE *file = fopen(filename, "rb");
|
|
void *buffer = NULL;
|
|
size_t size;
|
|
|
|
if (file == NULL)
|
|
error("failed to open file '%s' for reading: %s", filename, strerror(errno));
|
|
|
|
// get size
|
|
fseek(file, 0, SEEK_END);
|
|
size = ftell(file);
|
|
|
|
// if the file is empty, return NULL buffer and 0 size
|
|
if (size != 0) {
|
|
// allocate buffer
|
|
buffer = malloc(size + 1);
|
|
if (buffer == NULL)
|
|
error("could not allocate buffer for file '%s'", filename);
|
|
|
|
// read file
|
|
fseek(file, 0, SEEK_SET);
|
|
if (fread(buffer, size, 1, file) != 1)
|
|
error("error reading from file '%s': %s", filename, strerror(errno));
|
|
|
|
// null-terminate the buffer (in case of text files)
|
|
((char *)buffer)[size] = '\0';
|
|
}
|
|
|
|
fclose(file);
|
|
|
|
if (size_out != NULL)
|
|
*size_out = size;
|
|
return buffer;
|
|
}
|
|
|
|
void
|
|
util_write_whole_file(const char *filename, const void *data, size_t size)
|
|
{
|
|
FILE *file = fopen(filename, "wb");
|
|
|
|
if (file == NULL)
|
|
error("failed to open file '%s' for writing: %s", filename, strerror(errno));
|
|
|
|
if (fwrite(data, size, 1, file) != 1)
|
|
error("error writing to file '%s': %s", filename, strerror(errno));
|
|
|
|
fclose(file);
|
|
}
|
|
|
|
bool
|
|
str_is_c_identifier(const char *str)
|
|
{
|
|
// A C language identifier must:
|
|
// - ONLY contain [_, abc..xyz, ABC..XYZ, 0..9] (we do not support unicode or extensions like $)
|
|
// - NOT be a keyword
|
|
// - NOT start with a digit [0..9]
|
|
|
|
static const char *const c_kwds[] = {
|
|
"auto", "break", "case", "char", "const", "continue", "default", "do",
|
|
"double", "else", "enum", "extern", "float", "for", "goto", "if",
|
|
"inline", "int", "long", "register", "restrict", "return", "short", "signed",
|
|
"sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void",
|
|
"volatile", "while",
|
|
|
|
"_Alignas", "_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic", "_Imaginary", "_Noreturn",
|
|
"_Static_assert", "_Thread_local",
|
|
};
|
|
|
|
if (str == NULL) {
|
|
return false;
|
|
}
|
|
if (isdigit(str[0])) {
|
|
// Starts with a digit, fail
|
|
return false;
|
|
}
|
|
|
|
size_t len = strlen(str);
|
|
for (size_t i = 0; i < len; i++) {
|
|
char c = str[i];
|
|
|
|
bool alpha = isalpha(c);
|
|
bool digit = isdigit(c);
|
|
bool uscore = c == '_';
|
|
|
|
if (!(alpha || digit || uscore)) {
|
|
// Contains bad character, fail
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for (size_t i = 0; i < ARRAY_COUNT(c_kwds); i++) {
|
|
if (strequ(str, c_kwds[i])) {
|
|
// Matched a C keyword, fail
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|