diff --git a/TODO b/TODO new file mode 100644 index 0000000..edf0753 --- /dev/null +++ b/TODO @@ -0,0 +1,6 @@ +1 Fix arg parseing +2 Fix generated Makefile +3 Add Licence + +Ideas +1 Add --is-lib diff --git a/c-out/bin/yait b/c-out/bin/yait new file mode 100755 index 0000000..45bcda4 Binary files /dev/null and b/c-out/bin/yait differ diff --git a/c-out/obj/main.o b/c-out/obj/main.o new file mode 100644 index 0000000..8523098 Binary files /dev/null and b/c-out/obj/main.o differ diff --git a/config.mak b/config.mak new file mode 100644 index 0000000..fcef174 --- /dev/null +++ b/config.mak @@ -0,0 +1,4 @@ +PREFIX=/usr/bin/ +CFLAGS=-Wall -Wextra -ggdb +LDFLAGS= +CC=clang diff --git a/yait/contents.h b/yait/contents.h index 95c6d59..bf36f41 100644 --- a/yait/contents.h +++ b/yait/contents.h @@ -59,9 +59,7 @@ char *configure_template = line ("done") line () line ("printf \"checking for C compiler... \"") - line ("trycc gcc") - line ("trycc cc") - line ("trycc clang") + line ("%s") line ("printf \"%s\\n\" \"$CC\"") line () line ("printf \"checking weather C compiler works... \"") @@ -87,7 +85,7 @@ char *makefile_template = line ("prefix = /usr/bin") line () line ("%s_SRCS := $(shell find . -name '%s/*.c')") - line ("%s_OBJS := $(patsubst ./%.c,c-out/obj/%%.o,$(%s_SRCS))") + line ("%s_OBJS := $(patsubst ./%%.c,c-out/obj/%%.o,$(%s_SRCS))") line () line ("%s := c-out/bin/%s") line () @@ -127,7 +125,7 @@ char *makefile_template = line ("dist-clean: clean") line ("\trm -f config.mak") line () - line (".PHONY: all clean dist-clean install uninstall build format"); + line (".PHONY: all clean dist-clean install uninstall"); /* .clang-format template */ char *clang_format_template = diff --git a/yait/debug.h b/yait/debug.h index ea25e5b..be71958 100644 --- a/yait/debug.h +++ b/yait/debug.h @@ -11,9 +11,9 @@ } #else #define on_error(msg, code) \ - if (err) \ + if (code) \ { \ - printfn (msg ": %s", strerror (err)); \ + printfn (msg ": %s", strerror (code)); \ return code; \ } #endif diff --git a/yait/format.h b/yait/format.h index 106c23b..6c45aff 100644 --- a/yait/format.h +++ b/yait/format.h @@ -1,41 +1,39 @@ /* Copyright (C) vx_clutch - * + * * This file is part of yait * * This project and file is licenced under the BSD-3-Clause licence. - * + * */ #ifndef FORMAT_H #define FORMAT_H #include +#include -/* License type enumeration */ typedef enum { - BSD3, /* BSD 3-Clause License */ - GPLv3, /* GNU General Public License v3 */ - MIT, /* MIT License */ - UNlICENSE, /* Unlicense */ -} license_t; + BSD3, /* BSD 3-Clause Licence */ + GPLv3, /* GNU General Public Licence v3 */ + MIT, /* MIT Licence */ + UNLICENCE, /* Unlicence */ + LICENCE_HELP, /* Help case */ +} licence_t; -/* Library type enumeration - using bit flags for multiple selection */ +/* A bit field is used so that we can accomplish two things. (a) store lots of + libraries without taxing memory; and (b) a dynamic array is not neccescary. + */ typedef enum { - LIB_NONE = 0, /* No libraries selected */ - LIB_RAYLIB = 1 << 0, /* Raylib game library */ - LIB_WINAPI = 1 << 1, /* Windows API */ - LIB_CURL = 1 << 2, /* cURL library */ - /* Future libraries can be added here: - * LIB_OPENGL = 1 << 3, - * LIB_SDL2 = 1 << 4, - * LIB_GTK = 1 << 5, - * etc. - */ + LIB_NONE = 0, /* No libraries selected */ + LIB_RAYLIB = 1 << 0, /* Raylib game library */ + LIB_NCURSES = 1 << 1, /* Windows API */ + LIB_CURL = 1 << 2, /* cURL library */ + LIB_COUNT_, /* Number of Libraries */ + LIB_HELP, /* Help case */ } lib_flags_t; -/* Flag option type struct */ typedef struct { bool GNU; @@ -44,26 +42,39 @@ typedef struct bool use_cpp; } flags_t; -/* Project configuration structure */ typedef struct { - license_t license; /* License type for the project */ - char *project; /* Project name */ - char *name; /* Author/creator name */ + licence_t licence; /* Licence type for the project */ + char *project; /* Project name */ + char *name; /* Author/creator name ( if not provided infered on sanitize ) */ lib_flags_t libraries; /* Selected libraries (bit field) */ flags_t flag; /* Flags */ -} format_t; +} manifest_t; -/* Default values */ -#define DEFAULT_LICENSE BSD3 -#define DEFAULT_GIT_INIT true #define DEFAULT_CLANG_FORMAT true +#define DEFAULT_GIT_INIT true +#define DEFAULT_GNU false #define DEFAULT_LIBRARIES LIB_NONE +#define DEFAULT_LICENCE BSD3 -/* Helper macros for library operations */ #define HAS_LIBRARY(libs, lib) ((libs) & (lib)) #define ADD_LIBRARY(libs, lib) ((libs) |= (lib)) #define REMOVE_LIBRARY(libs, lib) ((libs) &= ~(lib)) -#define CLEAR_LIBRARIES(libs) ((libs) = LIB_NONE) + +static lib_flags_t +TOlibrary (char *src) +{ + if (strcmp (src, "raylib")) + return LIB_RAYLIB; + if (strcmp (src, "ncurse")) + return LIB_NCURSES; + if (strcmp (src, "ncurses")) + return LIB_NCURSES; + if (strcmp (src, "curl")) + return LIB_CURL; + if (strcmp (src, "help")) + return LIB_HELP; + return LIB_COUNT_; /* bad case */ +} #endif diff --git a/yait/main.c b/yait/main.c index 328d31a..f310ab3 100644 --- a/yait/main.c +++ b/yait/main.c @@ -3,8 +3,8 @@ * This file is part of yait * * This project and file is licenced under the BSD-3-Clause licence. - * - */ + * + */ // Usage: yait [OPTION]... PROJECT [NAME] @@ -22,22 +22,23 @@ #include "../core/print.h" #include "../core/standard.h" #include "contents.h" -#include "format.h" #include "debug.h" +#include "format.h" #define DEFAULT_USER_NAME "unknown" #define DEFAULT_PROJECT_NAME "Project" -#define DEFAULT_LICENSE BSD3 +#define DEFAULT_LICENCE BSD3 #define DEFAULT_GIT_INIT 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 */ + the project tree. This is used in reset_path_ () */ int depth; #define print_option(option, description) \ printf (" %-20s %-20s\n", option, description) +// clang-format off static void usage (int status) { @@ -50,18 +51,20 @@ usage (int status) printf ("Usage: yait [OPTION]... PROJECT [NAME]\n"); printf ("Creates a C project with opinionated defaults.\n"); printf ("When only given the first argument it will detect your name.\n\n"); - printf ("Mandatory arguments to long options are mandatory for short " - "options too\n"); - print_option ("-l, --license=NAME", - "Set license (gpl, mit, bsd) [default: bsd]"); + printf ("Mandatory arguments to long options are mandatory for short options too\n"); + print_option ("-l, --licence=NAME", "Set licence (gpl, mit, bsd) [default: bsd]"); + print_option ("--lib=LIB", "Add a library to the project. You can list libraries with --lib=help."); print_option ("--use-cpp", "Uses the CPP language instead of C"); print_option ("--git", "Initialize git repository"); print_option ("--GNU", "Adds standard GNU argument parsing to your project"); printf (" --help display this help text and exit\n"); printf (" --version output version information and exit\n"); } +// clang-format on -/* This macro exist purely because I like how it looks. */ +/* 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_ () @@ -77,43 +80,78 @@ reset_path_ () } static int -sanitize (format_t *fmt) +sanitize (manifest_t *m) { - if (!fmt->project) - fmt->project = DEFAULT_PROJECT_NAME; - if (!fmt->name) - fmt->name = DEFAULT_USER_NAME; - if (fmt->license != BSD3 && fmt->license != GPLv3 && fmt->license != MIT) - fmt->license = DEFAULT_LICENSE; - fmt->flag.git = fmt->flag.git ? true : DEFAULT_GIT_INIT; - fmt->flag.clang_format - = fmt->flag.clang_format ? true : DEFAULT_CLANG_FORMAT; - fmt->flag.GNU = fmt->flag.GNU ? true : false; + 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; } +#define get(url) status = system ("git submodule add -q " url) static int -create_license (format_t fmt, char **license_line_buffer) +create_libraries (manifest_t manifest) { - if (fmt.license == UNlICENSE) + int status = 0; + + if (!manifest.libraries) + { + return status; + } + + 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; +} + +static int +create_licence (manifest_t manifest, char **licence_line_buffer) +{ + if (manifest.licence == UNLICENCE) return 0; reset_path; - /* TODO: Run better checks on license_line_buffer to ensure we have enough + /* TODO: 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 (license_line_buffer != NULL); + figure out. */ + assert (licence_line_buffer != NULL); // TODO: Remove this and actually implement the features. #define TODO() \ printfn ("Not impl"); \ assert (1 == 2) - switch (fmt.license) + switch (manifest.licence) { case BSD3: - *license_line_buffer = "Bsd"; + *licence_line_buffer = "Bsd"; TODO (); break; case GPLv3: @@ -122,9 +160,9 @@ create_license (format_t fmt, char **license_line_buffer) case MIT: TODO (); break; - case UNlICENSE: + case UNLICENCE: default: - printfn ("bad logic in create_license_and_set_license_line()"); + printfn ("bad logic in create_licence ()"); return 1; } @@ -132,36 +170,35 @@ create_license (format_t fmt, char **license_line_buffer) } static int -maybe_apply_clang_format (format_t fmt) +maybe_create_clang_format (manifest_t manifest) { - if (!fmt.flag.clang_format) + if (!manifest.flag.clang_format) return 0; reset_path; - char *clang_fmt = "BasedOnStyle: LLVM\nIndentWidth: 2\nUseTab: Never\n"; - return create_file_with_content (".clang-format", clang_fmt, 0, NULL); + return create_file_with_content (".clang-format", clang_format_template); } static int -setup_git (format_t fmt) +setup_git (manifest_t manifest) { - if (!fmt.flag.git) + if (!manifest.flag.git) return 0; reset_path; - int err = system ("git init --quiet"); - if (err) - printfn ("failed on git initialize: %s", strerror (err)); + int status = system ("git init --quiet"); + if (status) + printfn ("failed on git initialize: %s", strerror (status)); - return err; + return status; } static int -create_makefile (format_t fmt) +create_makefile (manifest_t manifest) { - char *makefile_name = strdup (fmt.project); + char *makefile_name = strdup (manifest.project); if (!makefile_name) { printfn ("fatal: out of memory"); @@ -176,7 +213,7 @@ create_makefile (format_t fmt) create_file_with_content ("Makefile", makefile_template, makefile_name, makefile_name, makefile_name, makefile_name, - makefile_name, makefile_name, fmt.project, + makefile_name, makefile_name, manifest.project, makefile_name, makefile_name); free (makefile_name); @@ -184,38 +221,51 @@ create_makefile (format_t fmt) } static int -create_configure () +create_configure (manifest_t manifest) { + int status = 0; reset_path; - create_file_with_content ("configure", configure_template); - int err = system ("chmod +x configure"); - if (err) - printfn ("error: %s", strerror (err)); - return err; + 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; } static int -generate_source_code (format_t fmt) +generate_source_code (manifest_t manifest) { - int err; + int status; - debug ("take %s/%s", fmt.project, fmt.project); - err = create_and_enter_directory (fmt.project); - on_error ("failed to create or enter directory", err); + 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 (fmt.flag.GNU) + if (manifest.flag.GNU) { debug ("GNU flag source branch"); - create_file_with_content ("main.c", main_c_gnu_template, fmt.project, - fmt.name); + create_file_with_content ("main.c", main_c_gnu_template, + manifest.project, manifest.name); goto atexit_clean; } debug ("default sourcebranch"); - create_file_with_content ("main.c", main_c_template, fmt.project, fmt.name); + create_file_with_content ("main.c", main_c_template, manifest.project, + manifest.name); atexit_clean: reset_path; @@ -223,14 +273,13 @@ atexit_clean: } static int -parse_arguments (format_t *conf, int argc, char **argv) +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 }, - { "license", required_argument, 0, 4 }, - { 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; @@ -248,12 +297,16 @@ parse_arguments (format_t *conf, int argc, char **argv) case 3: conf->flag.git = 1; break; - case 4: // TODO: Licence + 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; } } + int positional_count = 0; for (int i = optind; i < argc; ++i) { @@ -264,56 +317,58 @@ parse_arguments (format_t *conf, int argc, char **argv) } if (positional_count == 0) - { - conf->project = argv[i]; - } + conf->name = argv[i]; else if (positional_count == 1) - { - conf->name = argv[i]; - } + conf->project = argv[i]; ++positional_count; } + return 0; } static int -create_project (format_t fmt) +create_project (manifest_t manifest) { - int err; + int status; debugc ("sanitize"); - err = sanitize (&fmt); - on_error ("failed to sanitize format", err); + status = sanitize (&manifest); + on_error ("failed to sanitize format", status); done; - debugc ("take %s", fmt.project); - err = create_and_enter_directory (fmt.project); + debugc ("take %s", manifest.project); + status = create_and_enter_directory (manifest.project); depth = 0; - on_error ("failed to create or enter directory", err); + on_error ("failed to create or enter directory", status); done; - // debug ("create licenseing"); - // err = create_license_if_needed (fmt); - // on_error ("failed to create license", err); - debugc ("create makefile"); - err = create_makefile (fmt); - on_error ("failed to create Makefile", err); + status = create_makefile (manifest); + on_error ("failed to create Makefile", status); done; debug ("setup git"); - err = setup_git (fmt); - if (err) - printfn ("warning: git initialization failed: %s", strerror (err)); + status = setup_git (manifest); + if (status) + { + printfn ("warning: git initialization failed: %s", strerror (status)); + } debug ("create .clang-format"); - err = maybe_apply_clang_format (fmt); - if (err) - printfn ("warning: clang-format setup failed: %s", strerror (err)); + status = maybe_create_clang_format (manifest); + if (status) + { + printfn ("warning: clang-format setup failed: %s", strerror (status)); + } debugc ("generate source code"); - err = generate_source_code (fmt); - on_error ("failed to generate source code", err); + 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; return 0; @@ -339,23 +394,18 @@ main (int argc, char **argv) return status; } - format_t conf = { 0 }; + manifest_t manifest = { 0 }; - // TODO: Argument Parsing - conf.project = "sample_project"; - conf.name = "vx_clutch"; + parse_arguments (&manifest, argc, argv); - if (!conf.name) + if (!manifest.name) // TODO: Move to sanitize { struct passwd *pw = getpwuid (getuid ()); - conf.name = (pw && pw->pw_name) ? pw->pw_name : DEFAULT_USER_NAME; + manifest.name = (pw && pw->pw_name) ? pw->pw_name : DEFAULT_USER_NAME; } - conf.flag.git = DEFAULT_GIT_INIT; - conf.flag.clang_format = DEFAULT_CLANG_FORMAT; - conf.license = DEFAULT_LICENSE; + status = create_project (manifest); - status = create_project (conf); if (!status) debug ("project made successfully"); else