diff --git a/c-out/bin/yait b/c-out/bin/yait new file mode 100755 index 0000000..d987686 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 index 76b785d..30f1055 100644 Binary files a/c-out/obj/main.o and b/c-out/obj/main.o differ diff --git a/config.mak b/config.mak index d6ba4f4..4f95eb0 100644 --- a/config.mak +++ b/config.mak @@ -1,4 +1,4 @@ PREFIX=/usr/bin/ -CFLAGS=-Wall -Wextra -O2 +CFLAGS=-Wall -Wextra -g LDFLAGS= -CC=gcc +CC=clang diff --git a/tools/Cleanup b/tools/Cleanup index 3831995..9008928 100755 --- a/tools/Cleanup +++ b/tools/Cleanup @@ -4,32 +4,9 @@ make dist-clean -lint_file() { - local output - output=$(clang-tidy "$1" 2>&1 | grep -v -E 'Error while trying to load a compilation database|No compilation database found|fixed-compilation-database:|json-compilation-database:|Running without flags.') - if [[ -n "$output" ]]; then - echo "[LINT] $1:" - echo "$output" - fi -} - -whitespace_cleanup() { - sed -i 's/[ \t]*$//' "$1" - awk 'BEGIN{ORS=""} {print $0 "\n"} END{}' "$1" > "$1.tmp" && mv "$1.tmp" "$1" -} - -comment_check() { - if grep -n -E 'TODO|FIXME' "$1"; then - echo "[WARN] $1 contains TODO/FIXME comments." - fi -} - process_file() { clang-format -i "$1" tools/check_header_footer "$1" - lint_file "$1" - whitespace_cleanup "$1" - comment_check "$1" } if [[ $# -gt 0 ]]; then diff --git a/tools/check_header b/tools/check_header new file mode 100755 index 0000000..a0cc5d2 --- /dev/null +++ b/tools/check_header @@ -0,0 +1,44 @@ +#!/bin/env bash + +# Usage: ./check_header + +if pwd | grep -q tools; then + cd .. +fi + +files=$(find yait \( -name '*.c' -o -name '*.h' \)) +files+=" " +files+=$(find core \( -name '*.c' -o -name '*.h' \)) +files+=" $(find . -maxdepth 1 -type f)" + +ignore="README COPYING .clang-format config.mak" + +if [ -z "$files" ]; then + echo "No files found" + exit 0 +fi + +missing="" + +for file in $files; do + if echo "$ignore" | grep -qw "$(basename "$file")"; then + continue + fi + echo -ne "$file... " + if grep -q "Copyright (C)" "$file"; then + echo -e "\033[1;32mOK\033[0m" + else + echo -e "\033[0;31mFAIL\033[0m" + missing+="$file " + fi +done + +if [ "$missing" = "" ]; then + echo -e "\033[1;32mAll checks pass.\033[0m" +else + echo -e "\033[0;31mThe follwing files are missing copyright information.\033[0m" +fi + +for file in $missing; do + echo " - $file" +done diff --git a/tools/check_header_footer b/tools/check_header_footer deleted file mode 100755 index 3eb2be7..0000000 --- a/tools/check_header_footer +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash - -# Usage: ./ensure_header_footer.sh filename - -FILE="$1" -HEADER=$(cat <<'EOF' -// Copyright (C) 2025 vx_clutch ( owestness@gmail.com ) -// See end of file for extended copyright information. -EOF -) -HEADER+=$'\n' -FOOTER=$(cat <<'EOF' - -/* yait is yet another init tool. - * Copyright (C) 2025 vx-clutch - * - * This file is part of yait. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation or - * other materials provided with the distribution. - * 3. Neither the name of vx-clutch nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -EOF -) - -if [[ -z "$FILE" ]]; then - echo "Usage: $0 " - exit 1 -fi - -if [[ ! -f "$FILE" ]]; then - echo "Error: File '$FILE' does not exist." - exit 1 -fi - -TMP_FILE="$(mktemp)" - -read -r FIRST_LINE < "$FILE" -if [[ "$FIRST_LINE" != "$HEADER" ]]; then - echo "$HEADER" > "$TMP_FILE" - cat "$FILE" >> "$TMP_FILE" - mv "$TMP_FILE" "$FILE" -else - rm "$TMP_FILE" -fi - -if [[ "$(tail -n 1 "$FILE")" != "$FOOTER" ]]; then - echo "$FOOTER" >> "$FILE" -fi - -echo "Checked '$FILE' for header/footer." diff --git a/yait/main.c b/yait/main.c index 41e8236..499f7c5 100644 --- a/yait/main.c +++ b/yait/main.c @@ -1,9 +1,12 @@ +// Usage: yait [OPTION]... [PROJECT] (NAME) + #include "../config.h" #include "../core/file.h" #include "../core/print.h" #include "../core/standard.h" #include "contents.h" #include "format.h" +#include #include #include #include @@ -12,184 +15,284 @@ #define DEBUG -#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 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(option, description) \ - printf(" %-20s %-20s\n", option, description) +#define print_option(option, description) \ + printf (" %-20s %-20s\n", option, description) +#define on_error(msg, code) \ + if (err) \ + { \ + printfn (msg ": %s", strerror (err)); \ + return code; \ + } -int create_license_if_needed(format_t); -int create_makefile(format_t); -int create_project(format_t); -int get_license_line_and_create_license(format_t, char**); -int maybe_apply_clang_format(format_t); -int sanitize(format_t *); -int setup_git_and_permissions(format_t); +#ifdef DEBUG +#define debug(fmt, ...) \ + fprintf (stderr, "\e[0;32m[%8d]\e[0;33m " fmt "\e[0m\n", __LINE__, \ + ##__VA_ARGS__) +#define debugc(fmt, ...) \ + fprintf (stderr, "\e[0;32m[%8d]\e[0;33m " fmt "...\e[0m", __LINE__, \ + ##__VA_ARGS__) +#define done fprintf(stderr, "done.\n") +#else +#define debug(fmt, ...) +#define debugc(fmt, ...) +#define done +#endif + +// int create_license_if_needed (format_t); +// int get_license_line_and_create_license (format_t, char **); +int create_configure (); +int create_makefile (format_t); +int create_project (format_t); +int generate_source_files (format_t); +int maybe_apply_clang_format (format_t); +int reset_path_ (); +int sanitize (format_t *); +int setup_git (format_t); + +int depth; void -usage(int status) +usage (int status) { if (status != 0) { - fprintf(stderr, "Try 'yait --help' for more information.\n"); + fprintf (stderr, "Try 'yait --help' for more information.\n"); return; } - 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: gpl]"); - 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"); + 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]"); + 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"); } int -main(int argc, char **argv) +main (int argc, char **argv) { if (argc < 2) { - printfn("error: not enough arguments."); + printfn ("error: not enough arguments."); return 1; } - int status = initialize_main(&argc, &argv); - status = parse_standard_options(usage, argc, argv); + int status = initialize_main (&argc, &argv); + status = parse_standard_options (usage, argc, argv); if (status && status != HELP_REQUESTED) { - printfn("error: %s", strerror(status)); + printfn ("error: %s", strerror (status)); return status; } - format_t conf; - conf.project = argv[0]; - conf.name = (argc > 2) ? argv[1] : NULL; + format_t conf = { 0 }; + + conf.project = argv[0]; // fix: project name is argv[1] + conf.name = (argc > 1) ? argv[1] : NULL; // fix: name is optional, at argv[2] if (!conf.name) { - struct passwd *pw = getpwuid(getuid()); + struct passwd *pw = getpwuid (getuid ()); conf.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.licence = DEFAULT_LICENSE; - #ifdef DEBUG - system(strcat("rm -rf ", conf.project)); - #endif - return create_project(conf); + + return create_project (conf); } int -create_project(format_t fmt) +create_project (format_t fmt) { int err; - err = create_and_enter_directory(fmt.project); - if (err) - { - printfn("failed to create or enter directory: %s", strerror(err)); - return err; - } + debugc ("sanitize... "); + err = sanitize (&fmt); + on_error ("failed to sanitize format", err); + done; - err = sanitize(&fmt); - if (err) - { - printfn("failed to sanitize format: %s", strerror(err)); - return err; - } + debugc ("take %s", fmt.project); + err = create_and_enter_directory (fmt.project); + on_error ("failed to create or enter directory", err); + done; + depth = 0; - err = create_license_if_needed(fmt); - if (err) - { - printfn("failed to create license: %s", strerror(err)); - return err; - } + // debug ("create licenseing"); + // err = create_license_if_needed (fmt); + // on_error ("failed to create license", err); - err = create_makefile(fmt); - if (err) - { - printfn("failed to create Makefile: %s", strerror(err)); - return err; - } + debugc ("create makefile"); + err = create_makefile (fmt); + on_error ("failed to create Makefile", err); + done; - err = setup_git_and_permissions(fmt); + debug ("setup git"); + err = setup_git (fmt); if (err) - { - printfn("warning: git initialization failed: %s", strerror(err)); - // continue even if git fails - } + printfn ("warning: git initialization failed: %s", strerror (err)); - err = maybe_apply_clang_format(fmt); + debug ("create .clang-format"); + err = maybe_apply_clang_format (fmt); if (err) - { - printfn("warning: clang-format setup failed: %s", strerror(err)); - } + printfn ("warning: clang-format setup failed: %s", strerror (err)); return 0; } +#define reset_path reset_path_ () int -sanitize(format_t *fmt) +reset_path_ () +{ + while (depth != 0) + { + if (chdir ("..") != 0) + return errno; + else + depth--; + } + return 0; +} + +int +sanitize (format_t *fmt) { if (!fmt->name) fmt->name = DEFAULT_USER_NAME; - return 0; } -int -create_license_if_needed(format_t fmt) -{ - char *license_line = NULL; - return get_license_line_and_create_license(fmt, &license_line); -} +// int +// create_license_if_needed (format_t fmt) +// { +// char *license_line = NULL; +// return get_license_line_and_create_license (fmt, &license_line); +// } +// +// int +// get_license_line_and_create_license (format_t fmt, char +// **license_line_buffer) +// { +// switch (fmt.licence) +// { +// case BSD3: +// *license_line_buffer = "License BSD-3-Clause: BSD-3-Clause " +// ""; +// return create_file_with_content ("COPYING", bsd3_license_template, +// YEAR, +// fmt.name); +// +// case GPLv3: +// default: +// *license_line_buffer = "License GPLv3: GNU GPL version 3 " +// ""; +// return create_file_with_content ("COPYING", gplv3_license_template, +// YEAR, +// fmt.name); +// } +// } int -get_license_line_and_create_license(format_t fmt, char **license_line_buffer) -{ - switch (fmt.licence) - { - case BSD3: - *license_line_buffer = - "License BSD-3-Clause: BSD-3-Clause "; - return create_file_with_content("COPYING", bsd3_license_template, YEAR, fmt.name); - - case GPLv3: - default: - *license_line_buffer = "License GPLv3: GNU GPL version 3 "; - return create_file_with_content("COPYING", gplv3_license_template, YEAR, fmt.name); - } -} - -int -maybe_apply_clang_format(format_t fmt) +maybe_apply_clang_format (format_t fmt) { if (!fmt.flag.clang_format) return 0; - const char *clang_fmt = "BasedOnStyle: LLVM\nIndentWidth: 2\nUseTab: Never\n"; - return create_file_with_content(".clang-format", clang_fmt, 0, NULL); + reset_path; + + char *clang_fmt = "BasedOnStyle: LLVM\nIndentWidth: 2\nUseTab: Never\n"; + return create_file_with_content (".clang-format", clang_fmt, 0, NULL); } int -setup_git_and_permissions(format_t fmt) +setup_git (format_t fmt) { if (!fmt.flag.git) return 0; - int err = system("git init --quiet"); + reset_path; + + int err = system ("git init --quiet"); if (err) - { - printfn("failed on git initialize: %s", strerror(err)); - } + printfn ("failed on git initialize: %s", strerror (err)); + return err; } + +int +create_makefile (format_t fmt) +{ + char *makefile_name = strdup (fmt.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; + + reset_path; + + create_file_with_content ("Makefile", makefile_template, makefile_name, + makefile_name, makefile_name, makefile_name, + makefile_name, makefile_name, fmt.project, + makefile_name); + + free (makefile_name); + return 0; +} + +int +create_configure () +{ + reset_path; + + create_file_with_content ("configure", configure_template); + int err = system ("chmod +x configure"); + if (err) + printfn ("error: %s", strerror (err)); + return err; +} + +int +generate_source_files (format_t fmt) +{ + int err; + + debug ("take %s/%s", fmt.project, fmt.project); + err = create_and_enter_directory (fmt.project); + on_error ("failed to create or enter directory", err); + + if (fmt.flag.GNU) + { + debug ("GNU flag source branch"); + + create_file_with_content ("main.c", main_c_gnu_template); + + goto atexit_clean; + } + + debug ("default sourcebranch"); + create_file_with_content ("main.c", main_c_template); + +atexit_clean: + reset_path; + return 0; +}