2021-10-01 22:19:29 +00:00
|
|
|
|
# Assert that FILE exists and is executable
|
|
|
|
|
#
|
|
|
|
|
# assertExecutable FILE
|
|
|
|
|
assertExecutable() {
|
|
|
|
|
local file="$1"
|
|
|
|
|
[[ -f "$file" && -x "$file" ]] || \
|
|
|
|
|
die "Cannot wrap '$file' because it is not an executable file"
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-31 23:02:08 +00:00
|
|
|
|
# Generate a binary executable wrapper for wrapping an executable.
|
|
|
|
|
# The binary is compiled from generated C-code using gcc.
|
2021-12-09 11:31:35 +00:00
|
|
|
|
# makeWrapper EXECUTABLE OUT_PATH ARGS
|
2021-05-31 23:02:08 +00:00
|
|
|
|
|
|
|
|
|
# ARGS:
|
|
|
|
|
# --argv0 NAME : set name of executed process to NAME
|
2021-08-23 21:44:57 +00:00
|
|
|
|
# (otherwise it’s called …-wrapped)
|
2021-12-02 01:29:00 +00:00
|
|
|
|
# --inherit-argv0 : the executable inherits argv0 from the wrapper.
|
|
|
|
|
# (use instead of --argv0 '$0')
|
2021-05-31 23:02:08 +00:00
|
|
|
|
# --set VAR VAL : add VAR with value VAL to the executable’s
|
|
|
|
|
# environment
|
|
|
|
|
# --set-default VAR VAL : like --set, but only adds VAR if not already set in
|
|
|
|
|
# the environment
|
|
|
|
|
# --unset VAR : remove VAR from the environment
|
2021-12-02 02:39:25 +00:00
|
|
|
|
# --chdir DIR : change working directory (use instead of --run "cd DIR")
|
2021-08-23 21:44:57 +00:00
|
|
|
|
# --add-flags FLAGS : add FLAGS to invocation of executable
|
|
|
|
|
|
|
|
|
|
# --prefix ENV SEP VAL : suffix/prefix ENV with VAL, separated by SEP
|
|
|
|
|
# --suffix
|
|
|
|
|
|
2021-05-31 23:02:08 +00:00
|
|
|
|
# To troubleshoot a binary wrapper after you compiled it,
|
|
|
|
|
# use the `strings` command or open the binary file in a text editor.
|
2021-12-09 11:31:35 +00:00
|
|
|
|
makeWrapper() {
|
2021-10-19 12:37:05 +00:00
|
|
|
|
assertExecutable "$1"
|
2021-12-02 01:07:17 +00:00
|
|
|
|
makeDocumentedCWrapper "$1" "${@:3}" | cc -Os -x c -o "$2" -
|
2021-05-31 23:02:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-09 11:31:35 +00:00
|
|
|
|
# Syntax: wrapProgram <PROGRAM> <MAKE-WRAPPER FLAGS...>
|
|
|
|
|
wrapProgram() {
|
2021-10-01 22:20:25 +00:00
|
|
|
|
local prog="$1"
|
|
|
|
|
local hidden
|
|
|
|
|
|
|
|
|
|
assertExecutable "$prog"
|
|
|
|
|
|
|
|
|
|
hidden="$(dirname "$prog")/.$(basename "$prog")"-wrapped
|
|
|
|
|
while [ -e "$hidden" ]; do
|
|
|
|
|
hidden="${hidden}_"
|
|
|
|
|
done
|
|
|
|
|
mv "$prog" "$hidden"
|
|
|
|
|
# Silence warning about unexpanded $0:
|
|
|
|
|
# shellcheck disable=SC2016
|
2021-12-09 11:31:35 +00:00
|
|
|
|
makeWrapper "$hidden" "$prog" --inherit-argv0 "${@:2}"
|
2021-10-01 22:20:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-07 00:50:38 +00:00
|
|
|
|
# Generate source code for the wrapper in such a way that the wrapper inputs
|
2021-05-31 23:02:08 +00:00
|
|
|
|
# will still be readable even after compilation
|
|
|
|
|
# makeDocumentedCWrapper EXECUTABLE ARGS
|
2021-12-09 11:31:35 +00:00
|
|
|
|
# ARGS: same as makeWrapper
|
2021-05-31 23:02:08 +00:00
|
|
|
|
makeDocumentedCWrapper() {
|
2021-10-01 15:43:23 +00:00
|
|
|
|
local src docs
|
|
|
|
|
src=$(makeCWrapper "$@")
|
2021-12-07 00:50:38 +00:00
|
|
|
|
docs=$(docstring "$@")
|
2021-10-01 15:43:23 +00:00
|
|
|
|
printf '%s\n\n' "$src"
|
|
|
|
|
printf '%s\n' "$docs"
|
2021-05-31 23:02:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# makeCWrapper EXECUTABLE ARGS
|
2021-12-09 11:31:35 +00:00
|
|
|
|
# ARGS: same as makeWrapper
|
2021-05-31 23:02:08 +00:00
|
|
|
|
makeCWrapper() {
|
2021-12-07 00:50:38 +00:00
|
|
|
|
local argv0 inherit_argv0 n params cmd main flagsBefore flags executable length
|
2021-12-01 22:27:26 +00:00
|
|
|
|
local uses_prefix uses_suffix uses_assert uses_assert_success uses_stdio uses_asprintf
|
2021-10-01 15:43:23 +00:00
|
|
|
|
executable=$(escapeStringLiteral "$1")
|
|
|
|
|
params=("$@")
|
2021-10-01 16:51:09 +00:00
|
|
|
|
length=${#params[*]}
|
|
|
|
|
for ((n = 1; n < length; n += 1)); do
|
2021-10-01 15:43:23 +00:00
|
|
|
|
p="${params[n]}"
|
|
|
|
|
case $p in
|
|
|
|
|
--set)
|
|
|
|
|
cmd=$(setEnv "${params[n + 1]}" "${params[n + 2]}")
|
2021-12-07 16:42:54 +00:00
|
|
|
|
main="$main$cmd"$'\n'
|
2021-10-01 15:43:23 +00:00
|
|
|
|
n=$((n + 2))
|
2021-12-07 16:42:54 +00:00
|
|
|
|
[ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 2 arguments"$'\n'
|
2021-10-01 15:43:23 +00:00
|
|
|
|
;;
|
|
|
|
|
--set-default)
|
|
|
|
|
cmd=$(setDefaultEnv "${params[n + 1]}" "${params[n + 2]}")
|
2021-12-07 16:42:54 +00:00
|
|
|
|
main="$main$cmd"$'\n'
|
2021-12-01 22:27:26 +00:00
|
|
|
|
uses_stdio=1
|
2021-12-01 21:49:20 +00:00
|
|
|
|
uses_assert_success=1
|
2021-10-01 15:43:23 +00:00
|
|
|
|
n=$((n + 2))
|
2021-12-07 16:42:54 +00:00
|
|
|
|
[ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 2 arguments"$'\n'
|
2021-10-01 15:43:23 +00:00
|
|
|
|
;;
|
|
|
|
|
--unset)
|
|
|
|
|
cmd=$(unsetEnv "${params[n + 1]}")
|
2021-12-07 16:42:54 +00:00
|
|
|
|
main="$main$cmd"$'\n'
|
2021-12-01 22:27:26 +00:00
|
|
|
|
uses_stdio=1
|
2021-12-01 21:49:20 +00:00
|
|
|
|
uses_assert_success=1
|
2021-10-01 15:43:23 +00:00
|
|
|
|
n=$((n + 1))
|
2021-12-07 16:42:54 +00:00
|
|
|
|
[ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 1 argument"$'\n'
|
2021-10-01 15:43:23 +00:00
|
|
|
|
;;
|
|
|
|
|
--prefix)
|
|
|
|
|
cmd=$(setEnvPrefix "${params[n + 1]}" "${params[n + 2]}" "${params[n + 3]}")
|
2021-12-07 16:42:54 +00:00
|
|
|
|
main="$main$cmd"$'\n'
|
2021-10-01 15:43:23 +00:00
|
|
|
|
uses_prefix=1
|
2021-12-01 22:27:26 +00:00
|
|
|
|
uses_asprintf=1
|
|
|
|
|
uses_stdio=1
|
2021-12-01 21:49:20 +00:00
|
|
|
|
uses_assert_success=1
|
2021-11-09 01:55:26 +00:00
|
|
|
|
uses_assert=1
|
2021-10-01 15:43:23 +00:00
|
|
|
|
n=$((n + 3))
|
2021-12-07 16:42:54 +00:00
|
|
|
|
[ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 3 arguments"$'\n'
|
2021-10-01 15:43:23 +00:00
|
|
|
|
;;
|
|
|
|
|
--suffix)
|
|
|
|
|
cmd=$(setEnvSuffix "${params[n + 1]}" "${params[n + 2]}" "${params[n + 3]}")
|
2021-12-07 16:42:54 +00:00
|
|
|
|
main="$main$cmd"$'\n'
|
2021-10-01 15:43:23 +00:00
|
|
|
|
uses_suffix=1
|
2021-12-01 22:27:26 +00:00
|
|
|
|
uses_asprintf=1
|
|
|
|
|
uses_stdio=1
|
2021-12-01 21:49:20 +00:00
|
|
|
|
uses_assert_success=1
|
2021-11-09 01:55:26 +00:00
|
|
|
|
uses_assert=1
|
2021-10-01 15:43:23 +00:00
|
|
|
|
n=$((n + 3))
|
2021-12-07 16:42:54 +00:00
|
|
|
|
[ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 3 arguments"$'\n'
|
2021-10-01 15:43:23 +00:00
|
|
|
|
;;
|
2021-12-02 02:39:25 +00:00
|
|
|
|
--chdir)
|
|
|
|
|
cmd=$(changeDir "${params[n + 1]}")
|
2021-12-07 16:42:54 +00:00
|
|
|
|
main="$main$cmd"$'\n'
|
2021-12-02 02:39:25 +00:00
|
|
|
|
uses_stdio=1
|
|
|
|
|
uses_assert_success=1
|
|
|
|
|
n=$((n + 1))
|
2021-12-07 16:42:54 +00:00
|
|
|
|
[ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 1 argument"$'\n'
|
2021-12-02 02:39:25 +00:00
|
|
|
|
;;
|
2021-10-01 15:43:23 +00:00
|
|
|
|
--add-flags)
|
|
|
|
|
flags="${params[n + 1]}"
|
|
|
|
|
flagsBefore="$flagsBefore $flags"
|
2021-11-09 01:55:26 +00:00
|
|
|
|
uses_assert=1
|
2021-10-01 15:43:23 +00:00
|
|
|
|
n=$((n + 1))
|
2021-12-07 16:42:54 +00:00
|
|
|
|
[ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 1 argument"$'\n'
|
2021-10-01 15:43:23 +00:00
|
|
|
|
;;
|
|
|
|
|
--argv0)
|
|
|
|
|
argv0=$(escapeStringLiteral "${params[n + 1]}")
|
2021-12-02 01:29:00 +00:00
|
|
|
|
inherit_argv0=
|
2021-10-01 15:43:23 +00:00
|
|
|
|
n=$((n + 1))
|
2021-12-07 16:42:54 +00:00
|
|
|
|
[ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 1 argument"$'\n'
|
2021-10-01 15:43:23 +00:00
|
|
|
|
;;
|
2021-12-02 01:29:00 +00:00
|
|
|
|
--inherit-argv0)
|
|
|
|
|
# Whichever comes last of --argv0 and --inherit-argv0 wins
|
|
|
|
|
inherit_argv0=1
|
|
|
|
|
;;
|
2021-10-01 15:43:23 +00:00
|
|
|
|
*) # Using an error macro, we will make sure the compiler gives an understandable error message
|
2021-12-09 12:00:24 +00:00
|
|
|
|
main="$main#error makeCWrapper: Unknown argument ${p}"$'\n'
|
2021-10-01 15:43:23 +00:00
|
|
|
|
;;
|
|
|
|
|
esac
|
2021-05-31 23:02:08 +00:00
|
|
|
|
done
|
2021-10-01 15:43:23 +00:00
|
|
|
|
# shellcheck disable=SC2086
|
2021-08-26 12:36:30 +00:00
|
|
|
|
[ -z "$flagsBefore" ] || main="$main"${main:+$'\n'}$(addFlags $flagsBefore)$'\n'$'\n'
|
2021-12-07 16:42:54 +00:00
|
|
|
|
[ -z "$inherit_argv0" ] && main="${main}argv[0] = \"${argv0:-${executable}}\";"$'\n'
|
|
|
|
|
main="${main}return execv(\"${executable}\", argv);"$'\n'
|
2021-08-23 21:44:57 +00:00
|
|
|
|
|
2021-12-01 22:27:26 +00:00
|
|
|
|
[ -z "$uses_asprintf" ] || printf '%s\n' "#define _GNU_SOURCE /* See feature_test_macros(7) */"
|
2021-10-01 15:43:23 +00:00
|
|
|
|
printf '%s\n' "#include <unistd.h>"
|
|
|
|
|
printf '%s\n' "#include <stdlib.h>"
|
2021-12-01 22:27:26 +00:00
|
|
|
|
[ -z "$uses_assert" ] || printf '%s\n' "#include <assert.h>"
|
|
|
|
|
[ -z "$uses_stdio" ] || printf '%s\n' "#include <stdio.h>"
|
2021-12-01 21:56:18 +00:00
|
|
|
|
[ -z "$uses_assert_success" ] || printf '\n%s\n' "#define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0)"
|
2021-12-01 22:27:26 +00:00
|
|
|
|
[ -z "$uses_prefix" ] || printf '\n%s\n' "$(setEnvPrefixFn)"
|
|
|
|
|
[ -z "$uses_suffix" ] || printf '\n%s\n' "$(setEnvSuffixFn)"
|
2021-10-01 15:43:23 +00:00
|
|
|
|
printf '\n%s' "int main(int argc, char **argv) {"
|
2021-12-07 16:42:54 +00:00
|
|
|
|
printf '\n%s' "$(indent4 "$main")"
|
|
|
|
|
printf '\n%s\n' "}"
|
2021-08-23 21:44:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addFlags() {
|
2021-10-01 15:43:23 +00:00
|
|
|
|
local result n flag flags var
|
|
|
|
|
var="argv_tmp"
|
2021-08-23 21:44:57 +00:00
|
|
|
|
flags=("$@")
|
|
|
|
|
for ((n = 0; n < ${#flags[*]}; n += 1)); do
|
2021-08-26 12:36:30 +00:00
|
|
|
|
flag=$(escapeStringLiteral "${flags[$n]}")
|
2021-12-07 16:42:54 +00:00
|
|
|
|
result="$result${var}[$((n+1))] = \"$flag\";"$'\n'
|
2021-08-23 21:44:57 +00:00
|
|
|
|
done
|
2021-12-07 16:42:54 +00:00
|
|
|
|
printf '%s\n' "char **$var = calloc($((n+1)) + argc, sizeof(*$var));"
|
|
|
|
|
printf '%s\n' "assert($var != NULL);"
|
|
|
|
|
printf '%s\n' "${var}[0] = argv[0];"
|
2021-10-01 15:43:23 +00:00
|
|
|
|
printf '%s' "$result"
|
2021-12-07 16:42:54 +00:00
|
|
|
|
printf '%s\n' "for (int i = 1; i < argc; ++i) {"
|
|
|
|
|
printf '%s\n' " ${var}[$n + i] = argv[i];"
|
|
|
|
|
printf '%s\n' "}"
|
|
|
|
|
printf '%s\n' "${var}[$n + argc] = NULL;"
|
|
|
|
|
printf '%s\n' "argv = $var;"
|
2021-08-23 21:44:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-02 02:39:25 +00:00
|
|
|
|
# chdir DIR
|
|
|
|
|
changeDir() {
|
|
|
|
|
local dir
|
|
|
|
|
dir=$(escapeStringLiteral "$1")
|
|
|
|
|
printf '%s' "assert_success(chdir(\"$dir\"));"
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-23 21:44:57 +00:00
|
|
|
|
# prefix ENV SEP VAL
|
|
|
|
|
setEnvPrefix() {
|
2021-10-01 15:43:23 +00:00
|
|
|
|
local env sep val
|
|
|
|
|
env=$(escapeStringLiteral "$1")
|
|
|
|
|
sep=$(escapeStringLiteral "$2")
|
|
|
|
|
val=$(escapeStringLiteral "$3")
|
|
|
|
|
printf '%s' "set_env_prefix(\"$env\", \"$sep\", \"$val\");"
|
2021-12-01 21:49:20 +00:00
|
|
|
|
assertValidEnvName "$1"
|
2021-08-23 21:44:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# suffix ENV SEP VAL
|
|
|
|
|
setEnvSuffix() {
|
2021-10-01 15:43:23 +00:00
|
|
|
|
local env sep val
|
|
|
|
|
env=$(escapeStringLiteral "$1")
|
|
|
|
|
sep=$(escapeStringLiteral "$2")
|
|
|
|
|
val=$(escapeStringLiteral "$3")
|
|
|
|
|
printf '%s' "set_env_suffix(\"$env\", \"$sep\", \"$val\");"
|
2021-12-01 21:49:20 +00:00
|
|
|
|
assertValidEnvName "$1"
|
2021-05-31 23:02:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# setEnv KEY VALUE
|
|
|
|
|
setEnv() {
|
2021-10-01 15:43:23 +00:00
|
|
|
|
local key value
|
|
|
|
|
key=$(escapeStringLiteral "$1")
|
|
|
|
|
value=$(escapeStringLiteral "$2")
|
|
|
|
|
printf '%s' "putenv(\"$key=$value\");"
|
2021-12-01 21:49:20 +00:00
|
|
|
|
assertValidEnvName "$1"
|
2021-05-31 23:02:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# setDefaultEnv KEY VALUE
|
|
|
|
|
setDefaultEnv() {
|
2021-10-01 15:43:23 +00:00
|
|
|
|
local key value
|
|
|
|
|
key=$(escapeStringLiteral "$1")
|
|
|
|
|
value=$(escapeStringLiteral "$2")
|
2021-12-01 21:49:20 +00:00
|
|
|
|
printf '%s' "assert_success(setenv(\"$key\", \"$value\", 0));"
|
|
|
|
|
assertValidEnvName "$1"
|
2021-05-31 23:02:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# unsetEnv KEY
|
|
|
|
|
unsetEnv() {
|
2021-10-01 15:43:23 +00:00
|
|
|
|
local key
|
|
|
|
|
key=$(escapeStringLiteral "$1")
|
2021-12-01 21:49:20 +00:00
|
|
|
|
printf '%s' "assert_success(unsetenv(\"$key\"));"
|
|
|
|
|
assertValidEnvName "$1"
|
2021-05-31 23:02:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Makes it safe to insert STRING within quotes in a C String Literal.
|
|
|
|
|
# escapeStringLiteral STRING
|
|
|
|
|
escapeStringLiteral() {
|
|
|
|
|
local result
|
|
|
|
|
result=${1//$'\\'/$'\\\\'}
|
|
|
|
|
result=${result//\"/'\"'}
|
|
|
|
|
result=${result//$'\n'/"\n"}
|
|
|
|
|
result=${result//$'\r'/"\r"}
|
2021-10-01 15:43:23 +00:00
|
|
|
|
printf '%s' "$result"
|
2021-05-31 23:02:08 +00:00
|
|
|
|
}
|
2021-08-23 21:44:57 +00:00
|
|
|
|
|
2021-12-07 16:42:54 +00:00
|
|
|
|
# Indents every non-empty line by 4 spaces. To avoid trailing whitespace, we don't indent empty lines
|
|
|
|
|
# indent4 TEXT_BLOCK
|
|
|
|
|
indent4() {
|
|
|
|
|
printf '%s' "$1" | awk '{ if ($0 != "") { print " "$0 } else { print $0 }}'
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-01 21:49:20 +00:00
|
|
|
|
assertValidEnvName() {
|
|
|
|
|
case "$1" in
|
2021-12-07 16:42:54 +00:00
|
|
|
|
*=*) printf '\n%s\n' "#error Illegal environment variable name \`$1\` (cannot contain \`=\`)";;
|
|
|
|
|
"") printf '\n%s\n' "#error Environment variable name can't be empty.";;
|
2021-12-01 21:49:20 +00:00
|
|
|
|
esac
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-23 21:44:57 +00:00
|
|
|
|
setEnvPrefixFn() {
|
2021-10-01 15:43:23 +00:00
|
|
|
|
printf '%s' "\
|
2021-12-01 22:27:26 +00:00
|
|
|
|
void set_env_prefix(char *env, char *sep, char *prefix) {
|
2021-10-01 15:43:23 +00:00
|
|
|
|
char *existing = getenv(env);
|
2021-12-01 22:27:26 +00:00
|
|
|
|
if (existing) {
|
|
|
|
|
char *val;
|
|
|
|
|
assert_success(asprintf(&val, \"%s%s%s\", prefix, sep, existing));
|
|
|
|
|
assert_success(setenv(env, val, 1));
|
|
|
|
|
free(val);
|
|
|
|
|
} else {
|
|
|
|
|
assert_success(setenv(env, prefix, 1));
|
|
|
|
|
}
|
2021-10-01 15:43:23 +00:00
|
|
|
|
}
|
|
|
|
|
"
|
2021-08-23 21:44:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setEnvSuffixFn() {
|
2021-10-01 15:43:23 +00:00
|
|
|
|
printf '%s' "\
|
2021-12-01 22:27:26 +00:00
|
|
|
|
void set_env_suffix(char *env, char *sep, char *suffix) {
|
2021-10-01 15:43:23 +00:00
|
|
|
|
char *existing = getenv(env);
|
2021-12-01 22:27:26 +00:00
|
|
|
|
if (existing) {
|
|
|
|
|
char *val;
|
|
|
|
|
assert_success(asprintf(&val, \"%s%s%s\", existing, sep, suffix));
|
|
|
|
|
assert_success(setenv(env, val, 1));
|
|
|
|
|
free(val);
|
|
|
|
|
} else {
|
|
|
|
|
assert_success(setenv(env, suffix, 1));
|
|
|
|
|
}
|
2021-10-01 15:43:23 +00:00
|
|
|
|
}
|
|
|
|
|
"
|
2021-08-23 21:44:57 +00:00
|
|
|
|
}
|
2021-12-07 00:50:38 +00:00
|
|
|
|
|
|
|
|
|
# Embed a C string which shows up as readable text in the compiled binary wrapper
|
|
|
|
|
# documentationString ARGS
|
|
|
|
|
docstring() {
|
|
|
|
|
printf '%s' "const char * DOCSTRING = \"$(escapeStringLiteral "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------------
|
|
|
|
|
# The C-code for this binary wrapper has been generated using the following command:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
makeCWrapper $(formatArgs "$@")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# (Use \`nix-shell -p makeBinaryWrapper\` to get access to makeCWrapper in your shell)
|
|
|
|
|
# ------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
")\";"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# formatArgs EXECUTABLE ARGS
|
|
|
|
|
formatArgs() {
|
|
|
|
|
printf '%s' "$1"
|
|
|
|
|
shift
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--set)
|
|
|
|
|
formatArgsLine 2 "$@"
|
|
|
|
|
shift 2
|
|
|
|
|
;;
|
|
|
|
|
--set-default)
|
|
|
|
|
formatArgsLine 2 "$@"
|
|
|
|
|
shift 2
|
|
|
|
|
;;
|
|
|
|
|
--unset)
|
|
|
|
|
formatArgsLine 1 "$@"
|
|
|
|
|
shift 1
|
|
|
|
|
;;
|
|
|
|
|
--prefix)
|
|
|
|
|
formatArgsLine 3 "$@"
|
|
|
|
|
shift 3
|
|
|
|
|
;;
|
|
|
|
|
--suffix)
|
|
|
|
|
formatArgsLine 3 "$@"
|
|
|
|
|
shift 3
|
|
|
|
|
;;
|
|
|
|
|
--chdir)
|
|
|
|
|
formatArgsLine 1 "$@"
|
|
|
|
|
shift 1
|
|
|
|
|
;;
|
|
|
|
|
--add-flags)
|
|
|
|
|
formatArgsLine 1 "$@"
|
|
|
|
|
shift 1
|
|
|
|
|
;;
|
|
|
|
|
--argv0)
|
|
|
|
|
formatArgsLine 1 "$@"
|
|
|
|
|
shift 1
|
|
|
|
|
;;
|
|
|
|
|
--inherit-argv0)
|
|
|
|
|
formatArgsLine 0 "$@"
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
shift
|
|
|
|
|
done
|
|
|
|
|
printf '%s\n' ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# formatArgsLine ARG_COUNT ARGS
|
|
|
|
|
formatArgsLine() {
|
|
|
|
|
local ARG_COUNT LENGTH
|
|
|
|
|
ARG_COUNT=$1
|
|
|
|
|
LENGTH=$#
|
|
|
|
|
shift
|
|
|
|
|
printf '%s' $' \\\n '"$1"
|
|
|
|
|
shift
|
|
|
|
|
while [ "$ARG_COUNT" -gt $((LENGTH - $# - 2)) ]; do
|
|
|
|
|
printf ' %s' "${1@Q}"
|
|
|
|
|
shift
|
|
|
|
|
done
|
|
|
|
|
}
|