From ba6fa37d6254d35960c9902d43f7f16dc8370279 Mon Sep 17 00:00:00 2001 From: sdomi Date: Fri, 7 Mar 2025 02:26:18 +0100 Subject: [PATCH 1/3] template: cleanup rest sed generators --- src/template.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/template.sh b/src/template.sh index 9ab870b..eb74cbc 100755 --- a/src/template.sh +++ b/src/template.sh @@ -37,16 +37,16 @@ function render() { rm "$subtemplate" elif [[ "$key" == "@"* && "${ref["$key"]}" != '' ]]; then local value="$(tr -d "${_tpl_ctrl}${_tpl_newline}" <<< "${ref["$key"]}" | sed -E 's/\&/�UwU�/g')" - echo "s${_tpl_ctrl}"'\{\{\'"$key"'\}\}'"${_tpl_ctrl}${value}${_tpl_ctrl}g;" >> "$tmp" #' + echo "s${_tpl_ctrl}\{\{$key\}\}${_tpl_ctrl}${value}${_tpl_ctrl}g;" >> "$tmp" elif [[ "$key" == "+"* ]]; then # date mode if [[ ! "${ref["$key"]}" ]]; then # special case: if the date is empty, # make the output empty too - echo "s${_tpl_ctrl}\{\{\\$key\}\}${_tpl_ctrl}${_tpl_ctrl}g;" >> "$tmp" #' + echo "s${_tpl_ctrl}\{\{\\$key\}\}${_tpl_ctrl}${_tpl_ctrl}g;" >> "$tmp" else local value printf -v value "%(${cfg[template_date_format]})T" "${ref["$key"]}" - echo "s${_tpl_ctrl}\{\{\\$key\}\}${_tpl_ctrl}${value}${_tpl_ctrl};" >> "$tmp" #' + echo "s${_tpl_ctrl}\{\{\\$key\}\}${_tpl_ctrl}${value}${_tpl_ctrl};" >> "$tmp" fi elif [[ "$key" == '?'* ]]; then local _key="\\?${key/?/}" @@ -69,9 +69,9 @@ function render() { else local value="$(echo -n "${ref["$key"]}" | tr -d "${_tpl_ctrl}${_tpl_newline}" | tr $'\n' "${_tpl_newline}" | sed -E 's/\\\\/�OwO�/g;s/\\//g;s/�OwO�/\\/g' | html_encode | sed -E 's/\&/�UwU�/g')" fi - echo "s${_tpl_ctrl}"'\{\{\.'"$key"'\}\}'"${_tpl_ctrl}${value}${_tpl_ctrl}g;" >> "$tmp" + echo "s${_tpl_ctrl}\{\{\.$key\}\}${_tpl_ctrl}${value}${_tpl_ctrl}g;" >> "$tmp" else - echo "s${_tpl_ctrl}"'\{\{\.'"$key"'\}\}'"${_tpl_ctrl}${_tpl_ctrl}g;" >> "$tmp" + echo "s${_tpl_ctrl}\{\{\.$key\}\}${_tpl_ctrl}${_tpl_ctrl}g;" >> "$tmp" fi done unset IFS @@ -141,10 +141,10 @@ _template_gen_special_uri() { # {{-uri-}}, where num is amount of slashed parts to include sort <<< ${_template_uri_list[*]} | uniq | while read num; do uri="$(grep -Poh '^(/.*?){'"$((num+1))"'}' <<< "${r[url_clean]}/")" - echo "s${_tpl_ctrl}"'\{\{-uri-'"$num"'\}\}'"${_tpl_ctrl}${uri}${_tpl_ctrl}g;" + echo "s${_tpl_ctrl}\{\{-uri-$num\}\}${_tpl_ctrl}${uri}${_tpl_ctrl}g;" done # for replacing plain {{-uri}} without a number - echo "s${_tpl_ctrl}"'\{\{-uri\}\}'"${_tpl_ctrl}${r[url_clean]}${_tpl_ctrl}g;" + echo "s${_tpl_ctrl}\{\{-uri\}\}${_tpl_ctrl}${r[url_clean]}${_tpl_ctrl}g;" } # render_unsafe(array, template_file) From 86f424fb3023afe0b599454f11098770c47486de Mon Sep 17 00:00:00 2001 From: sdomi Date: Fri, 7 Mar 2025 02:26:46 +0100 Subject: [PATCH 2/3] template: deprecate render_unsafe we haven't needed this in a million years, and using it supports poorly-written templates. --- src/template.sh | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/src/template.sh b/src/template.sh index eb74cbc..07497eb 100755 --- a/src/template.sh +++ b/src/template.sh @@ -147,31 +147,6 @@ _template_gen_special_uri() { echo "s${_tpl_ctrl}\{\{-uri\}\}${_tpl_ctrl}${r[url_clean]}${_tpl_ctrl}g;" } -# render_unsafe(array, template_file) -function render_unsafe() { - local template="$(cat "$2")" - local -n ref=$1 - local tmp=$(mktemp) - for key in ${!ref[@]}; do - if [[ "$key" == "_"* ]]; then # iter mode - # grep "start _test" -A99999 | grep "end _test" -B99999 - local -n item_array=${ref["$key"]} - local value - for ((_i = 0; _i < ${#item_array[@]}; _i++)); do - value+="$(xxd -p <<< "${item_array[$_i]}" | tr -d '\n' | sed -E 's/../\\x&/g')" - done - echo 's/\{\{'"$key"'\}\}/'"$value"'/g' >> "$tmp" - else - local value="$(xxd -p <<< "${ref["$key"]}" | tr -d '\n' | sed -E 's/../\\x&/g')" - echo 's/\{\{\.'"$key"'\}\}/'"$value"'/g' >> "$tmp" - fi - done - - sed -E -f "$tmp" <<< "$template" - rm "$tmp" -} - - # mmmm this should be a library because i am so much copying those later # _nested_random function _nested_random() { From 44c2aec5ca7574fa1fa84a813d9944ff779e55aa Mon Sep 17 00:00:00 2001 From: sdomi Date: Fri, 7 Mar 2025 03:29:37 +0100 Subject: [PATCH 3/3] template: eliminate all temporary file i/o this commit replaces all file i/o with file substitutions, bringing the whole engine more closely in-line with how it used to look, at least initially, before it turned out that keeping the filters inline is a no-go due to command length limits. This also brings a modest performance improvement (~1.35s -> ~1.2s on my test page) --- src/template.sh | 56 +++++++++++++++++++------------------------------ 1 file changed, 21 insertions(+), 35 deletions(-) diff --git a/src/template.sh b/src/template.sh index 07497eb..0ab44dd 100755 --- a/src/template.sh +++ b/src/template.sh @@ -11,67 +11,57 @@ function render() { else local template="$(tr -d ${_tpl_ctrl} < "$2" | sed -E 's/\\/\\\\/g')" fi + local buf= local -n ref=$1 - local tmp=$(mktemp) local key IFS=$'\n' for key in ${!ref[@]}; do if [[ "$key" == "_"* ]]; then # iter mode - local subtemplate=$(mktemp) - echo "$template" | grep "{{start $key}}" -A99999 | grep "{{end $key}}" -B99999 | tr '\n' "${_tpl_newline}" > "$subtemplate" - - echo "s${_tpl_ctrl}\{\{start $key\}\}.*\{\{end $key\}\}${_tpl_ctrl}\{\{$key\}\}${_tpl_ctrl};" >> "$tmp" + local subtemplate="$(grep "{{start $key}}" -A99999 <<< "$template" | grep "{{end $key}}" -B99999 | tr '\n' "${_tpl_newline}")" local -n asdf=${ref["$key"]} local j local value='' for j in ${!asdf[@]}; do local -n fdsa=_${asdf[$j]} - - value+="$(render fdsa "$subtemplate" true)" + value+="$(render fdsa /dev/stdin true <<< "$subtemplate")" done - value="$(tr -d "${_tpl_ctrl}" <<< "$value" | sed -E "s${_tpl_ctrl}"'\{\{start '"$key"'\}\}'"${_tpl_ctrl}${_tpl_ctrl};s${_tpl_ctrl}"'\{\{end '"$key"'\}\}'"${_tpl_ctrl}${_tpl_ctrl}")" - echo "s${_tpl_ctrl}\{\{$key\}\}${_tpl_ctrl}${value}${_tpl_ctrl};" >> "$tmp" - rm "$subtemplate" + buf+="s${_tpl_ctrl}\{\{start $key\}\}.*\{\{end $key\}\}${_tpl_ctrl}\{\{$key\}\}${_tpl_ctrl};s${_tpl_ctrl}\{\{$key\}\}${_tpl_ctrl}$(tr -d "${_tpl_ctrl}" <<< "$value" | sed -E "s${_tpl_ctrl}"'\{\{start '"$key"'\}\}'"${_tpl_ctrl}${_tpl_ctrl};s${_tpl_ctrl}"'\{\{end '"$key"'\}\}'"${_tpl_ctrl}${_tpl_ctrl}")${_tpl_ctrl};" + unset "$subtemplate" elif [[ "$key" == "@"* && "${ref["$key"]}" != '' ]]; then local value="$(tr -d "${_tpl_ctrl}${_tpl_newline}" <<< "${ref["$key"]}" | sed -E 's/\&/�UwU�/g')" - echo "s${_tpl_ctrl}\{\{$key\}\}${_tpl_ctrl}${value}${_tpl_ctrl}g;" >> "$tmp" + buf+="s${_tpl_ctrl}\{\{$key\}\}${_tpl_ctrl}${value}${_tpl_ctrl}g;" elif [[ "$key" == "+"* ]]; then # date mode if [[ ! "${ref["$key"]}" ]]; then # special case: if the date is empty, # make the output empty too - echo "s${_tpl_ctrl}\{\{\\$key\}\}${_tpl_ctrl}${_tpl_ctrl}g;" >> "$tmp" + buf+="s${_tpl_ctrl}\{\{\\$key\}\}${_tpl_ctrl}${_tpl_ctrl}g;" else local value printf -v value "%(${cfg[template_date_format]})T" "${ref["$key"]}" - echo "s${_tpl_ctrl}\{\{\\$key\}\}${_tpl_ctrl}${value}${_tpl_ctrl};" >> "$tmp" + buf+="s${_tpl_ctrl}\{\{\\$key\}\}${_tpl_ctrl}${value}${_tpl_ctrl};" fi elif [[ "$key" == '?'* ]]; then local _key="\\?${key/?/}" - local subtemplate=$(mktemp) - echo "s${_tpl_ctrl}"'\{\{start '"$_key"'\}\}((.*)\{\{else '"$_key"'\}\}.*\{\{end '"$_key"'\}\}|(.*)\{\{end '"$_key"'\}\})'"${_tpl_ctrl}"'\2\3'"${_tpl_ctrl};" >> "$subtemplate" - # TODO: check if this is needed? # the code below makes sure to resolve the conditional blocks # *before* anything else. I can't think of *why* this is needed # right now, but I definitely had a reason in this. Question is, what reason. - cat <<< $(cat "$subtemplate" "$tmp") > "$tmp" # call that cat abuse + buf+="s${_tpl_ctrl}"'\{\{start '"$_key"'\}\}((.*)\{\{else '"$_key"'\}\}.*\{\{end '"$_key"'\}\}|(.*)\{\{end '"$_key"'\}\})'"${_tpl_ctrl}"'\2\3'"${_tpl_ctrl};${buf}" # MAYBE_SLOW - rm "$subtemplate" elif [[ "${ref["$key"]}" != "" ]]; then - echo "VALUE: ${ref["$key"]}" > /dev/stderr if [[ "$3" != true ]]; then local value="$(html_encode <<< "${ref["$key"]}" | tr -d "${_tpl_ctrl}" | sed -E 's/\&/�UwU�/g')" else local value="$(echo -n "${ref["$key"]}" | tr -d "${_tpl_ctrl}${_tpl_newline}" | tr $'\n' "${_tpl_newline}" | sed -E 's/\\\\/�OwO�/g;s/\\//g;s/�OwO�/\\/g' | html_encode | sed -E 's/\&/�UwU�/g')" fi - echo "s${_tpl_ctrl}\{\{\.$key\}\}${_tpl_ctrl}${value}${_tpl_ctrl}g;" >> "$tmp" + buf+="s${_tpl_ctrl}\{\{\.$key\}\}${_tpl_ctrl}${value}${_tpl_ctrl}g;" else - echo "s${_tpl_ctrl}\{\{\.$key\}\}${_tpl_ctrl}${_tpl_ctrl}g;" >> "$tmp" + buf+="s${_tpl_ctrl}\{\{\.$key\}\}${_tpl_ctrl}${_tpl_ctrl}g;" fi done unset IFS @@ -80,36 +70,32 @@ function render() { # achtung: even though this is *after* the main loop, it actually executes sed reaplces *before* it; # recursion is currently unsupported here, i feel like it may break things? if [[ "$template" == *'{{#'* && "$3" != true ]]; then - local subtemplate=$(mktemp) + local subtemplate= while read key; do # below check prevents the loop loading itself as a template. # this is possibly not enough to prevent all recursions, but # i see it as a last-ditch measure. so it'll do here. if [[ "$file" == "$2" ]]; then - echo "s${_tpl_ctrl}\{\{\#$key\}\}${_tpl_ctrl}I cowardly refuse to endlessly recurse\!${_tpl_ctrl}g;" >> "$subtemplate" + subtemplate+="s${_tpl_ctrl}\{\{\#$key\}\}${_tpl_ctrl}I cowardly refuse to endlessly recurse\!${_tpl_ctrl}g;" elif [[ -f "$key" ]]; then - echo "s${_tpl_ctrl}\{\{\#$key\}\}${_tpl_ctrl}$(tr -d "${_tpl_ctrl}${_tpl_newline}" < "$key" | tr $'\n' "${_tpl_newline}" | sed 's/\&/�UwU�/g')${_tpl_ctrl};" >> "$subtemplate" + subtemplate+="s${_tpl_ctrl}\{\{\#$key\}\}${_tpl_ctrl}$(tr -d "${_tpl_ctrl}${_tpl_newline}" < "$key" | tr $'\n' "${_tpl_newline}" | sed 's/\&/�UwU�/g')${_tpl_ctrl};" _template_find_special_uri "$(cat "$key")" fi done <<< "$(grep -Poh '{{#.*?}}' <<< "$template" | sed 's/{{#//;s/}}$//')" - cat <<< $(cat "$subtemplate" "$tmp") > "$tmp" - rm "$subtemplate" + buf="${subtemplate}$buf" fi _template_find_special_uri "$template" - _template_gen_special_uri >> "$tmp" + buf+="$(_template_gen_special_uri)" if [[ "$3" != true ]]; then # are we recursing? - cat "$tmp" | tr '\n' "${_tpl_newline}" | sed -E $'s/\02;\01/\02;/g;s/\02g;\01/\02g;/g' > "${tmp}_" # i'm sorry what is this sed replace?? - - echo 's/\{\{start \?([a-zA-Z0-9_-]*[^}])\}\}(.*\{\{else \?\1\}\}(.*)\{\{end \?\1\}\}|.*\{\{end \?\1\}\})/\3/g' >> "${tmp}_" - template="$(tr '\n' ${_tpl_newline} <<< "$template" | sed -E -f "${tmp}_" | tr "${_tpl_newline}" '\n')" - sed -E 's/�UwU�/\&/g' <<< "$template" - rm "$tmp" "${tmp}_" + tr '\n' ${_tpl_newline} <<< "$template" | sed -E -f <( + tr '\n' "${_tpl_newline}" <<< "$buf" | sed -E $'s/\02;\01/\02;/g;s/\02g;\01/\02g;/g' # i'm sorry what is this sed replace?? + echo -n 's/\{\{start \?([a-zA-Z0-9_-]*[^}])\}\}(.*\{\{else \?\1\}\}(.*)\{\{end \?\1\}\}|.*\{\{end \?\1\}\})/\3/g' + ) | tr "${_tpl_newline}" '\n' | sed -E 's/�UwU�/\&/g' else - tr '\n' "${_tpl_newline}" <<< "$template" | sed -E -f "$tmp" | tr "${_tpl_newline}" '\n' - rm "$tmp" + tr '\n' "${_tpl_newline}" <<< "$template" | sed -E -f <(echo -n "$buf") | tr "${_tpl_newline}" '\n' fi [[ "$3" != true ]] && _template_uri_list=()