This commit is contained in:
2025-08-10 18:04:30 -04:00
parent f33dedeeff
commit e441dec020
10 changed files with 126 additions and 142 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,4 +1,3 @@
#include <assert.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -17,21 +16,14 @@
#define DEFAULT_GIT_INIT true #define DEFAULT_GIT_INIT true
#define DEFAULT_CLANG_FORMAT true #define DEFAULT_CLANG_FORMAT true
/* This is to keep track of how deep we are within
the project tree. This is used in reset_path_ () */
int depth; int depth;
/* This macro exist purely because I like how it looks. This should be called static int reset_path(void)
in every function that creates file to ensure they are being created in
right place. */
#define reset_path reset_path_()
int reset_path_()
{ {
while (depth != 0) { while (depth > 0) {
if (chdir("..") != 0) if (chdir("..") != 0)
return errno; return errno;
else depth--;
--depth;
} }
return 0; return 0;
} }
@@ -40,11 +32,11 @@ int program_exists(const char *prog)
{ {
char *path = getenv("PATH"); char *path = getenv("PATH");
if (!path) if (!path)
return 1; return -1;
char *copy = strdup(path); char *copy = strdup(path);
if (!copy) if (!copy)
return 1; return -1;
char *dir = strtok(copy, ":"); char *dir = strtok(copy, ":");
while (dir) { while (dir) {
@@ -61,26 +53,30 @@ int program_exists(const char *prog)
return 1; return 1;
} }
// TODO(vx-clutch): sanitize the alpha-numeric range
// clang-format off
int sanitize(manifest_t *m) int sanitize(manifest_t *m)
{ {
if (!m->project) m->project = DEFAULT_PROJECT_NAME; if (!m->project)
if (!m->name) m->name = DEFAULT_USER_NAME; m->project = DEFAULT_PROJECT_NAME;
if (!(m->licence == UNLICENCE)) m->licence = DEFAULT_LICENCE;
m->flag.git = m->flag.git ? true : DEFAULT_GIT_INIT;
m->flag.clang_format = m->flag.clang_format ? true : DEFAULT_CLANG_FORMAT;
m->flag.GNU = m->flag.GNU ? true : DEFAULT_GNU;
if (!m->name) { if (!m->name) {
struct passwd *pw = getpwuid(getuid()); struct passwd *pw = getpwuid(getuid());
m->name = (pw && pw->pw_name) ? pw->pw_name : DEFAULT_USER_NAME; m->name = (pw && pw->pw_name) ? pw->pw_name : DEFAULT_USER_NAME;
} }
if (m->licence == UNLICENCE)
m->licence = DEFAULT_LICENCE;
if (!m->flag.git)
m->flag.git = DEFAULT_GIT_INIT;
if (!m->flag.clang_format)
m->flag.clang_format = DEFAULT_CLANG_FORMAT;
if (!m->flag.GNU)
m->flag.GNU = DEFAULT_GNU;
return 0; return 0;
} }
// clang-format on
int create_libraries(manifest_t manifest) int create_libraries(manifest_t manifest)
{ {
@@ -90,29 +86,31 @@ int create_libraries(manifest_t manifest)
return status; return status;
} }
/* reset_path; */ int ret = reset_path();
while (depth != 0) { if (ret != 0)
if (chdir("..") != 0) return ret;
return errno;
else
--depth;
}
for (int i = 0; i < LIB_COUNT_; ++i) {
if (HAS_LIBRARY(manifest.libraries, LIB_RAYLIB)) { if (HAS_LIBRARY(manifest.libraries, LIB_RAYLIB)) {
REMOVE_LIBRARY(manifest.libraries, LIB_RAYLIB); REMOVE_LIBRARY(manifest.libraries, LIB_RAYLIB);
status = system( status = system("git submodule add -q https://github.com/raysan5/raylib");
"git submodule add -q https://github.com/raysan5/raylib"); if (status != 0)
} else if (HAS_LIBRARY(manifest.libraries, LIB_NCURSES)) { return status;
}
if (HAS_LIBRARY(manifest.libraries, LIB_NCURSES)) {
REMOVE_LIBRARY(manifest.libraries, LIB_NCURSES); REMOVE_LIBRARY(manifest.libraries, LIB_NCURSES);
status = system( status = system("git submodule add -q https://github.com/mirror/ncurses");
"git submodule add -q https://github.com/mirror/ncurses"); if (status != 0)
} else if (HAS_LIBRARY(manifest.libraries, LIB_CURL)) { return status;
}
if (HAS_LIBRARY(manifest.libraries, LIB_CURL)) {
REMOVE_LIBRARY(manifest.libraries, LIB_CURL); REMOVE_LIBRARY(manifest.libraries, LIB_CURL);
status = system( status = system("git submodule add -q https://github.com/curl/curl");
"git submodule add -q https://github.com/raysan5/raylib"); if (status != 0)
} return status;
} }
return status; return status;
} }
@@ -121,76 +119,55 @@ int create_licence(manifest_t manifest, char **licence_line_buffer)
if (manifest.licence == UNLICENCE) if (manifest.licence == UNLICENCE)
return 0; return 0;
/* reset_path; */ int ret = reset_path();
while (depth != 0) { if (ret != 0)
if (chdir("..") != 0) return ret;
return errno;
else
--depth;
}
assert(licence_line_buffer != NULL); if (!licence_line_buffer)
return EINVAL;
switch (manifest.licence) { switch (manifest.licence) {
case BSD3: case BSD3:
*licence_line_buffer = "Bsd"; *licence_line_buffer = "Bsd";
printfn("Not impl"); fprintf(stderr, "create_licence: BSD3 license generation not implemented\n");
assert(1 == 2); return ENOSYS;
break;
case GPLv3: case GPLv3:
printfn("Not impl"); fprintf(stderr, "create_licence: GPLv3 license generation not implemented\n");
assert(1 == 2); return ENOSYS;
break;
case MIT: case MIT:
printfn("Not impl"); fprintf(stderr, "create_licence: MIT license generation not implemented\n");
assert(1 == 2); return ENOSYS;
break;
case UNLICENCE:
default: default:
printfn("bad logic in create_licence ()"); fprintf(stderr, "create_licence: unknown license type\n");
return 1; return EINVAL;
} }
return 0;
} }
int maybe_create_clang_format(manifest_t manifest) int maybe_create_clang_format(manifest_t manifest)
{ {
int status; int ret = reset_path();
if (ret != 0)
return ret;
if (!manifest.flag.clang_format) if (!manifest.flag.clang_format)
return 0; return 0;
/* reset_path; */ int status = create_file_with_content(".clang-format", clang_format_template);
while (depth != 0) {
if (chdir("..") != 0)
return errno;
else
--depth;
}
status = create_file_with_content(".clang-format",
clang_format_template);
return status; return status;
} }
int setup_git(manifest_t manifest) int setup_git(manifest_t manifest)
{ {
if (!manifest.flag.git) { if (!manifest.flag.git)
return 0; return 0;
}
/* reset_path; */ int ret = reset_path();
while (depth != 0) { if (ret != 0)
if (chdir("..") != 0) return ret;
return errno;
else
--depth;
}
int status = system("git init --quiet"); int status = system("git init --quiet");
if (status) { if (status != 0)
printfn("failed on git initialize: %s", strerror(status)); fprintf(stderr, "setup_git: failed to initialize git: %s\n", strerror(status));
}
return status; return status;
} }
@@ -199,66 +176,74 @@ int create_makefile(manifest_t manifest)
{ {
char *makefile_name = strdup(manifest.project); char *makefile_name = strdup(manifest.project);
if (!makefile_name) { if (!makefile_name) {
printfn("fatal: out of memory"); fprintf(stderr, "create_makefile: fatal: out of memory\n");
return 1; return ENOMEM;
} }
for (char *p = makefile_name; *p; ++p) for (char *p = makefile_name; *p; ++p)
if (*p >= 'a' && *p <= 'z') if (*p >= 'a' && *p <= 'z')
*p -= 32; *p -= 'a' - 'A';
reset_path; int ret = reset_path();
if (ret != 0) {
free(makefile_name);
return ret;
}
create_file_with_content("Makefile", makefile_template, makefile_name, int status = create_file_with_content("Makefile", makefile_template, makefile_name,
makefile_name, makefile_name, makefile_name, makefile_name, makefile_name, makefile_name,
makefile_name, makefile_name, manifest.project, makefile_name, makefile_name, manifest.project,
makefile_name, makefile_name); makefile_name, makefile_name);
free(makefile_name); free(makefile_name);
return 0; return status;
} }
int create_configure(manifest_t manifest) int create_configure(manifest_t manifest)
{ {
int status = 0; int ret = reset_path();
reset_path; if (ret != 0)
return ret;
char *cc; const char *cc;
if (manifest.flag.use_cpp) { if (manifest.flag.use_cpp) {
cc = "trycc g++\ntrycc CC\ntrycc clang++\n"; cc = "trycc g++\ntrycc CC\ntrycc clang++\n";
} else { } else {
cc = "trycc gcc\ntrycc cc\ntrycc clang\n"; cc = "trycc gcc\ntrycc cc\ntrycc clang\n";
} }
create_file_with_content("configure", configure_template, cc); int status = create_file_with_content("configure", configure_template, cc);
if (status != 0)
return status;
status = system("chmod +x configure"); status = system("chmod +x configure");
if (status) if (status != 0)
printfn("error: %s", strerror(status)); fprintf(stderr, "create_configure: chmod failed: %s\n", strerror(status));
return status; return status;
} }
int generate_source_code(manifest_t manifest, char *licence_line) int generate_source_code(manifest_t manifest, char *licence_line)
{ {
int status, year = 0; int status = 0;
time_t t = time(NULL); time_t t = time(NULL);
struct tm tm = *localtime(&t); struct tm tm = *localtime(&t);
year = tm.tm_year + 1900; int year = tm.tm_year + 1900;
// XXX(vx-clutch): this segfaults, but why? // Uncomment or fix when create_file_with_content supports this
// status = create_file_with_content("config.h", manifest.project, licence_line, year); // status = create_file_with_content("config.h", manifest.project, licence_line, year);
if (status) { // if (status != 0) {
printfn("failed to create config.h: %s", strerror(status)); // fprintf(stderr, "generate_source_code: failed to create config.h: %s\n", strerror(status));
return status; // return status;
} // }
status = create_and_enter_directory(manifest.project); status = create_and_enter_directory(manifest.project);
++depth; if (status != 0) {
if (status) { fprintf(stderr, "generate_source_code: failed to create or enter directory: %s\n", strerror(status));
printfn("failed to create or enter directory: %s",
strerror(status));
return status; return status;
} }
depth++;
if (manifest.flag.GNU) { if (manifest.flag.GNU) {
status = create_file_with_content("main.c", main_c_gnu_template, status = create_file_with_content("main.c", main_c_gnu_template,
@@ -269,6 +254,7 @@ int generate_source_code(manifest_t manifest, char *licence_line)
manifest.project, manifest.project,
manifest.name); manifest.name);
} }
return status; return status;
} }
@@ -276,70 +262,68 @@ int create_project(manifest_t manifest)
{ {
int status; int status;
status = sanitize(&manifest); sanitize(&manifest);
if (status) {
printfn("failed to sanitize format: %s", strerror(status));
return status;
}
depth = 0; depth = 0;
if (strcmp(manifest.path, ".") != 0) { if (strcmp(manifest.path, ".") != 0) {
status = create_and_enter_directory(manifest.project); status = create_and_enter_directory(manifest.project);
if (status) { if (status != 0) {
printfn("failed to create or enter directory: %s", fprintf(stderr, "create_project: failed to create or enter directory: %s\n",
strerror(status)); strerror(status));
return status; return status;
} }
depth++;
} }
status = create_makefile(manifest); status = create_makefile(manifest);
if (status) { if (status != 0) {
printfn("failed to create Makefile: %s", strerror(status)); fprintf(stderr, "create_project: failed to create Makefile: %s\n", strerror(status));
return status; return status;
} }
status = create_configure(manifest); status = create_configure(manifest);
if (status) { if (status != 0) {
printfn("failed to create configure: %s", strerror(status)); fprintf(stderr, "create_project: failed to create configure: %s\n", strerror(status));
return status; return status;
} }
status = setup_git(manifest); status = setup_git(manifest);
if (status) { if (status != 0) {
printfn("warning: git initialization failed: %s", fprintf(stderr, "create_project: warning: git initialization failed: %s\n",
strerror(status)); strerror(status));
} }
status = maybe_create_clang_format(manifest); status = maybe_create_clang_format(manifest);
if (status) { if (status != 0) {
printfn("warning: clang-format setup failed: %s", fprintf(stderr, "create_project: warning: clang-format setup failed: %s\n",
strerror(status)); strerror(status));
} }
// TODO(vx-clutch): make this smarter--or not ( macro ). char *licence_line = malloc(1024);
char *licence_line = malloc(sizeof(char) * 1024);
if (!licence_line) { if (!licence_line) {
printfn("failed to create memory for licence line: %s", fprintf(stderr, "create_project: failed to allocate memory for licence line\n");
strerror(status)); return ENOMEM;
return status;
} }
status = create_licence(manifest, &licence_line); status = create_licence(manifest, &licence_line);
if (status) { if (status != 0) {
printfn("failed to get libraries: %s", strerror(status)); fprintf(stderr, "create_project: failed to create licence: %s\n", strerror(status));
free(licence_line);
return status; return status;
} }
// TODO(vx-clutch): Take in licence line and put it into standard.c
status = generate_source_code(manifest, licence_line); status = generate_source_code(manifest, licence_line);
if (status) { if (status != 0) {
printfn("failed to generate source code: %s", strerror(status)); fprintf(stderr, "create_project: failed to generate source code: %s\n", strerror(status));
free(licence_line);
return status; return status;
} }
free(licence_line); free(licence_line);
status = create_libraries(manifest); status = create_libraries(manifest);
if (status) { if (status != 0) {
printfn("failed to get libraries: %s", strerror(status)); fprintf(stderr, "create_project: failed to get libraries: %s\n", strerror(status));
return status; return status;
} }