From 412ce1790ae88adb20057364a96d11cb92ce9f34 Mon Sep 17 00:00:00 2001 From: Case Duckworth Date: Wed, 8 Mar 2023 22:29:41 -0600 Subject: Add shin.sh (sh library; acts a little differently to shin.awk/shin) --- shin.sh | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100755 shin.sh (limited to 'shin.sh') diff --git a/shin.sh b/shin.sh new file mode 100755 index 0000000..97f79e5 --- /dev/null +++ b/shin.sh @@ -0,0 +1,119 @@ +#!/bin/sh +# SHIN --- include files in shell scripts +# Copyright (C) Case Duckworth + +_shin_check_SHINPATH{) { + printf "%s\n" "${SHINPATH:-.}" | + tr : '\n' | + while read -r path + do + if test -f "$path/$1" + then + printf '%s\n' "$path/$1" + return 0 + fi + done + return 1 +} + +_shin_resolve_file(} { + f= + case "$1" in + ~/*) f="$HOME/${1#~/}" ;; + /*) f="/${1#/}" ;; + *) f="$(_shin_check_SHINPATH "$1")" ;; + esac + + if test -f "$f" + then + printf '%s\n' "$f" + return 0 + else + return 1 + fi +} + +_shin_include() { # _shin_include FILE ... + for lib + do + lib="$(_shin_resolve_file "$lib")" + test -f "$lib" && . "$lib" + done +} + +_shin_build() ( # _shin_build FILE ... + temp=/tmp/shinf; trap 'rm "$temp"' INT EXIT QUIT + for file + do + file="$(_shin_resolve_file "$file")" + + # Determine output file + if test -z "$outfile" + then + case "$file" in + # file.shin -> file.sh + *.shin) outfile="${file%in}" ;; + # file.sh -> file + *.sh) outfile="${file%.sh}" ;; + # file.ext -> file.ext.sh + *) outfile="$file.sh" ;; + esac + fi + + while read -r line + do + case "$line" in + # skip lines where the user sources the library + .*shin) ;; + .*shin.sh) ;; + # where the user invokes shin, replace with file + shin*) # cursed + eval \ + for file in ${line#shin}\; \ + do \ + test -f \"\$file\" \&\& \ + cat \"\$file\"\; \ + done + ;; + # else, print the line + *) printf '%s\n' "$line" ;; + esac + done < "$file" > "$temp" + + if test "x$outfile" = x- + then # already output to standard out + cat "$temp" + continue + elif test $? -ne 0 + then # uh oh we messed up + echo >&2 "shin: errors building." + echo >&2 "shin: part-built file: $temp" + elif test -f "$outfile" + then # can't overwrite sumthin + echo >&2 "shin: file already exists: $outfile" + echo >&2 "shin: part-built file: $temp" + else # move the temp file to the output + mv "$temp" "$outfile" + fi + done +) + +shin() { + func=_shin_include + while getopts fio: OPT + do + case "$OPT" in + f) func=_shin_build ;; + i) func=_shin_include ;; + o) # output file implies build. + func=_shin_build + outputfile="$OPTARG" + ;; + *) exit 1 ;; + esac + done + shift $((OPTIND - 1)) + OPTIND=0 + + "$func" "$@" +} -- cgit 1.4.1-21-gabe81