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

View File

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

View File

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

View File

@@ -246,13 +246,6 @@ char *standard_h_template =
line ("#ifndef STANDARD_H")
line ("#define STANDARD_H")
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 ()
line ("#endif");

View File

@@ -4,7 +4,7 @@
*
* This project and file is licenced under the BSD-3-Clause licence.
* <https://opensource.org/licence/bsd-3-clause>
*/
*/
// Usage: yait [OPTION]... PROJECT [NAME]
@@ -35,8 +35,8 @@
the project tree. This is used in reset_path_ () */
int depth;
#define print_option(option, description) \
printf (" %-20s %-20s\n", option, description)
#define print_option(option, description) \
printf(" %-20s %-20s\n", option, description)
// clang-format off
static void
@@ -65,350 +65,329 @@ usage (int status)
/* 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
right place. */
#define reset_path reset_path_ ()
static int
reset_path_ ()
#define reset_path reset_path_()
static int reset_path_()
{
while (depth != 0)
{
if (chdir ("..") != 0)
return errno;
else
--depth;
}
return 0;
while (depth != 0) {
if (chdir("..") != 0)
return errno;
else
--depth;
}
return 0;
}
static int
sanitize (manifest_t *m)
// TODO(vx-clutch): sanitize the alpha-numeric range
static int sanitize(manifest_t *m)
{
if (!m->project)
m->project = DEFAULT_PROJECT_NAME;
if (!m->name)
m->name = DEFAULT_USER_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->project)
m->project = DEFAULT_PROJECT_NAME;
if (!m->name)
m->name = DEFAULT_USER_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;
return 0;
if (!m->name) {
struct passwd *pw = getpwuid(getuid());
m->name = (pw && pw->pw_name) ? pw->pw_name : DEFAULT_USER_NAME;
}
return 0;
}
#define get(url) status = system ("git submodule add -q " url)
static int
create_libraries (manifest_t manifest)
#define get(url) status = system("git submodule add -q " url)
static int create_libraries(manifest_t manifest)
{
int status = 0;
int status = 0;
if (!manifest.libraries)
{
return status;
}
if (!manifest.libraries) {
return status;
}
reset_path;
reset_path;
for (int i = 0; i < LIB_COUNT_; ++i)
{
if HAS_LIBRARY (manifest.libraries, LIB_RAYLIB)
{
REMOVE_LIBRARY (manifest.libraries, LIB_RAYLIB);
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;
for (int i = 0; i < LIB_COUNT_; ++i) {
if HAS_LIBRARY (manifest.libraries, LIB_RAYLIB) {
REMOVE_LIBRARY(manifest.libraries, LIB_RAYLIB);
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");
}
}
return status;
}
static int
create_licence (manifest_t manifest, char **licence_line_buffer)
static int create_licence(manifest_t manifest, char **licence_line_buffer)
{
if (manifest.licence == UNLICENCE)
return 0;
if (manifest.licence == UNLICENCE)
return 0;
reset_path;
/* TODO: Run better checks on licence_line_buffer to ensure we have enough
reset_path;
/* 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
figure out. */
assert (licence_line_buffer != NULL);
assert(licence_line_buffer != NULL);
// TODO: Remove this and actually implement the features.
#define TODO() \
printfn ("Not impl"); \
assert (1 == 2)
// TODO(vx-clutch): Remove this and actually implement the features.
#define TODO() \
printfn("Not impl"); \
assert(1 == 2)
switch (manifest.licence)
{
case BSD3:
*licence_line_buffer = "Bsd";
TODO ();
break;
case GPLv3:
TODO ();
break;
case MIT:
TODO ();
break;
case UNLICENCE:
default:
printfn ("bad logic in create_licence ()");
return 1;
}
return 0;
switch (manifest.licence) {
case BSD3:
*licence_line_buffer = "Bsd";
TODO();
break;
case GPLv3:
TODO();
break;
case MIT:
TODO();
break;
case UNLICENCE:
default:
printfn("bad logic in create_licence ()");
return 1;
}
return 0;
}
static int
maybe_create_clang_format (manifest_t manifest)
static int maybe_create_clang_format(manifest_t manifest)
{
if (!manifest.flag.clang_format)
return 0;
int status;
if (!manifest.flag.clang_format)
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);
return status;
}
static int
setup_git (manifest_t manifest)
static int setup_git(manifest_t manifest)
{
if (!manifest.flag.git)
return 0;
if (!manifest.flag.git) {
return 0;
}
reset_path;
reset_path;
int status = system("git init --quiet");
if (status) {
printfn("failed on git initialize: %s", strerror(status));
}
int status = system ("git init --quiet");
if (status)
printfn ("failed on git initialize: %s", strerror (status));
return status;
return status;
}
static int
create_makefile (manifest_t manifest)
static int create_makefile(manifest_t manifest)
{
char *makefile_name = strdup (manifest.project);
if (!makefile_name)
{
printfn ("fatal: out of memory");
return 1;
}
char *makefile_name = strdup(manifest.project);
if (!makefile_name) {
printfn("fatal: out of memory");
return 1;
}
for (char *p = makefile_name; *p; ++p)
if (*p >= 'a' && *p <= 'z')
*p -= 32;
for (char *p = makefile_name; *p; ++p)
if (*p >= 'a' && *p <= 'z')
*p -= 32;
reset_path;
reset_path;
create_file_with_content ("Makefile", makefile_template, makefile_name,
makefile_name, makefile_name, makefile_name,
makefile_name, makefile_name, manifest.project,
makefile_name, makefile_name);
create_file_with_content("Makefile", makefile_template, makefile_name,
makefile_name, makefile_name, makefile_name,
makefile_name, makefile_name, manifest.project,
makefile_name, makefile_name);
free (makefile_name);
return 0;
free(makefile_name);
return 0;
}
static int
create_configure (manifest_t manifest)
static int create_configure(manifest_t manifest)
{
int status = 0;
reset_path;
int status = 0;
reset_path;
char *cc;
if (manifest.flag.use_cpp)
{
cc = "trycc g++\ntrycc CC\ntrycc clang++\n";
}
else
{
cc = "trycc gcc\ntrycc cc\ntrycc clang\n";
}
char *cc;
if (manifest.flag.use_cpp) {
cc = "trycc g++\ntrycc CC\ntrycc clang++\n";
} else {
cc = "trycc gcc\ntrycc cc\ntrycc clang\n";
}
create_file_with_content ("configure", configure_template, cc);
status = system ("chmod +x configure");
if (status)
printfn ("error: %s", strerror (status));
return status;
create_file_with_content("configure", configure_template, cc);
status = system("chmod +x configure");
if (status)
printfn("error: %s", strerror(status));
return status;
}
static int
generate_source_code (manifest_t manifest)
static int generate_source_code(manifest_t manifest)
{
int status;
int status;
debug ("take %s/%s", manifest.project, manifest.project);
status = create_and_enter_directory (manifest.project);
on_error ("failed to create or enter directory", status);
++depth;
debug("take %s/%s", manifest.project, manifest.project);
status = create_and_enter_directory(manifest.project);
on_error("failed to create or enter directory", status);
++depth;
if (manifest.flag.GNU)
{
debug ("GNU flag source branch");
if (manifest.flag.GNU) {
debug("GNU flag source branch");
create_file_with_content ("main.c", main_c_gnu_template,
manifest.project, manifest.name);
create_file_with_content("main.c", main_c_gnu_template,
manifest.project, manifest.name);
goto atexit_clean;
}
goto atexit_clean;
}
debug ("default sourcebranch");
create_file_with_content ("main.c", main_c_template, manifest.project,
manifest.name);
debug("default sourcebranch");
create_file_with_content("main.c", main_c_template, manifest.project,
manifest.name);
atexit_clean:
reset_path;
return 0;
reset_path;
return 0;
}
static int
parse_arguments (manifest_t *conf, int argc, char **argv)
static int parse_arguments(manifest_t *conf, int argc, char **argv)
{
static struct option long_options[] = {
{ "GNU", no_argument, 0, 1 }, { "use-cpp", no_argument, 0, 2 },
{ "git", no_argument, 0, 3 }, { "licence", required_argument, 0, 4 },
{ "lib", required_argument, 0, 5 }, { 0, 0, 0, 0 }
};
static struct option long_options[] = {
{ "GNU", no_argument, 0, 1 },
{ "use-cpp", no_argument, 0, 2 },
{ "git", no_argument, 0, 3 },
{ "licence", required_argument, 0, 4 },
{ "lib", required_argument, 0, 5 },
{ 0, 0, 0, 0 }
};
int opt;
int long_index = 0;
int opt;
int long_index = 0;
while ((opt = getopt_long (argc, argv, "", long_options, &long_index)) != -1)
{
switch (opt)
{
case 1:
conf->flag.GNU = 1;
break;
case 2:
conf->flag.use_cpp = 1;
break;
case 3:
conf->flag.git = 1;
break;
case 4: // TODO: implement the licence options, and make it lowercase.
break;
case 5:
ADD_LIBRARY (conf->libraries, TOlibrary (optarg)); // TODO: Get this working
break;
case '?':
break;
}
}
while ((opt = getopt_long(argc, argv, "", long_options, &long_index)) !=
-1) {
switch (opt) {
case 1:
conf->flag.GNU = 1;
break;
case 2:
conf->flag.use_cpp = 1;
break;
case 3:
conf->flag.git = 1;
break;
case 4: // TODO(vx-clutch): implement the licence options, and make it lowercase.
break;
case 5:
ADD_LIBRARY(
conf->libraries,
TOlibrary(
optarg)); // TODO(vx-clutch): Get this working
break;
case '?':
break;
}
}
int positional_count = 0;
for (int i = optind; i < argc; ++i)
{
if (argv[i][0] == '-')
{
fprintf (stderr, "Unknown flag: %s\n", argv[i]);
continue;
}
int positional_count = 0;
for (int i = optind; i < argc; ++i) {
if (argv[i][0] == '-') {
fprintf(stderr, "Unknown flag: %s\n", argv[i]);
continue;
}
if (positional_count == 0)
conf->name = argv[i];
else if (positional_count == 1)
conf->project = argv[i];
++positional_count;
}
if (positional_count == 0)
conf->name = argv[i];
else if (positional_count == 1)
conf->project = argv[i];
++positional_count;
}
return 0;
return 0;
}
static int
create_project (manifest_t manifest)
static int create_project(manifest_t manifest)
{
int status;
int status;
debugc ("sanitize");
status = sanitize (&manifest);
on_error ("failed to sanitize format", status);
done;
debugc("sanitize");
status = sanitize(&manifest);
on_error("failed to sanitize format", status);
done;
debugc ("take %s", manifest.project);
status = create_and_enter_directory (manifest.project);
depth = 0;
on_error ("failed to create or enter directory", status);
done;
debugc("take %s", manifest.project);
status = create_and_enter_directory(manifest.project);
depth = 0;
on_error("failed to create or enter directory", status);
done;
debugc ("create makefile");
status = create_makefile (manifest);
on_error ("failed to create Makefile", status);
done;
debugc("create makefile");
status = create_makefile(manifest);
on_error("failed to create Makefile", status);
done;
debug ("setup git");
status = setup_git (manifest);
if (status)
{
printfn ("warning: git initialization failed: %s", strerror (status));
}
debug("setup git");
status = setup_git(manifest);
if (status) {
printfn("warning: git initialization failed: %s",
strerror(status));
}
debug ("create .clang-format");
status = maybe_create_clang_format (manifest);
if (status)
{
printfn ("warning: clang-format setup failed: %s", strerror (status));
}
debug("create .clang-format");
status = maybe_create_clang_format(manifest);
if (status) {
printfn("warning: clang-format setup failed: %s",
strerror(status));
}
debugc ("generate source code");
status = generate_source_code (manifest);
on_error ("failed to generate source code", status);
done;
debugc("generate source code");
status = generate_source_code(manifest);
on_error("failed to generate source code", status);
done;
debugc ("get libraries");
status = create_libraries (manifest);
on_error ("failed to get libraries", status);
done;
debugc("get libraries");
status = create_libraries(manifest);
on_error("failed to get libraries", status);
done;
return 0;
return 0;
}
int
main (int argc, char **argv)
int main(int argc, char **argv)
{
int status;
int status;
manifest_t manifest = { 0 };
if (argc < 2)
{
printfn ("error: not enough arguments.");
return 1;
}
if (argc == 0) {
status = 1; // emit suggestion
usage(status);
return 1;
}
status = parse_standard_options (usage, argc, argv);
status = parse_standard_options(usage, argc, argv);
if (status && status != HELP_REQUESTED) {
printfn("error: %s", strerror(status));
return status;
}
if (status && status != HELP_REQUESTED)
{
printfn ("error: %s", strerror (status));
return status;
}
// TODO(vx-clutch): runtime git bin check
manifest_t manifest = { 0 };
parse_arguments(&manifest, argc, argv);
status = create_project(manifest);
parse_arguments (&manifest, argc, argv);
#ifdef DEBUG
if (!status)
debug("project made successfully");
else
debug("something when wrong");
#endif
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);
if (!status)
debug ("project made successfully");
else
debug ("something when wrong");
exit (status);
return status;
}