#! /bin/sh
# Highly opinionated C and SH project generator

scriptversion="0.3.0"

#
# Copyright (C) 2025-2026 fSD THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

me=$(basename "$0")
version="$me/fSD v$scriptversion

Copyright (C) 2025-2026 fSD.
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law."

usage="\
Usage: $me [OPTION]... <version> <dir>
Highly opinionated C and SH project generator

Options:
   --help         print this help and exit
   --version      output version information

   -x <language>    set project type
   -d <description> set a description
   -S               small project creation
   -f               overwrite existing files
   -a <author>      set project author
   -r               initialize Git repository for the project
   -q               surpress output"

x=c                        # language
d="Does a thing"           # package description
S=                         # small project creation (bool)
f=                         # force (bool)
a=$(git config user.name)  # author
r=                         # initialize repository (bool)
q=                         # surpress output

say() {
    if [ -z "$q" ]; then
        echo "$me: $*"
    fi
}

lsay() {
    if [ -z "$q" ]; then
        echo " => $*"
    fi
}

# main creation routine
create_project() {
	name=$1
	
	if ! echo "$name" | grep -qE '^[A-Za-z0-9_-]+$'; then
		say "invalid name '$name'"
		exit 1
	fi

	# creates a shell project
	shell() {
		outfile="$name"

		if [ -z "$S" ]; then
			if [ -d "$name" ]; then
				if ! [ -z "$f" ]; then
					rm -rf "$name"
				fi
			fi

			mkdir "$name" || exit 1
			cd "$name" || exit 1

			cat <<EOF > LICENSE
ISC License

Copyright (c) $(date "+%Y") $a

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
EOF
			cat <<EOF > Makefile
all:
	@echo "nothing to do"

install:
	cp bin/$name /usr/local/bin
	cp $name.1 /usr/local/share/man/man1/$name.1
	chmod 644 /usr/local/share/man/man1/$name.1

uninstall:
	\$(RM) /usr/local/bin/$name
	\$(RM) /usr/local/share/man/man1/$name.1
EOF
			cat <<EOF > README.md
# $name

YOUR_WEBSITE

$d:

- Feature 1
- Feature 2
    * feature 2a

## Install

#### Dependencies

- \`fzf\` - terminal fuzzy finder

**Note**: \`fzf\` is used as an example dependency

\`\`\`bash
git clone YOUR_REPO_URL
cd $name
sudo make install
\`\`\`

## Usage

This tool runs via the command \`$name\`.

- \`$name -k\`   -- Does option k
EOF

			mkdir bin || exit 1
			outfile="bin/$outfile"
		fi
		cat <<EOF > "$outfile"
#! /bin/sh
# $d

scriptversion="1"

#
# 
# Copyright (C) $(date "+%Y") $a
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

me=\$0
version="\$me/$a v\$scriptversion

Copyright (C) $(date "+%Y") $a.
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law."

usage="\
Usage: \$me [OPTION]... <arg1> <arg2>
$d

Options:
   --help         print this help and exit
   --version      output version information"

say() {
    if [ -z "\$q" ]; then
        echo "\$me: \$*"
    fi
}

lsay() {
    if [ -z "\$q" ]; then
        echo " => \$*"
    fi
}

if ! [ \$# -gt 0 ]; then
	echo "\$usage"
	exit 0
fi

while [ \$# -gt 0 ]; do
  case \$1 in
    --help) echo "\$usage"; exit 0 ;;
    --version) echo "\$version"; exit 0 ;;
    -*) echo "\$me: Unknown option '\$1'." >&2; exit 1 ;;
  esac
done

say hello world
EOF
		chmod +x "$outfile"
	}

	# creates a C project
	c() {
		if [ -d "$name" ]; then
			if ! [ -z "$f" ]; then
				rm -rf "$name"
			fi
		fi
		mkdir "$name" || exit 1
		cd "$name" || exit 1
		cat <<EOF > README
$name
$(echo "$name" | sed 's/./=/g')
$d


Requirements
------------
In order to build $name you need the LIBRARY header files.


Instillation
------------
Edit config.mk to match your local setup ($name is installed into
the /usr/local namesapce by default).

Afterwards enter the following command to build and install $name (if
necessary as root):

	make clean install

Running $name
$(echo "Running $name" | sed 's/./=/g')
To run $name use the following command:

	./$name

Configuration
-------------
The configuration of $name is done by creating a custom config.h
and (re)compiling the source code.
EOF
			cat <<EOF > LICENSE
ISC License

Copyright (c) $(date "+%Y") $a

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
EOF
		cat <<EOF > Makefile
# $name
# See LICENSE file for copyright and license details.

include config.mk

SRC = $name.c
OBJ = \${SRC:.c=.o}

all: $name

.c.o:
	\${CC} -c \${CFLAGS} \$<

\${OBJ}: config.h config.mk

config.h:
	cp config.def.h \$@

$name: \${OBJ}
	\${CC} -o \$@ \${OBJ} \${LDFLAGS}

clean:
	rm -f $name \${OBJ} $name-\${VERSION}.tar.gz

dist: clean
	mkdir -p $name-\${VERSION}
	cp -R LICENSE Makefile README config.def.h config.mk\
		$name.1 \${SRC} $name-\${VERSION}
	tar -cf $name-\${VERSION}.tar $name-\${VERSION}
	gzip $name-\${VERSION}.tar
	rm -rf $name-\${VERSION}

install: all
	mkdir -p \${DESTDIR}\${PREFIX}/bin
	cp -f $name \${DESTDIR}\${PREFIX}/bin
	chmod 755 \${DESTDIR}\${PREFIX}/bin/$name
	mkdir -p \${DESTDIR}\${MANPREFIX}/man1
	sed "s/VERSION/\${VERSION}/g" < $name.1 > \${DESTDIR}\${MANPREFIX}/man1/$name.1
	chmod 644 \${DESTDIR}\${MANPREFIX}/man1/$name.1

uninstall:
	rm -f \${DESTDIR}\${PREFIX}/bin/$name\
		\${DESTDIR}\${MANPREFIX}/man1/$name.1

.PHONY: all clean dist install uninstall
EOF
		cat <<EOF > config.def.h
/* See LICENSE file for copyright and license details. */
EOF
		cat <<EOF > config.mk
# $name version
VERSION = 0.1

# Customize below to fit your system

# paths
PREFIX = /usr/local
MANPREFIX = \${PREFIX}/share/man

# includes and libs
INCS = 
LIBS = 

# flags
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"\${VERSION}\"
CFLAGS   = -g -std=c99 -pedantic -Wall -O0 \${INCS} \${CPPFLAGS}
CFLAGS   = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os \${INCS} \${CPPFLAGS}
LDFLAGS  = \${LIBS}

# compiler and linker
CC = cc
EOF
		cat <<EOF > arg.h
/*
 * Copy me if you can.
 * by 20h
 */

#ifndef ARG_H__
#define ARG_H__

extern char *argv0;

/* use main(int argc, char *argv[]) */
#define ARGBEGIN	for (argv0 = *argv, argv++, argc--;\
					argv[0] && argv[0][1]\\
					&& argv[0][0] == '-';\\
					argc--, argv++) {\\
				char argc_;\\
				char **argv_;\\
				int brk_;\\
				if (argv[0][1] == '-' && argv[0][2] == '\\0') {\\
					argv++;\\
					argc--;\\
					break;\\
				}\\
				for (brk_ = 0, argv[0]++, argv_ = argv;\\
						argv[0][0] && !brk_;\\
						argv[0]++) {\\
					if (argv_ != argv)\\
						break;\\
					argc_ = argv[0][0];\\
					switch (argc_)

/* Handles obsolete -NUM syntax */
#define ARGNUM				case '0':\\
					case '1':\\
					case '2':\\
					case '3':\\
					case '4':\\
					case '5':\\
					case '6':\\
					case '7':\\
					case '8':\\
					case '9'

#define ARGEND			}\\
			}

#define ARGC()		argc_

#define ARGNUMF(base)	(brk_ = 1, estrtol(argv[0], (base)))

#define EARGF(x)	((argv[0][1] == '\\0' && argv[1] == NULL)?\\
				((x), abort(), (char *)0) :\\
				(brk_ = 1, (argv[0][1] != '\\0')?\\
					(&argv[0][1]) :\\
					(argc--, argv++, argv[0])))

#define ARGF()		((argv[0][1] == '\\0' && argv[1] == NULL)?\\
				(char *)0 :\\
				(brk_ = 1, (argv[0][1] != '\\0')?\\
					(&argv[0][1]) :\\
					(argc--, argv++, argv[0])))

#endif
EOF
		cat <<EOF > "$name.c"
/* See LICENSE file for license details. */
#include <stdio.h>
#include <stdlib.h>

#include "arg.h"
#include "config.h"

char *argv0;

static void
usage(void) {
	fprintf(stderr, "%s: usage: $name [-v]\\n", argv0);
	exit(1);
}

int
main(int argc, char *argv[]) {

	ARGBEGIN {
	case 'v':
		printf("$name/$a version %s\\n", VERSION);
		exit(0);
	default:
		usage();
	} ARGEND;

	puts("Hello, World!");

	return 0;
}
EOF
	}

	case $x in
		sh) shell ;;
		*) c ;;
	esac

	if ! [ -z "$r" ]; then
		git init -q || echo "$me: error: could not initilzie git repository" >&2
	fi

	say "made $name at $(realpath "$name")"
	cd ..
}

if ! [ $# -gt 0 ]; then
	echo "$usage"
	exit 0
fi

while [ $# -gt 0 ]; do
  case $1 in
    --help) echo "$usage"; exit 0 ;;
    --version) echo "$version"; exit 0 ;;
    -x) shift; x="$1"; shift ;;
    -d) shift; d="$1"; shift ;;
    -S) S=true; shift ;;
    -f) f=true; shift ;;
    -a) shift; a="$1"; shift ;;
    -r) r=true; shift ;;
    -q) q=true; shift ;;
    -*) echo "$me: Unknown option '$1'." >&2; exit 1 ;;
    *) create_project "$1"; shift ;;
  esac
done
