save
This commit is contained in:
BIN
c-out/bin/yait
Executable file
BIN
c-out/bin/yait
Executable file
Binary file not shown.
BIN
c-out/obj/main.o
BIN
c-out/obj/main.o
Binary file not shown.
@@ -1,4 +1,4 @@
|
||||
PREFIX=/usr/bin/
|
||||
CFLAGS=-Wall -Wextra -O2
|
||||
CFLAGS=-Wall -Wextra -g
|
||||
LDFLAGS=
|
||||
CC=gcc
|
||||
CC=clang
|
||||
|
||||
@@ -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
|
||||
|
||||
44
tools/check_header
Executable file
44
tools/check_header
Executable file
@@ -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
|
||||
@@ -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 <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."
|
||||
315
yait/main.c
315
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; \
|
||||
}
|
||||
|
||||
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 "
|
||||
// "<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
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user