2015-10-02 14:06:16 +00:00
|
|
|
#!/usr/bin/env bash
|
2015-01-27 12:05:06 +00:00
|
|
|
#
|
2015-10-02 14:06:16 +00:00
|
|
|
#/ Mo is a mustache template rendering software written in bash. It inserts
|
|
|
|
#/ environment variables into templates.
|
|
|
|
#/
|
|
|
|
#/ Simply put, mo will change {{VARIABLE}} into the value of that
|
|
|
|
#/ environment variable. You can use {{#VARIABLE}}content{{/VARIABLE}} to
|
|
|
|
#/ conditionally display content or iterate over the values of an array.
|
|
|
|
#/
|
|
|
|
#/ Learn more about mustache templates at https://mustache.github.io/
|
2015-01-27 12:05:06 +00:00
|
|
|
#
|
|
|
|
# Mo is under a MIT style licence with an additional non-advertising clause.
|
|
|
|
# See LICENSE.md for the full text.
|
|
|
|
#
|
|
|
|
# This is open source! Please feel free to contribute.
|
|
|
|
#
|
|
|
|
# https://github.com/tests-always-included/mo
|
2015-01-23 17:43:08 +00:00
|
|
|
|
2015-01-26 18:51:28 +00:00
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Public: Template parser function. Writes templates to stdout.
|
|
|
|
#
|
2016-07-21 14:45:31 +00:00
|
|
|
# $0 - Name of the mo file, used for getting the help message.
|
|
|
|
# --help - Display a help message.
|
|
|
|
# --source=FILE - Source a file into the environment before processint
|
|
|
|
# template files.
|
|
|
|
# -- - Used to indicate the end of options. You may optionally
|
|
|
|
# use this when filenames may start with two hyphens.
|
|
|
|
# $@ - Filenames to parse.
|
2015-10-02 14:46:57 +00:00
|
|
|
#
|
|
|
|
# Returns nothing.
|
|
|
|
mo() (
|
2015-10-02 15:47:53 +00:00
|
|
|
# This function executes in a subshell so IFS is reset.
|
|
|
|
# Namespace this variable so we don't conflict with desired values.
|
2016-07-21 14:45:31 +00:00
|
|
|
local moContent f2source files doubleHyphens
|
2015-10-02 14:46:57 +00:00
|
|
|
|
|
|
|
IFS=$' \n\t'
|
2016-07-21 14:34:02 +00:00
|
|
|
files=()
|
2016-07-21 14:45:31 +00:00
|
|
|
doubleHyphens=false
|
2016-07-21 11:07:02 +00:00
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
if [[ $# -gt 0 ]]; then
|
2016-07-21 14:11:11 +00:00
|
|
|
for arg in "$@"; do
|
2016-07-21 14:45:31 +00:00
|
|
|
if $doubleHyphens; then
|
|
|
|
# After we encounter two hyphens together, all the rest
|
|
|
|
# of the arguments are files.
|
|
|
|
files=("${files[@]}" "$arg")
|
|
|
|
else
|
|
|
|
case "$arg" in
|
|
|
|
-h|--h|--he|--hel|--help)
|
|
|
|
moUsage "$0"
|
|
|
|
exit 0
|
|
|
|
;;
|
|
|
|
|
|
|
|
--source=*)
|
|
|
|
f2source="${1#--source=}"
|
|
|
|
|
|
|
|
if [[ -f "$f2source" ]]; then
|
|
|
|
. "$f2source"
|
|
|
|
else
|
|
|
|
echo "No such file: $f2source" >&2
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
|
|
|
|
--)
|
|
|
|
# Set a flag indicating we've encountered double hyphens
|
|
|
|
doubleHyphens=true
|
|
|
|
;;
|
|
|
|
|
|
|
|
*)
|
|
|
|
# Every arg that is not a flag or a option should be a file
|
|
|
|
files=("${files[@]}" "$arg")
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
fi
|
2016-07-21 14:11:11 +00:00
|
|
|
done
|
2015-10-02 14:46:57 +00:00
|
|
|
fi
|
|
|
|
|
2016-07-21 14:11:11 +00:00
|
|
|
moGetContent moContent "${files[@]}"
|
2015-10-02 15:47:53 +00:00
|
|
|
moParse "$moContent" "" true
|
2015-10-02 14:46:57 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# Internal: Scan content until the right end tag is found. Creates an array
|
|
|
|
# with the following members:
|
|
|
|
#
|
|
|
|
# [0] = Content before end tag
|
|
|
|
# [1] = End tag (complete tag)
|
|
|
|
# [2] = Content after end tag
|
2015-01-26 18:51:28 +00:00
|
|
|
#
|
|
|
|
# Everything using this function uses the "standalone tags" logic.
|
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# $1 - Name of variable for the array
|
|
|
|
# $2 - Content
|
|
|
|
# $3 - Name of end tag
|
|
|
|
# $4 - If -z, do standalone tag processing before finishing
|
|
|
|
#
|
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moFindEndTag() {
|
2015-10-02 15:47:53 +00:00
|
|
|
local content scanned standaloneBytes tag
|
2015-01-26 18:51:28 +00:00
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
#: Find open tags
|
2015-10-02 15:47:53 +00:00
|
|
|
scanned=""
|
|
|
|
moSplit content "$2" '{{' '}}'
|
2015-01-26 18:51:28 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
while [[ "${#content[@]}" -gt 1 ]]; do
|
|
|
|
moTrimWhitespace tag "${content[1]}"
|
2015-05-05 15:46:06 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
#: Restore content[1] before we start using it
|
|
|
|
content[1]='{{'"${content[1]}"'}}'
|
2015-01-26 18:51:28 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
case $tag in
|
2015-01-26 18:51:28 +00:00
|
|
|
'#'* | '^'*)
|
2015-10-02 14:46:57 +00:00
|
|
|
#: Start another block
|
2015-10-02 15:47:53 +00:00
|
|
|
scanned="${scanned}${content[0]}${content[1]}"
|
|
|
|
moTrimWhitespace tag "${tag:1}"
|
|
|
|
moFindEndTag content "${content[2]}" "$tag" "loop"
|
|
|
|
scanned="${scanned}${content[0]}${content[1]}"
|
|
|
|
content=${content[2]}
|
2015-01-26 18:51:28 +00:00
|
|
|
;;
|
|
|
|
|
|
|
|
'/'*)
|
2015-10-02 14:46:57 +00:00
|
|
|
#: End a block - could be ours
|
2015-10-02 15:47:53 +00:00
|
|
|
moTrimWhitespace tag "${tag:1}"
|
|
|
|
scanned="$scanned${content[0]}"
|
2015-01-26 18:51:28 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
if [[ "$tag" == "$3" ]]; then
|
2015-10-02 14:46:57 +00:00
|
|
|
#: Found our end tag
|
2015-10-02 15:47:53 +00:00
|
|
|
if [[ -z "$4" ]] && moIsStandalone standaloneBytes "$scanned" "${content[2]}" true; then
|
2015-10-02 14:46:57 +00:00
|
|
|
#: This is also a standalone tag - clean up whitespace
|
|
|
|
#: and move those whitespace bytes to the "tag" element
|
2015-10-02 15:47:53 +00:00
|
|
|
standaloneBytes=( $standaloneBytes )
|
|
|
|
content[1]="${scanned:${standaloneBytes[0]}}${content[1]}${content[2]:0:${standaloneBytes[1]}}"
|
|
|
|
scanned="${scanned:0:${standaloneBytes[0]}}"
|
|
|
|
content[2]="${content[2]:${standaloneBytes[1]}}"
|
2015-01-26 18:51:28 +00:00
|
|
|
fi
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
local "$1" && moIndirectArray "$1" "$scanned" "${content[1]}" "${content[2]}"
|
2015-01-26 18:51:28 +00:00
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
scanned="$scanned${content[1]}"
|
|
|
|
content=${content[2]}
|
2015-01-26 18:51:28 +00:00
|
|
|
;;
|
|
|
|
|
|
|
|
*)
|
2015-10-02 14:46:57 +00:00
|
|
|
#: Ignore all other tags
|
2015-10-02 15:47:53 +00:00
|
|
|
scanned="${scanned}${content[0]}${content[1]}"
|
|
|
|
content=${content[2]}
|
2015-01-26 18:51:28 +00:00
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
moSplit content "$content" '{{' '}}'
|
2015-01-26 18:51:28 +00:00
|
|
|
done
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
#: Did not find our closing tag
|
2015-10-02 15:47:53 +00:00
|
|
|
scanned="$scanned${content[0]}"
|
|
|
|
local "$1" && moIndirectArray "$1" "${scanned}" "" ""
|
2015-01-23 17:43:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Find the first index of a substring. If not found, sets the
|
|
|
|
# index to -1.
|
2015-01-27 01:55:06 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# $1 - Destination variable for the index
|
|
|
|
# $2 - Haystack
|
|
|
|
# $3 - Needle
|
|
|
|
#
|
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moFindString() {
|
2015-10-02 15:47:53 +00:00
|
|
|
local pos string
|
2015-01-27 01:55:06 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
string=${2%%$3*}
|
|
|
|
[[ "$string" == "$2" ]] && pos=-1 || pos=${#string}
|
|
|
|
local "$1" && moIndirect "$1" $pos
|
2015-01-27 01:55:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Generate a dotted name based on current context and target name.
|
|
|
|
#
|
|
|
|
# $1 - Target variable to store results
|
|
|
|
# $2 - Context name
|
|
|
|
# $3 - Desired variable name
|
2015-01-27 01:55:06 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moFullTagName() {
|
2015-08-27 14:42:01 +00:00
|
|
|
if [[ -z "$2" ]] || [[ "$2" == *.* ]]; then
|
2015-10-02 14:06:16 +00:00
|
|
|
local "$1" && moIndirect "$1" "$3"
|
2015-01-27 01:55:06 +00:00
|
|
|
else
|
2015-10-02 14:06:16 +00:00
|
|
|
local "$1" && moIndirect "$1" "${2}.${3}"
|
2015-01-27 01:55:06 +00:00
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Fetches the content to parse into a variable. Can be a list of
|
|
|
|
# partials for files or the content from stdin.
|
|
|
|
#
|
|
|
|
# $1 - Variable name to assign this content back as
|
2015-10-07 20:23:50 +00:00
|
|
|
# $2-@ - File names (optional)
|
2015-01-27 01:55:06 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moGetContent() {
|
2015-10-02 15:47:53 +00:00
|
|
|
local content filename target
|
2015-01-27 01:55:06 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
target=$1
|
2015-01-27 01:55:06 +00:00
|
|
|
shift
|
|
|
|
if [[ "${#@}" -gt 0 ]]; then
|
2015-10-02 15:47:53 +00:00
|
|
|
content=""
|
2015-01-27 01:55:06 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
for filename in "$@"; do
|
2015-10-02 14:46:57 +00:00
|
|
|
#: This is so relative paths work from inside template files
|
2015-10-02 15:47:53 +00:00
|
|
|
content="$content"'{{>'"$filename"'}}'
|
2015-01-27 01:55:06 +00:00
|
|
|
done
|
|
|
|
else
|
2015-10-02 15:47:53 +00:00
|
|
|
moLoadFile content /dev/stdin
|
2015-01-27 01:55:06 +00:00
|
|
|
fi
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
local "$target" && moIndirect "$target" "$content"
|
2015-01-27 01:55:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Indent a string, placing the indent at the beginning of every
|
2015-01-27 01:55:06 +00:00
|
|
|
# line that has any content.
|
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# $1 - Name of destination variable to get an array of lines
|
|
|
|
# $2 - The indent string
|
|
|
|
# $3 - The string to reindent
|
|
|
|
#
|
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moIndentLines() {
|
2015-10-02 15:47:53 +00:00
|
|
|
local content fragment len posN posR result trimmed
|
2015-01-27 01:55:06 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
result=""
|
|
|
|
len=$((${#3} - 1))
|
2015-10-02 14:46:57 +00:00
|
|
|
|
|
|
|
#: This removes newline and dot from the workaround in moPartial
|
2015-10-02 15:47:53 +00:00
|
|
|
content="${3:0:$len}"
|
2015-01-27 01:55:06 +00:00
|
|
|
|
|
|
|
if [ -z "$2" ]; then
|
2015-10-02 15:47:53 +00:00
|
|
|
local "$1" && moIndirect "$1" "$content"
|
2015-01-27 01:55:06 +00:00
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
moFindString posN "$content" $'\n'
|
|
|
|
moFindString posR "$content" $'\r'
|
2015-01-27 01:55:06 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
while [[ "$posN" -gt -1 ]] || [[ "$posR" -gt -1 ]]; do
|
|
|
|
if [[ "$posN" -gt -1 ]]; then
|
|
|
|
fragment="${content:0:$posN + 1}"
|
|
|
|
content=${content:$posN + 1}
|
2015-01-27 01:55:06 +00:00
|
|
|
else
|
2015-10-02 15:47:53 +00:00
|
|
|
fragment="${content:0:$posR + 1}"
|
|
|
|
content=${content:$posR + 1}
|
2015-01-27 01:55:06 +00:00
|
|
|
fi
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
moTrimChars trimmed "$fragment" false true " " $'\t' $'\n' $'\r'
|
2015-01-27 01:55:06 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
if [ ! -z "$trimmed" ]; then
|
|
|
|
fragment="$2$fragment"
|
2015-01-27 01:55:06 +00:00
|
|
|
fi
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
result="$result$fragment"
|
|
|
|
moFindString posN "$content" $'\n'
|
|
|
|
moFindString posR "$content" $'\r'
|
2015-01-27 01:55:06 +00:00
|
|
|
done
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
moTrimChars trimmed "$content" false true " " $'\t'
|
2015-01-27 01:55:06 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
if [ ! -z "$trimmed" ]; then
|
|
|
|
content="$2$content"
|
2015-01-27 01:55:06 +00:00
|
|
|
fi
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
result="$result$content"
|
2015-01-27 01:55:06 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
local "$1" && moIndirect "$1" "$result"
|
2015-01-27 01:55:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Send a variable up to the parent of the caller of this function.
|
2015-01-27 01:55:06 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# $1 - Variable name
|
|
|
|
# $2 - Value
|
|
|
|
#
|
|
|
|
# Examples
|
|
|
|
#
|
|
|
|
# callFunc () {
|
|
|
|
# local "$1" && moIndirect "$1" "the value"
|
|
|
|
# }
|
2015-10-02 15:47:53 +00:00
|
|
|
# callFunc dest
|
|
|
|
# echo "$dest" # writes "the value"
|
2015-10-02 14:46:57 +00:00
|
|
|
#
|
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moIndirect() {
|
2015-01-27 01:55:06 +00:00
|
|
|
unset -v "$1"
|
|
|
|
printf -v "$1" '%s' "$2"
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Send an array as a variable up to caller of a function
|
|
|
|
#
|
|
|
|
# $1 - Variable name
|
2015-10-07 20:23:50 +00:00
|
|
|
# $2-@ - Array elements
|
2015-10-02 14:46:57 +00:00
|
|
|
#
|
|
|
|
# Examples
|
2015-01-27 01:55:06 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# callFunc () {
|
|
|
|
# local myArray=(one two three)
|
|
|
|
# local "$1" && moIndirectArray "$1" "${myArray[@]}"
|
|
|
|
# }
|
2015-10-02 15:47:53 +00:00
|
|
|
# callFunc dest
|
|
|
|
# echo "${dest[@]}" # writes "one two three"
|
2015-10-02 14:46:57 +00:00
|
|
|
#
|
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moIndirectArray() {
|
2015-01-27 01:55:06 +00:00
|
|
|
unset -v "$1"
|
|
|
|
eval $1=\(\"\${@:2}\"\)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Determine if a given environment variable exists and if it is
|
|
|
|
# an array.
|
|
|
|
#
|
|
|
|
# $1 - Name of environment variable
|
2015-01-27 01:55:06 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# Examples
|
2015-01-27 01:55:06 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# var=(abc)
|
|
|
|
# if moIsArray var; then
|
|
|
|
# echo "This is an array"
|
|
|
|
# echo "Make sure you don't accidentally use \$var"
|
|
|
|
# fi
|
|
|
|
#
|
|
|
|
# Returns 0 if the name is not empty, 1 otherwise.
|
2015-10-02 14:06:16 +00:00
|
|
|
moIsArray() {
|
2015-10-02 15:47:53 +00:00
|
|
|
# Namespace this variable so we don't conflict with what we're testing.
|
|
|
|
local moTestResult
|
2015-01-27 01:55:06 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
moTestResult=$(declare -p "$1" 2>/dev/null) || return 1
|
|
|
|
[[ "${moTestResult:0:10}" == "declare -a" ]] && return 0
|
|
|
|
[[ "${moTestResult:0:10}" == "declare -A" ]] && return 0
|
2015-01-27 01:55:06 +00:00
|
|
|
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Determine if the given name is a defined function.
|
|
|
|
#
|
|
|
|
# $1 - Function name to check
|
|
|
|
#
|
|
|
|
# Examples
|
2015-01-27 01:55:06 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# moo () {
|
|
|
|
# echo "This is a function"
|
|
|
|
# }
|
|
|
|
# if moIsFunction moo; then
|
|
|
|
# echo "moo is a defined function"
|
|
|
|
# fi
|
2015-01-27 01:55:06 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# Returns 0 if the name is a function, 1 otherwise.
|
2015-10-02 14:06:16 +00:00
|
|
|
moIsFunction() {
|
2015-10-02 15:47:53 +00:00
|
|
|
local functionList functionName
|
2015-01-27 01:55:06 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
functionList=$(declare -F)
|
|
|
|
functionList=( ${functionList//declare -f /} )
|
2015-01-27 14:29:08 +00:00
|
|
|
|
2015-12-21 15:02:42 +00:00
|
|
|
for functionName in "${functionList[@]}"; do
|
2015-10-02 15:47:53 +00:00
|
|
|
if [[ "$functionName" == "$1" ]]; then
|
2015-01-27 01:55:06 +00:00
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Determine if the tag is a standalone tag based on whitespace
|
|
|
|
# before and after the tag.
|
2015-01-27 01:55:06 +00:00
|
|
|
#
|
|
|
|
# Passes back a string containing two numbers in the format "BEFORE AFTER"
|
|
|
|
# like "27 10". It indicates the number of bytes remaining in the "before"
|
|
|
|
# string (27) and the number of bytes to trim in the "after" string (10).
|
|
|
|
# Useful for string manipulation:
|
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# $1 - Variable to set for passing data back
|
|
|
|
# $2 - Content before the tag
|
|
|
|
# $3 - Content after the tag
|
|
|
|
# $4 - true/false: is this the beginning of the content?
|
2015-01-27 01:55:06 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# Examples
|
|
|
|
#
|
|
|
|
# moIsStandalone RESULT "$before" "$after" false || return 0
|
|
|
|
# RESULT_ARRAY=( $RESULT )
|
|
|
|
# echo "${before:0:${RESULT_ARRAY[0]}}...${after:${RESULT_ARRAY[1]}}"
|
|
|
|
#
|
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moIsStandalone() {
|
2015-10-02 15:47:53 +00:00
|
|
|
local afterTrimmed beforeTrimmed char
|
2015-01-27 01:55:06 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
moTrimChars beforeTrimmed "$2" false true " " $'\t'
|
|
|
|
moTrimChars afterTrimmed "$3" true false " " $'\t'
|
|
|
|
char=$((${#beforeTrimmed} - 1))
|
|
|
|
char=${beforeTrimmed:$char}
|
2015-01-27 01:55:06 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
if [[ "$char" != $'\n' ]] && [[ "$char" != $'\r' ]]; then
|
|
|
|
if [[ ! -z "$char" ]] || ! $4; then
|
2015-08-21 16:56:52 +00:00
|
|
|
return 1
|
2015-01-27 01:55:06 +00:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
char=${afterTrimmed:0:1}
|
2015-01-27 01:55:06 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
if [[ "$char" != $'\n' ]] && [[ "$char" != $'\r' ]] && [[ ! -z "$char" ]]; then
|
2015-08-21 16:56:52 +00:00
|
|
|
return 2
|
2015-01-27 01:55:06 +00:00
|
|
|
fi
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
if [[ "$char" == $'\r' ]] && [[ "${afterTrimmed:1:1}" == $'\n' ]]; then
|
|
|
|
char="$char"$'\n'
|
2015-01-27 01:55:06 +00:00
|
|
|
fi
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
local "$1" && moIndirect "$1" "$((${#beforeTrimmed})) $((${#3} + ${#char} - ${#afterTrimmed}))"
|
2015-01-27 01:55:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Join / implode an array
|
2015-05-05 15:46:06 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# $1 - Variable name to receive the joined content
|
|
|
|
# $2 - Joiner
|
|
|
|
# $3-$* - Elements to join
|
|
|
|
#
|
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moJoin() {
|
2015-10-02 15:47:53 +00:00
|
|
|
local joiner part result target
|
2015-05-05 15:46:06 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
target=$1
|
|
|
|
joiner=$2
|
|
|
|
result=$3
|
2015-05-05 15:46:06 +00:00
|
|
|
shift 3
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
for part in "$@"; do
|
|
|
|
result="$result$joiner$part"
|
2015-05-05 15:46:06 +00:00
|
|
|
done
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
local "$target" && moIndirect "$target" "$result"
|
2015-05-05 15:46:06 +00:00
|
|
|
}
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Read a file into a variable.
|
|
|
|
#
|
|
|
|
# $1 - Variable name to receive the file's content
|
|
|
|
# $2 - Filename to load
|
2015-01-27 01:55:06 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moLoadFile() {
|
2015-10-02 15:47:53 +00:00
|
|
|
local content len
|
2015-01-27 01:55:06 +00:00
|
|
|
|
|
|
|
# The subshell removes any trailing newlines. We forcibly add
|
|
|
|
# a dot to the content to preserve all newlines.
|
|
|
|
# TODO: remove cat and replace with read loop?
|
2015-10-02 14:46:57 +00:00
|
|
|
|
2016-07-21 14:45:31 +00:00
|
|
|
content=$(cat -- $2; echo '.')
|
2015-10-02 15:47:53 +00:00
|
|
|
len=$((${#content} - 1))
|
|
|
|
content=${content:0:$len} # Remove last dot
|
2015-01-27 01:55:06 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
local "$1" && moIndirect "$1" "$content"
|
2015-01-27 01:55:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Process a chunk of content some number of times. Writes output
|
|
|
|
# to stdout.
|
|
|
|
#
|
|
|
|
# $1 - Content to parse repeatedly
|
|
|
|
# $2 - Tag prefix (context name)
|
2015-10-07 20:23:50 +00:00
|
|
|
# $3-@ - Names to insert into the parsed content
|
2015-01-27 01:55:06 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moLoop() {
|
2015-10-02 15:47:53 +00:00
|
|
|
local content context contextBase
|
2015-01-27 01:55:06 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
content=$1
|
|
|
|
contextBase=$2
|
2015-01-27 01:55:06 +00:00
|
|
|
shift 2
|
|
|
|
|
|
|
|
while [[ "${#@}" -gt 0 ]]; do
|
2015-10-02 15:47:53 +00:00
|
|
|
moFullTagName context "$contextBase" "$1"
|
|
|
|
moParse "$content" "$context" false
|
2015-01-27 01:55:06 +00:00
|
|
|
shift
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Parse a block of text, writing the result to stdout.
|
|
|
|
#
|
|
|
|
# $1 - Block of text to change
|
|
|
|
# $2 - Current name (the variable NAME for what {{.}} means)
|
|
|
|
# $3 - true when no content before this, false otherwise
|
2015-01-23 17:43:08 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moParse() {
|
2015-10-02 15:47:53 +00:00
|
|
|
# Keep naming variables mo* here to not overwrite needed variables
|
2015-01-23 17:43:08 +00:00
|
|
|
# used in the string replacements
|
2015-10-02 15:47:53 +00:00
|
|
|
local moBlock moContent moCurrent moIsBeginning moTag
|
2015-01-23 17:43:08 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
moCurrent=$2
|
|
|
|
moIsBeginning=$3
|
2015-01-23 17:43:08 +00:00
|
|
|
|
|
|
|
# Find open tags
|
2015-10-02 15:47:53 +00:00
|
|
|
moSplit moContent "$1" '{{' '}}'
|
2015-01-23 17:43:08 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
while [[ "${#moContent[@]}" -gt 1 ]]; do
|
|
|
|
moTrimWhitespace moTag "${moContent[1]}"
|
2015-01-23 17:43:08 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
case $moTag in
|
2015-01-23 17:43:08 +00:00
|
|
|
'#'*)
|
|
|
|
# Loop, if/then, or pass content through function
|
|
|
|
# Sets context
|
2015-10-02 15:47:53 +00:00
|
|
|
moStandaloneAllowed moContent "${moContent[@]}" $moIsBeginning
|
|
|
|
moTrimWhitespace moTag "${moTag:1}"
|
|
|
|
moFindEndTag moBlock "$moContent" "$moTag"
|
|
|
|
moFullTagName moTag "$moCurrent" "$moTag"
|
2015-01-23 17:43:08 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
if moTest "$moTag"; then
|
2015-01-23 17:43:08 +00:00
|
|
|
# Show / loop / pass through function
|
2015-10-02 15:47:53 +00:00
|
|
|
if moIsFunction "$moTag"; then
|
2015-10-02 14:46:57 +00:00
|
|
|
#: TODO: Consider piping the output to moGetContent
|
|
|
|
#: so the lambda does not execute in a subshell?
|
2015-10-02 15:47:53 +00:00
|
|
|
moContent=$($moTag "${moBlock[0]}")
|
|
|
|
moParse "$moContent" "$moCurrent" false
|
|
|
|
moContent="${moBlock[2]}"
|
|
|
|
elif moIsArray "$moTag"; then
|
|
|
|
eval 'moLoop "${moBlock[0]}" "$moTag" "${!'"$moTag"'[@]}"'
|
2015-01-23 17:43:08 +00:00
|
|
|
else
|
2015-10-02 15:47:53 +00:00
|
|
|
moParse "${moBlock[0]}" "$moCurrent" false
|
2015-01-23 17:43:08 +00:00
|
|
|
fi
|
|
|
|
fi
|
2015-01-26 18:51:28 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
moContent="${moBlock[2]}"
|
2015-01-23 17:43:08 +00:00
|
|
|
;;
|
|
|
|
|
|
|
|
'>'*)
|
|
|
|
# Load partial - get name of file relative to cwd
|
2015-10-02 15:47:53 +00:00
|
|
|
moPartial moContent "${moContent[@]}" $moIsBeginning "$moCurrent"
|
2015-01-23 17:43:08 +00:00
|
|
|
;;
|
|
|
|
|
|
|
|
'/'*)
|
2015-01-26 18:51:28 +00:00
|
|
|
# Closing tag - If hit in this loop, we simply ignore
|
2015-10-02 14:06:16 +00:00
|
|
|
# Matching tags are found in moFindEndTag
|
2015-10-02 15:47:53 +00:00
|
|
|
moStandaloneAllowed moContent "${moContent[@]}" $moIsBeginning
|
2015-01-23 17:43:08 +00:00
|
|
|
;;
|
|
|
|
|
|
|
|
'^'*)
|
|
|
|
# Display section if named thing does not exist
|
2015-10-02 15:47:53 +00:00
|
|
|
moStandaloneAllowed moContent "${moContent[@]}" $moIsBeginning
|
|
|
|
moTrimWhitespace moTag "${moTag:1}"
|
|
|
|
moFindEndTag moBlock "$moContent" "$moTag"
|
|
|
|
moFullTagName moTag "$moCurrent" "$moTag"
|
2015-01-23 17:43:08 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
if ! moTest "$moTag"; then
|
|
|
|
moParse "${moBlock[0]}" "$moCurrent" false "$moCurrent"
|
2015-01-23 17:43:08 +00:00
|
|
|
fi
|
2015-01-26 18:51:28 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
moContent="${moBlock[2]}"
|
2015-01-23 17:43:08 +00:00
|
|
|
;;
|
|
|
|
|
|
|
|
'!'*)
|
2015-01-26 03:31:21 +00:00
|
|
|
# Comment - ignore the tag content entirely
|
|
|
|
# Trim spaces/tabs before the comment
|
2015-10-02 15:47:53 +00:00
|
|
|
moStandaloneAllowed moContent "${moContent[@]}" $moIsBeginning
|
2015-01-23 17:43:08 +00:00
|
|
|
;;
|
|
|
|
|
|
|
|
.)
|
|
|
|
# Current content (environment variable or function)
|
2015-10-02 15:47:53 +00:00
|
|
|
moStandaloneDenied moContent "${moContent[@]}"
|
|
|
|
moShow "$moCurrent" "$moCurrent"
|
2015-01-23 17:43:08 +00:00
|
|
|
;;
|
|
|
|
|
2015-01-26 03:31:21 +00:00
|
|
|
'=')
|
|
|
|
# Change delimiters
|
|
|
|
# Any two non-whitespace sequences separated by whitespace.
|
|
|
|
# TODO
|
2015-10-02 15:47:53 +00:00
|
|
|
moStandaloneAllowed moContent "${moContent[@]}" $moIsBeginning
|
2015-01-26 03:31:21 +00:00
|
|
|
;;
|
|
|
|
|
2015-01-23 17:43:08 +00:00
|
|
|
'{'*)
|
|
|
|
# Unescaped - split on }}} not }}
|
2015-10-02 15:47:53 +00:00
|
|
|
moStandaloneDenied moContent "${moContent[@]}"
|
|
|
|
moContent="${moTag:1}"'}}'"$moContent"
|
|
|
|
moSplit moContent "$moContent" '}}}'
|
|
|
|
moTrimWhitespace moTag "${moContent[0]}"
|
|
|
|
moFullTagName moTag "$moCurrent" "$moTag"
|
|
|
|
moContent=${moContent[1]}
|
2015-01-23 17:43:08 +00:00
|
|
|
|
|
|
|
# Now show the value
|
2015-10-02 15:47:53 +00:00
|
|
|
moShow "$moTag" "$moCurrent"
|
2015-01-23 17:43:08 +00:00
|
|
|
;;
|
|
|
|
|
2015-01-23 20:26:56 +00:00
|
|
|
'&'*)
|
|
|
|
# Unescaped
|
2015-10-02 15:47:53 +00:00
|
|
|
moStandaloneDenied moContent "${moContent[@]}"
|
|
|
|
moTrimWhitespace moTag "${moTag:1}"
|
|
|
|
moFullTagName moTag "$moCurrent" "$moTag"
|
|
|
|
moShow "$moTag" "$moCurrent"
|
2015-01-23 20:26:56 +00:00
|
|
|
;;
|
|
|
|
|
2015-01-23 17:43:08 +00:00
|
|
|
*)
|
|
|
|
# Normal environment variable or function call
|
2015-10-02 15:47:53 +00:00
|
|
|
moStandaloneDenied moContent "${moContent[@]}"
|
|
|
|
moFullTagName moTag "$moCurrent" "$moTag"
|
|
|
|
moShow "$moTag" "$moCurrent"
|
2015-01-23 17:43:08 +00:00
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
moIsBeginning=false
|
|
|
|
moSplit moContent "$moContent" '{{' '}}'
|
2015-01-23 17:43:08 +00:00
|
|
|
done
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
echo -n "${moContent[0]}"
|
2015-01-23 17:43:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Process a partial.
|
2015-01-26 21:09:27 +00:00
|
|
|
#
|
|
|
|
# Indentation should be applied to the entire partial
|
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# Prefix all variables.
|
2015-01-26 21:09:27 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# $1 - Name of destination "content" variable.
|
|
|
|
# $2 - Content before the tag that was not yet written
|
|
|
|
# $3 - Tag content
|
|
|
|
# $4 - Content after the tag
|
|
|
|
# $5 - true/false: is this the beginning of the content?
|
|
|
|
# $6 - Current context name
|
|
|
|
#
|
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moPartial() {
|
2015-10-02 15:47:53 +00:00
|
|
|
# Namespace variables here to prevent conflicts.
|
|
|
|
local moContent moFilename moIndent moPartial moStandalone
|
|
|
|
|
|
|
|
if moIsStandalone moStandalone "$2" "$4" $5; then
|
|
|
|
moStandalone=( $moStandalone )
|
|
|
|
echo -n "${2:0:${moStandalone[0]}}"
|
|
|
|
moIndent=${2:${moStandalone[0]}}
|
|
|
|
moContent=${4:${moStandalone[1]}}
|
2015-01-26 21:09:27 +00:00
|
|
|
else
|
2015-10-02 15:47:53 +00:00
|
|
|
moIndent=""
|
2015-01-26 21:09:27 +00:00
|
|
|
echo -n "$2"
|
2015-10-02 15:47:53 +00:00
|
|
|
moContent=$4
|
2015-01-26 21:09:27 +00:00
|
|
|
fi
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
moTrimWhitespace moFilename "${3:1}"
|
2015-01-26 21:09:27 +00:00
|
|
|
|
|
|
|
# Execute in subshell to preserve current cwd and environment
|
|
|
|
(
|
|
|
|
# TODO: Remove dirname and use a function instead
|
2016-07-21 14:45:31 +00:00
|
|
|
cd "$(dirname -- "$moFilename")"
|
2015-10-02 15:47:53 +00:00
|
|
|
moIndentLines moPartial "$moIndent" "$(
|
|
|
|
moLoadFile moPartial "${moFilename##*/}"
|
2015-01-26 21:09:27 +00:00
|
|
|
|
|
|
|
# Fix bash handling of subshells
|
2015-10-02 14:06:16 +00:00
|
|
|
# The extra dot is removed in moIndentLines
|
2015-10-02 15:47:53 +00:00
|
|
|
echo -n "${moPartial}."
|
2015-01-26 21:09:27 +00:00
|
|
|
)"
|
2015-10-02 15:47:53 +00:00
|
|
|
moParse "$moPartial" "$6" true
|
2015-01-26 21:09:27 +00:00
|
|
|
)
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
local "$1" && moIndirect "$1" "$moContent"
|
2015-01-26 21:09:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Show an environment variable or the output of a function to
|
|
|
|
# stdout.
|
|
|
|
#
|
|
|
|
# Limit/prefix any variables used.
|
2015-01-27 01:55:06 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# $1 - Name of environment variable or function
|
|
|
|
# $2 - Current context
|
2015-01-26 21:09:27 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moShow() {
|
2015-10-02 15:47:53 +00:00
|
|
|
# Namespace these variables
|
|
|
|
local moJoined moNameParts
|
2015-01-27 00:23:28 +00:00
|
|
|
|
2015-10-02 14:06:16 +00:00
|
|
|
if moIsFunction "$1"; then
|
2015-01-27 01:55:06 +00:00
|
|
|
CONTENT=$($1 "")
|
2015-10-02 14:06:16 +00:00
|
|
|
moParse "$CONTENT" "$2" false
|
2015-01-27 00:23:28 +00:00
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
moSplit moNameParts "$1" "."
|
2015-05-05 15:46:06 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
if [[ -z "${moNameParts[1]}" ]]; then
|
2015-10-02 14:06:16 +00:00
|
|
|
if moIsArray "$1"; then
|
2015-10-02 15:47:53 +00:00
|
|
|
eval moJoin moJoined "," "\${$1[@]}"
|
|
|
|
echo -n "$moJoined"
|
2015-05-05 15:46:06 +00:00
|
|
|
else
|
|
|
|
echo -n "${!1}"
|
|
|
|
fi
|
2015-01-27 01:55:06 +00:00
|
|
|
else
|
|
|
|
# Further subindexes are disallowed
|
2015-10-02 15:47:53 +00:00
|
|
|
eval 'echo -n "${'"${moNameParts[0]}"'['"${moNameParts[1]%%.*}"']}"'
|
2015-01-27 01:55:06 +00:00
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2015-01-26 21:09:27 +00:00
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Split a larger string into an array.
|
|
|
|
#
|
|
|
|
# $1 - Destination variable
|
|
|
|
# $2 - String to split
|
|
|
|
# $3 - Starting delimiter
|
|
|
|
# $4 - Ending delimiter (optional)
|
2015-01-27 01:55:06 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moSplit() {
|
2015-10-02 15:47:53 +00:00
|
|
|
local pos result
|
2015-01-26 21:09:27 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
result=( "$2" )
|
|
|
|
moFindString pos "${result[0]}" "$3"
|
2015-01-26 21:09:27 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
if [[ "$pos" -ne -1 ]]; then
|
2015-01-27 01:55:06 +00:00
|
|
|
# The first delimiter was found
|
2015-10-02 15:47:53 +00:00
|
|
|
result[1]=${result[0]:$pos + ${#3}}
|
|
|
|
result[0]=${result[0]:0:$pos}
|
2015-01-26 21:09:27 +00:00
|
|
|
|
2015-01-27 01:55:06 +00:00
|
|
|
if [[ ! -z "$4" ]]; then
|
2015-10-02 15:47:53 +00:00
|
|
|
moFindString pos "${result[1]}" "$4"
|
2015-01-26 21:09:27 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
if [[ "$pos" -ne -1 ]]; then
|
2015-01-27 01:55:06 +00:00
|
|
|
# The second delimiter was found
|
2015-10-02 15:47:53 +00:00
|
|
|
result[2]="${result[1]:$pos + ${#4}}"
|
|
|
|
result[1]="${result[1]:0:$pos}"
|
2015-01-27 01:55:06 +00:00
|
|
|
fi
|
|
|
|
fi
|
2015-01-26 21:09:27 +00:00
|
|
|
fi
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
local "$1" && moIndirectArray "$1" "${result[@]}"
|
2015-01-26 21:09:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Handle the content for a standalone tag. This means removing
|
|
|
|
# whitespace (not newlines) before a tag and whitespace and a newline after
|
|
|
|
# a tag. That is, assuming, that the line is otherwise empty.
|
2015-01-26 03:31:21 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# $1 - Name of destination "content" variable.
|
|
|
|
# $2 - Content before the tag that was not yet written
|
|
|
|
# $3 - Tag content (not used)
|
|
|
|
# $4 - Content after the tag
|
|
|
|
# $5 - true/false: is this the beginning of the content?
|
|
|
|
#
|
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moStandaloneAllowed() {
|
2015-10-02 15:47:53 +00:00
|
|
|
local bytes
|
2015-01-26 03:31:21 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
if moIsStandalone bytes "$2" "$4" $5; then
|
|
|
|
bytes=( $bytes )
|
|
|
|
echo -n "${2:0:${bytes[0]}}"
|
|
|
|
local "$1" && moIndirect "$1" "${4:${bytes[1]}}"
|
2015-01-26 03:31:21 +00:00
|
|
|
else
|
|
|
|
echo -n "$2"
|
2015-10-02 14:06:16 +00:00
|
|
|
local "$1" && moIndirect "$1" "$4"
|
2015-01-26 03:31:21 +00:00
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Handle the content for a tag that is never "standalone". No
|
|
|
|
# adjustments are made for newlines and whitespace.
|
|
|
|
#
|
|
|
|
# $1 - Name of destination "content" variable.
|
|
|
|
# $2 - Content before the tag that was not yet written
|
|
|
|
# $3 - Tag content (not used)
|
|
|
|
# $4 - Content after the tag
|
2015-01-26 03:31:21 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moStandaloneDenied() {
|
2015-01-26 03:31:21 +00:00
|
|
|
echo -n "$2"
|
2015-10-02 14:06:16 +00:00
|
|
|
local "$1" && moIndirect "$1" "$4"
|
2015-01-26 03:31:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Determines if the named thing is a function or if it is a
|
|
|
|
# non-empty environment variable.
|
2015-01-23 17:43:08 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# Do not use variables without prefixes here if possible as this needs to
|
|
|
|
# check if any name exists in the environment
|
2015-01-23 17:43:08 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# $1 - Name of environment variable or function
|
|
|
|
# $2 - Current value (our context)
|
2015-01-23 17:43:08 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# Returns 0 if the name is not empty, 1 otherwise.
|
2015-10-02 14:06:16 +00:00
|
|
|
moTest() {
|
2015-01-23 17:43:08 +00:00
|
|
|
# Test for functions
|
2015-10-02 14:06:16 +00:00
|
|
|
moIsFunction "$1" && return 0
|
2015-01-23 17:43:08 +00:00
|
|
|
|
2015-10-02 14:06:16 +00:00
|
|
|
if moIsArray "$1"; then
|
2015-01-23 17:43:08 +00:00
|
|
|
# Arrays must have at least 1 element
|
2015-05-05 15:46:06 +00:00
|
|
|
eval '[[ "${#'"$1"'[@]}" -gt 0 ]]' && return 0
|
2015-01-23 17:43:08 +00:00
|
|
|
else
|
|
|
|
# Environment variables must not be empty
|
|
|
|
[[ ! -z "${!1}" ]] && return 0
|
|
|
|
fi
|
|
|
|
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Trim the leading whitespace only.
|
|
|
|
#
|
|
|
|
# $1 - Name of destination variable
|
|
|
|
# $2 - The string
|
|
|
|
# $3 - true/false - trim front?
|
|
|
|
# $4 - true/false - trim end?
|
2015-10-07 20:23:50 +00:00
|
|
|
# $5-@ - Characters to trim
|
2015-01-23 17:43:08 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moTrimChars() {
|
2015-10-02 15:47:53 +00:00
|
|
|
local back current front last target varName
|
2015-01-23 17:43:08 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
target=$1
|
|
|
|
current=$2
|
|
|
|
front=$3
|
|
|
|
back=$4
|
|
|
|
last=""
|
2015-10-02 14:46:57 +00:00
|
|
|
shift 4 # Remove target, string, trim front flag, trim end flag
|
2015-01-23 17:43:08 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
while [[ "$current" != "$last" ]]; do
|
|
|
|
last=$current
|
2015-01-23 17:43:08 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
for varName in "$@"; do
|
|
|
|
$front && current="${current/#$varName}"
|
|
|
|
$back && current="${current/%$varName}"
|
2015-01-23 17:43:08 +00:00
|
|
|
done
|
|
|
|
done
|
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
local "$target" && moIndirect "$target" "$current"
|
2015-01-26 03:31:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Trim leading and trailing whitespace from a string.
|
2015-01-26 03:31:21 +00:00
|
|
|
#
|
2015-10-02 14:46:57 +00:00
|
|
|
# $1 - Name of variable to store trimmed string
|
|
|
|
# $2 - The string
|
|
|
|
#
|
|
|
|
# Returns nothing.
|
2015-10-02 14:06:16 +00:00
|
|
|
moTrimWhitespace() {
|
2015-10-02 15:47:53 +00:00
|
|
|
local result
|
2015-01-26 03:31:21 +00:00
|
|
|
|
2015-10-02 15:47:53 +00:00
|
|
|
moTrimChars result "$2" true true $'\r' $'\n' $'\t' " "
|
|
|
|
local "$1" && moIndirect "$1" "$result"
|
2015-01-23 17:43:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# Internal: Displays the usage for mo. Pulls this from the file that
|
|
|
|
# contained the `mo` function. Can only work when the right filename
|
|
|
|
# comes is the one argument, and that only happens when `mo` is called
|
|
|
|
# with `$0` set to this file.
|
2015-10-02 14:06:16 +00:00
|
|
|
#
|
|
|
|
# $1 - Filename that has the help message
|
|
|
|
#
|
|
|
|
# Returns nothing.
|
|
|
|
moUsage() {
|
2015-12-21 15:03:10 +00:00
|
|
|
grep '^#/' "$1" | cut -c 4-
|
2015-10-02 14:06:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-02 14:46:57 +00:00
|
|
|
# If sourced, load all functions.
|
|
|
|
# If executed, perform the actions as expected.
|
2015-08-21 16:56:52 +00:00
|
|
|
if [[ "$0" == "$BASH_SOURCE" ]] || ! [[ -n "$BASH_SOURCE" ]]; then
|
|
|
|
mo "$@"
|
|
|
|
fi
|