#!/bin/sh # HAT TRICK # (C) 2022 C. Duckworth [ "x$DEBUG" = "xYES" ] && set -x : "${HTDAT:=$(date +%s)}" : "${HTTMP:=/tmp/ht}"; mkdir -p "$HTTMP" : "${HTENV:=$HTTMP/env-$HTDAT.sh}" : "${HTBOD:=$HTTMP/bod-$HTDAT.txt}" export HTDAT HTTMP HTENV HTBOD HT_TMPL_COUNT=1 HT_TMPL_PRE=: print() { # print STRING... ## A sane version of `echo`. printf '%s\n' "$*" } htt() { # htt FILES... # Like `cat`, but with templating. ht_end="ht_main_$HTDAT_$HT_TMPL_COUNT" # be extra double sure eval "$(print "cat <<$ht_end"; cat "$@"; print; print "$ht_end")" HT_TMPL_COUNT=$(expr $HT_TMPL_COUNT + 1) } ht_build_env() { # ht_build_env FILE... print "body() { cat \"$HTBOD\"; }" > "$HTENV" : > "$HTBOD"; # clear while read -r line; do case "$line" in *@@*:*@@*) # "simple" metadata; just a string print "$line" | sed 's/.*@@\([^:]*\): \?\(.*\)@@.*/\1() { print "\2"; }/' ;; *@@*::*@@*) # "complex" metadata: can be anything print "$line" | sed 's/.*@@\([^:]*\):: \?\(.*\)@@.*/\1() { \2 ; }/' ;; esac | sed '/%s() {.*}/d' >> "$HTENV" # Still print the line to the body (no need to escape or w/e) print "$line" >> "$HTBOD" done env | grep '^HT' | sort | uniq >> "$HTENV" } ht_main() { # main TEMPLATE < INPUT ## Apply TEMPLATE to INPUT and print it. # TEMPLATE will be interpreted as a heredoc. if [ $# -eq 0 ]; then print "ht.sh TEMPLATE < INPUT" >&2 exit 1 fi eval "ht_build_env; . \"$HTENV\"; htt \"\$@\";"; } # To keep this POSIX-compliant, we can't use a bashism like # [[ "$0" == # "$BASH_SOURCE[0]" ]]. However, there are still ways to guess # whether the user is sourcing this file as a library or executing it as a # script. case "$0" in *ht.sh) ht_main "$@" ;; *) print "Sourcing ht.sh" ;; esac