This commit is contained in:
2025-08-05 12:30:03 -04:00
parent 0ef8ca973c
commit 3b496786e4
6 changed files with 418 additions and 352 deletions

View File

@@ -1 +1,108 @@
BasedOnStyle: GNU ---
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentGotoLabels: false
IndentPPDirectives: None
IndentWidth: 8
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 8
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 10
PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0
PenaltyBreakString: 10
PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: false
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatementsExceptForEachMacros
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp03
TabWidth: 8
UseTab: Always
...

View File

@@ -14,57 +14,49 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
int int create_file_with_content(char *path, char *format, ...)
create_file_with_content (char *path, char *format, ...)
{ {
FILE *fp = fopen (path, "w"); FILE *fp = fopen(path, "w");
if (!fp) if (!fp) {
{
return -1; return -1;
} }
va_list args; va_list args;
va_start (args, format); va_start(args, format);
vfprintf (fp, format, args); vfprintf(fp, format, args);
va_end (args); va_end(args);
fclose (fp); fclose(fp);
return 0; return 0;
} }
int int create_directory(char *format, ...)
create_directory (char *format, ...)
{ {
va_list args; va_list args;
va_start (args, format); va_start(args, format);
char path[MAX_PATH_LENGTH]; char path[MAX_PATH_LENGTH];
int result = vsnprintf (path, sizeof (path), format, args); int result = vsnprintf(path, sizeof(path), format, args);
va_end (args); va_end(args);
/* Check if the path was truncated */ /* Check if the path was truncated */
if (result >= (int)sizeof (path)) if (result >= (int)sizeof(path)) {
{
return ENAMETOOLONG; return ENAMETOOLONG;
} }
if (mkdir (path, DEFAULT_DIR_PERMISSIONS) < 0) if (mkdir(path, DEFAULT_DIR_PERMISSIONS) < 0) {
{
return errno; return errno;
} }
return 0; return 0;
} }
int int create_and_enter_directory(const char *dirname)
create_and_enter_directory (const char *dirname)
{ {
int err = create_directory ("%s", dirname); int err = create_directory("%s", dirname);
if (err) if (err) {
{
return err; return err;
} }
if (chdir (dirname) != 0) if (chdir(dirname) != 0) {
{
return errno; return errno;
} }
return 0; return 0;

View File

@@ -10,15 +10,14 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
int int printfn(char *format, ...)
printfn (char *format, ...)
{ {
int len; int len;
va_list args; va_list args;
va_start (args, format); va_start(args, format);
fprintf (stderr, "yait: "); fprintf(stderr, "yait: ");
len = vfprintf (stderr, format, args); len = vfprintf(stderr, format, args);
fprintf (stderr, "\n"); /* Use stderr consistently */ fprintf(stderr, "\n"); /* Use stderr consistently */
va_end (args); va_end(args);
return len; return len;
} }

View File

@@ -15,25 +15,21 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
int int parse_standard_options(void (*usage)(int), int argc, char **argv)
parse_standard_options (void (*usage) (int), int argc, char **argv)
{ {
for (int i = 0; i < argc; ++i) for (int i = 0; i < argc; ++i) {
{ if (strcmp(argv[i], "--help") == 0) {
if (strcmp (argv[i], "--help") == 0) usage(0);
{ exit(EXIT_SUCCESS);
usage (0); } else if (strcmp(argv[i], "--version") == 0) {
exit (EXIT_SUCCESS); printf("%s %s %d\nCopyright (C) %d %s.\n%s\nThis is "
}
else if (strcmp (argv[i], "--version") == 0)
{
printf ("%s %s %d\nCopyright (C) %d %s.\n%s\nThis is "
"free software: " "free software: "
"you are free to change and redistribute " "you are free to change and redistribute "
"it.\nThere is NO " "it.\nThere is NO "
"WARRNTY, to the extent permitted by law.\n", "WARRNTY, to the extent permitted by law.\n",
PROGRAM, VERSION, COMMIT, YEAR, AUTHORS, LICENSE_LINE); PROGRAM, VERSION, COMMIT, YEAR, AUTHORS,
exit (EXIT_SUCCESS); LICENSE_LINE);
exit(EXIT_SUCCESS);
} }
} }
return HELP_REQUESTED; return HELP_REQUESTED;

View File

@@ -246,13 +246,6 @@ char *standard_h_template =
line ("#ifndef STANDARD_H") line ("#ifndef STANDARD_H")
line ("#define STANDARD_H") line ("#define STANDARD_H")
line () line ()
line ("/**")
line (" * Parse standard command line options (--help, --version)")
line (" * @param usage_func Function pointer to usage display function")
line (" * @param argc Argument count")
line (" * @param argv Argument vector")
line (" * @return 0 on success, 1 if help/version requested, errno on error")
line (" */")
line ("int parse_standard_options(void (*usage_func)(), int argc, char **argv);") line ("int parse_standard_options(void (*usage_func)(), int argc, char **argv);")
line () line ()
line ("#endif"); line ("#endif");

View File

@@ -36,7 +36,7 @@
int depth; int depth;
#define print_option(option, description) \ #define print_option(option, description) \
printf (" %-20s %-20s\n", option, description) printf(" %-20s %-20s\n", option, description)
// clang-format off // clang-format off
static void static void
@@ -65,13 +65,11 @@ usage (int status)
/* This macro exist purely because I like how it looks. This should be called /* This macro exist purely because I like how it looks. This should be called
in every function that creates file to ensure they are being created in in every function that creates file to ensure they are being created in
right place. */ right place. */
#define reset_path reset_path_ () #define reset_path reset_path_()
static int static int reset_path_()
reset_path_ ()
{ {
while (depth != 0) while (depth != 0) {
{ if (chdir("..") != 0)
if (chdir ("..") != 0)
return errno; return errno;
else else
--depth; --depth;
@@ -79,8 +77,8 @@ reset_path_ ()
return 0; return 0;
} }
static int // TODO(vx-clutch): sanitize the alpha-numeric range
sanitize (manifest_t *m) static int sanitize(manifest_t *m)
{ {
if (!m->project) if (!m->project)
m->project = DEFAULT_PROJECT_NAME; m->project = DEFAULT_PROJECT_NAME;
@@ -89,119 +87,112 @@ sanitize (manifest_t *m)
if (!(m->licence == UNLICENCE)) if (!(m->licence == UNLICENCE))
m->licence = DEFAULT_LICENCE; m->licence = DEFAULT_LICENCE;
m->flag.git = m->flag.git ? true : DEFAULT_GIT_INIT; m->flag.git = m->flag.git ? true : DEFAULT_GIT_INIT;
m->flag.clang_format = m->flag.clang_format ? true : DEFAULT_CLANG_FORMAT; m->flag.clang_format = m->flag.clang_format ? true :
DEFAULT_CLANG_FORMAT;
m->flag.GNU = m->flag.GNU ? true : DEFAULT_GNU; m->flag.GNU = m->flag.GNU ? true : DEFAULT_GNU;
if (!m->name) {
struct passwd *pw = getpwuid(getuid());
m->name = (pw && pw->pw_name) ? pw->pw_name : DEFAULT_USER_NAME;
}
return 0; return 0;
} }
#define get(url) status = system ("git submodule add -q " url) #define get(url) status = system("git submodule add -q " url)
static int static int create_libraries(manifest_t manifest)
create_libraries (manifest_t manifest)
{ {
int status = 0; int status = 0;
if (!manifest.libraries) if (!manifest.libraries) {
{
return status; return status;
} }
reset_path; reset_path;
for (int i = 0; i < LIB_COUNT_; ++i) 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);
{ get("https://github.com/raysan5/raylib");
REMOVE_LIBRARY (manifest.libraries, LIB_RAYLIB); } else if HAS_LIBRARY (manifest.libraries, LIB_NCURSES) {
get ("https://github.com/raysan5/raylib"); REMOVE_LIBRARY(manifest.libraries, LIB_NCURSES);
get("https://github.com/mirror/ncurses");
} else if HAS_LIBRARY (manifest.libraries, LIB_CURL) {
REMOVE_LIBRARY(manifest.libraries, LIB_CURL);
get("https://github.com/raysan5/raylib");
} }
else if HAS_LIBRARY (manifest.libraries, LIB_NCURSES)
{
REMOVE_LIBRARY (manifest.libraries, LIB_NCURSES);
get ("https://github.com/mirror/ncurses");
} }
else if HAS_LIBRARY (manifest.libraries, LIB_CURL)
{
REMOVE_LIBRARY (manifest.libraries, LIB_CURL);
get ("https://github.com/raysan5/raylib");
}
reset_path;
}
return status; return status;
} }
static int static int create_licence(manifest_t manifest, char **licence_line_buffer)
create_licence (manifest_t manifest, char **licence_line_buffer)
{ {
if (manifest.licence == UNLICENCE) if (manifest.licence == UNLICENCE)
return 0; return 0;
reset_path; reset_path;
/* TODO: Run better checks on licence_line_buffer to ensure we have enough /* TODO(vx-clutch): Run better checks on licence_line_buffer to ensure we have enough
space. This could be done through a multitude of ways; that is for you to space. This could be done through a multitude of ways; that is for you to
figure out. */ figure out. */
assert (licence_line_buffer != NULL); assert(licence_line_buffer != NULL);
// TODO: Remove this and actually implement the features. // TODO(vx-clutch): Remove this and actually implement the features.
#define TODO() \ #define TODO() \
printfn ("Not impl"); \ printfn("Not impl"); \
assert (1 == 2) assert(1 == 2)
switch (manifest.licence) switch (manifest.licence) {
{
case BSD3: case BSD3:
*licence_line_buffer = "Bsd"; *licence_line_buffer = "Bsd";
TODO (); TODO();
break; break;
case GPLv3: case GPLv3:
TODO (); TODO();
break; break;
case MIT: case MIT:
TODO (); TODO();
break; break;
case UNLICENCE: case UNLICENCE:
default: default:
printfn ("bad logic in create_licence ()"); printfn("bad logic in create_licence ()");
return 1; return 1;
} }
return 0; return 0;
} }
static int static int maybe_create_clang_format(manifest_t manifest)
maybe_create_clang_format (manifest_t manifest)
{ {
int status;
if (!manifest.flag.clang_format) if (!manifest.flag.clang_format)
return 0; return 0;
reset_path; reset_path;
return create_file_with_content (".clang-format", clang_format_template); status = create_file_with_content(".clang-format",
} clang_format_template);
static int
setup_git (manifest_t manifest)
{
if (!manifest.flag.git)
return 0;
reset_path;
int status = system ("git init --quiet");
if (status)
printfn ("failed on git initialize: %s", strerror (status));
return status; return status;
} }
static int static int setup_git(manifest_t manifest)
create_makefile (manifest_t manifest)
{ {
char *makefile_name = strdup (manifest.project); if (!manifest.flag.git) {
if (!makefile_name) return 0;
{ }
printfn ("fatal: out of memory"); reset_path;
int status = system("git init --quiet");
if (status) {
printfn("failed on git initialize: %s", strerror(status));
}
return status;
}
static int create_makefile(manifest_t manifest)
{
char *makefile_name = strdup(manifest.project);
if (!makefile_name) {
printfn("fatal: out of memory");
return 1; return 1;
} }
@@ -211,60 +202,54 @@ create_makefile (manifest_t manifest)
reset_path; reset_path;
create_file_with_content ("Makefile", makefile_template, makefile_name, 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 0;
} }
static int static int create_configure(manifest_t manifest)
create_configure (manifest_t manifest)
{ {
int status = 0; int status = 0;
reset_path; reset_path;
char *cc; 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); create_file_with_content("configure", configure_template, cc);
status = system ("chmod +x configure"); status = system("chmod +x configure");
if (status) if (status)
printfn ("error: %s", strerror (status)); printfn("error: %s", strerror(status));
return status; return status;
} }
static int static int generate_source_code(manifest_t manifest)
generate_source_code (manifest_t manifest)
{ {
int status; int status;
debug ("take %s/%s", manifest.project, manifest.project); debug("take %s/%s", manifest.project, manifest.project);
status = create_and_enter_directory (manifest.project); status = create_and_enter_directory(manifest.project);
on_error ("failed to create or enter directory", status); on_error("failed to create or enter directory", status);
++depth; ++depth;
if (manifest.flag.GNU) if (manifest.flag.GNU) {
{ debug("GNU flag source branch");
debug ("GNU flag source branch");
create_file_with_content ("main.c", main_c_gnu_template, create_file_with_content("main.c", main_c_gnu_template,
manifest.project, manifest.name); manifest.project, manifest.name);
goto atexit_clean; goto atexit_clean;
} }
debug ("default sourcebranch"); debug("default sourcebranch");
create_file_with_content ("main.c", main_c_template, manifest.project, create_file_with_content("main.c", main_c_template, manifest.project,
manifest.name); manifest.name);
atexit_clean: atexit_clean:
@@ -272,22 +257,23 @@ atexit_clean:
return 0; return 0;
} }
static int static int parse_arguments(manifest_t *conf, int argc, char **argv)
parse_arguments (manifest_t *conf, int argc, char **argv)
{ {
static struct option long_options[] = { static struct option long_options[] = {
{ "GNU", no_argument, 0, 1 }, { "use-cpp", no_argument, 0, 2 }, { "GNU", no_argument, 0, 1 },
{ "git", no_argument, 0, 3 }, { "licence", required_argument, 0, 4 }, { "use-cpp", no_argument, 0, 2 },
{ "lib", required_argument, 0, 5 }, { 0, 0, 0, 0 } { "git", no_argument, 0, 3 },
{ "licence", required_argument, 0, 4 },
{ "lib", required_argument, 0, 5 },
{ 0, 0, 0, 0 }
}; };
int opt; int opt;
int long_index = 0; int long_index = 0;
while ((opt = getopt_long (argc, argv, "", long_options, &long_index)) != -1) while ((opt = getopt_long(argc, argv, "", long_options, &long_index)) !=
{ -1) {
switch (opt) switch (opt) {
{
case 1: case 1:
conf->flag.GNU = 1; conf->flag.GNU = 1;
break; break;
@@ -297,10 +283,13 @@ parse_arguments (manifest_t *conf, int argc, char **argv)
case 3: case 3:
conf->flag.git = 1; conf->flag.git = 1;
break; break;
case 4: // TODO: implement the licence options, and make it lowercase. case 4: // TODO(vx-clutch): implement the licence options, and make it lowercase.
break; break;
case 5: case 5:
ADD_LIBRARY (conf->libraries, TOlibrary (optarg)); // TODO: Get this working ADD_LIBRARY(
conf->libraries,
TOlibrary(
optarg)); // TODO(vx-clutch): Get this working
break; break;
case '?': case '?':
break; break;
@@ -308,11 +297,9 @@ parse_arguments (manifest_t *conf, int argc, char **argv)
} }
int positional_count = 0; int positional_count = 0;
for (int i = optind; i < argc; ++i) for (int i = optind; i < argc; ++i) {
{ if (argv[i][0] == '-') {
if (argv[i][0] == '-') fprintf(stderr, "Unknown flag: %s\n", argv[i]);
{
fprintf (stderr, "Unknown flag: %s\n", argv[i]);
continue; continue;
} }
@@ -326,89 +313,81 @@ parse_arguments (manifest_t *conf, int argc, char **argv)
return 0; return 0;
} }
static int static int create_project(manifest_t manifest)
create_project (manifest_t manifest)
{ {
int status; int status;
debugc ("sanitize"); debugc("sanitize");
status = sanitize (&manifest); status = sanitize(&manifest);
on_error ("failed to sanitize format", status); on_error("failed to sanitize format", status);
done; done;
debugc ("take %s", manifest.project); debugc("take %s", manifest.project);
status = create_and_enter_directory (manifest.project); status = create_and_enter_directory(manifest.project);
depth = 0; depth = 0;
on_error ("failed to create or enter directory", status); on_error("failed to create or enter directory", status);
done; done;
debugc ("create makefile"); debugc("create makefile");
status = create_makefile (manifest); status = create_makefile(manifest);
on_error ("failed to create Makefile", status); on_error("failed to create Makefile", status);
done; done;
debug ("setup git"); debug("setup git");
status = setup_git (manifest); status = setup_git(manifest);
if (status) if (status) {
{ printfn("warning: git initialization failed: %s",
printfn ("warning: git initialization failed: %s", strerror (status)); strerror(status));
} }
debug ("create .clang-format"); debug("create .clang-format");
status = maybe_create_clang_format (manifest); status = maybe_create_clang_format(manifest);
if (status) if (status) {
{ printfn("warning: clang-format setup failed: %s",
printfn ("warning: clang-format setup failed: %s", strerror (status)); strerror(status));
} }
debugc ("generate source code"); debugc("generate source code");
status = generate_source_code (manifest); status = generate_source_code(manifest);
on_error ("failed to generate source code", status); on_error("failed to generate source code", status);
done; done;
debugc ("get libraries"); debugc("get libraries");
status = create_libraries (manifest); status = create_libraries(manifest);
on_error ("failed to get libraries", status); on_error("failed to get libraries", status);
done; done;
return 0; return 0;
} }
int int main(int argc, char **argv)
main (int argc, char **argv)
{ {
int status; int status;
manifest_t manifest = { 0 };
if (argc < 2) if (argc == 0) {
{ status = 1; // emit suggestion
printfn ("error: not enough arguments."); usage(status);
return 1; return 1;
} }
status = parse_standard_options (usage, argc, argv); status = parse_standard_options(usage, argc, argv);
if (status && status != HELP_REQUESTED) {
if (status && status != HELP_REQUESTED) printfn("error: %s", strerror(status));
{
printfn ("error: %s", strerror (status));
return status; return status;
} }
manifest_t manifest = { 0 }; // TODO(vx-clutch): runtime git bin check
parse_arguments (&manifest, argc, argv); parse_arguments(&manifest, argc, argv);
status = create_project(manifest);
if (!manifest.name) // TODO: Move to sanitize
{
struct passwd *pw = getpwuid (getuid ());
manifest.name = (pw && pw->pw_name) ? pw->pw_name : DEFAULT_USER_NAME;
}
status = create_project (manifest);
#ifdef DEBUG
if (!status) if (!status)
debug ("project made successfully"); debug("project made successfully");
else else
debug ("something when wrong"); debug("something when wrong");
#endif
exit (status); return status;
} }