From 1e08c7e33b00e57f840ae8eb57246ac3144289d5 Mon Sep 17 00:00:00 2001 From: vx-clutch Date: Fri, 18 Jul 2025 20:05:28 -0400 Subject: [PATCH] bulk changes --- config.h | 6 ++ core/file.c | 36 ++++++------ core/file.h | 29 +++++++++- core/print.c | 4 +- core/print.h | 11 +++- core/standard.c | 6 +- core/standard.h | 9 ++- yait/format.h | 36 +++++++----- yait/main.c | 142 ++++++++++++++++++++++++++++++++++-------------- 9 files changed, 196 insertions(+), 83 deletions(-) diff --git a/config.h b/config.h index b9db241..6de86b8 100644 --- a/config.h +++ b/config.h @@ -1,10 +1,16 @@ #ifndef CONFIG_H #define CONFIG_H +/* Program information */ #define PROGRAM "yait" #define LICENSE_LINE "License BSD-3-Clause: BSD-3-Clause " #define AUTHORS "vx_clutch" #define VERSION "pre-alpha" #define YEAR 2025 +/* Custom error codes */ +#define HELP_REQUESTED 2 +#define ERROR_MEMORY_ALLOCATION 3 +#define ERROR_DIRECTORY_CREATION 4 + #endif diff --git a/core/file.c b/core/file.c index bd79a6c..cf7b61d 100644 --- a/core/file.c +++ b/core/file.c @@ -1,4 +1,5 @@ #include "file.h" +#include "../config.h" #include #include #include @@ -6,38 +7,39 @@ #include int -touch (char *path, char *format, ...) +create_file_with_content (char *path, char *format, ...) { FILE *fp = fopen (path, "w"); if (!fp) { - return 0; - } - - else - { - va_list args; - va_start (args, format); - vfprintf (fp, format, args); - va_end (args); + return -1; } + va_list args; + va_start (args, format); + vfprintf (fp, format, args); + va_end (args); fclose (fp); return 0; } int -dir (char *format, ...) +create_directory (char *format, ...) { va_list args; va_start (args, format); - char path[1024]; - vsnprintf (path, sizeof (path), format, args); - + char path[MAX_PATH_LENGTH]; + int result = vsnprintf (path, sizeof (path), format, args); va_end (args); - if (mkdir (path, 0777) < 0) + /* Check if the path was truncated */ + if (result >= (int)sizeof (path)) + { + return ENAMETOOLONG; + } + + if (mkdir (path, DEFAULT_DIR_PERMISSIONS) < 0) { return errno; } @@ -46,9 +48,9 @@ dir (char *format, ...) } int -take (const char *dirname) +create_and_enter_directory (const char *dirname) { - int err = dir ("%s", dirname); + int err = create_directory ("%s", dirname); if (err) { return err; diff --git a/core/file.h b/core/file.h index 46869af..c5cdc1d 100644 --- a/core/file.h +++ b/core/file.h @@ -3,9 +3,32 @@ #include -int take(const char *dirname); +/* Constants for file operations */ +#define DEFAULT_DIR_PERMISSIONS 0755 +#define MAX_PATH_LENGTH 1024 -int touch(char *, char *, ...); -int dir(char *, ...); +/** + * Create directory and change into it + * @param dirname Directory name to create and enter + * @return 0 on success, errno on failure + */ +int create_and_enter_directory(const char *dirname); + +/** + * Create a file with formatted content + * @param path File path to create + * @param format Format string for file content + * @param ... Variable arguments for formatting + * @return 0 on success, -1 on failure + */ +int create_file_with_content(char *path, char *format, ...); + +/** + * Create a directory with formatted path + * @param format Format string for directory path + * @param ... Variable arguments for formatting + * @return 0 on success, errno on failure + */ +int create_directory(char *format, ...); #endif diff --git a/core/print.c b/core/print.c index 1ba0bfe..c9226a7 100644 --- a/core/print.c +++ b/core/print.c @@ -3,14 +3,14 @@ #include int -printfn (char *format, ...) +print_error_with_prefix (char *format, ...) { int len; va_list args; va_start (args, format); fprintf (stderr, "yait: "); len = vfprintf (stderr, format, args); - putchar ('\n'); + fprintf (stderr, "\n"); /* Use stderr consistently */ va_end (args); return len; } diff --git a/core/print.h b/core/print.h index 4daf967..bebec9d 100644 --- a/core/print.h +++ b/core/print.h @@ -4,6 +4,15 @@ #include #include -int printfn(char *, ...); +/** + * Print a formatted message to stderr with program prefix and newline + * @param format Format string (printf-style) + * @param ... Variable arguments for formatting + * @return Number of characters printed + */ +int print_error_with_prefix(char *format, ...); + +/* Legacy function name for backward compatibility */ +#define printfn print_error_with_prefix #endif diff --git a/core/standard.c b/core/standard.c index 4bcf4f5..8c68159 100644 --- a/core/standard.c +++ b/core/standard.c @@ -12,7 +12,7 @@ parse_standard_options (void (*usage) (int), int argc, char **argv) if (strcmp (argv[i], "--help") == 0) { usage (0); - exit (0); + exit (EXIT_SUCCESS); } else if (strcmp (argv[i], "--version") == 0) { @@ -20,8 +20,8 @@ parse_standard_options (void (*usage) (int), int argc, char **argv) "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 (0); + exit (EXIT_SUCCESS); } } - return 1; + return HELP_REQUESTED; } diff --git a/core/standard.h b/core/standard.h index f419887..fe59d76 100644 --- a/core/standard.h +++ b/core/standard.h @@ -1,6 +1,13 @@ #ifndef STANDARD_H #define STANDARD_H -int parse_standard_options(void (*)(), int argc, char **argv); +/** + * Parse standard command line options (--help, --version) + * @param usage_func Function pointer to usage display function + * @param argc Argument count + * @param argv Argument vector + * @return 0 on success, 1 if help/version requested, errno on error + */ +int parse_standard_options(void (*usage_func)(), int argc, char **argv); #endif diff --git a/yait/format.h b/yait/format.h index 0ec37d2..fe30cdb 100644 --- a/yait/format.h +++ b/yait/format.h @@ -1,27 +1,35 @@ -#ifndef CORE_H -#define CORE_H +#ifndef FORMAT_H +#define FORMAT_H #include +/* License type enumeration */ typedef enum { - BSD3, - GPLv3, - MIT, - UNLICENCE, + BSD3, /* BSD 3-Clause License */ + GPLv3, /* GNU General Public License v3 */ + MIT, /* MIT License */ + UNLICENCE, /* Unlicense */ } licence_t; +/* Library type enumeration */ typedef enum { - RAYLIB, - WINAPI, - cURL, + RAYLIB, /* Raylib game library */ + WINAPI, /* Windows API */ + cURL, /* cURL library */ } lib_t; +/* Project configuration structure */ typedef struct { - bool git; - bool clang_format; - licence_t licence; - char *project; - char *name; + bool git; /* Whether to initialize git repository */ + bool clang_format; /* Whether to create .clang-format file */ + licence_t licence; /* License type for the project */ + char *project; /* Project name */ + char *name; /* Author/creator name */ } format_t; +/* Default values */ +#define DEFAULT_LICENSE BSD3 +#define DEFAULT_GIT_INIT true +#define DEFAULT_CLANG_FORMAT true + #endif diff --git a/yait/main.c b/yait/main.c index d212732..6629569 100644 --- a/yait/main.c +++ b/yait/main.c @@ -10,12 +10,27 @@ #include #include -int create (format_t); +/* Constants for program behavior */ +#define DEFAULT_USER_NAME "unknown" +#define DEFAULT_PROJECT_NAME "Project" +#define DEFAULT_LICENSE BSD3 +#define DEFAULT_GIT_INIT true +#define DEFAULT_CLANG_FORMAT true -#define print_option(left, right) \ - printf (" %-20s %-20s" \ - "\n", \ - left, right) +/** + * Create a new C project with the specified configuration + * @param fmt Project configuration structure + * @return 0 on success, non-zero on failure + */ +int create_project (format_t fmt); + +/** + * Print a formatted option line for help text + * @param option The option name (left side) + * @param description The option description (right side) + */ +#define print_option(option, description) \ + printf (" %-20s %-20s\n", option, description) void usage (int status) @@ -49,10 +64,10 @@ main (int argc, char **argv) return 1; } int status = parse_standard_options (usage, argc, argv); - if (status && status != 1) + if (status && status != HELP_REQUESTED) { printfn ("error: %s", strerror (status)); - return 1; + return status; } format_t conf; conf.project = argv[1]; @@ -61,19 +76,28 @@ main (int argc, char **argv) else { struct passwd *pw = getpwuid (getuid ()); - conf.name = pw ? pw->pw_name : NULL; + if (pw && pw->pw_name) + conf.name = pw->pw_name; + else + conf.name = DEFAULT_USER_NAME; } - conf.git = true; - conf.clang_format = true; - conf.licence = BSD3; - create (conf); - return 0; + conf.git = DEFAULT_GIT_INIT; + conf.clang_format = DEFAULT_CLANG_FORMAT; + conf.licence = DEFAULT_LICENSE; + + int result = create_project (conf); + return result; } +/** + * Create a new C project with the specified configuration + * @param fmt Project configuration structure + * @return 0 on success, non-zero on failure + */ int -create (format_t fmt) +create_project (format_t fmt) { - int err = take (fmt.project); + int err = create_and_enter_directory (fmt.project); if (err) { printfn ("failed to create or enter directory: %s", strerror (err)); @@ -81,7 +105,9 @@ create (format_t fmt) } if (fmt.git) system ("git init --quiet"); - touch ("README", + if (!fmt.name) + fmt.name = DEFAULT_USER_NAME; + create_file_with_content ("README", "%s ( concise description )\n\n" "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do " "eiusmod tempor\n" @@ -94,8 +120,8 @@ create (format_t fmt) "fugiat nulla pariatur. Excepteur sint occaecat cupidatat non " "proident, sunt in\n" "culpa qui officia deserunt mollit anim id est laborum.", - fmt.project); - touch ("configure", + fmt.project ? fmt.project : DEFAULT_PROJECT_NAME); + create_file_with_content ("configure", "#!/bin/sh\n" "\n" "usage() {\n" @@ -153,30 +179,60 @@ create (format_t fmt) "printf \"LDFLAGS=%%s\\n\" \"$LDFLAGS\" >> config.mak\n" "printf \"CC=%%s\\n\" \"$CC\" >> config.mak\n" "printf \"done\\n\"\n"); - char *mkfile_name; - strcpy(mkfile_name, fmt.project); - for (char *p = mkfile_name; *p; ++p) *p = toupper(*p); - touch ("Makefile", - "prefix = /usr/bin\n\n%s_SRCS := $(wildcard yait/*.c) $(wildcard " - "core/*.c)\n%s_OBJS := $(patsubst " - "yait/%.c,c-out/obj/%.o,$(%s_SRCS))\n\n%s := " - "c-out/bin/yait\n\n-include config.mak\n\nifeq ($(wildcard " - "config.mak),)\nall:\n\t@echo \"File config.mak not found, run " - "configure\"\n\t@exit 1\nelse\n\nall: build $(%s) " - "$(%s_DOC)\n\nbuild:\n\tmkdir -p c-out/bin\n\tmkdir -p " - "c-out/obj\n\nc-out/obj/%.o: yait/%.c\n\t$(CC) $(CFLAGS) -c $< -o " - "$@\n\n$(%s): $(%s_OBJS)\n\t$(CC) $(CFLAGS) -DCOMMIT=$(shell git " - "rev-list --count --all) $^ -o $@\n\n\nendif\n\ninstall:\n\t@echo " - "\"NOT IMPL\"\n\texit 1\n\nuninstall:\n\t@echo \"NOT IMPL\"\n\texit " - "1\n\nclean:\n\trm -rf c-out\n\ndist-clean: clean\n\trm -f " - "config.mak\n\n.PHONY: all clean dist-clean install uninstall build " - "format\n", mkfile_name, mkfile_name, mkfile_name, mkfile_name, mkfile_name, mkfile_name); + // Create a safe uppercase version of the project name for Makefile variables + char *mkfile_name = strdup (fmt.project); + if (!mkfile_name) + { + printfn ("fatal: out of memory"); + return 1; + } + // Convert to uppercase safely, only for ASCII characters + for (char *p = mkfile_name; *p; ++p) + { + if (*p >= 'a' && *p <= 'z') + *p = *p - 'a' + 'A'; + } + create_file_with_content ("Makefile", + "prefix = /usr/bin\n\n" + "%s_SRCS := $(wildcard *.c)\n" + "%s_OBJS := $(patsubst %%.c,c-out/obj/%%.o,$(%s_SRCS))\n\n" + "%s := c-out/bin/%s\n\n" + "-include config.mak\n\n" + "ifeq ($(wildcard config.mak),)\n" + "all:\n" + "\t@echo \"File config.mak not found, run configure\"\n" + "\t@exit 1\n" + "else\n\n" + "all: build $(%s)\n\n" + "build:\n" + "\tmkdir -p c-out/bin\n" + "\tmkdir -p c-out/obj\n\n" + "c-out/obj/%%.o: %%.c\n" + "\t$(CC) $(CFLAGS) -c $< -o $@\n\n" + "$(%s): $(%s_OBJS)\n" + "\t$(CC) $(CFLAGS) -DCOMMIT=$(shell git rev-list --count --all " + "2>/dev/null || echo 0) $^ -o $@\n\n" + "endif\n\n" + "install:\n" + "\t@echo \"NOT IMPL\"\n" + "\texit 1\n\n" + "uninstall:\n" + "\t@echo \"NOT IMPL\"\n" + "\texit 1\n\n" + "clean:\n" + "\trm -rf c-out\n\n" + "dist-clean: clean\n" + "\trm -f config.mak\n\n" + ".PHONY: all clean dist-clean install uninstall build format\n", + mkfile_name, mkfile_name, mkfile_name, mkfile_name, fmt.project, + mkfile_name, mkfile_name, mkfile_name); + free (mkfile_name); if (fmt.clang_format) - touch (".clang-format", "Language: Cpp\nBasedOnStyle: GNU\n"); + create_file_with_content (".clang-format", "Language: Cpp\nBasedOnStyle: GNU\n"); switch (fmt.licence) { case BSD3: - touch ( + create_file_with_content ( "COPYING", "BSD 3-Clause License\n\nCopyright (c) %d, " "%s\n\nRedistribution and use in source and binary forms, " @@ -184,7 +240,7 @@ create (format_t fmt) "following conditions are met:\n\n1. Redistributions of source code " "must retain the above copyright notice, this\n list of " "conditions and the following disclaimer.\n\n2. Redistributions in " - "binary form must reproduce the above copyright notice,\n this " + "binary form must reproduce the above copyright notice,\n this\n" "list of conditions and the following disclaimer in the " "documentation\n and/or other materials provided with the " "distribution.\n\n3. Neither the name of the copyright holder nor " @@ -205,13 +261,15 @@ create (format_t fmt) "POSSIBILITY OF SUCH DAMAGE.\n", YEAR, fmt.name); break; + case GPLv3: default: break; } - take (fmt.project); - touch ("main.c", + create_and_enter_directory (fmt.project); + create_file_with_content ("main.c", "#include \n\nint main(void) {\n printf(\"%s: Hello " "%s!\\n\");\nreturn 0;\n}", - fmt.project, fmt.name); + fmt.project ? fmt.project : DEFAULT_PROJECT_NAME, + fmt.name ? fmt.name : "World"); return 0; }