From b4d834728e89beb57377fd810abf9ee8a3365d42 Mon Sep 17 00:00:00 2001 From: Case Duckworth Date: Tue, 26 Jul 2022 23:10:44 -0500 Subject: Initial commit --- COPYING | 9 +++++++++ Makefile | 31 +++++++++++++++++++++++++++++ README.md | 36 ++++++++++++++++++++++++++++++++++ shin | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ shin.awk | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 203 insertions(+) create mode 100644 COPYING create mode 100644 Makefile create mode 100644 README.md create mode 100755 shin create mode 100755 shin.awk diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..0520203 --- /dev/null +++ b/COPYING @@ -0,0 +1,9 @@ +Copyright (C) 2022 Case Duckworth + +Usage of the works is permitted provided that this instrument is +retained with the works, so that any entity that uses the works is +notified of this instrument. + +DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. + + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a9401a1 --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +NAME = shin +DESC = Include shell scripts in other shell scripts + +DESTDIR = +PREFIX = /usr/local + +BIN = $(DESTDIR)$(PREFIX)/bin/$(NAME) + +.PHONY: help +help: + @echo "$(NAME) : $(DESC)" + @echo "(C) 2022 Case Duckworth " + @echo "Licensed under the Fair License; see COPYING for details." + @echo + @echo "TARGETS:" + @echo " install Install $(NAME) to $(BIN)." + @echo " link Install $(NAME) using symlinks." + @echo " Probably only useful for development." + @echo " uninstall Uninstall $(NAME)-related files." + +.PHONY: install +install: $(NAME) + install -D $< $(BIN) + +.PHONY: link +link: + ln -sf $(PWD)/$(NAME) $(BIN) + +.PHONY: uninstall +uninstall: + rm $(BIN) diff --git a/README.md b/README.md new file mode 100644 index 0000000..4b68c96 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +# shin +## include shell files + +built to scratch a personal itch. SHIN is an awk(1) script that plops include +files in to .shin files. here's the usage text: + +``` +SHIN: include shell files in other shell files +USAGE: shin FILE... + +FILEs named FILE.shin will be built to FILE.sh in the same directory. +to include files in shin files, use the following comment syntax: + +#< INCLUDE + +shin will add INCLUDE below that comment, as well as a comment +denoting the end of INCLUDE. +``` + +it's really that simple. and stupid. + +## configuration + +SHIN will look for include files in the current directory, unless you set the +SHINPATH environment variable. $SHINPATH is a colon-separated list of +directories like $PATH or $MANPATH. + +## extras + +`shin.awk` is the plain awk script. because awk is dumb about handling +arguments, `shin` is a shell script that will do `shin.awk`'s work unless you +pass `shin -h`, in which case it will print a helpful message. + +## license + +SHIN is licensed under the FAIR license. see COPYING for details. diff --git a/shin b/shin new file mode 100755 index 0000000..b966091 --- /dev/null +++ b/shin @@ -0,0 +1,67 @@ +#!/bin/sh +# SHIN v. 0/1 +# Copyright (C) Case Duckworth +# Licensed under the Fair License. See COPYING for details. + +_shin() { + awk 'BEGIN { + if (ENVIRON["SHINPATH"]) split(ENVIRON["SHINPATH"], SHINPATH, ":") + else SHINPATH[1] = "." +} +FNR == 1 { outfile = FILENAME; sub(/in$/, "", outfile) } +{ print($0) > outfile } +/^# outfile + close(inclfile) + sub(/", $0) + print > outfile +} +function shin_test(filename) { + if (! system("test -f \"" f "\"")) return filename + print("Cannot find \"" filename "\" in " sp) > (STDERR ? STDERR : "/dev/stderr") + exit 1 +} +function shin_resolve(filename) { + if (match(filename, "^/")) return shin_test(filename) + if (match(filename, "^~")) return shin_test(ENVIRON["HOME"] "/" substr(filename, 2)) + sub(/^[ \t]*/, "", filename) + sub(/[ \t]*$/, "", filename) + sp = "" + for (p in SHINPATH) { + sp = sp (sp ? ", " : "") "\"" SHINPATH[p] "\"" + f = SHINPATH[p] "/" filename + gsub("//", "/", f) + return shin_test(f) + } +}' +} + +if [ "x$1" = -h ]; then + cat <<\EOF +SHIN: include shell files in other shell files +USAGE: shin [-h] FILE... + +FLAGS: + -h Show this help and exit. + +PARAMETERS: + FILE... Input files. FILEs named FILE.shin will be built to + FILE.sh in the same directory. To include files in + shin files, use the following comment syntax: + + #< INCLUDE + + If INCLUDE begins with / or ~, it's taken as a literal + file name; otherwise SHINPATH will be searched for the + file. SHINPATH is a colon-separated list of paths + like $PATH. If SHINPATH is unset, it defaults to the + current directory. + + If INCLUDE is not found, shin will error and quit. + Otherwise, shin will add INCLUDE below that comment, + as well as a comment denoting the end of the INCLUDE. +EOF +else + _shin "$@" +fi diff --git a/shin.awk b/shin.awk new file mode 100755 index 0000000..80c76aa --- /dev/null +++ b/shin.awk @@ -0,0 +1,60 @@ +#!/usr/bin/awk -f +# SHIN: include files in shell scripts +# by Case Duckworth +# usage: shin -- FILE.shin... +# each FILE.shin will output to FILE.sh in the same directory +BEGIN { + if (ENVIRON["SHINPATH"]) { + split(ENVIRON["SHINPATH"], SHINPATH, ":") + } else { + SHINPATH[1] = "." + } +} + +FNR == 1 { + outfile = FILENAME + sub(/in$/, "", outfile) +} + +{ + print($0) > outfile +} + +/^# outfile + } + close(inclfile) + sub(/", $0) + print > outfile +} + + +function shin_resolve(filename) +{ + if (match(filename, "^/")) { + return shin_test(filename) + } + if (match(filename, "^~")) { + return shin_test(ENVIRON["HOME"] "/" substr(filename, 2)) + } + sub(/^[ \t]*/, "", filename) + sub(/[ \t]*$/, "", filename) + sp = "" + for (p in SHINPATH) { + sp = sp (sp ? ", " : "") "\"" SHINPATH[p] "\"" + f = SHINPATH[p] "/" filename + gsub("//", "/", f) + return shin_test(f) + } +} + +function shin_test(filename) +{ + if (! system("test -f \"" f "\"")) { + return filename + } + print("Cannot find \"" filename "\" in " sp) > (STDERR ? STDERR : "/dev/stderr") + exit 1 +} -- cgit 1.4.1-21-gabe81