Fix shellcheck warnings. Use single quotes for printf format strings. Switch to strncpy in concat3. Use multiline strings to print C functions. Switch from if/elif to case.

This commit is contained in:
Tobias Bergkvist 2021-10-01 17:43:23 +02:00
parent b58c857bfb
commit b62216a211

View File

@ -26,132 +26,146 @@ makeBinaryWrapper() {
# makeDocumentedCWrapper EXECUTABLE ARGS # makeDocumentedCWrapper EXECUTABLE ARGS
# ARGS: same as makeBinaryWrapper # ARGS: same as makeBinaryWrapper
makeDocumentedCWrapper() { makeDocumentedCWrapper() {
local src=$(makeCWrapper "$@") local src docs
local docs=$(documentationString "$src") src=$(makeCWrapper "$@")
printf "%s\n" "$src" docs=$(documentationString "$src")
printf "\n%s\n" "$docs" printf '%s\n\n' "$src"
printf '%s\n' "$docs"
} }
# makeCWrapper EXECUTABLE ARGS # makeCWrapper EXECUTABLE ARGS
# ARGS: same as makeBinaryWrapper # ARGS: same as makeBinaryWrapper
makeCWrapper() { makeCWrapper() {
local argv0 n params cmd main flagsBefore flags local argv0 n params cmd main flagsBefore flags executable params
local uses_prefix uses_suffix uses_concat3 executable=$(escapeStringLiteral "$1")
local executable=$(escapeStringLiteral "$1") params=("$@")
local params=("$@")
for ((n = 1; n < ${#params[*]}; n += 1)); do for ((n = 1; n < ${#params[*]}; n += 1)); do
p="${params[$n]}" p="${params[n]}"
if [[ "$p" == "--set" ]]; then case $p in
cmd=$(setEnv "${params[$((n + 1))]}" "${params[$((n + 2))]}") --set)
cmd=$(setEnv "${params[n + 1]}" "${params[n + 2]}")
main="$main $cmd"$'\n' main="$main $cmd"$'\n'
n=$((n + 2)) n=$((n + 2))
elif [[ "$p" == "--set-default" ]]; then ;;
cmd=$(setDefaultEnv "${params[$((n + 1))]}" "${params[$((n + 2))]}") --set-default)
cmd=$(setDefaultEnv "${params[n + 1]}" "${params[n + 2]}")
main="$main $cmd"$'\n' main="$main $cmd"$'\n'
n=$((n + 2)) n=$((n + 2))
elif [[ "$p" == "--unset" ]]; then ;;
cmd=$(unsetEnv "${params[$((n + 1))]}") --unset)
cmd=$(unsetEnv "${params[n + 1]}")
main="$main $cmd"$'\n' main="$main $cmd"$'\n'
n=$((n + 1)) n=$((n + 1))
elif [[ "$p" == "--prefix" ]]; then ;;
cmd=$(setEnvPrefix "${params[$((n + 1))]}" "${params[$((n + 2))]}" "${params[$((n + 3))]}") --prefix)
cmd=$(setEnvPrefix "${params[n + 1]}" "${params[n + 2]}" "${params[n + 3]}")
main="$main $cmd"$'\n' main="$main $cmd"$'\n'
uses_prefix=1 uses_prefix=1
uses_concat3=1 uses_concat3=1
n=$((n + 3)) n=$((n + 3))
elif [[ "$p" == "--suffix" ]]; then ;;
cmd=$(setEnvSuffix "${params[$((n + 1))]}" "${params[$((n + 2))]}" "${params[$((n + 3))]}") --suffix)
cmd=$(setEnvSuffix "${params[n + 1]}" "${params[n + 2]}" "${params[n + 3]}")
main="$main $cmd"$'\n' main="$main $cmd"$'\n'
uses_suffix=1 uses_suffix=1
uses_concat3=1 uses_concat3=1
n=$((n + 3)) n=$((n + 3))
elif [[ "$p" == "--add-flags" ]]; then ;;
flags="${params[$((n + 1))]}" --add-flags)
flags="${params[n + 1]}"
flagsBefore="$flagsBefore $flags" flagsBefore="$flagsBefore $flags"
n=$((n + 1)) n=$((n + 1))
elif [[ "$p" == "--argv0" ]]; then ;;
argv0=$(escapeStringLiteral "${params[$((n + 1))]}") --argv0)
argv0=$(escapeStringLiteral "${params[n + 1]}")
n=$((n + 1)) n=$((n + 1))
else ;;
# Using an error macro, we will make sure the compiler gives an understandable error message *) # Using an error macro, we will make sure the compiler gives an understandable error message
printf "%s\n" " #error makeCWrapper did not understand argument ${p}" printf '%s\n' " #error makeCWrapper did not understand argument ${p}"
fi ;;
esac
done done
# shellcheck disable=SC2086
[ -z "$flagsBefore" ] || main="$main"${main:+$'\n'}$(addFlags $flagsBefore)$'\n'$'\n' [ -z "$flagsBefore" ] || main="$main"${main:+$'\n'}$(addFlags $flagsBefore)$'\n'$'\n'
main="$main argv[0] = \"${argv0:-${executable}}\";"$'\n' main="$main argv[0] = \"${argv0:-${executable}}\";"$'\n'
main="$main return execv(\"${executable}\", argv);"$'\n' main="$main return execv(\"${executable}\", argv);"$'\n'
printf "%s\n" "#include <unistd.h>" printf '%s\n' "#include <unistd.h>"
printf "%s\n" "#include <stdlib.h>" printf '%s\n' "#include <stdlib.h>"
[ -z "$uses_concat3" ] || printf "%s\n" "#include <string.h>" [ -z "$uses_concat3" ] || printf '%s\n' "#include <string.h>"
[ -z "$uses_concat3" ] || printf "\n%s\n" "$(concat3Fn)" [ -z "$uses_concat3" ] || printf '\n%s\n' "$(concat3Fn)"
[ -z "$uses_prefix" ] || printf "\n%s\n" "$(setEnvPrefixFn)" [ -z "$uses_prefix" ] || printf '\n%s\n' "$(setEnvPrefixFn)"
[ -z "$uses_suffix" ] || printf "\n%s\n" "$(setEnvSuffixFn)" [ -z "$uses_suffix" ] || printf '\n%s\n' "$(setEnvSuffixFn)"
printf "\n%s" "int main(int argc, char **argv) {" printf '\n%s' "int main(int argc, char **argv) {"
printf "\n%s" "$main" printf '\n%s' "$main"
printf "%s\n" "}" printf '%s\n' "}"
} }
addFlags() { addFlags() {
local result n flag flags local result n flag flags var
local var="argv_tmp" var="argv_tmp"
flags=("$@") flags=("$@")
for ((n = 0; n < ${#flags[*]}; n += 1)); do for ((n = 0; n < ${#flags[*]}; n += 1)); do
flag=$(escapeStringLiteral "${flags[$n]}") flag=$(escapeStringLiteral "${flags[$n]}")
result="$result $var[$((n+1))] = \"$flag\";"$'\n' result="$result ${var}[$((n+1))] = \"$flag\";"$'\n'
done done
printf " %s\n" "char **$var = malloc(sizeof(*$var) * ($((n+1)) + argc));" printf ' %s\n' "char **$var = malloc(sizeof(*$var) * ($((n+1)) + argc));"
printf " %s\n" "$var[0] = argv[0];" printf ' %s\n' "${var}[0] = argv[0];"
printf "%s" "$result" printf '%s' "$result"
printf " %s\n" "for (int i = 1; i < argc; ++i) {" printf ' %s\n' "for (int i = 1; i < argc; ++i) {"
printf " %s\n" " $var[$n + i] = argv[i];" printf ' %s\n' " ${var}[$n + i] = argv[i];"
printf " %s\n" "}" printf ' %s\n' "}"
printf " %s\n" "$var[$n + argc] = NULL;" printf ' %s\n' "${var}[$n + argc] = NULL;"
printf " %s\n" "argv = $var;" printf ' %s\n' "argv = $var;"
} }
# prefix ENV SEP VAL # prefix ENV SEP VAL
setEnvPrefix() { setEnvPrefix() {
local env=$(escapeStringLiteral "$1") local env sep val
local sep=$(escapeStringLiteral "$2") env=$(escapeStringLiteral "$1")
local val=$(escapeStringLiteral "$3") sep=$(escapeStringLiteral "$2")
printf "%s" "set_env_prefix(\"$env\", \"$sep\", \"$val\");" val=$(escapeStringLiteral "$3")
printf '%s' "set_env_prefix(\"$env\", \"$sep\", \"$val\");"
} }
# suffix ENV SEP VAL # suffix ENV SEP VAL
setEnvSuffix() { setEnvSuffix() {
local env=$(escapeStringLiteral "$1") local env sep val
local sep=$(escapeStringLiteral "$2") env=$(escapeStringLiteral "$1")
local val=$(escapeStringLiteral "$3") sep=$(escapeStringLiteral "$2")
printf "%s" "set_env_suffix(\"$env\", \"$sep\", \"$val\");" val=$(escapeStringLiteral "$3")
printf '%s' "set_env_suffix(\"$env\", \"$sep\", \"$val\");"
} }
# setEnv KEY VALUE # setEnv KEY VALUE
setEnv() { setEnv() {
local key=$(escapeStringLiteral "$1") local key value
local value=$(escapeStringLiteral "$2") key=$(escapeStringLiteral "$1")
printf "%s" "putenv(\"$key=$value\");" value=$(escapeStringLiteral "$2")
printf '%s' "putenv(\"$key=$value\");"
} }
# setDefaultEnv KEY VALUE # setDefaultEnv KEY VALUE
setDefaultEnv() { setDefaultEnv() {
local key=$(escapeStringLiteral "$1") local key value
local value=$(escapeStringLiteral "$2") key=$(escapeStringLiteral "$1")
printf "%s" "setenv(\"$key\", \"$value\", 0);" value=$(escapeStringLiteral "$2")
printf '%s' "setenv(\"$key\", \"$value\", 0);"
} }
# unsetEnv KEY # unsetEnv KEY
unsetEnv() { unsetEnv() {
local key=$(escapeStringLiteral "$1") local key
printf "%s" "unsetenv(\"$key\");" key=$(escapeStringLiteral "$1")
printf '%s' "unsetenv(\"$key\");"
} }
# Put the entire source code into const char* SOURCE_CODE to make it readable after compilation. # Put the entire source code into const char* SOURCE_CODE to make it readable after compilation.
# documentationString SOURCE_CODE # documentationString SOURCE_CODE
documentationString() { documentationString() {
local docs=$(escapeStringLiteral $'\n----------\n// This binary wrapper was compiled from the following generated C-code:\n'"$1"$'\n----------\n') local docs
printf "%s" "const char * SOURCE_CODE = \"$docs\";" docs=$(escapeStringLiteral $'\n----------\n// This binary wrapper was compiled from the following generated C-code:\n'"$1"$'\n----------\n')
printf '%s' "const char * SOURCE_CODE = \"$docs\";"
} }
# Makes it safe to insert STRING within quotes in a C String Literal. # Makes it safe to insert STRING within quotes in a C String Literal.
@ -162,37 +176,43 @@ escapeStringLiteral() {
result=${result//\"/'\"'} result=${result//\"/'\"'}
result=${result//$'\n'/"\n"} result=${result//$'\n'/"\n"}
result=${result//$'\r'/"\r"} result=${result//$'\r'/"\r"}
printf "%s" "$result" printf '%s' "$result"
} }
concat3Fn() { concat3Fn() {
printf "%s\n" 'char *concat3(char *x, char *y, char *z) {' printf '%s' "\
printf "%s\n" ' int xn = strlen(x);' char *concat3(char *x, char *y, char *z) {
printf "%s\n" ' int yn = strlen(y);' int xn = strlen(x);
printf "%s\n" ' int zn = strlen(z);' int yn = strlen(y);
printf "%s\n" ' char *res = malloc(sizeof(*res)*(xn + yn + zn + 1));' int zn = strlen(z);
printf "%s\n" ' for (int i = 0; i < xn; ++i) res[i] = x[i];' char *res = malloc(sizeof(*res)*(xn + yn + zn + 1));
printf "%s\n" ' for (int i = 0; i < yn; ++i) res[xn+i] = y[i];' strncpy(res, x, xn);
printf "%s\n" ' for (int i = 0; i < zn; ++i) res[xn+yn+i] = z[i];' strncpy(res + xn, y, yn);
printf "%s\n" " res[xn+yn+zn] = '\0';" strncpy(res + xn + yn, z, zn);
printf "%s\n" ' return res;' res[xn + yn + zn] = '\0';
printf "%s\n" '}' return res;
}
"
} }
setEnvPrefixFn() { setEnvPrefixFn() {
printf "%s\n" 'void set_env_prefix(char *env, char *sep, char *val) {' printf '%s' "\
printf "%s\n" ' char *existing = getenv(env);' void set_env_prefix(char *env, char *sep, char *val) {
printf "%s\n" ' if (existing) val = concat3(val, sep, existing);' char *existing = getenv(env);
printf "%s\n" ' setenv(env, val, 1);' if (existing) val = concat3(val, sep, existing);
printf "%s\n" ' if (existing) free(val);' setenv(env, val, 1);
printf "%s\n" '}' if (existing) free(val);
}
"
} }
setEnvSuffixFn() { setEnvSuffixFn() {
printf "%s\n" 'void set_env_suffix(char *env, char *sep, char *val) {' printf '%s' "\
printf "%s\n" ' char *existing = getenv(env);' void set_env_suffix(char *env, char *sep, char *val) {
printf "%s\n" ' if (existing) val = concat3(existing, sep, val);' char *existing = getenv(env);
printf "%s\n" ' setenv(env, val, 1);' if (existing) val = concat3(existing, sep, val);
printf "%s\n" ' if (existing) free(val);' setenv(env, val, 1);
printf "%s\n" '}' if (existing) free(val);
}
"
} }