1
0
Fork 0
mirror of https://github.com/zeldaret/oot.git synced 2024-12-29 08:16:11 +00:00
oot/tools/audio/util.c
Tharo df5d4cb467
[Audio 10/10] Loose ends (#2337)
* Introduce afile_sizes, generate headers of sizes for soundfonts and sequences

* Initial tools/audio README

* Versioning for samplebank extraction

* Clean up the disassemble_sequence.py runnable interface

* Add static assertions for maximum bank sizes

* Boost optimization for audio tools

* Samplebank XML doc

* Soundfont XML doc

* More docs in sampleconv for vadpcm

* Various tools fixes/cleanup

* VADPCM doc

* Try to fix md formatting

* VADPCM doc can come later

* Fix merge with PR 9

* Fix blobs from MM

* Try to fix bss

* Try fix bss round 2

* Fix sampleconv memset bug

* Suggested documentation tweaks
2024-12-13 19:26:36 -05:00

143 lines
3.8 KiB
C

/* SPDX-FileCopyrightText: Copyright (C) 2024 ZeldaRET */
/* SPDX-License-Identifier: CC0-1.0 */
#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;
}