yait

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit d847c2fcb6e0a488d1342fd75bfbe1a3135c7ebf
parent 90fadf3980c5c531e105edb1843a84abb2e2bea5
Author: vx-clutch <[email protected]>
Date:   Sun, 28 Sep 2025 22:06:39 -0400

save

Diffstat:
A.gitmodules | 3+++
MMakefile | 8++++----
MTODO | 2+-
Agcklib | 1+
Minclude/yait.h | 17+----------------
Alib/err.c | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/err.h | 24++++++++++++++++++++++++
Alib/proginfo.c | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/proginfo.h | 22++++++++++++++++++++++
Alib/str_dup.c | 12++++++++++++
Alib/str_dup.h | 6++++++
Alib/xmem.c | 36++++++++++++++++++++++++++++++++++++
Alib/xmem.h | 18++++++++++++++++++
Msrc/create_project.c | 326++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/main.c | 277+++++++++++++++++--------------------------------------------------------------
Asrc/name.c | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/name.h | 14++++++++++++++
Dsrc/standard.c | 34----------------------------------
Dsrc/standard.h | 8--------
Msrc/util.c | 2+-
20 files changed, 630 insertions(+), 444 deletions(-)

diff --git a/.gitmodules b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "gcklib"] + path = gcklib + url = https://github.com/gck-org/gcklib diff --git a/Makefile b/Makefile @@ -1,11 +1,11 @@ PREFIX = /usr/bin/ -YAIT_SRCS := $(wildcard src/*.c) +YAIT_SRCS := $(wildcard src/*.c) $(wildcard lib/*.c) YAIT_OBJS := $(patsubst src/%.c,build/obj/%.o,$(YAIT_SRCS)) YAIT := bin/yait -ALLOWED_DIRS = doc include man src tools +ALLOWED_DIRS = doc include man src tools lib DISTDIRS := $(sort $(shell find . -maxdepth 1 -type d -not -name '.' -printf '%f\n')) -include config.mak @@ -23,10 +23,10 @@ build: mkdir -p build/obj build/obj/%.o: src/%.c config.mak - $(CC) $(CFLAGS) -DCOMMIT=$(shell git rev-list --count --all) -Iinclude -c $< -o $@ + $(CC) $(CFLAGS) -DCOMMIT=$(shell git rev-list --count --all) -Iinclude -Ilib -c $< -o $@ $(YAIT): $(YAIT_OBJS) - $(CC) $(CFLAGS) -Iinclude -DCOMMIT=$(shell git rev-list --count --all) $^ -o $@ + $(CC) $(CFLAGS) -Iinclude -Ilib -DCOMMIT=$(shell git rev-list --count --all) $^ -o $@ endif diff --git a/TODO b/TODO @@ -3,7 +3,7 @@ GCK yait - TODO Todo: * Refactor to more GNU style main - * Implement the extra option + * Factor out str_dup * Build tarball with Makefile * Polish for 1.0 diff --git a/gcklib b/gcklib @@ -0,0 +1 @@ +Subproject commit 432788eb5f78afb08b7c011b81118c7f9bc520d9 diff --git a/include/yait.h b/include/yait.h @@ -9,25 +9,10 @@ #ifndef YAIT_H #define YAIT_H -typedef enum { MIT, GPL, BSD, UNL, LCOUNT } licence_t; -typedef enum { MAKE, CMAKE, AUTOTOOLS, BARE, BCOUNT } built_t; +typedef enum { MIT, GPL, BSD } licence_t; typedef struct { licence_t licence; - built_t build; - - bool lib; - - bool git; - bool flat; - bool open_editor; - - struct { - bool build_nob; - bool tools_format; - bool tools_Cleanup; - } extra; - char *project; char *author; char *editor; diff --git a/lib/err.c b/lib/err.c @@ -0,0 +1,151 @@ +/* Copyright (C) GCK + * + * This file is part of gcklib + * + * This project and file is licensed under the BSD-3-Clause license. + * <https://opensource.org/licenses/BSD-3-Clause> + */ + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "err.h" + +#define RESET "\e[0m" +#define ERROR "\e[1;91m" +#define WARN "\e[1;95m" +#define NOTE "\e[1;94m" +#define HINT "\e[38;5;166m" + +static bool __check(void) +{ + static int done = 0; + static bool cached = false; + + if (!done) { + const char *term = getenv("TERM"); + cached = isatty(STDOUT_FILENO) && term != NULL && + (strstr(term, "color") != NULL || + strstr(term, "ansi") != NULL || + strstr(term, "xterm") != NULL); + done = 1; + } + + return cached; +} + +void errorf(const char *format, ...) +{ + va_list args; + va_start(args, format); + + if (__check()) { + fprintf(stderr, "%serror%s: ", ERROR, RESET); + } else { + fputs("error: ", stderr); + } + + vfprintf(stderr, format, args); + fputc('\n', stderr); + + va_end(args); +} +void fatalf(const char *format, ...) +{ + va_list args; + va_start(args, format); + + if (__check()) { + fprintf(stderr, "%sfatal%s: ", ERROR, RESET); + } else { + fputs("fatal: ", stderr); + } + + vfprintf(stderr, format, args); + fputc('\n', stderr); + + va_end(args); + + exit(EXIT_FAILURE); +} +void warnf(const char *format, ...) +{ + va_list args; + va_start(args, format); + + if (__check()) { + fprintf(stderr, "%swarning%s: ", WARN, RESET); + } else { + fputs("warning: ", stderr); + } + + vfprintf(stderr, format, args); + fputc('\n', stderr); + + va_end(args); +} +void notef(const char *format, ...) +{ + va_list args; + va_start(args, format); + + if (__check()) { + fprintf(stderr, "%snote%s: ", NOTE, RESET); + } else { + fputs("note: ", stderr); + } + + vfprintf(stderr, format, args); + fputc('\n', stderr); + + va_end(args); +} +void hintf(const char *format, ...) +{ + va_list args; + va_start(args, format); + + if (__check()) { + fprintf(stderr, "%shint: ", HINT); + } else { + fputs("hint: ", stderr); + } + + vfprintf(stderr, format, args); + + if (__check()) { + fprintf(stderr, "%s\n", RESET); + } else { + fputc('\n', stderr); + } + + va_end(args); +} + +void errorfa(int code) +{ + errorf(strerror(code)); +} + +void fatalfa(int code) +{ + fatalf(strerror(code)); +} + +void notefa(int code) +{ + notef(strerror(code)); +} + +void warnfa(int code) +{ + warnf(strerror(code)); +} + +void hintfa(int code) +{ + hintf(strerror(code)); +} diff --git a/lib/err.h b/lib/err.h @@ -0,0 +1,24 @@ +/* Copyright (C) GCK + * + * This file is part of gcklib + * + * This project and file is licensed under the BSD-3-Clause licence. + * <https://opensource.org/licence/bsd-3-clause> + */ + +#ifndef ERR_H +#define ERR_H + +void errorf(const char *format, ...); +void fatalf(const char *format, ...); +void notef(const char *format, ...); +void warnf(const char *format, ...); +void hintf(const char *format, ...); + +void errorfa(int code); +void fatalfa(int code); +void notefa(int code); +void warnfa(int code); +void hintfa(int code); + +#endif diff --git a/lib/proginfo.c b/lib/proginfo.c @@ -0,0 +1,52 @@ +/* Copyright (C) GCK + * + * This file is part of gcklib + * + * This project and file is licensed under the BSD-3-Clause licence. + * <https://opensource.org/licence/bsd-3-clause> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "../config.h" + +#include "proginfo.h" + +const char *prog_name = ""; + +void set_prog_name(const char *name) +{ + prog_name = prog_name ? name : ""; +} + +void emit_try_help() +{ + printf("Try '%s --help' for more information\n", prog_name); +} + +void emit_version() +{ + printf("\ +%s %s %d\n\ +Copyright (C) %d GCK.\n\ +This is free software: you are free to change and redistribute it.\n\ +There is NO WARRNTY, to the extent permitted by law.\n\ +", + prog_name, VERSION, COMMIT, YEAR); +} + +int parse_standard_options(int argc, char **argv, void (*usage)(int), + void (*version)()) +{ + for (int i = 0; i < argc; ++i) { + if (!strcmp(argv[i], "--help")) { + usage(0); + exit(EXIT_SUCCESS); + } else if (!strcmp(argv[i], "--version")) { + emit_version(); + exit(EXIT_SUCCESS); + } + } + return 0; +} diff --git a/lib/proginfo.h b/lib/proginfo.h @@ -0,0 +1,22 @@ +/* Copyright (C) GCK + * + * This file is part of gcklib + * + * This project and file is licensed under the BSD-3-Clause licence. + * <https://opensource.org/licence/bsd-3-clause> + */ + +#ifndef proginfo_H +#define proginfo_H + +extern const char *prog_name; + +void set_prog_name(const char *name); + +void emit_try_help(); +void emit_version(); + +int parse_standard_options(int argc, char **argv, void (*usage)(int), + void (*version)()); + +#endif diff --git a/lib/str_dup.c b/lib/str_dup.c @@ -0,0 +1,12 @@ +#include <stdlib.h> +#include <string.h> +#include "xmem.h" + +#include "str_dup.h" + +char *str_dup(char *s) +{ + char *new = xmalloc(strlen(s) + 1); + strcpy(new, s); + return new; +} diff --git a/lib/str_dup.h b/lib/str_dup.h @@ -0,0 +1,6 @@ +#ifndef STR_DUP_H +#define STR_DUP_H + +char *str_dup(char *s); + +#endif diff --git a/lib/xmem.c b/lib/xmem.c @@ -0,0 +1,36 @@ +/* Copyright (C) GCK + * + * This file is part of gcklib + * + * This project and file is licensed under the BSD-3-Clause licence. + * <https://opensource.org/licence/bsd-3-clause> + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "err.h" + +#include "xmem.h" + +void *ensure_nonnull(void *ptr) +{ + if (ptr == NULL) + fatalf("memory exhausted"); + return ptr; +} + +void *xmalloc(size_t size) +{ + return ensure_nonnull(malloc(size)); +} + +void *xrealloc(void *ptr, size_t size) +{ + return ensure_nonnull(realloc(ptr, size)); +} + +void *xcalloc(size_t nmemb, size_t size) +{ + return ensure_nonnull(calloc(nmemb, size)); +} diff --git a/lib/xmem.h b/lib/xmem.h @@ -0,0 +1,18 @@ +/* Copyright (C) GCK + * + * This file is part of gcklib + * + * This project and file is licensed under the BSD-3-Clause licence. + * <https://opensource.org/licence/bsd-3-clause> + */ + +#ifndef xmem_H +#define xmem_H + +#include <stdlib.h> + +void *xmalloc(size_t size); +void *xrealloc(void *ptr, size_t size); +void *xcalloc(size_t nmemb, size_t size); + +#endif diff --git a/src/create_project.c b/src/create_project.c @@ -17,166 +17,166 @@ #include "licences/licences.h" #include "util.h" -int create_project(manifest_t manifest) -{ - int status; - char buffer[BUFSIZ], *main_source; - - status = mkdir_p(manifest.project); - if (status) - return 1; - - status = chdir(manifest.project); - if (status) - return 1; - - cfprintf( - "README", - "%s ( short description )\n\nThis cool project actions adverbly.\n", - manifest.project); - - if (manifest.build != BARE) { - main_source = manifest.flat ? "main.c" : "src/main.c"; - cfprintf(main_source, "#include <stdio.h>\n" - "\n" - "int main()\n" - "{\n" - "\tputs(\"Hello, World!\");\n" - "\treturn 0;\n" - "}\n"); - } - char *upr_name = tostrupr(manifest.project); - switch (manifest.build) { - case MAKE: - cfprintf( - "Makefile", - "PREFIX = /usr/bin\n" - "\n" - "%s_SRCS := $(wildcard src/*.c)\n" - "%s_OBJS := $(patsubst src/%.c,build/obj/%.o,$(%s_SRCS))" - "\n" - "%s := bin/%s" - "\n" - "-include config.mak\n" - "\n" - "ifeq ($(wildcard config.mak),)\n", - upr_name, upr_name, upr_name, upr_name, - manifest.project); - break; - case CMAKE: - cfprintf("CMakeLists.txt", - "cmake_minimum_required(VERSION 3.16)\n" - "\n" - "project(%s\n" - " VERSION 0.1.0\n" - " LANGUAGES C)\n" - "\n" - "set(CMAKE_C_STANDARD 23)\n" - "set(CMAKE_C_STANDARD_REQUIRED ON)\n" - "set(CMAKE_C_EXTENSIONS OFF)\n" - "\n" - "include(GNUInstallDirs)\n" - "\n" - "add_executable(%s\n" - " src/main.c\n" - ")\n" - "\n" - "install(TARGETS %s\n" - " RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}\n" - ")\n", - manifest.project, manifest.project, manifest.project); - break; - case AUTOTOOLS: - cfprintf("configure.ac", - "AC_PREREQ([2.69])\n" - "AC_INIT([%s], [0.1], [[email protected]])\n" - "AM_INIT_AUTOMAKE([foreign -Wall])\n" - "AC_CONFIG_SRCDIR([src/main.c])\n" - "AC_CONFIG_HEADERS([config.h])" - "AC_PROG_CC\n" - "AC_CONFIG_FILES([Makefile src/Makefile])\n" - "AC_OUTPUT\n", - manifest.project); - cfprintf("Makefile.am", "SUBDIRS = src\n"); - cfprintf("src/Makefile.am", - "bin_PROGRAMS = %s\n" - "%s_SOURCES = main.c\n", - manifest.project, manifest.project); - cfprintf("bootstrap", - "#!/bin/sh\n" - "set -e\n" - "\n" - "autoreconf --install --verbose --force\n"); - break; - case BARE: - snprintf(buffer, BUFSIZ, "%s.c", manifest.project); - cfprintf(buffer, ""); - main_source = str_dup(buffer); - cfprintf("Makefile", - ".POSIX:\n" - "CC ::= gcc\n" - "CFLAGS ::= -std=c23 -Wall -Wextra -Wpedantic\n" - "\n" - "all: %s\n" - "\n" - "clean:\n" - "\t$(RM) %s", - manifest.project, manifest.project); - break; - case BCOUNT: - default: - abort(); - } - - flast = true; - switch (manifest.licence) { - case MIT: - cfprintf("COPYING", "%s", MIT_txt); - break; - case GPL: - cfprintf("COPYING", "%s", GPL_3_0_txt); - break; - case BSD: - cfprintf("COPYING", "%s", BSD_3_Clause_txt); - break; - case UNL: - cfprintf("COPYING", "%s", UNLICENSE_txt); - break; - case LCOUNT: - default: - abort(); - } - - if (!manifest.git) { - fprintf(stderr, "Initializing git reposity"); - status = system("git init --quiet"); - if (status) - fprintf(stderr, ", failed.\n"); - else - fprintf(stderr, ", done.\n"); - } - - if (manifest.build == AUTOTOOLS) { - fprintf(stderr, "Changing files permissions 1"); - struct stat st; - if (stat("bootstrap", &st) == -1) { - perror("stat failed"); - return 1; - } - mode_t new_mode = st.st_mode | S_IXUSR; - if (chmod("bootstrap", new_mode) == -1) { - perror("chmod failed"); - return 1; - } - fprintf(stderr, ", done.\n"); - } - - if (manifest.open_editor) { - snprintf(buffer, BUFSIZ, "$EDITOR %s", main_source); - status = system(buffer); - if (status) - fprintf(stderr, "Could not open editor"); - } - - return 0; -} +// int create_project(manifest_t manifest) +// { +// int status; +// char buffer[BUFSIZ], *main_source; +// +// status = mkdir_p(manifest.project); +// if (status) +// return 1; +// +// status = chdir(manifest.project); +// if (status) +// return 1; +// +// cfprintf( +// "README", +// "%s ( short description )\n\nThis cool project actions adverbly.\n", +// manifest.project); +// +// if (manifest.build != BARE) { +// main_source = manifest.flat ? "main.c" : "src/main.c"; +// cfprintf(main_source, "#include <stdio.h>\n" +// "\n" +// "int main()\n" +// "{\n" +// "\tputs(\"Hello, World!\");\n" +// "\treturn 0;\n" +// "}\n"); +// } +// char *upr_name = tostrupr(manifest.project); +// switch (manifest.build) { +// case MAKE: +// cfprintf( +// "Makefile", +// "PREFIX = /usr/bin\n" +// "\n" +// "%s_SRCS := $(wildcard src/*.c)\n" +// "%s_OBJS := $(patsubst src/%.c,build/obj/%.o,$(%s_SRCS))" +// "\n" +// "%s := bin/%s" +// "\n" +// "-include config.mak\n" +// "\n" +// "ifeq ($(wildcard config.mak),)\n", +// upr_name, upr_name, upr_name, upr_name, +// manifest.project); +// break; +// case CMAKE: +// cfprintf("CMakeLists.txt", +// "cmake_minimum_required(VERSION 3.16)\n" +// "\n" +// "project(%s\n" +// " VERSION 0.1.0\n" +// " LANGUAGES C)\n" +// "\n" +// "set(CMAKE_C_STANDARD 23)\n" +// "set(CMAKE_C_STANDARD_REQUIRED ON)\n" +// "set(CMAKE_C_EXTENSIONS OFF)\n" +// "\n" +// "include(GNUInstallDirs)\n" +// "\n" +// "add_executable(%s\n" +// " src/main.c\n" +// ")\n" +// "\n" +// "install(TARGETS %s\n" +// " RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}\n" +// ")\n", +// manifest.project, manifest.project, manifest.project); +// break; +// case AUTOTOOLS: +// cfprintf("configure.ac", +// "AC_PREREQ([2.69])\n" +// "AC_INIT([%s], [0.1], [[email protected]])\n" +// "AM_INIT_AUTOMAKE([foreign -Wall])\n" +// "AC_CONFIG_SRCDIR([src/main.c])\n" +// "AC_CONFIG_HEADERS([config.h])" +// "AC_PROG_CC\n" +// "AC_CONFIG_FILES([Makefile src/Makefile])\n" +// "AC_OUTPUT\n", +// manifest.project); +// cfprintf("Makefile.am", "SUBDIRS = src\n"); +// cfprintf("src/Makefile.am", +// "bin_PROGRAMS = %s\n" +// "%s_SOURCES = main.c\n", +// manifest.project, manifest.project); +// cfprintf("bootstrap", +// "#!/bin/sh\n" +// "set -e\n" +// "\n" +// "autoreconf --install --verbose --force\n"); +// break; +// case BARE: +// snprintf(buffer, BUFSIZ, "%s.c", manifest.project); +// cfprintf(buffer, ""); +// main_source = str_dup(buffer); +// cfprintf("Makefile", +// ".POSIX:\n" +// "CC ::= gcc\n" +// "CFLAGS ::= -std=c23 -Wall -Wextra -Wpedantic\n" +// "\n" +// "all: %s\n" +// "\n" +// "clean:\n" +// "\t$(RM) %s", +// manifest.project, manifest.project); +// break; +// case BCOUNT: +// default: +// abort(); +// } +// +// flast = true; +// switch (manifest.licence) { +// case MIT: +// cfprintf("COPYING", "%s", MIT_txt); +// break; +// case GPL: +// cfprintf("COPYING", "%s", GPL_3_0_txt); +// break; +// case BSD: +// cfprintf("COPYING", "%s", BSD_3_Clause_txt); +// break; +// case UNL: +// cfprintf("COPYING", "%s", UNLICENSE_txt); +// break; +// case LCOUNT: +// default: +// abort(); +// } +// +// if (!manifest.git) { +// fprintf(stderr, "Initializing git reposity"); +// status = system("git init --quiet"); +// if (status) +// fprintf(stderr, ", failed.\n"); +// else +// fprintf(stderr, ", done.\n"); +// } +// +// if (manifest.build == AUTOTOOLS) { +// fprintf(stderr, "Changing files permissions 1"); +// struct stat st; +// if (stat("bootstrap", &st) == -1) { +// perror("stat failed"); +// return 1; +// } +// mode_t new_mode = st.st_mode | S_IXUSR; +// if (chmod("bootstrap", new_mode) == -1) { +// perror("chmod failed"); +// return 1; +// } +// fprintf(stderr, ", done.\n"); +// } +// +// if (manifest.open_editor) { +// snprintf(buffer, BUFSIZ, "$EDITOR %s", main_source); +// status = system(buffer); +// if (status) +// fprintf(stderr, "Could not open editor"); +// } +// +// return 0; +// } diff --git a/src/main.c b/src/main.c @@ -8,258 +8,101 @@ // Usage: yait [OPTION]... <PROJECT> -#define _POSIX_C_SOURCE 200809L // popen extention #include <getopt.h> #include <pwd.h> #include <stdio.h> #include <stdlib.h> #include <limits.h> -#include <string.h> +#include <errno.h> #include <unistd.h> #include <stdarg.h> +#include <string.h> +#include "../lib/proginfo.h" +#include "../lib/err.h" #include "../include/yait.h" -#include "standard.h" -#include "util.h" #include "../config.h" +#include "name.h" -#define print_option(option, description) \ - printf(" %-20s %-20s\n", option, description) +static struct option longopts[] = { { "author", required_argument, 0, 'a' }, + { "licence", required_argument, 0, 'l' }, + { 0, 0, 0, 0 } }; -static void usage(int status) -{ - if (status != 0) { - puts("Try 'yait --help' for more information."); - return; - } +static int exit_status; - printf("Usage: %s [OPTION]... [project-name]\n", PROGRAM); - fputs("\ -Generates an optionated C project.\n", - stdout); - puts(""); - fputs("\ - --help display this help and exit\n\ - --version display version information and eixt\n", - stdout); - puts(""); - fputs("\ - --git Initialize git repository (default)\n\ - --no-git Do not initialize git repository\n\ - --lib Make this a library\n\ - -l <licence> Set licence. This list can be found by passing 'list'\n\ - -E Open $EDITOR after project creation\n\ - --autotools Use the autotools build system\n\ - --cmake Use the cmake build system\n\ - --make Use the GNU make build system (default)\n\ - --bare Minimal C project structure\n\ - --flat All files in project root.\n\ - --extras=<arg1>,<arg2> Extra build options, Pass list to list out options.\n", - stdout); -} +static void usage(int status); -void print_lines(const char *first, ...) +int main(int argc, char **argv) { - va_list args; - const char *s; - - va_start(args, first); - - for (s = first; s != NULL; s = va_arg(args, const char *)) - printf("%s\n", s); + int optc; + int lose = 0; + set_prog_name(argv[0]); - va_end(args); -} - -static inline int parse_extras_token(manifest_t *conf, const char *s) -{ - if (!strcmp(s, "list")) { - print_lines("nob", "Cleanup", "format", NULL); - exit(EXIT_SUCCESS); - } + exit_status = EXIT_SUCCESS; - if (!strcmp(s, "nob")) - return conf->extra.build_nob = true, 0; - if (!strcmp(s, "Cleanup")) - return conf->extra.tools_Cleanup = true, 0; - if (!strcmp(s, "format")) - return conf->extra.tools_format = true, 0; - fprintf(stderr, "Option '%s' is not valid. See %s --extras=list\n", s, - PROGRAM); - return 1; -} + manifest_t manifest = { + .author = get_name(), + .editor = NULL, + .licence = BSD, + .project = "Project", + }; -static int parse_arguments(manifest_t *conf, int argc, char **argv) -{ - int opt, option_index; + parse_standard_options(argc, argv, usage, emit_version); - // clang-format off - static struct option long_opts[] = { - { "git", no_argument, 0, 'g' }, - { "no-git", no_argument, 0, 'G' }, - { "lib", no_argument, 0, 'L' }, - { "autotools", no_argument, 0, 'a' }, - { "cmake", no_argument, 0, 'c' }, - { "make", no_argument, 0, 'm' }, - { "bare", no_argument, 0, 'B' }, - { "flat", no_argument, 0, 'f' }, - { "author", required_argument, 0, 'A' }, - { "extras", required_argument, 0, 0 }, - { 0, 0, 0, 0 } }; - // clang-format on + while ((optc = getopt_long(argc, argv, "a:l:E", longopts, NULL)) != -1) - while ((opt = getopt_long(argc, argv, "gGLbacmBfAl:E", long_opts, - &option_index)) != -1) { - if (opt == 0 && - strcmp(long_opts[option_index].name, "extras") == 0) { - int err; - char *arg = optarg; - char *token = strtok(arg, ","); - while (token) { - err = parse_extras_token(conf, token); - if (err) - exit(err); - token = strtok(NULL, ","); - } - } - switch (opt) { - case 'g': - conf->git = true; - break; - case 'G': - conf->git = false; - break; - case 'L': - conf->lib = true; - break; - case 'a': - conf->build = AUTOTOOLS; - break; - case 'c': - conf->build = CMAKE; - break; - case 'm': - conf->build = MAKE; - break; - case 'B': - conf->build = BARE; - break; - case 'f': - conf->flat = true; - break; - case 'A': - conf->author = optarg; - break; + switch (optc) { case 'l': if (!strcmp(optarg, "list")) { - print_lines("MIT", "BSD", "GPL", "UNL", NULL); + printf("BSD\nGPL\nMIT\n"); exit(EXIT_SUCCESS); } - conf->licence = TOlicence(optarg); + if (!strcmp(optarg, "GPL")) + manifest.licence = GPL; + else if (!strcmp(optarg, "MIT")) + manifest.licence = MIT; + else { + printf("BSD\nGPL\nMIT\n"); + exit(EXIT_FAILURE); + } break; case 'E': - conf->open_editor = true; - conf->editor = getenv("EDITOR"); + manifest.editor = getenv("EDITOR"); break; default: - return 1; + lose = 1; } - } - if (optind >= argc) { - return HELP_REQUESTED; + char *cwd = getcwd(NULL, 0); + if (!cwd) { + fatalfa(errno); } - conf->project = str_dup(argv[optind]); - - return 0; -} - -int get_name(char **output) -{ - FILE *fp; - char buf[256]; - char *res = NULL; - struct passwd *pw; - - fp = popen("git config --get user.name", "r"); - if (fp) { - if (fgets(buf, sizeof buf, fp)) { - size_t len = strlen(buf); - if (len > 0 && buf[len - 1] == '\n') - buf[len - 1] = '\0'; - res = strdup(buf); - } - pclose(fp); - } - - if (!res) { - pw = getpwuid(getuid()); - if (!pw || !pw->pw_name) - return -1; - res = strdup(pw->pw_name); - } - - if (!res) - return -1; + fprintf(stderr, "Created %s at\n %s\n", manifest.project, cwd); + free(cwd); - *output = res; - return 0; + return exit_status; } -int main(int argc, char **argv) +static void usage(int status) { - int status; - manifest_t manifest = { - .project = "Project", - .author = "author", - .editor = "vim", - - .licence = UNL, - - .git = true, - .build = MAKE, - .flat = false, - .open_editor = false, - .lib = false, - - .extra.build_nob = false, - .extra.tools_format = false, - .extra.tools_Cleanup = false, - }; - - status = parse_standard_options(usage, argc, argv); - if (status != 0 && status != HELP_REQUESTED) - return fprintf(stderr, "error: %s\n", strerror(status)), - EXIT_FAILURE; - - status = parse_arguments(&manifest, argc, argv); - if (status == HELP_REQUESTED) { - usage(0); - } - - if (status) { - return EXIT_FAILURE; - } - - get_name(&manifest.author); - status = create_project(manifest); - - if (status) { - fprintf(stderr, "%s\n", strerror(status)); - return EXIT_FAILURE; - } - - char *cwd; - - cwd = getcwd(NULL, 0); - if (cwd == NULL) { - perror("getcwd"); - exit(EXIT_FAILURE); + if (status != 0) { + puts("Try 'yait --help' for more information."); + return; } - fprintf(stderr, "Created %s at\n %s\n", manifest.project, cwd); - - free(cwd); - - return EXIT_SUCCESS; + printf("Usage: %s [OPTION]... [project-name]\n", PROGRAM); + fputs("\ +Generates an optionated C project.\n", + stdout); + puts(""); + fputs("\ + --help display this help and exit\n\ + --version display version information and eixt\n", + stdout); + puts(""); + fputs("\ + -E Open $EDITOR after project creation (default false)\n\ + --author=NAME Set the program author (default git username)\n\ + --licence=LICENCE Set the program licence (default BSD)\n", + stdout); } diff --git a/src/name.c b/src/name.c @@ -0,0 +1,61 @@ +/* Copyright (C) GCK + * + * This file is part of yait + * + * This project and file is licenced under the BSD-3-Clause licence. + * <https://opensource.org/licence/bsd-3-clause> + */ + +#include <string.h> +#include <unistd.h> +#include <sys/wait.h> +#include <pwd.h> + +#include "../lib/str_dup.h" + +#include "name.h" + +char *get_name() +{ + int fds[2]; + if (pipe(fds) == -1) + goto sysuser; + + pid_t pid = fork(); + if (pid == -1) { + close(fds[0]); + close(fds[1]); + goto sysuser; + } + + if (pid == 0) { + dup2(fds[1], STDOUT_FILENO); + close(fds[0]); + close(fds[1]); + execlp("git", "git", "config", "--get", "user.name", + (char *)NULL); + _exit(127); + } + + close(fds[1]); + char buf[256]; + ssize_t n = read(fds[0], buf, sizeof buf - 1); + close(fds[0]); + int status; + waitpid(pid, &status, 0); + if (n > 0 && WIFEXITED(status) && WEXITSTATUS(status) == 0) { + buf[n] = 0; + buf[strcspn(buf, "\n")] = 0; + return str_dup(buf); + } + +sysuser: { + char *name = getlogin(); + if (name) + return str_dup(name); + struct passwd *pw = getpwuid(getuid()); + if (pw && pw->pw_name) + return str_dup(pw->pw_name); +} + return "author"; +} diff --git a/src/name.h b/src/name.h @@ -0,0 +1,14 @@ +/* Copyright (C) GCK + * + * This file is part of yait + * + * This project and file is licenced under the BSD-3-Clause licence. + * <https://opensource.org/licence/bsd-3-clause> + */ + +#ifndef NAME_H +#define NAME_H + +char *get_name(); + +#endif diff --git a/src/standard.c b/src/standard.c @@ -1,34 +0,0 @@ -/* Copyright (C) GCK - * - * This file is part of yait - * - * This project and file is licenced under the BSD-3-Clause licence. - * <https://opensource.org/license/bsd-3-clause> - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "../config.h" -#include "standard.h" - -int parse_standard_options(void (*usage)(int), int argc, char **argv) -{ - for (int i = 0; i < argc; ++i) { - if (strcmp(argv[i], "--help") == 0) { - usage(0); - exit(EXIT_SUCCESS); - } else if (strcmp(argv[i], "--version") == 0) { - printf("%s %s %d\nCopyright (C) %d %s.\n%s\nThis is " - "free software: " - "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(EXIT_SUCCESS); - } - } - return HELP_REQUESTED; -} diff --git a/src/standard.h b/src/standard.h @@ -1,8 +0,0 @@ -#ifndef STANDARD_H -#define STANDARD_H - -#define HELP_REQUESTED 2 - -int parse_standard_options(void (*usage)(int), int argc, char **argv); - -#endif diff --git a/src/util.c b/src/util.c @@ -28,7 +28,7 @@ licence_t TOlicence(char *src) if (!strcmp(s, "BSD")) return BSD; free(s); - return UNL; + return BSD; } char *str_dup(const char *s)