Initial commit

This commit is contained in:
xSlendiX 2022-12-12 20:36:48 +02:00
commit d244528dfb
8 changed files with 778 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
tbuild

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "tomlc99"]
path = tomlc99
url = https://github.com/cktan/tomlc99

27
LICENSE.md Normal file
View File

@ -0,0 +1,27 @@
# DON'T BE A DICK PUBLIC LICENSE
> Version 1.1, December 2016
> Copyright (C) 2022 Slendi <slendi@socopon.com>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document.
> DON'T BE A DICK PUBLIC LICENSE
> TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
1. Do whatever you like with the original work, just don't be a dick.
Being a dick includes - but is not limited to - the following instances:
1a. Outright copyright infringement - Don't just copy this and change the name.
1b. Selling the unmodified original with no work done what-so-ever, that's REALLY being a dick.
1c. Modifying the original work to contain hidden harmful content. That would make you a PROPER dick.
2. If you become rich through modifications, related works/services, or supporting the original work,
share the love. Only a dick would make loads off this work and not buy the original work's
creator(s) a pint.
3. Code is provided with no warranty. Using somebody else's code and bitching when it goes wrong makes
you a DONKEY dick. Fix the problem yourself. A non-dick would submit the fix back.

BIN
RedSeaGen Executable file

Binary file not shown.

BIN
RedSeaGen.exe Normal file

Binary file not shown.

4
build.sh Executable file
View File

@ -0,0 +1,4 @@
cd tomlc99
make
cd ..
cc tomlc99/toml.o main.c -o tbuild

741
main.c Normal file
View File

@ -0,0 +1,741 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <unistd.h>
#include <libgen.h>
#include <dirent.h>
#include <ctype.h>
#include <stdarg.h>
#include "tomlc99/toml.h"
// FIXME: This is hardcoded, fix it.
char *python_interpreter_path = "/usr/local/bin/python3";
bool can_run_command(const char *cmd) {
if(strchr(cmd, '/')) {
return access(cmd, X_OK)==0;
}
const char *path = getenv("PATH");
if(!path) return false;
char *buf = malloc(strlen(path)+strlen(cmd)+3);
if(!buf) return false;
for(; *path; ++path) {
char *p = buf;
for(; *path && *path!=':'; ++path,++p)
*p = *path;
if(p==buf) *p++='.';
if(p[-1]!='/') *p++='/';
strcpy(p, cmd);
if(access(buf, X_OK)==0) {
free(buf);
return true;
}
if(!*path) break;
}
free(buf);
return false;
}
#define BUFFER_SIZE 1024
bool copy_directory(const char *src_path, const char *dest_path) {
DIR *src_dir = opendir(src_path);
if (src_dir == NULL) {
// Failed to open source directory
return false;
}
// Create destination directory if it doesn't exist
mkdir(dest_path, 0755);
// Copy files and directories from source to destination
struct dirent *entry;
while ((entry = readdir(src_dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
// Skip "." and ".." directories
continue;
}
char src_file_path[BUFFER_SIZE];
snprintf(src_file_path, BUFFER_SIZE, "%s/%s", src_path, entry->d_name);
char dest_file_path[BUFFER_SIZE];
snprintf(dest_file_path, BUFFER_SIZE, "%s/%s", dest_path, entry->d_name);
struct stat src_file_stat;
stat(src_file_path, &src_file_stat);
if (S_ISDIR(src_file_stat.st_mode)) {
// Recursively copy directories
if (!copy_directory(src_file_path, dest_file_path)) {
return false;
}
} else if (S_ISREG(src_file_stat.st_mode)) {
// Copy regular files
FILE *src_file = fopen(src_file_path, "rb");
if (src_file == NULL) {
// Failed to open source file
return false;
}
FILE *dest_file = fopen(dest_file_path, "wb");
if (dest_file == NULL) {
// Failed to open destination file
fclose(src_file);
return false;
}
// Copy file contents
char buffer[BUFFER_SIZE];
size_t bytes_read;
while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, src_file)) > 0) {
fwrite(buffer, 1, bytes_read, dest_file);
}
fclose(src_file);
fclose(dest_file);
} else {
// Skip other file types
continue;
}
}
closedir(src_dir);
return true;
}
void clear_directory(char const *path) {
DIR *dir = opendir(path);
if (dir == NULL) {
// Unable to open the directory
perror("opendir");
return;
}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
// Skip "." and ".." entries
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
// Get the full path of the entry
char entry_path[1024];
snprintf(entry_path, sizeof(entry_path), "%s/%s", path, entry->d_name);
// Check if the entry is a directory
struct stat entry_stat;
if (stat(entry_path, &entry_stat) != 0) {
perror("stat");
continue;
}
if (S_ISDIR(entry_stat.st_mode)) {
// Remove the directory recursively
clear_directory(entry_path);
if (rmdir(entry_path) != 0) {
perror("rmdir");
}
} else {
// Remove the entry
if (unlink(entry_path) != 0) {
perror("unlink");
}
}
}
closedir(dir);
}
#define MANIFEST_FNAME "tos_project.toml"
char* find_project_root(void)
{
char* result = NULL;
// Get the current working directory
char cwd[1024];
if (getcwd(cwd, sizeof(cwd)) == NULL) {
return NULL;
}
// Check if the current working directory contains the file "tos_project.toml"
size_t file_path_len = strlen(cwd) + strlen("/tos_project.toml") + 1;
char file_path[file_path_len];
snprintf(file_path, file_path_len, "%s/tos_project.toml", cwd);
if (access(file_path, F_OK) == 0) {
// The file exists, so we can return the path to the directory containing it
result = malloc(strlen(cwd) + 1);
strncpy(result, cwd, strlen(cwd) + 1);
return result;
}
// The file does not exist in the current working directory, so we need to search backwards
size_t len = strlen(cwd);
for (int i = len - 1; i >= 0; i--) {
if (cwd[i] == '/') {
// We found a directory separator, so we can check if the parent directory contains the file
cwd[i] = '\0';
snprintf(file_path, file_path_len, "%s/tos_project.toml", cwd);
if (access(file_path, F_OK) == 0) {
// The file exists, so we can return the path to the parent directory containing it
result = malloc(strlen(cwd) + 1);
strncpy(result, cwd, strlen(cwd) + 1);
break;
}
}
}
return result;
}
#define SAMPLE_MANIFEST "[General]\n" \
"Name=\"%s\"\n" \
"Author=\"%s\"\n" \
"Version=\"0.1\"\n" \
"\n" \
"[Dependencies]\n"
typedef struct project_manifest {
char *name, *author, *version;
// FIXME: Add dependencies.
} project_manifest;
void free_manifest(project_manifest *manifest) {
free(manifest->name);
free(manifest->author);
free(manifest->version);
}
project_manifest* load_manifest(char const *path) {
FILE* fp;
char errbuf[200];
fp = fopen(path, "r");
if (!fp) {
fputs("Error: Cannot load manifest file: Cannot open file.\n", stderr);
return NULL;
}
project_manifest *new = calloc(1, sizeof(project_manifest));
toml_table_t *conf = toml_parse_file(fp, errbuf, sizeof(errbuf));
fclose(fp);
if (!conf) {
fprintf(stderr, "Error: Cannot load manifest file: Cannot parse file.\n", errbuf);
return NULL;
}
toml_table_t *general = toml_table_in(conf, "General");
if (!general) {
fprintf(stderr, "Error: Cannot load manifest file: Cannot find [General] table.\n", errbuf);
return NULL;
}
toml_datum_t name = toml_string_in(general, "Name");
if (!name.ok) {
fprintf(stderr, "Error: Cannot load manifest file: Cannot find Name field.\n", errbuf);
return NULL;
}
toml_datum_t author = toml_string_in(general, "Author");
if (!author.ok) {
fprintf(stderr, "Error: Cannot load manifest file: Cannot find Author field.\n", errbuf);
return NULL;
}
toml_datum_t version = toml_string_in(general, "Version");
if (!version.ok) {
fprintf(stderr, "Error: Cannot load manifest file: Cannot find Version field.\n", errbuf);
return NULL;
}
new->name = name.u.s;
new->author = author.u.s;
new->version = version.u.s;
// FIXME: Add dependencies.
toml_free(conf);
printf("%s, %s, %s\n", new->name, new->author, new->version);
return new;
}
char buffer_text_format[2048];
char *text_format(char const *format, ...) {
va_list args;
va_start(args, format);
vsprintf(buffer_text_format, format, args);
va_end(args);
return buffer_text_format;
}
char *get_username(void) {
#if defined(_WIN32)
// FIXME: This leaks memory.
TCHAR infoBuf[105];
DWORD bufCharCount = 105;
if( !GetUserName( infoBuf, &bufCharCount ) )
printError( TEXT("GetUserName") );
char *c_szText[105];
wcstombs(c_szText, infoBuf, wcslen(infoBuf) + 1);
return c_szText;
#else
uid_t uid = geteuid();
struct passwd *pw = getpwuid(uid);
if (pw == NULL)
return NULL;
return pw->pw_name;
#endif
}
bool create_manifest_file(char const *project_path) {
char *name;
char cwd[4096];
if (strlen(project_path) == 1 && project_path[0] == '.') {
if (getcwd(cwd, sizeof(cwd)) == NULL) {
fputs("Error: Cannot create manifest: Cannot get current working directory.\n", stderr);
return false;
} else {
name = malloc((strlen(cwd)+1)*sizeof(char));
strcpy(name, cwd);
}
} else {
name = basename((char *)project_path);
}
char *uname = get_username();
FILE *fd = fopen(text_format("%s/" MANIFEST_FNAME, project_path), "w+");
if (fd == NULL) {
fputs("Error: Cannot create manifest: Cannot open manifest file.\n", stderr);
return false;
}
fprintf(fd, SAMPLE_MANIFEST, name, uname);
fclose(fd);
return true;
}
void print_help(char **argv) {
printf("Usage: %s [command]\n", argv[0]);
fputs("\nCommands:\n", stderr);
fputs(" * init|i [path=.] - Setup a new project.\n", stderr);
fputs(" * build|. - Build project in current working directory.\n", stderr);
fputs(" * clean - Clean output code in current working directory.\n", stderr);
fputs("\nTo see manifest file usage, check out man tbuild(1)\n", stderr);
}
bool file_exists(char const *path) {
struct stat st = {0};
return (stat(path, &st) != -1);
}
// FIXME: Implement for Windows.
bool makedir(char const *path) {
struct stat st = {0};
if (stat(path, &st) == -1) {
mkdir(path, 0700);
} else {
fprintf(stderr, "Warning: File already exists. Continuing anyway.");
return false;
}
return true;
}
bool makedir_parenting(char const *path) {
char *p;
struct stat st = {0};
for(p=strchr(path+1, '/'); p; p=strchr(p+1, '/')){
*p = 0;
if(stat(path, &st) == -1 && makedir(path) == true)
return true;
*p = '/';
}
if(stat(path, &st) == -1)
makedir(path);
return true;
}
void replace_in_file(char const *file, char const *text_to_find, char const *text_to_replace) {
FILE *input = fopen(file, "r");
FILE *output = fopen("temp.txt", "w");
char buffer[512];
while (fgets(buffer, sizeof(buffer), input) != NULL) {
char *pos = strstr(buffer, text_to_find);
if (pos == NULL) {
fputs(buffer, output);
continue;
}
char *temp = calloc(strlen(buffer) - strlen(text_to_find) + strlen(text_to_replace) + 1, 1);
memcpy(temp, buffer, pos - buffer);
memcpy(temp + (pos - buffer), text_to_replace, strlen(text_to_replace));
memcpy(temp + (pos - buffer) + strlen(text_to_replace),
pos + strlen(text_to_find),
1 + strlen(buffer) - ((pos - buffer) + strlen(text_to_find)));
fputs(temp, output);
free(temp);
}
fclose(output);
fclose(input);
rename("temp.txt", file);
}
void convert_to_zealos(char const *path) {
DIR *dir;
struct dirent *entry;
struct stat s;
if (!(dir = opendir(path)))
return;
if (!(entry = readdir(dir)))
return;
do {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
char fpath[1024];
int len = snprintf(fpath, sizeof(fpath)-1, "%s/%s", path, entry->d_name);
fpath[len] = 0;
if (lstat(fpath, &s) == 0 && S_ISDIR(s.st_mode)) { // Is directory?
convert_to_zealos(fpath);
continue;
}
if (fpath[len-2] != 'H' || fpath[len-3] != '.')
continue;
printf("Converting %s\n", entry->d_name);
replace_in_file(fpath, "MemCpy", "MemCopy");
replace_in_file(fpath, "MemCpy", "MemCopy");
replace_in_file(fpath, "MemCmp", "MemCompare");
replace_in_file(fpath, "StrCpy", "StrCopy");
replace_in_file(fpath, "StrCmp", "StrCompare");
replace_in_file(fpath, "StrICmp", "StrICompare");
replace_in_file(fpath, "StrNCmp", "StrNCompare");
replace_in_file(fpath, "StrNICmp", "StrNICompare");
replace_in_file(fpath, "BEqu", "BEqual");
replace_in_file(fpath, "LBEqu", "LBEqual");
replace_in_file(fpath, "ms", "mouse");
replace_in_file(fpath, "Snd", "Sound");
replace_in_file(fpath, "SndTaskEndCB", "SoundTaskEndCB");
replace_in_file(fpath, "mp_cnt", "mp_count");
replace_in_file(fpath, "QueIns", "QueueInsert");
replace_in_file(fpath, "QueInit", "QueueInit");
replace_in_file(fpath, "QueRem", "QueueRemove");
replace_in_file(fpath, "QueDel", "QueueDel");
replace_in_file(fpath, "MsSet", "MouseSet");
replace_in_file(fpath, "UnusedStk", "UnusedStack");
replace_in_file(fpath, "word_lst", "word_list");
replace_in_file(fpath, "FileExtRem", "FileExtRemove");
replace_in_file(fpath, "cnts", "counts");
replace_in_file(fpath, "PostMsg", "MessagePost");
replace_in_file(fpath, "PostMsgWait", "MessagePostWait");
replace_in_file(fpath, "QSort", "QuickSort");
replace_in_file(fpath, "QSortI64", "QuickSortI64");
replace_in_file(fpath, "ScanMsg", "MessageScan");
replace_in_file(fpath, "cnts", "counts");
replace_in_file(fpath, "Dsk", "Disk");
replace_in_file(fpath, "collision_cnt", "collision_count");
replace_in_file(fpath, "Drv", "Drive");
replace_in_file(fpath, "DrvRep", "DriveRep");
replace_in_file(fpath, "Drv2Let", "Drive2Letter");
replace_in_file(fpath, "LstSub", "ListSub");
replace_in_file(fpath, "LstMatch", "ListMatch");
replace_in_file(fpath, "DefineLstLoad", "DefineListLoad");
replace_in_file(fpath, "ExtDft", "ExtDefault");
replace_in_file(fpath, "ExtChg", "ExtChange");
replace_in_file(fpath, "RegDft", "RegDefault");
replace_in_file(fpath, "\"HC\"", "\"CC\"");
replace_in_file(fpath, "CDrv", "CDrive");
replace_in_file(fpath, "CDbgInfo", "CDebugInfo");
replace_in_file(fpath, "dbg_info", "debug_info");
replace_in_file(fpath, "StrFirstRem", "StrFirstRemove");
replace_in_file(fpath, "StrLastRem", "StrLastRemove");
replace_in_file(fpath, "TempleOS/Apps", "/Apps");
replace_in_file(fpath, "adam_task", "sys_task");
replace_in_file(fpath, "JobQue", "JobQueue");
replace_in_file(fpath, "MSG_", "MESSAGE_");
replace_in_file(fpath, ".HC", ".ZC");
replace_in_file(fpath, "Msg", "Message");
replace_in_file(fpath, "MusicSettingsRst", "MusicSettingsReset");
replace_in_file(fpath, "hndlr", "handler");
replace_in_file(fpath, "FifoU8Rem", "FifoU8Remove");
replace_in_file(fpath, "GodBitsIns", "GodBitsInsert");
replace_in_file(fpath, "fp_draw_ms", "fp_draw_mouse");
replace_in_file(fpath, "DrawStdMs", "DrawStdMouse");
replace_in_file(fpath, "WIG_TASK_DFT", "WIG_TASK_DEFAULT");
replace_in_file(fpath, "DirMk", "DirMake");
replace_in_file(fpath, "GetI64", "I64Get");
replace_in_file(fpath, "GetF64", "F64Get");
replace_in_file(fpath, "GetStr", "StrGet");
replace_in_file(fpath, "GetChar", "CharGet");
// Added from Anfintony's Insecticide November 24 2022
replace_in_file(fpath, "GetMsg", "MessageGet");
replace_in_file(fpath, "DRV_SIGNATURE_VAL", "DRIVE_SIGNATURE_VAL");
replace_in_file(fpath, "dv_signature", "drive_signature");
replace_in_file(fpath, "DrvTextAttrGet", "DriveTextAttrGet");
replace_in_file(fpath, "DrvIsWritable", "DriveIsWritable");
replace_in_file(fpath, "gr_palette_std", "gr32_palette_std");
replace_in_file(fpath, "GetKey", "KeyGet");
replace_in_file(fpath, "STD_DISTRO_DVD_CFG", "STD_DISTRO_DVD_CONFIG");
replace_in_file(fpath, "CBGR48", "CBGR24");
replace_in_file(fpath, "CFreeLst", "CFreeList");
replace_in_file(fpath, "DrvLock", "DriveLock");
replace_in_file(fpath, "DrvUnlock", "DriveUnlock");
replace_in_file(fpath, "DrvChk", "DriveCheck");
replace_in_file(fpath, "AMAlloc", "SysMAlloc");
replace_in_file(fpath, "Let2Drv", "Letter2Drive");
replace_in_file(fpath, "Let2Let", "Letter2Letter");
replace_in_file(fpath, "Let2BlkDev", "Letter2BlkDev");
replace_in_file(fpath, "first_drv_let", "first_drive_let");
// Added by Doodguy and Anfintony November 25 2022
replace_in_file(fpath, "ScanKey", "KeyScan");
replace_in_file(fpath, "ScanChar", "CharScan");
replace_in_file(fpath, "fp_final_scrn_update", "fp_final_screen_update");
entry->d_name[strlen(entry->d_name)-2] = 'Z';
rename(fpath, text_format("%s/%s", path, entry->d_name));
} while ((entry = readdir(dir)));
closedir(dir);
}
bool run_scripts(char const *path) {
DIR *dir;
struct dirent *entry;
struct stat s;
if (!(dir = opendir(path)))
return false;
if (!(entry = readdir(dir)))
return false;
do {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
char fpath[1024];
int len = snprintf(fpath, sizeof(fpath)-1, "%s/%s", path, entry->d_name);
fpath[len] = 0;
if (lstat(fpath, &s) == 0 && S_ISDIR(s.st_mode)) { // Is directory?
run_scripts(fpath);
continue;
}
if (fpath[len-3] != 'p' || fpath[len-2] != 'y' || fpath[len-3] != '.')
continue;
printf("Running %s\n", entry->d_name);
char *argv[] = {
fpath,
NULL
};
execve(python_interpreter_path, argv, NULL);
} while ((entry = readdir(dir)));
closedir(dir);
return true;
}
int main(int argc, char **argv) {
if (argc < 2) {
puts("No arguments provided.\n");
print_help(argv);
return 0;
}
char path_save[PATH_MAX];
char abs_exe_path[PATH_MAX];
char *p;
if(!(p = strrchr(argv[0], '/')))
getcwd(abs_exe_path, sizeof(abs_exe_path));
else {
*p = '\0';
getcwd(path_save, sizeof(path_save));
chdir(argv[0]);
getcwd(abs_exe_path, sizeof(abs_exe_path));
chdir(path_save);
}
char *project_path = ".";
char cmd = tolower(argv[1][0]);
if (cmd == 'i') {
if (argc > 2) {
project_path = calloc(1, (strlen(argv[2])+1)*sizeof(char));
strcpy(project_path, argv[2]);
}
fprintf(stderr, "Initializing project in `%s`.\n", project_path);
bool ret = true;
if (!(strlen(project_path) == 1 && project_path[0] == '.'))
ret = makedir_parenting(project_path);
if (!ret) {
fputs("Error: Cannot create project: Cannot create directories.\n", stderr);
return -1;
}
// Check if manifest file exists.
if (file_exists(text_format("%s/" MANIFEST_FNAME, project_path))) {
fputs("Error: Cannot create project: Project already exists!\n", stderr);
return -1;
}
create_manifest_file(project_path);
if (can_run_command("git"))
system(text_format("git init %s", project_path));
// Free only if alloc'ed, "." doesn't count since it is embedded in the program itself.
// Trying to free it if it's "." would cause a crash cause of this.
if (argc > 2)
free(project_path);
} else if (cmd == 'b' || cmd == '.') {
struct {
bool zeal_build;
} options = { 0 };
for (int i = 2; i < argc; i++) {
if (argv[i][0] != '-')
continue;
if (argv[i][1] == '-') {
if (strcmp(argv[i], "--zeal"))
options.zeal_build = true;
continue;
}
for (int j = 1; j < strlen(argv[i]); j++) {
switch (argv[i][j]) {
case 'z':
case 'Z':
options.zeal_build = true;
break;
}
}
}
// Find project root.
char cwd[4096];
if (getcwd(cwd, sizeof(cwd)) == NULL) {
fputs("Error: Cannot build project: Cannot get current working directory.\n", stderr);
return 1;
}
project_path = find_project_root();
if (project_path == NULL) {
fputs("Error: Cannot build project: Not in a project directory.\n", stderr);
return 1;
}
project_manifest* manifest = load_manifest(text_format("%s/" MANIFEST_FNAME, project_path));
puts(buffer_text_format);
// TODO: Validate dependencies.
// Create build directory
text_format("%s/build", project_path);
char *build_dir = malloc((strlen(buffer_text_format)+1)*sizeof(char));
strcpy(build_dir, buffer_text_format);
text_format("%s/src", project_path);
char *src_dir = malloc((strlen(buffer_text_format)+1)*sizeof(char));
strcpy(src_dir, buffer_text_format);
if (!file_exists(build_dir)) {
bool status = makedir(build_dir);
if (!status) {
fputs("Error: Cannot build project: Cannot create build directory.\n", stderr);
free_manifest(manifest);
return 1;
}
}
// Clear and populate.
puts("Populating build directory...");
clear_directory(build_dir);
copy_directory(src_dir, build_dir);
if (file_exists(text_format("%s/libs", project_path)))
copy_directory(src_dir, buffer_text_format);
// Run scripts (if any)
puts("Running scripts...");
// FIXME: This is incredibly hacky.
text_format("%s/scripts", project_path);
char *scripts_dir = malloc((strlen(buffer_text_format)+1)*sizeof(char));
strcpy(scripts_dir, buffer_text_format);
if (file_exists(scripts_dir)) {
if (!run_scripts(scripts_dir)) {
fputs("Failed running script!\b", stderr);
return -1;
}
}
if (options.zeal_build) {
puts("Converting to ZealOS...");
convert_to_zealos(build_dir);
}
// TODO: Obfuscate code if enabled.
text_format("%s/output", project_path);
char *out_dir = malloc((strlen(buffer_text_format)+1)*sizeof(char));
strcpy(out_dir, buffer_text_format);
if (!file_exists(out_dir)) {
bool status = makedir(out_dir);
if (!status) {
fputs("Error: Cannot build project: Cannot create output directory.\n", stderr);
free_manifest(manifest);
return 1;
}
}
if (options.zeal_build)
text_format("%s/output/%s-%s.zeal.ISO.C", project_path, manifest->name, manifest->version);
else
text_format("%s/output/%s-%s.ISO.C", project_path, manifest->name, manifest->version);
char *iso_c = malloc((strlen(buffer_text_format)+1)*sizeof(char));
strcpy(iso_c, buffer_text_format);
#if defined(_WIN32)
system(text_format("%s/RedSeaGen.exe '%s' '%s'", abs_exe_path, build_dir, iso_c));
#else
system(text_format("%s/RedSeaGen '%s' '%s'", abs_exe_path, build_dir, iso_c));
#endif
free(build_dir);
free_manifest(manifest);
}
}

1
tomlc99 Submodule

@ -0,0 +1 @@
Subproject commit 894902820a3ea2f1ec470cd7fe338bde54045cf5