tbuild/main.c
xSlendiX f6e8b0f73c Fix src code generation.
This patch remooves the new line before the string ends, it also makes
the default code actually work (no longer tries to be Wordle).

Signed-off-by: xSlendiX <slendi@socopon.com>
2022-12-18 11:20:39 +02:00

886 lines
25 KiB
C

#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 {
char *name, *uri;
} dependency;
#define MAX_DEP 20
typedef struct project_manifest {
char *name, *author, *version;
dependency dependencies[MAX_DEP];
size_t dependencies_amount;
} project_manifest;
void free_manifest(project_manifest *manifest) {
int i;
free(manifest->name);
free(manifest->author);
free(manifest->version);
for (i = 0; i < manifest->dependencies_amount; i++) {
free(manifest->dependencies[i].name);
free(manifest->dependencies[i].uri);
}
}
project_manifest* load_manifest(char const *path) {
FILE* fp;
int i;
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: %s\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");
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");
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");
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");
return NULL;
}
new->name = name.u.s;
new->author = author.u.s;
new->version = version.u.s;
new->dependencies_amount = 0;
// FIXME: Add dependencies.
toml_table_t *dependencies = toml_table_in(conf, "Dependencies");
if (!dependencies) {
fprintf(stderr, "Error: Cannot load manifest file: Cannot find [Dependencies] table.\n");
return NULL;
}
for (i = 0; ; i++) {
int j;
char const *key = toml_key_in(dependencies, i);
if (!key) break;
toml_datum_t dep_uri = toml_string_in(dependencies, key);
new->dependencies_amount++;
char *name = calloc(1, sizeof(char) * (strlen(key) + 1));
strcpy(name, key);
char *url = calloc(1, sizeof(char) * (strlen(dep_uri.u.s) + 1));
strcpy(url, dep_uri.u.s);
// HACK: Just replace the system command...
for (j = 0; j < strlen(name); j++)
if (name[j] == '\'')
name[j] = ' ';
for (j = 0; j < strlen(url); j++)
if (url[j] == '\'')
url[j] = ' ';
dependency dep = {
name, url
};
new->dependencies[i] = dep;
}
toml_free(conf);
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) {
int i;
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 = basename(cwd);
}
} else {
name = basename((char *)project_path);
}
char *uname = get_username();
if (!uname) {
fputs("Error: Cannot create manifest: Cannot get username.\n", stderr);
return false;
}
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|. [--zeal|-z|-Z] - 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);
// Credit: ZealOS ConversionScript.
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);
FILE *fp = fopen(text_format("%s/.gitignore", project_path), "w+");
if (fp) {
fputs("build\nout\n", fp);
fclose(fp);
} else {
fputs("Warning: Cannot open .gitignore!\n", stderr);
}
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(src_dir)) {
bool status = makedir(src_dir);
if (!status) {
fputs("Error: Cannot initialize project: Cannot create src directory.\n", stderr);
return 1;
}
fp = fopen(text_format("%s/Main.HC", src_dir), "w+");
fputs("U0 Main() {\n\
\"Hello, world!\\n\";\n\
}\n", fp);
fclose(fp);
fp = fopen(text_format("%s/Load.HC", src_dir), "w+");
fputs("Cd(__DIR__);;\n\
#include \"Main\"\n", fp);
fclose(fp);
fp = fopen(text_format("%s/Run.HC", src_dir), "w+");
fputs("Cd(__DIR__);;\n\
#include \"Load\"\n\
\"Running...\\n\";\n\
Main;\n", fp);
fclose(fp);
fp = fopen(text_format("%s/RunCD.HC", src_dir), "w+");
fputs("#include \"Load\"\n\
\"Running from CD...\\n\";\n\
Main;\n", fp);
fclose(fp);
fp = fopen(text_format("%s/Install.HC", src_dir), "w+");
fputs("// TODO: Add support for multiple partitions, not just C:\n\
if (!FileFind(\"C:/Apps/Main\",,FUF_JUST_DIRS)) {\n\
\"Installing...\\n\";\n\
DirMk(\"C:/Apps/Main\");\n\
} else \"Updating...\\n\";\n\
CopyTree(\"T:/\", \"C:/Apps/Main\");\n\
Del(\"C:/Apps/Main/RunCD.*\");\n\
\"Done!\\n\";\n", fp);
fclose(fp);
}
if (can_run_command("git"))
system(text_format("git init %s", project_path));
free(src_dir);
// 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 == '.') {
int i;
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));
if (!manifest) {
fputs("Error: Cannot build project: Failed to open manifest.\n", stderr);
return 1;
}
puts(buffer_text_format);
text_format("%s/lib", project_path);
char *lib_dir = malloc((strlen(buffer_text_format)+1)*sizeof(char));
strcpy(lib_dir, buffer_text_format);
if (!file_exists(lib_dir)) {
bool status = makedir(lib_dir);
if (!status) {
fputs("Error: Cannot build project: Cannot create lib directory.\n", stderr);
free_manifest(manifest);
return 1;
}
}
for (i = 0; i < manifest->dependencies_amount; i++) {
dependency dep = manifest->dependencies[i];
printf("%s -> %s (%i)\n", dep.name, dep.uri, i);
puts(text_format("%s/%s", lib_dir, dep.name));
if (!file_exists(text_format("%s/%s", lib_dir, dep.name)))
system(text_format("git clone --depth 1 --recursive --shallow-submodules '%s' '%s/%s'", dep.uri, lib_dir, dep.name));
else
// FIXME: Make this cross platform.
system(text_format("cd '%s/%s' && git pull", lib_dir, dep.name));
}
// 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);
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;
}
}
text_format("%s/src", project_path);
char *src_dir = malloc((strlen(buffer_text_format)+1)*sizeof(char));
strcpy(src_dir, buffer_text_format);
// Clear and populate.
puts("Populating build directory...");
clear_directory(build_dir);
copy_directory(src_dir, build_dir);
if (file_exists(lib_dir))
copy_directory(lib_dir, build_dir);
// 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("RedSeaGen.exe '%s' '%s'", build_dir, iso_c));
#else
system(text_format("RedSeaGen '%s' '%s'", build_dir, iso_c));
#endif
//abs_exe_path,
free(build_dir);
free(out_dir);
free(scripts_dir);
free(lib_dir);
free(project_path);
free_manifest(manifest);
}
}