diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c2ba7a4 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "gcklib"] + path = gcklib + url = https://github.com/gck-org/gcklib diff --git a/Makefile b/Makefile index 9335231..53a44a1 100644 --- 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 index cefcaf3..18eb2ad 100644 --- 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 new file mode 160000 index 0000000..432788e --- /dev/null +++ b/gcklib @@ -0,0 +1 @@ +Subproject commit 432788eb5f78afb08b7c011b81118c7f9bc520d9 diff --git a/include/yait.h b/include/yait.h index 2074218..ef2a3ac 100644 --- 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 new file mode 100644 index 0000000..2bd1436 --- /dev/null +++ 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. + * + */ + +#include +#include +#include +#include +#include + +#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 new file mode 100644 index 0000000..6b53e21 --- /dev/null +++ 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. + * + */ + +#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 new file mode 100644 index 0000000..410408f --- /dev/null +++ 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. + * + */ + +#include +#include +#include +#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 new file mode 100644 index 0000000..2a426c6 --- /dev/null +++ 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. + * + */ + +#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 new file mode 100644 index 0000000..3c4f1c2 --- /dev/null +++ b/lib/str_dup.c @@ -0,0 +1,12 @@ +#include +#include +#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 new file mode 100644 index 0000000..7ab6a61 --- /dev/null +++ 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 new file mode 100644 index 0000000..dac8abe --- /dev/null +++ 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. + * + */ + +#include +#include + +#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 new file mode 100644 index 0000000..2d4ccc3 --- /dev/null +++ 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. + * + */ + +#ifndef xmem_H +#define xmem_H + +#include + +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 index 00d7886..24fe92d 100644 --- 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 \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], [bug-report@exmaple.com])\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 \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], [bug-report@exmaple.com])\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 index 40aee22..c43bea6 100644 --- a/src/main.c +++ b/src/main.c @@ -8,23 +8,80 @@ // Usage: yait [OPTION]... -#define _POSIX_C_SOURCE 200809L // popen extention #include #include #include #include #include -#include +#include #include #include +#include +#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 int exit_status; + +static void usage(int status); + +int main(int argc, char **argv) +{ + int optc; + int lose = 0; + set_prog_name(argv[0]); + + exit_status = EXIT_SUCCESS; + + manifest_t manifest = { + .author = get_name(), + .editor = NULL, + .licence = BSD, + .project = "Project", + }; + + parse_standard_options(argc, argv, usage, emit_version); + + while ((optc = getopt_long(argc, argv, "a:l:E", longopts, NULL)) != -1) + + switch (optc) { + case 'l': + if (!strcmp(optarg, "list")) { + printf("BSD\nGPL\nMIT\n"); + exit(EXIT_SUCCESS); + } + 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': + manifest.editor = getenv("EDITOR"); + break; + default: + lose = 1; + } + + char *cwd = getcwd(NULL, 0); + if (!cwd) { + fatalfa(errno); + } + fprintf(stderr, "Created %s at\n %s\n", manifest.project, cwd); + free(cwd); + + return exit_status; +} static void usage(int status) { @@ -44,222 +101,8 @@ Generates an optionated C project.\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 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=, Extra build options, Pass list to list out options.\n", + -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); } - -void print_lines(const char *first, ...) -{ - 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); - - 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); - } - - 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; -} - -static int parse_arguments(manifest_t *conf, int argc, char **argv) -{ - int opt, option_index; - - // 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 ((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; - case 'l': - if (!strcmp(optarg, "list")) { - print_lines("MIT", "BSD", "GPL", "UNL", NULL); - exit(EXIT_SUCCESS); - } - conf->licence = TOlicence(optarg); - break; - case 'E': - conf->open_editor = true; - conf->editor = getenv("EDITOR"); - break; - default: - return 1; - } - } - - if (optind >= argc) { - return HELP_REQUESTED; - } - 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; - - *output = res; - return 0; -} - -int main(int argc, char **argv) -{ - 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); - } - - fprintf(stderr, "Created %s at\n %s\n", manifest.project, cwd); - - free(cwd); - - return EXIT_SUCCESS; -} diff --git a/src/name.c b/src/name.c new file mode 100644 index 0000000..6210ac9 --- /dev/null +++ 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. + * + */ + +#include +#include +#include +#include + +#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 new file mode 100644 index 0000000..8d6e1fc --- /dev/null +++ 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. + * + */ + +#ifndef NAME_H +#define NAME_H + +char *get_name(); + +#endif diff --git a/src/standard.c b/src/standard.c deleted file mode 100644 index 697017f..0000000 --- a/src/standard.c +++ /dev/null @@ -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. - * - */ - -#include -#include -#include - -#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 deleted file mode 100644 index a71b41d..0000000 --- a/src/standard.h +++ /dev/null @@ -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 index 61d3ba7..ed2808d 100644 --- 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)