save
This commit is contained in:
263
src/contents.h
Normal file
263
src/contents.h
Normal file
@@ -0,0 +1,263 @@
|
||||
/* Copyright (C) vx_clutch
|
||||
*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
#ifndef CONTENTS_H
|
||||
#define CONTENTS_H
|
||||
|
||||
#define line(l) l "\n"
|
||||
|
||||
/* README template */
|
||||
char *readme_template =
|
||||
line ("%s ( concise description )")
|
||||
line ()
|
||||
line ("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor")
|
||||
line ("incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis")
|
||||
line ("nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.")
|
||||
line ("Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu")
|
||||
line ("fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in")
|
||||
line ("culpa qui officia deserunt mollit anim id est laborum.");
|
||||
|
||||
/* configure script template */
|
||||
char *configure_template =
|
||||
line ("#!/bin/sh")
|
||||
line ()
|
||||
line ("usage() {")
|
||||
line ("cat <<EOF")
|
||||
line ("Usage: $0 [OPTION]... [VAR=VALUE]...")
|
||||
line ()
|
||||
line ("To assign environment variables (e.g., CC, CFLAGS...), specify them as")
|
||||
line ("VAR=VALUE.")
|
||||
line ()
|
||||
line (" CC C compiler command [detected]")
|
||||
line (" CFLAGS C compiler flags [-g, ...]")
|
||||
line ()
|
||||
line ("EOF")
|
||||
line ("exit 0")
|
||||
line ("}")
|
||||
line ()
|
||||
line ("echo () { printf \"%s\\n\" \"$*\" ; }")
|
||||
line ("cmdexists () { type \"$1\" >/dev/null 2>&1 ; }")
|
||||
line ("trycc () { test -z \"$CC\" && cmdexists \"$1\" && CC=$1 ; }")
|
||||
line ()
|
||||
line ("prefix=/usr/bin/")
|
||||
line ("CFLAGS=\"-Wall -Wextra -O2\"")
|
||||
line ("LDFLAGS=")
|
||||
line ("CC=")
|
||||
line ()
|
||||
line ("for arg ; do")
|
||||
line ("case \"$arg\" in")
|
||||
line ("--help|h) usage ;;")
|
||||
line ("CFLAGS=*) CFLAGS=${arg#*=} ;;")
|
||||
line ("LDFLAGS=*) LDFLAGS=${arg#*=} ;;")
|
||||
line ("esac")
|
||||
line ("done")
|
||||
line ()
|
||||
line ("printf \"checking for C compiler... \"")
|
||||
line ("%s")
|
||||
line ("printf \"%s\\n\" \"$CC\"")
|
||||
line ()
|
||||
line ("printf \"checking weather C compiler works... \"")
|
||||
line ("status=\"fail\"")
|
||||
line ("tmpc=\"$(mktemp -d)/test.c\"")
|
||||
line ("echo \"typedef int x;\" > \"$tmpc\"")
|
||||
line ("if output=$($CC $CFLAGS -c -o /dev/null \"$tmpc\" 2>&1) ; then")
|
||||
line ("printf \"yes\\n\"")
|
||||
line ("else")
|
||||
line ("printf \"no; %s\\n\" \"$output\"")
|
||||
line ("exit 1")
|
||||
line ("fi")
|
||||
line ()
|
||||
line ("printf \"creating config.mak... \"")
|
||||
line ("printf \"PREFIX=%s\\n\" \"$prefix\" > config.mak")
|
||||
line ("printf \"CFLAGS=%s\\n\" \"$CFLAGS\" >> config.mak")
|
||||
line ("printf \"LDFLAGS=%s\\n\" \"$LDFLAGS\" >> config.mak")
|
||||
line ("printf \"CC=%s\\n\" \"$CC\" >> config.mak")
|
||||
line ("printf \"done\\n\"");
|
||||
|
||||
/* Makefile template */
|
||||
char *makefile_template =
|
||||
line ("prefix = /usr/bin")
|
||||
line ()
|
||||
line ("%s_SRCS := $(wildcard %s/*.c)")
|
||||
line ("%s_OBJS := $(patsubst ./%s/%%.c,c-out/obj/%%.o,$(%s_SRCS))")
|
||||
line ()
|
||||
line ("%s := c-out/bin/%s")
|
||||
line ()
|
||||
line ("-include config.mak")
|
||||
line ()
|
||||
line ("ifeq ($(wildcard config.mak),)")
|
||||
line ("all:")
|
||||
line ("\t@echo \"File config.mak not found, run configure\"")
|
||||
line ("\t@exit 1")
|
||||
line ("else")
|
||||
line ()
|
||||
line ("all: build $(%s)")
|
||||
line ()
|
||||
line ("build:")
|
||||
line ("\tmkdir -p c-out/bin")
|
||||
line ("\tmkdir -p c-out/obj")
|
||||
line ()
|
||||
line ("c-out/obj/%%.o: %s/%%.c")
|
||||
line ("\t$(CC) $(CFLAGS) -c $< -o $@")
|
||||
line ()
|
||||
line ("$(%s): $(%s_OBJS)")
|
||||
line ("\t$(CC) $(CFLAGS) -DCOMMIT=$(shell git rev-list --count --all 2>/dev/null || echo 0) $^ -o $@")
|
||||
line ()
|
||||
line ("endif")
|
||||
line ()
|
||||
line ("install:")
|
||||
line ("\t@echo \"NOT IMPL\"")
|
||||
line ("\texit 1")
|
||||
line ()
|
||||
line ("uninstall:")
|
||||
line ("\t@echo \"NOT IMPL\"")
|
||||
line ("\texit 1")
|
||||
line ()
|
||||
line ("clean:")
|
||||
line ("\trm -rf c-out")
|
||||
line ()
|
||||
line ("dist-clean: clean")
|
||||
line ("\trm -f config.mak")
|
||||
line ()
|
||||
line (".PHONY: all clean dist-clean install uninstall");
|
||||
|
||||
/* .clang-format template */
|
||||
char *clang_format_template =
|
||||
line ("BasedOnStyle: GNU");
|
||||
|
||||
/* BSD 3-Clause License template */
|
||||
char *bsd3_license_template =
|
||||
line ("BSD 3-Clause License")
|
||||
line ()
|
||||
line ("Copyright (c) %d, %s")
|
||||
line ()
|
||||
line ("Redistribution and use in source and binary forms, with or without")
|
||||
line ("modification, are permitted provided that the following conditions are met:")
|
||||
line ()
|
||||
line ("1. Redistributions of source code must retain the above copyright notice, this")
|
||||
line (" list of conditions and the following disclaimer.")
|
||||
line ()
|
||||
line ("2. Redistributions in binary form must reproduce the above copyright notice,")
|
||||
line (" this list of conditions and the following disclaimer in the documentation")
|
||||
line (" and/or other materials provided with the distribution.")
|
||||
line ()
|
||||
line ("3. Neither the name of the copyright holder nor the names of its")
|
||||
line (" contributors may be used to endorse or promote products derived from")
|
||||
line (" this software without specific prior written permission.")
|
||||
line ()
|
||||
line ("THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"")
|
||||
line ("AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE")
|
||||
line ("IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE")
|
||||
line ("DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE")
|
||||
line ("FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL")
|
||||
line ("DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR")
|
||||
line ("SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER")
|
||||
line ("CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,")
|
||||
line ("OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE")
|
||||
line ("OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.");
|
||||
|
||||
/* MIT License template */
|
||||
char *mit_license_template =
|
||||
line ("THIS IS THE MIT LICENSE");
|
||||
|
||||
/* GPLv3 License template */
|
||||
char *gplv3_license_template =
|
||||
line ("THIS IS THE GPLv3 LICENSE");
|
||||
|
||||
/* config.h template */
|
||||
char *config_h_template =
|
||||
line ("#ifndef CONFIG_H")
|
||||
line ("#define CONFIG_H")
|
||||
line ()
|
||||
line ("/* Program information */")
|
||||
line ("#define PROGRAM \"%s\"")
|
||||
line ("#define LICENSE_LINE \"%s\"")
|
||||
line ("#define AUTHORS \"%s\"")
|
||||
line ("#define VERSION \"pre-alpha\"")
|
||||
line ("#define YEAR 2025")
|
||||
line ()
|
||||
line ("#define HELP_REQUESTED 2")
|
||||
line ("#define ERROR_MEMORY_ALLOCATION 3")
|
||||
line ("#define ERROR_DIRECTORY_CREATION 4")
|
||||
line ()
|
||||
line ("#endif");
|
||||
|
||||
/* main.c (non-GNU) template */
|
||||
char *main_c_template =
|
||||
line ("#include <stdio.h>")
|
||||
line ()
|
||||
line ("int main(void) {")
|
||||
line (" printf(\"%s: Hello %s!\\n\");")
|
||||
line (" return 0;")
|
||||
line ("}");
|
||||
|
||||
/* main.c (GNU) template */
|
||||
char *main_c_gnu_template =
|
||||
line ("#include <stdio.h>")
|
||||
line ("#include \"standard.h\"")
|
||||
line ()
|
||||
line ("void usage(int status) {")
|
||||
line (" fprintf(stderr, \"Usage: %s [OPTION...]\\n\");")
|
||||
line (" fprintf(stderr, \" --help\\tdisplay the help text and exit\\n\");")
|
||||
line (" fprintf(stderr, \" --version\\toutput version information and exit\\n\");")
|
||||
line ("}")
|
||||
line ()
|
||||
line ("int main(int argc, char **argv) {")
|
||||
line (" parse_standard_options(usage, argc, argv);")
|
||||
line (" printf(\"%s: Hello %s!\\n\");")
|
||||
line (" return 0;")
|
||||
line ("}");
|
||||
|
||||
/* standard.c template */
|
||||
char *standard_c_template =
|
||||
line ("#include \"standard.h\"")
|
||||
line ("#include \"../config.h\"")
|
||||
line ("#include <stdio.h>")
|
||||
line ("#include <stdlib.h>")
|
||||
line ("#include <string.h>")
|
||||
line ()
|
||||
line ("int")
|
||||
line ("parse_standard_options (void (*usage) (int), int argc, char **argv)")
|
||||
line ("{")
|
||||
line (" for (int i = 1; i < argc; ++i)")
|
||||
line (" {")
|
||||
line (" if (strcmp (argv[i], \"--help\") == 0)")
|
||||
line (" {")
|
||||
line (" usage (0);")
|
||||
line (" exit (EXIT_SUCCESS);")
|
||||
line (" }")
|
||||
line (" else if (strcmp (argv[i], \"--version\") == 0)")
|
||||
line (" {")
|
||||
line (" 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 );")
|
||||
line (" exit (EXIT_SUCCESS);")
|
||||
line (" }")
|
||||
line (" }")
|
||||
line (" return HELP_REQUESTED;")
|
||||
line ("}");
|
||||
|
||||
/* standard.h template */
|
||||
char *standard_h_template =
|
||||
line ("#ifndef STANDARD_H")
|
||||
line ("#define STANDARD_H")
|
||||
line ()
|
||||
line ("int parse_standard_options(void (*usage_func)(), int argc, char **argv);")
|
||||
line ()
|
||||
line ("#endif");
|
||||
|
||||
/* WHATNEXT.md template */
|
||||
char *what_next_template =
|
||||
line ("# What next?")
|
||||
line ("")
|
||||
line ("## Steps")
|
||||
line (" - Write a description in the README")
|
||||
line (" - Write the usage function ( write to stderr )")
|
||||
line (" - Start writing your program");
|
||||
|
||||
#endif
|
||||
// clang-format on
|
||||
340
src/create_project.c
Normal file
340
src/create_project.c
Normal file
@@ -0,0 +1,340 @@
|
||||
/* Copyright (C) vx_clutch
|
||||
*
|
||||
* 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 <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "manifest.h"
|
||||
#include "contents.h"
|
||||
#include "yait.h"
|
||||
|
||||
#define DEFAULT_USER_NAME "unknown"
|
||||
#define DEFAULT_PROJECT_NAME "Project"
|
||||
#define DEFAULT_LICENCE BSD3
|
||||
#define DEFAULT_GIT_INIT true
|
||||
#define DEFAULT_CLANG_FORMAT true
|
||||
#define DEFAULT_GNU false
|
||||
|
||||
int program_exists(const char *prog)
|
||||
{
|
||||
char *path = getenv("PATH");
|
||||
if (!path)
|
||||
return -1;
|
||||
|
||||
char *copy = strdup(path);
|
||||
if (!copy)
|
||||
return -1;
|
||||
|
||||
char *dir = strtok(copy, ":");
|
||||
while (dir) {
|
||||
char buf[4096];
|
||||
snprintf(buf, sizeof(buf), "%s/%s", dir, prog);
|
||||
if (access(buf, X_OK) == 0) {
|
||||
free(copy);
|
||||
return 0;
|
||||
}
|
||||
dir = strtok(NULL, ":");
|
||||
}
|
||||
|
||||
free(copy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sanitize(manifest_t *m)
|
||||
{
|
||||
int status;
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
|
||||
status = program_exists("git");
|
||||
if (status != 0)
|
||||
return fprintf(stderr, "git binary not present\n"),
|
||||
EXIT_FAILURE;
|
||||
|
||||
if (!m->project)
|
||||
m->project = DEFAULT_PROJECT_NAME;
|
||||
|
||||
if (!m->name)
|
||||
m->name = (pw && pw->pw_name) ? pw->pw_name : DEFAULT_USER_NAME;
|
||||
|
||||
if (m->licence == UNLICENCE)
|
||||
m->licence = DEFAULT_LICENCE;
|
||||
|
||||
if (!m->flag.git)
|
||||
m->flag.git = DEFAULT_GIT_INIT;
|
||||
|
||||
if (!m->flag.clang_format)
|
||||
m->flag.clang_format = DEFAULT_CLANG_FORMAT;
|
||||
|
||||
if (!m->flag.GNU)
|
||||
m->flag.GNU = DEFAULT_GNU;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int create_libraries(manifest_t manifest)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (!manifest.libraries) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (HAS_LIBRARY(manifest.libraries, LIB_RAYLIB)) {
|
||||
fputs("Pulling raylib", stderr);
|
||||
REMOVE_LIBRARY(manifest.libraries, LIB_RAYLIB);
|
||||
status = system(
|
||||
"git submodule add --quiet https://github.com/raysan5/raylib");
|
||||
if (status != 0)
|
||||
return status;
|
||||
fputs(", done.\n", stderr);
|
||||
}
|
||||
|
||||
if (HAS_LIBRARY(manifest.libraries, LIB_NCURSES)) {
|
||||
fputs("Pulling ncurses", stderr);
|
||||
REMOVE_LIBRARY(manifest.libraries, LIB_NCURSES);
|
||||
status = system(
|
||||
"git submodule add --quiet https://github.com/mirror/ncurses");
|
||||
if (status != 0)
|
||||
return status;
|
||||
fputs(", done.\n", stderr);
|
||||
}
|
||||
|
||||
if (HAS_LIBRARY(manifest.libraries, LIB_CURL)) {
|
||||
fputs("Pulling curl", stderr);
|
||||
REMOVE_LIBRARY(manifest.libraries, LIB_CURL);
|
||||
status = system(
|
||||
"git submodule add --quiet https://github.com/curl/curl");
|
||||
if (status != 0)
|
||||
return status;
|
||||
fputs(", done.\n", stderr);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int create_licence(manifest_t manifest, char **licence_line_buffer)
|
||||
{
|
||||
if (manifest.licence == UNLICENCE)
|
||||
return 0;
|
||||
|
||||
if (!licence_line_buffer)
|
||||
return EINVAL;
|
||||
|
||||
switch (manifest.licence) {
|
||||
case BSD3:
|
||||
*licence_line_buffer = "Bsd";
|
||||
fprintf(stderr,
|
||||
"create_licence: BSD3 license generation not implemented\n");
|
||||
return ENOSYS;
|
||||
case GPLv3:
|
||||
fprintf(stderr,
|
||||
"create_licence: GPLv3 license generation not implemented\n");
|
||||
return ENOSYS;
|
||||
case MIT:
|
||||
fprintf(stderr,
|
||||
"create_licence: MIT license generation not implemented\n");
|
||||
return ENOSYS;
|
||||
default:
|
||||
fprintf(stderr, "create_licence: unknown license type\n");
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int maybe_create_clang_format(manifest_t manifest)
|
||||
{
|
||||
if (!manifest.flag.clang_format)
|
||||
return 0;
|
||||
|
||||
int status = create_file_with_content(".clang-format",
|
||||
clang_format_template);
|
||||
return status;
|
||||
}
|
||||
|
||||
int setup_git(manifest_t manifest)
|
||||
{
|
||||
if (!manifest.flag.git)
|
||||
return 0;
|
||||
|
||||
int status = system("git init --quiet");
|
||||
if (status == -1) {
|
||||
fprintf(stderr, "...: %s\n", strerror(errno));
|
||||
} else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
||||
fprintf(stderr, "...: exited with status %d\n",
|
||||
WEXITSTATUS(status));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int create_makefile(manifest_t manifest)
|
||||
{
|
||||
char *m = strdup(manifest.project);
|
||||
char *M = strdup(manifest.project);
|
||||
if (!M) {
|
||||
fputs("create_makefile: fatal: out of memory\n", stderr);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
for (char *p = M; *p; ++p)
|
||||
if (*p >= 'a' && *p <= 'z')
|
||||
*p -= 'a' - 'A';
|
||||
|
||||
int status = create_file_with_content(strcat(m, "Makefile"),
|
||||
makefile_template, M, m, M, m, M,
|
||||
M, m, M, m, M, m);
|
||||
|
||||
free(m);
|
||||
free(M);
|
||||
return status;
|
||||
}
|
||||
|
||||
int create_configure(manifest_t manifest)
|
||||
{
|
||||
const char *cc;
|
||||
if (manifest.flag.use_cpp) {
|
||||
cc = "trycc g++\ntrycc CC\ntrycc clang++\n";
|
||||
} else {
|
||||
cc = "trycc gcc\ntrycc cc\ntrycc clang\n";
|
||||
}
|
||||
|
||||
int status =
|
||||
create_file_with_content("configure", configure_template, cc);
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
status = system("chmod +x configure");
|
||||
if (status != 0)
|
||||
fprintf(stderr, "create_configure: chmod failed: %s\n",
|
||||
strerror(status));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int generate_source_code(manifest_t manifest, char *licence_line)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
time_t t = time(NULL);
|
||||
struct tm tm = *localtime(&t);
|
||||
int year = tm.tm_year + 1900;
|
||||
|
||||
status = create_file_with_content("config.h", config_h_template,
|
||||
manifest.project, licence_line, year);
|
||||
if (status != 0) {
|
||||
fprintf(stderr,
|
||||
"generate_source_code: failed to create config.h: %s\n",
|
||||
strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
if (status != 0) {
|
||||
fprintf(stderr,
|
||||
"generate_source_code: failed to create or enter directory: %s\n",
|
||||
strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
if (manifest.flag.GNU) {
|
||||
status = create_file_with_content(
|
||||
strcat(manifest.project, "main.c"), main_c_gnu_template,
|
||||
manifest.project, manifest.name);
|
||||
} else {
|
||||
status = create_file_with_content(
|
||||
strcat(manifest.project, "main.c"), main_c_template,
|
||||
manifest.project, manifest.name);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int create_project(manifest_t manifest)
|
||||
{
|
||||
int status;
|
||||
|
||||
sanitize(&manifest);
|
||||
|
||||
// TODO(vx-clutch): take dir.
|
||||
|
||||
// status = create_makefile(manifest);
|
||||
// if (status != 0) {
|
||||
// fprintf(stderr,
|
||||
// "create_project: failed to create Makefile: %s\n",
|
||||
// strerror(status));
|
||||
// return status;
|
||||
// }
|
||||
//
|
||||
// status = create_configure(manifest);
|
||||
// if (status != 0) {
|
||||
// fprintf(stderr,
|
||||
// "create_project: failed to create configure: %s\n",
|
||||
// strerror(status));
|
||||
// return status;
|
||||
// }
|
||||
//
|
||||
// status = maybe_create_clang_format(manifest);
|
||||
// if (status != 0) {
|
||||
// fprintf(stderr,
|
||||
// "create_project: warning: clang-format setup failed: %s\n",
|
||||
// strerror(status));
|
||||
// }
|
||||
//
|
||||
// char *licence_line = malloc(1024);
|
||||
// if (!licence_line) {
|
||||
// fputs("create_project: failed to allocate memory for licence line\n",
|
||||
// stderr);
|
||||
// return ENOMEM;
|
||||
// }
|
||||
//
|
||||
// status = create_licence(manifest, &licence_line);
|
||||
// if (status != 0) {
|
||||
// fprintf(stderr,
|
||||
// "create_project: failed to create licence: %s\n",
|
||||
// strerror(status));
|
||||
// free(licence_line);
|
||||
// return status;
|
||||
// }
|
||||
//
|
||||
// status = generate_source_code(manifest, licence_line);
|
||||
// if (status != 0) {
|
||||
// fprintf(stderr,
|
||||
// "create_project: failed to generate source code: %s\n",
|
||||
// strerror(status));
|
||||
// free(licence_line);
|
||||
// return status;
|
||||
// }
|
||||
//
|
||||
// free(licence_line);
|
||||
//
|
||||
// status = create_libraries(manifest);
|
||||
// if (status != 0) {
|
||||
// printfn("failed to get libraries: %s", strerror(status));
|
||||
// return status;
|
||||
// }
|
||||
//
|
||||
// status = setup_git(manifest);
|
||||
// if (status != 0) {
|
||||
// printfn("warning: git initialization failed: %s",
|
||||
// strerror(status));
|
||||
// }
|
||||
|
||||
char *cwd = getcwd(NULL, 0);
|
||||
if (!cwd) {
|
||||
printfn("could not get current working directory");
|
||||
return 1;
|
||||
}
|
||||
fprintf(stderr, "Created %s at\n %s\n", manifest.project, cwd);
|
||||
free(cwd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
88
src/file.c
Normal file
88
src/file.c
Normal file
@@ -0,0 +1,88 @@
|
||||
/* Copyright (C) vx_clutch
|
||||
*
|
||||
* 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 <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "yait.h"
|
||||
|
||||
int files_made = 0;
|
||||
|
||||
static int mkdir_p(const char *path)
|
||||
{
|
||||
char *copypath = strdup(path);
|
||||
char *p = copypath;
|
||||
int status = 0;
|
||||
|
||||
if (!copypath)
|
||||
return -1;
|
||||
|
||||
if (copypath[0] == '/')
|
||||
p++;
|
||||
|
||||
for (; *p; p++) {
|
||||
if (*p == '/') {
|
||||
*p = '\0';
|
||||
if (mkdir(copypath, 0777) && errno != EEXIST) {
|
||||
status = -1;
|
||||
break;
|
||||
}
|
||||
*p = '/';
|
||||
}
|
||||
}
|
||||
|
||||
if (!status && mkdir(copypath, 0777) && errno != EEXIST)
|
||||
status = -1;
|
||||
|
||||
free(copypath);
|
||||
return status;
|
||||
}
|
||||
|
||||
int create_file_with_content(const char *path, const char *format, ...)
|
||||
{
|
||||
char *dirpath;
|
||||
const char *slash = strrchr(path, '/');
|
||||
if (slash) {
|
||||
size_t len = slash - path;
|
||||
dirpath = malloc(len + 1);
|
||||
if (!dirpath)
|
||||
return -1;
|
||||
memcpy(dirpath, path, len);
|
||||
dirpath[len] = '\0';
|
||||
if (mkdir_p(dirpath)) {
|
||||
free(dirpath);
|
||||
return -1;
|
||||
}
|
||||
free(dirpath);
|
||||
}
|
||||
|
||||
FILE *fp = fopen(path, "w");
|
||||
if (!fp)
|
||||
return -1;
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
if (vfprintf(fp, format, args) < 0) {
|
||||
va_end(args);
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
++files_made;
|
||||
emit_progress("Creating files", files_made);
|
||||
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
167
src/main.c
Normal file
167
src/main.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/* Copyright (C) vx_clutch
|
||||
*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
// Usage: yait [OPTION]... <PATH>
|
||||
|
||||
#include <getopt.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../config.h"
|
||||
#include "../core/yait.h"
|
||||
#include "../core/manifest.h"
|
||||
|
||||
#define print_option(option, description) \
|
||||
printf(" %-20s %-20s\n", option, description)
|
||||
|
||||
// clang-format off
|
||||
static void
|
||||
usage (int status)
|
||||
{
|
||||
if (status != 0)
|
||||
{
|
||||
fprintf (stderr, "Try 'yait --help' for more information.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf ("Usage: yait [OPTION]... <PATH>\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, --licence=NAME", "Set licence (gpl, mit, bsd) [default: bsd]");
|
||||
print_option ("--lib=LIB", "Add a library to the project. You can list libraries with --lib=help.");
|
||||
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");
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
static int parse_arguments(manifest_t *conf, int argc, char **argv)
|
||||
{
|
||||
static struct option long_options[] = {
|
||||
{ "GNU", no_argument, 0, 'g' },
|
||||
{ "use-cpp", no_argument, 0, 'c' },
|
||||
{ "git", no_argument, 0, 'i' },
|
||||
{ "licence", required_argument, 0, 'l' },
|
||||
{ "lib", required_argument, 0, 'L' },
|
||||
{ "help", no_argument, 0, 'h' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt_long(argc, argv, "gcil:L:h", long_options,
|
||||
NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'g':
|
||||
conf->flag.GNU = true;
|
||||
break;
|
||||
case 'c':
|
||||
conf->flag.use_cpp = true;
|
||||
break;
|
||||
case 'i':
|
||||
conf->flag.git = true;
|
||||
break;
|
||||
case 'l':
|
||||
if (strcmp(optarg, "bsd") == 0)
|
||||
conf->licence = BSD3;
|
||||
else if (strcmp(optarg, "gpl") == 0)
|
||||
conf->licence = GPLv3;
|
||||
else if (strcmp(optarg, "mit") == 0)
|
||||
conf->licence = MIT;
|
||||
else {
|
||||
fprintf(stderr, "Unknown licence: %s\n",
|
||||
optarg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'L':
|
||||
if (strcmp(optarg, "help"))
|
||||
fprintf(stderr, "raylib\nncurses\ncurl\n");
|
||||
else
|
||||
ADD_LIBRARY(conf->libraries, TOLibrary(optarg));
|
||||
break;
|
||||
case 'h':
|
||||
usage(0);
|
||||
exit(0);
|
||||
default:
|
||||
usage(1);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
fprintf(stderr, "Missing required path argument\n");
|
||||
usage(1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
conf->project = argv[optind++];
|
||||
|
||||
if (optind < argc)
|
||||
conf->name = argv[optind++];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_name(char **output)
|
||||
{
|
||||
FILE *pipe;
|
||||
char buffer[128];
|
||||
size_t output_len = 0;
|
||||
|
||||
*output = NULL; // make sure it's NULL before realloc
|
||||
|
||||
pipe = popen("git config user.name", "r");
|
||||
if (!pipe)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), pipe) != NULL) {
|
||||
size_t chunk_len = strlen(buffer);
|
||||
char *new_output = realloc(*output, output_len + chunk_len + 1);
|
||||
if (!new_output) {
|
||||
free(*output);
|
||||
pclose(pipe);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
*output = new_output;
|
||||
memcpy((*output) + output_len, buffer, chunk_len);
|
||||
output_len += chunk_len;
|
||||
(*output)[output_len] = '\0';
|
||||
}
|
||||
pclose(pipe);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int status;
|
||||
manifest_t manifest = { 0 };
|
||||
|
||||
status = parse_standard_options(usage, argc, argv);
|
||||
if (status != 0 && status != HELP_REQUESTED)
|
||||
return fprintf(stderr, "error: %s\n", strerror(status)),
|
||||
EXIT_FAILURE;
|
||||
|
||||
parse_arguments(&manifest, argc, argv);
|
||||
|
||||
if (!manifest.name) {
|
||||
status = get_name(&manifest.name);
|
||||
if (status != 0 || !manifest.name || manifest.name[0] == '\0') {
|
||||
fprintf(stderr, "Could not determine user name\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
status = create_project(manifest);
|
||||
return status == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
37
src/standard.c
Normal file
37
src/standard.c
Normal file
@@ -0,0 +1,37 @@
|
||||
/* Copyright (C) vx_clutch
|
||||
*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#ifndef COMMIT
|
||||
#define COMMIT 0
|
||||
#endif
|
||||
|
||||
#include "yait.h"
|
||||
#include "../config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.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;
|
||||
}
|
||||
29
src/yait.h
Normal file
29
src/yait.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* Copyright (C) vx_clutch
|
||||
*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#ifndef YAIT_H
|
||||
#define YAIT_H
|
||||
|
||||
/* Constants for file operations */
|
||||
#define DEFAULT_DIR_PERMISSIONS 0755
|
||||
#define MAX_PATH_LENGTH 1024
|
||||
|
||||
int printfn(char *format, ...);
|
||||
|
||||
int create_file_with_content(const char *path, const char *format, ...);
|
||||
|
||||
int parse_standard_options(void (*usage_func)(), int argc, char **argv);
|
||||
|
||||
int program_exists(const char *prog);
|
||||
|
||||
#include "manifest.h"
|
||||
int create_project(manifest_t manifest);
|
||||
|
||||
void emit_progress(const char *action, int count);
|
||||
|
||||
#endif // YAIT_H
|
||||
Reference in New Issue
Block a user