diff --git a/.gitignore b/.gitignore index 63b4de9..76be36b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,2 @@ -bin/ -build/ +yait *.o -config.mak -config.status -*cache* diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..69acf08 --- /dev/null +++ b/Makefile @@ -0,0 +1,38 @@ +# Makefile for yait + +# Make the build silent by default +V = + +ifeq ($(strip $(V)),) + E = @echo + Q = @ +else + E = @\# + Q = +endif +export E Q + +PROGRAM = yait +SRC = $(wildcard *.c) +OBJ = $(SRC:.c=.o) + +CC = gcc +WARNINGS = -Wall -Wstrict-prototypes +CFLAGS = -O2 $(WARNINGS) -g +DEFINES = +LIBS = +LDFLAGS = +BINDIR = /usr/bin +LIBDIR = /usr/lib + +$(PROGRAM): $(OBJ) + $(E) " LINK " $@ + $(Q) $(CC) $(LDFLAGS) $(DEFINES) -o $@ $(OBJ) $(LIBS) + +clean: + $(E) " CLEAN" + $(Q) rm -f $(PROGRAM) $(OBJ) + +.c.o: + $(E) " CC " $@ + $(Q) $(CC) $(CFLAGS) $(DEFINES) -c $< -o $@ diff --git a/README b/README new file mode 100644 index 0000000..6388567 --- /dev/null +++ b/README @@ -0,0 +1,49 @@ ++---------------+ +| yait/fSD 1.0 | ++---------------+ + + Highly opinionated C and SH project generator + + yait was written by vx-clutch + + Copyright Notices: + + yait 1.0 (c) Copyright 2025 fSD. + Reference the COPYING file for detailed information + + +WHAT IS yait/fSD? + +yait/fSD 1.0 is an optionated C and SH project generator. For C project +generation is produces a similar layout to the source of this project. On +SH it generates a shell script with useful useful scaffolding for a +script. + + +WHAT IS NEW + +Features: + +o This is the inital commit, EVERYTHING is new! + +Bug fixes - not very interesting: + +o None + +Something is gone: + +o None + + +HOW TO BUILD yait/fSD? + +o UNIX: Compile the packge with make and install manually with for your + given system. + + +ACKNOWLEDGEMENTS AND STATUS + +This project's file strucutre, file format, and certain contents are +derived from uEmacs/PK 4.0 specifically from the Linux Torvalds +distribution on GitHub. The README on from uEmacs/PK 4.0 has greater and +more accurate attributions, if you desire. diff --git a/estruct.h b/estruct.h new file mode 100644 index 0000000..63e9f2b --- /dev/null +++ b/estruct.h @@ -0,0 +1,12 @@ +#ifndef ESTRUCT_H_ +#define ESTRUCT_H_ + +/* Configuration options */ + +#define QLICENSE 0 /* Force use the default license option */ +#define LICENSE "BSD-3-Clause" /* Default SPDX-License-Identifier */ + +#define QAUTHOR 0 /* Force use the default author option */ +#define AUTHOR "fSD" /* Default author*/ + +#endif /* ESTRUCT_H_ */ diff --git a/file.c b/file.c new file mode 100644 index 0000000..a675866 --- /dev/null +++ b/file.c @@ -0,0 +1,78 @@ +/* file.c + * + * The routines in this file handle the reading, writing + * and lookup of disk files. All of details about the + * reading and writing of the disk are in "fileio.c". + * + * written by vx-clutch + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "file.h" +#include "globals.h" + +int ffwrite(char *path, char *fmt, ...) { + FILE *f; + va_list ap; + int r; + + f = fopen(path, "w"); + if (!f) + return -1; + + va_start(ap, fmt); + r = vfprintf(f, fmt, ap); + va_end(ap); + + fclose(f); + return r < 0 ? -1 : 0; +} + +int fmkdir(char *fmt, ...) +{ + va_list ap; + char path[NPAT]; + char tmp[NPAT]; + char *p; + + va_start(ap, fmt); + vsnprintf(path, sizeof(path), fmt, ap); + va_end(ap); + + strncpy(tmp, path, sizeof(tmp) - 1); + tmp[sizeof(tmp) - 1] = '\0'; + + for (p = tmp + 1; *p; p++) { + if (*p == '/') { + *p = '\0'; + if (mkdir(tmp, 0755) < 0 && errno != EEXIST) + return -1; + *p = '/'; + } + } + + if (mkdir(tmp, 0755) < 0 && errno != EEXIST) + return -1; + + return 0; +} + +int ffexist(char *fmt, ...) { + char path[NPAT]; + va_list ap; + struct stat st; + + va_start(ap, fmt); + vsnprintf(path, sizeof(path), fmt, ap); + va_end(ap); + + return stat(path, &st) == 0; +} diff --git a/file.h b/file.h new file mode 100644 index 0000000..7fd9740 --- /dev/null +++ b/file.h @@ -0,0 +1,8 @@ +#ifndef FILE_H_ +#define FILE_H_ + +int ffwrite(char *path, char *fmt, ...); +int fmkdir(char *path, ...); +int ffexist(char *fmt, ...); + +#endif /* FILE_H_ */ diff --git a/globals.h b/globals.h new file mode 100644 index 0000000..93367a5 --- /dev/null +++ b/globals.h @@ -0,0 +1,6 @@ +#ifndef GLOBALS_H_ +#define GLOBALS_H_ + +#define NPAT 4096 /* number of bytes for path buffer */ + +#endif /* GLOBALS_H_ */ diff --git a/input.c b/input.c new file mode 100644 index 0000000..a57703c --- /dev/null +++ b/input.c @@ -0,0 +1,70 @@ +/* input.c + * + * Various input routines + * + * written by vx-clutch + */ + +#include +#include +#include +#include + +#include "input.h" + +char *getstring(char *fmt, ...) { + va_list args; + va_start(args, fmt); + + printf("? "); + vprintf(fmt, args); + putc(' ', stdout); + + va_end(args); + fflush(stdout); + + char *buf = NULL; + size_t size = 0; + ssize_t len = getline(&buf, &size, stdin); + + if (len < 0) { + free(buf); + return NULL; + } + + if (len > 0 && buf[len - 1] == '\n') + buf[len - 1] = '\0'; + + return buf; +} + +int yes_no_prompt(const char *fmt, ...) { + char prompt[256]; + + va_list ap; + va_start(ap, fmt); + vsnprintf(prompt, sizeof prompt, fmt, ap); + va_end(ap); + + char buf[64]; + for (;;) { + fprintf(stderr, "? %s", prompt); + fputs(" (y/n) ", stdout); + fflush(stdout); + + if (!fgets(buf, sizeof buf, stdin)) + return 0; + + size_t i = 0; + while (buf[i] && isspace((unsigned char)buf[i])) + i++; + if (!buf[i]) + continue; + + char c = tolower((unsigned char)buf[i]); + if (c == 'y') + return 1; + if (c == 'n') + return 0; + } +} diff --git a/input.h b/input.h new file mode 100644 index 0000000..12b1e74 --- /dev/null +++ b/input.h @@ -0,0 +1,9 @@ +#ifndef INPUT_H_ +#define INPUT_H_ + +enum { TRUE, FALSE, GUARANTEE }; + +char *getstring(char *fmt, ...); +int mlyesno(char *fmt, ...); + +#endif /* INPUT_H_ */ diff --git a/main.c b/main.c new file mode 100644 index 0000000..38b95ea --- /dev/null +++ b/main.c @@ -0,0 +1,74 @@ +/* + * main.c + * + * yait/fSD 1.0 + * + * Copying policy: + * + * yait 1.0 can be copied and distributed freely for any + * non-commercial purposes. yait 1.0 can only be incorporated + * into commercial software with the permission of the current author. + * + * This file contains the main driving routine, and some handling + * for C/SH distinction. + * + */ + +#include +#include +#include + +#include "shell.h" +#include "usage.h" +#include "version.h" +#include "proj.h" + +void usage(int status) +{ + printf("Usage: %s filename\n", PROGRAM_NAME); + printf(" or: %s [options]\n\n", PROGRAM_NAME); + fputs(" -S enable shell creation mode\n", stdout); + fputs(" --help display this help and exit\n", stdout); + fputs(" --version output version information and exit\n", stdout); + + exit(status); +} + +int main(int argc, char **argv) +{ + int c = 0; + int S = 0; + int carg; + + if (argc == 2) { + if (strcmp(argv[1], "--help") == 0) { + usage(EXIT_FAILURE); + } + if (strcmp(argv[1], "--version") == 0) { + version(); + exit(EXIT_SUCCESS); + } + } + + for (carg = 0; carg < argc; ++carg) { + if (argv[carg][0] == '-') { + switch (argv[carg][1]) { + case 'S': + S = 1; + break; + } + } + } + + if (argc < 2 || c) + die("not enough arguments"); + + char *package = argv[carg - 1]; + + if (S) + makeshell(package); + else + makeproj(package); + + return 0; +} diff --git a/proj.c b/proj.c new file mode 100644 index 0000000..923a240 --- /dev/null +++ b/proj.c @@ -0,0 +1,74 @@ +/* proj.c + * + * The routines in this file generater an + * opinionated C project. + * + * written by vx-clutch + */ + +#include + +#include "estruct.h" +#include "file.h" +#include "input.h" +#include "proj.h" +#include "usage.h" + +int makeproj(char *src) +{ + if (ffexist(src)) + die("%s already exists", src); + + fmkdir(src); + if (chdir(src)) + die("could not cd into %s", src); + + ffwrite("main.c", "\ +/*\n\ + * main.c\n\ + *\n\ + * package/Author 1.0\n\ + *\n\ + * Copying policy\n\ + *\n\ + * yait 1.0 can be copied and distributed freely for any\n\ + * non-commercial purposes. yait 1.0 can only be incorporated\n\ + * into commercial software with the permission of the current author.\n\ + *\n\ + * This file contains the main driving routine.\n\ + *\n\ + */\n\ +\n\ +#include \n\ +#include \n\ +#include \n\ +\n\ +void usage(int status)\n\ +{\n\ + printf(\"Usage: %%s REQUIRED POSITIONAL ARGUMENT\\n\", PROGRAM_NAME);\n\ + printf(\" or: %%s [options]\\n\\n\", PROGRAM_NAME);\n\ + fputs(\" --help display this help and exit\\n\", stdout);\n\ + fputs(\" --version output version information and exit\\n\", stdout);\n\ +\n\ + exit(status);\n\ +}\n\ +\n\ +int main(int argc, char **argv)\n\ +{\n\ + int carg;\n\ +\n\ + if (argc == 2) {\n\ + if (strcmp(argv[1], \"--help\") == 0) {\n\ + usage(EXIT_FAILURE);\n\ + }\n\ + if (strcmp(argv[1], \"--version\") == 0) {\n\ + version();\n\ + exit(EXIT_SUCCESS);\n\ + }\n\ + }\n\ +\n\ + return 0;\n\ +}"); + + return 0; +} diff --git a/proj.h b/proj.h new file mode 100644 index 0000000..70a996e --- /dev/null +++ b/proj.h @@ -0,0 +1,6 @@ +#ifndef PROJ_H_ +#define PROJ_H_ + +int makeproj(char *src); + +#endif /* PROJ_H_ */ diff --git a/shell.c b/shell.c new file mode 100644 index 0000000..f45e375 --- /dev/null +++ b/shell.c @@ -0,0 +1,68 @@ +/* shell.c + * + * The routines in this file generater an + * opiionated shell script. + * + * written by vx-clutch + */ + +#include +#include + +#include "estruct.h" +#include "file.h" +#include "input.h" +#include "shell.h" +#include "usage.h" + +int makeshell(char *src) +{ + if (ffexist(src)) + die("%s already exists", src); + + char *license = LICENSE; + if (!QLICENSE) + license = getstring("License"); + char *description = getstring("Description"); + + ffwrite(src, "\ +#!/bin/sh\n\ +# SPDX-License-Identifier: %s\n\ +#\n\ +# %s\n\ +\n\ +me=$0\n\ +scriptversion=\"1.0.0\"\n\ +\n\ +version=\"$me $scriptversion\n\ +\n\ +Copyright (C) %d %s.\n\ +This is free software; you are free to change and redistribute it.\n\ +There is NO WARRANTY, to the extent permitted by law.\"\n\ +\n\ +usage=\"\\\n\ +Usage: $me [OPTION]...\n\ +%s\n\ +\n\ +Options:\n\ + --help print this help and exit\n\ + --version output version information\n\"\n\ +\n\ +while [ $# -gt 0 ]; do\n\ + case $1 in\n\ + --help) echo \"$usage\"; exit 0 ;;\n\ + --version) echo \"$version\"; exit 0 ;;\n\ + -*)\n\ + echo \"$0: Unknown option '$1'.\" >&2\n\ + echo \"$0: Try '--help' for more information.\" >&2\n\ + exit 1 ;;\n\ + esac\n\ + shift\n\ +done", license, description, 2025, "fSD", description); + + struct stat st; + if (stat(src, &st) == 0) + chmod(src, st.st_mode | S_IXUSR | S_IXGRP | S_IXOTH); + + return 0; +} diff --git a/shell.h b/shell.h new file mode 100644 index 0000000..6d21aab --- /dev/null +++ b/shell.h @@ -0,0 +1,6 @@ +#ifndef SHELL_H_ +#define SHELL_H_ + +int makeshell(char *src); + +#endif /* SHELL_H_ */ diff --git a/usage.c b/usage.c new file mode 100644 index 0000000..2d33500 --- /dev/null +++ b/usage.c @@ -0,0 +1,22 @@ +#include "usage.h" + +#include +#include +#include + +static void report(const char* prefix, const char *err, va_list params) +{ + char msg[4096]; + vsnprintf(msg, sizeof(msg), err, params); + fprintf(stderr, "%s%s\n", prefix, msg); +} + +void die(const char* err, ...) +{ + va_list params; + + va_start(params, err); + report("fatal: ", err, params); + va_end(params); + exit(128); +} diff --git a/usage.h b/usage.h new file mode 100644 index 0000000..ba78993 --- /dev/null +++ b/usage.h @@ -0,0 +1,6 @@ +#ifndef USAGE_H_ +#define USAGE_H_ + +void die(const char* err, ...); + +#endif /* USAGE_H_ */ diff --git a/version.c b/version.c new file mode 100644 index 0000000..d974764 --- /dev/null +++ b/version.c @@ -0,0 +1,7 @@ +#include +#include "version.h" + +void version(void) +{ + printf("%s version %s\n", PROGRAM_NAME_LONG, VERSION); +} diff --git a/version.h b/version.h new file mode 100644 index 0000000..800c888 --- /dev/null +++ b/version.h @@ -0,0 +1,12 @@ +#ifndef VERSION_H_ +#define VERSION_H_ + +#define PROGRAM_NAME "yait" +#define PROGRAM_NAME_LONG "yait/fSD" + +#define VERSION "1.0.0" + +/* Print the version string. */ +void version(void); + +#endif /* VERSION_H_ */