commit 9e94f5ce44b60d6922ac7424abaaec8b89ae1dd0
parent f62cecbfd3a130fa9289ef6f2885a394a05e0989
Author: vx-clutch <[email protected]>
Date: Wed, 23 Jul 2025 13:40:29 -0400
save
Diffstat:
7 files changed, 251 insertions(+), 198 deletions(-)
diff --git a/c-out/bin/yait b/c-out/bin/yait
Binary files differ.
diff --git a/c-out/obj/main.o b/c-out/obj/main.o
Binary files differ.
diff --git 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
@@ -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
@@ -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
@@ -1,71 +0,0 @@
-#!/bin/bash
-
-# Usage: ./ensure_header_footer.sh filename
-
-FILE="$1"
-HEADER=$(cat <<'EOF'
-// Copyright (C) 2025 vx_clutch ( [email protected] )
-// 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 <filename>"
- 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
@@ -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 <errno.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
@@ -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; \
+ }
+#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 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);
+// 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_ ()
{
- if (!fmt->name)
- fmt->name = DEFAULT_USER_NAME;
-
+ while (depth != 0)
+ {
+ if (chdir ("..") != 0)
+ return errno;
+ else
+ depth--;
+ }
return 0;
}
int
-create_license_if_needed(format_t fmt)
+sanitize (format_t *fmt)
{
- char *license_line = NULL;
- return get_license_line_and_create_license(fmt, &license_line);
+ if (!fmt->name)
+ fmt->name = DEFAULT_USER_NAME;
+ return 0;
}
-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 <https://opensource.org/licence/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 <https://www.gnu.org/licenses/gpl-3.0.html>";
- return create_file_with_content("COPYING", gplv3_license_template, YEAR, fmt.name);
- }
-}
+// 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 "
+// "<https://opensource.org/license/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 "
+// "<https://www.gnu.org/licenses/gpl-3.0.html>";
+// 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));
+
+ return err;
+}
+
+int
+create_makefile (format_t fmt)
+{
+ char *makefile_name = strdup (fmt.project);
+ if (!makefile_name)
{
- printfn("failed on git initialize: %s", strerror(err));
+ 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;
+}