lib.array.count () { eval echo \${#$1[@]}; } lib.array.dump () { declare ref2="$1[@]"; IFS='' printf %s$'\1' "${!ref2}"; } lib.array.keys () { eval echo \${!$1[@]}; } lib.array.ids () { echo $(printf "$1[%i] " $(lib.array.keys $1)); } lib.array.pop () { [[ $1 == -d ]] && { declare d="${2//%/%%}"; shift 2; } declare d="${d:-$'\n'}" var=$1; declare -i count=`lib.array.count $1`; (( count )) || return; count=$(( count - $2)); eval "set -- \${$var[@]:$count}"; printf %s "$1"; shift; declare arg=''; for arg; do printf -- "$d%s" "$arg"; done; eval declare -ga $var="'(\${$var[@]:0:$count})'" } lib.array.push () { declare target=$1; shift; declare -i index=$(lib.array.count $target); declare IFS=''; for item; do printf -v $target[index++] %s "$item"; done; } lib.array.read () { echo unset $( lib.array.gen.range $1 0-$((`lib.array.count $1` - 1)) ); declare -i i=0; while read -d$'\1' $1[i++]; do true; done; unset $1[$((i-1))]; } lib.array.shift () { [[ $1 == -d ]] && { declare d="${2//%/%%}"; shift 2; } declare d="${d:-'\n'}" var=$1; declare -i count=`lib.array.count $1`; (( count )) || return; (( $2 <= count )) || return; count=$2; eval "set -- \${$var[@]:0:$count}"; printf -- %s "$1"; shift; declare arg=''; for arg; do printf -- ''"$d%s" "$arg"; done; eval declare -ga $var="'(\${$var[@]:$count})'"; } lib.lang.bash.function () { (($#)) || return; (printf '%s\n{\n' "$1 ()"; shift; (($#)) || set -- /dev/stdin; for file; do IFS='' read -rN0 source < "$file"; printf '%s' "$source"; done; printf '\n}\n\n'; ) } lib.shell.error () { declare -A trace; read trace[line] trace[sub] trace[file] < <(caller 0); [[ -z "${trace[line]}" ]] && trace[line]=$BASH_LINENO; [[ -z "${trace[file]}" ]] && { trace[file]=`readlink -e /dev/stdin`; trace[file]=${trace[file]/`pwd`\/}; } [[ -z "${trace[sub]}" ]] && trace[sub]="${FUNCNAME[1]}"; [[ -z "${trace[sub]}" ]] && trace[sub]="main"; [[ "${trace[sub]}" =~ ^"$FUNCNAME"$ ]] && { trace[file]=$0; trace[sub]="fatal: main"; }; [[ "${trace[sub]}" =~ ^source$ ]] && { trace[sub]="main"; }; printf %s\\n "($SHLVL) ${trace[file]}: ${trace[sub]}: line ${trace[line]}`printf ': %s' "${@}"`" >&2; unset e; ${e:?"`printf %b '\E[2K\E[1A'`"}; } lib.var.id () { [[ "$1" =~ ^([a-zA-Z\_][a-zA-Z0-9_]+)\.(.*)$ ]] && { echo ${BASH_REMATCH[1]}[${BASH_REMATCH[2]//:/.}]; return; } [[ "$1" =~ ^([a-zA-Z\_][a-zA-Z0-9_]+)\[? ]] && { echo "$1"; return; } lib.shell.error "\`$1'" "is not a valid variant label"; } lib.param.source () { if [[ "$1 $2" == 'shift loop' ]]; then shift 2; declare expr="${1}"; declare body="${2#$(printf '\n')*}"; declare fallback=${3:-'lib.shell.error "$1" "unhandled invocation operator"}'}; printf 'while [[ "${1}" =~ %s ]]; do\n\n%s\n\n%s;\n\ndone;\n' "$expr" "${body}" "${fallback%*;}"; return; else if [[ "$1 $2" == 'parse option' ]]; then shift 2; declare postop=${4}; [[ -z "$postop" ]] || postop="${postop%*;};"; printf '%s\n' '[[ "$1" =~ ^('$1')$ ]] && { '`lib.var.id $2`'="'$3'"; shift 1; '"$postop"' };'; return; else if [[ "$1 $2" == 'parse argument' ]]; then shift 2; declare postop=${3}; [[ -z "$postop" ]] || postop="${postop%*;};"; printf '[[ "$1" =~ ^(%s)=?(.*)$ ]] && { ' "$1"; printf '[[ -z "${BASH_REMATCH[2]}" ]] && { %s="$2"; shift 2; } || ' "`lib.var.id $2`"; printf '{ %s="${BASH_REMATCH[2]}"; shift 1; }; %s };\n' "`lib.var.id $2`" "$postop"; return; fi; fi; fi } lib.param.unique () { local arg; local -A RECORDS; for arg; do if [[ ${RECORDS[$arg]} == defined ]]; then continue; fi; RECORDS[$arg]=defined; echo "$arg"; done; } lib.path.list () { declare -i __recursive=0; eval "$(lib.param.source parse option -r __recursive 1)"; (shopt -s dotglob; path="${1+${1%/}/}"; shift; [[ -d "$path" || -z "$path" ]] || { echo $FUNCNAME: error: \`$path\' is not a directory >&2; return 1; } IFS=$'\1'; for f in `printf '%s\1' "$path"*`; do IFS=$' \t\n'; [[ "$f" != '*' ]] && printf '%s\n' "$f"; [[ "$__recursive" == 1 && -d "$f" ]] && $FUNCNAME -r "$f"; done; ); } lib.param.filter () { declare -i inverted=0; eval "$(lib.param.source parse option '-i|--inverted' inverted 1)"; declare arg rx="$1"; shift; (( $# )) || return 2; (( inverted )) && { for arg; do [[ "$arg" =~ $rx ]] || printf '%s\n' "$arg"; done; } || { for arg; do [[ "$arg" =~ $rx ]] && printf '%s\n' "$arg"; done; }; } lib.read.for () { # Usage: lib.read.for [line|char|record delimiter "char"] [do command] [in file ...] declare -A env[line]=0 env[delimited]=0 env[binary]=0; declare -i EOF; if [[ "$1" == char ]]; then env[binary]=1; shift; elif [[ "$1" == line ]]; then env[line]=1; shift; elif [[ "$1$2" == recorddelimiter ]]; then env[delimited]=1 env[delimiter]="$3"; shift 2; shift; fi; # remove that shift and ur dead on the next comparison. [[ "$_" == shift ]] && { [[ "$1" == do ]] && { env[command]="$2"; shift 2; }; [[ $? && "$1" == in ]] && shift; }; (($#)) || set -- /dev/stdin; env[files]=$#; (( env[binary] )) && { declare file char; [[ -n "${env[command]}" ]] && { for file; do EOF=0; while (( ! EOF )); do read -rN1 char; EOF=$?; true; ${env[command]} "$char" || return; done <"$file"; done; return; } || { for file; do while read -rN1 char; do printf "%c" "$char"; done <"$file"; done; return; } } || (( env[line] )) && { declare file line; [[ -n "${env[command]}" ]] && { for file; do while IFS='' read -r line; do EOF=0 ${env[command]} "$line" || return; done <"$file"; EOF=1 ${env[command]} "$line"; done; return; } || { "$BASH_SOURCE: $FUNCNAME: $LINENO: error: set line: callback"; return; } } || (( env[delimited] )) && { declare file record; [[ -n "${env[command]}" ]] && { for file; do while IFS='' read -rd "${env[delimiter]}" record; do EOF=0 ${env[command]} "$record" || return; done <"$file"; EOF=1 ${env[command]} "$record"; done; return; } || { "$BASH_SOURCE: $FUNCNAME: $LINENO: error: set delimited: callback"; return; } } || { declare file content; [[ -n "${env[command]}" ]] && { for file; do IFS='' read -rN0 content <"$file"; ${env[command]} '%s' "$content" || return; done; return; } || \ for file; do IFS='' read -rN0 content <"$file"; printf '%s' "$content"; done; }; } lib.var.engine () { [[ "$1" == --initialize ]] && { (( VARENGINE )) && return; declare script="/tmp/$$.$RANDOM.`date +%s`.var.eng"; cat <<-"EOF" > "$script"; exec 4>&- 5>&-; rm $0; shopt -s expand_aliases; declare -i LINE; alias io.send="printf %s$'\1'" io.receive="read -rd $'\1'"; property.var.name () { [[ "$1" =~ ^([a-zA-Z_][a-zA-Z0-9_]+)\.(.*)$ ]] && { echo "${BASH_REMATCH[1]}[${BASH_REMATCH[2]}]"; return; } [[ "$1" =~ ^([a-zA-Z_][a-zA-Z0-9_]+)\[? ]] && { echo "$1"; return; } echo "$0: error: \`$1'" "is not a valid variant label" >&2; } property.var.declared () { eval [[ "\${$1+declared}" == 'declared' ]] && \ io.send true || io.send false; } property.var.filter () { declare arg rx="$1" rxm='&&'; shift; [[ ${rx:0:1} == - ]] && { rx="${rx:1}"; rxm='||' } (( $# )) || return 2; declare action='for arg; do [[ "$arg" =~ $rx ]] '"$rxm"' printf "%s\\n" "$arg"; done;'; eval "$action"; } lib.var.engine.parse () { let LINE++; [[ -z "$line" ]] && return; declare -a cmd; read -a cmd <<<"$line"; if [[ "${cmd}" == exit ]]; then $line; fi; if [[ "${cmd}" == erase ]]; then unset "`property.var.name ${cmd[1]}`"; return; fi; if [[ "${cmd}" == defined ]]; then property.var.declared "`property.var.name ${cmd[1]}`"; return; fi; if [[ "${cmd}" == set ]]; then declare "___varname___"="`property.var.name "${cmd[1]}"`"; declare -gA "${___varname___}"; [[ "$___varname___" =~ ^IFS$ ]] && ___varname___ = _; IFS='' io.receive "${___varname___}"; return; fi; if [[ "${cmd}" == get ]]; then declare _vn="`property.var.name "${cmd[1]}"`"; printf '%s' "${!_vn}"; io.send ''; return; fi; if [[ "${cmd}" == names ]]; then property.var.filter "${cmd[1]}" `printf '${!%s@} ' {a..z} {A..Z} | eval echo "$(read -rN0; echo $REPLY)"`; io.send ''; return; fi; if [[ "${cmd}" == keys ]]; then declare _vn; printf -v _vn 'printf '\'${cmd[1]}'.%%s\n'\'' ${!%s[@]}' "`property.var.name "${cmd[1]}"`"; property.var.filter "${cmd[2]:-.*}" $(eval $_vn); io.send ''; return; fi; printf %s\\n "$0: line $LINE: unrecognized command: $cmd" >&2; } while IFS='' read -r line; do let LINE++; lib.var.engine.parse "$line"; done; [[ -n "$line" ]] && lib.var.engine.parse "$line"; EOF declare stderr=/dev/`ps "$$" | { read; read _ termio _; echo "$termio"; }`; exec 4<> <(:) 5<> <(:); { exec 6> "$stderr"; exec -a "$FUNCNAME" bash "$script" <&4 >&5 2>&6 & } 2>&-; declare -gA VARENGINE=$! VARENGINE[stdin]="/dev/fd/4" \ VARENGINE[stdout]="/dev/fd/5" VARENGINE[pid]=$!; return; }; var () { (( ! VARENGINE[pid] )) && { echo $FUNCNAME: fatal: no property engine alive >&2; return 127; }; # logic check that does not really do anything apparently useful (( VARENGINE[ppid] != $$ )) && { echo $FUNCNAME: error: incorrect process rights: $* >&2; return 2; } # logic check that does not really do anything apparently useful (( VARENGINE[pshlvl] != SHLVL )) && { echo $FUNCNAME: error: incorrect shell level: $* >&2; return 2; } [[ "$1" == set ]] && { # echo set >&2; # logic check that does not really do anything apparently useful while (( VARENGINE[transfer] )); do sleep 0.001; done; VARENGINE[transfer]=1; echo "$1 $2"; shift 2; (( $# )) && ( IFS=''; printf %s "$@"; ) || "lib.read.for"; echo -n $'\1'; VARENGINE[transfer]=0; return; } > "${VARENGINE[stdin]}"; [[ "$1" =~ ^defined$ ]] && { # logic check that does not really do anything apparently useful while (( VARENGINE[transfer] )); do sleep 0.001; done; VARENGINE[transfer]=1; echo "$1 $2" > "${VARENGINE[stdin]}"; IFS='' read -rd $'\1' < "${VARENGINE[stdout]}"; VARENGINE[transfer]=0; [[ "$REPLY" == true ]]; return; }; [[ "$1" =~ ^erase$ ]] && { # logic check that does not really do anything apparently useful while (( VARENGINE[transfer] )); do sleep 0.001; done; VARENGINE[transfer]=1; echo "$1 $2" > "${VARENGINE[stdin]}"; VARENGINE[transfer]=0; return; }; [[ "$1" =~ ^keys$ ]] && { # echo get >&2; # logic check that does not really do anything apparently useful while (( VARENGINE[transfer] )); do sleep 0.001; done; VARENGINE[transfer]=1; echo "$1 $2 $3" > "${VARENGINE[stdin]}"; IFS='' read -rd $'\1' $4 < "${VARENGINE[stdout]}"; VARENGINE[transfer]=0; [[ -z "$4" ]] && IFS='' printf %s "$REPLY"; return; }; [[ "$1" =~ ^get|names$ ]] && { # echo get >&2; # logic check that does not really do anything apparently useful while (( VARENGINE[transfer] )); do sleep 0.001; done; VARENGINE[transfer]=1; echo "$1 $2" > "${VARENGINE[stdin]}"; IFS='' read -rd $'\1' $3 < "${VARENGINE[stdout]}"; VARENGINE[transfer]=0; [[ -z "$3" ]] && IFS='' printf %s "$REPLY"; return; }; }; lib.var.engine --initialize && \ declare -gA VARENGINE[ppid]=$$ VARENGINE[pshlvl]=$SHLVL VARENGINE[transfer]=0; true; } lib.cache () { lib.var.engine; var defined lib || var set lib ""; lib.cache.name () { declare -A _opt[function]=0; eval "$(lib.param.source parse option -f _opt[function] 1)"; printf -v "$1" %s "${!1//\//.}"; (( _opt[function] )) && printf -v "$1" %s "${!1%.sh}"; } lib.cache.get () { declare alias="$1"; lib.cache.name -f alias; var defined lib.cache.$alias && var get "lib.cache.$alias" $2; } lib.cache.set () { declare alias="$1"; lib.cache.name -f alias; var set "lib.cache.$alias" "${@:2}"; } lib.cache.list () { declare data alias="$1"; lib.cache.name -f alias; shift; lib.cache.get $alias data; (($#)) && { lib.param.unique ${data} ${@} | lib.cache.set $alias; } || { printf %s\\n "$FUNCNAME: error: missing parameters" >&2; return 1; }; } lib.cache () { [[ -z "$1" ]] && return; declare file="$1"; ((job && tot)) || lib.cache.term.status "caching $file"; [[ -d "$file" ]] && { lib.cache.term.status "caching directory $file"; lib.cache.list dirs "${file}"; return; }; [[ "$file" =~ \.sh$ ]] && { lib.cache.list funcs "${file}"; lib.cache.set "${file%.sh}.file" "$file"; lib.cache.set "${file}" < "$file"; return; }; [[ "$file" =~ \.dep$ ]] && { lib.cache.list deps "${file}"; lib.cache.set "${file}.file" "$file"; lib.cache.set "${file}" < "$file"; return; }; lib.cache.list other "${file}"; } lib.cache.update () { declare arg; for arg; do lib.cache "$arg"; done; } lib.cache.import () { eval "$(lib.cache.make "$@")"; } lib.cache.stale () { declare file; for file in `lib.cache.get funcs`; do [[ -N "$file" || ! -e "${file%.sh}.dep" ]] && { echo "$file"; continue; }; done; } lib.cache.make () { var set lib.cache.build ""; declare function body deps list; (($#)) || set -- `lib.cache.get funcs`; for function; do lib.cache.name -f function; lib.cache.get $function.dep deps; printf -v list '%s\n' "${list}${deps}${function}"; done; lib.cache.list build `lib.param.unique $list`; for function in `lib.cache.get build`; do lib.cache.get $function | lib.lang.bash.function $function; done; } lib.cache.term.status () { { printf "%b" '\E[A\E[2K'; printf "%s\n" "$*"; } >&2; } lib.cache.chain () { lib.cache.scan.dep () { declare functions dep dat depfile datfile; lib.cache.get funcs functions; lib.param.unique $(for function; do lib.cache.name -f function; datfile="${function//.//}.sh" depfile="${function//.//}.dep"; [[ -e "$depfile" && ! -N "$datfile" && ! -N $depfile ]] && { lib.cache.get "$function.dep"; echo "$function"; continue; } || { lib.cache.term.status "($job/$tot) scanning $function ..."; [[ -N "$datfile" ]] && lib.cache.set "$function" < "$datfile"; lib.cache.get "$function" body; for name in $functions; do lib.cache.name -f name; datfile="${name//.//}.sh" depfile="${name//.//}.dep"; [[ "$name" =~ "$function" ]] && continue; [[ "$body" =~ [^\.]?"$name"[^\.]? ]] && { printf -v dat %s "`lib.cache.scan.dep "$name"`"; [[ ! -e $depfile || $datfile -nt $depfile ]] && { lib.cache.term.status "($job/$tot) caching ${name//\//.}.dep ..."; echo "$dat" > "${depfile}"; } lib.cache "${depfile}"; echo "$dat"; echo "$name"; continue; } done; } done ); } lib.cache.make.deps () { (($#)) || set -- `lib.cache.get funcs`; declare file dep; for file; do dep="${file%.sh}.dep"; [[ "$dep" -nt "$file" ]] || { lib.cache.term.status "($job/$tot) writing ${dep//\//.} ..."; lib.cache.scan.dep $file > "$dep"; lib.cache "$dep"; } done; } (($#)) || { set -- `lib.cache.stale`; } (($#)) && { echo ''; ls "$@"; echo ''$'\n'; } >&2; declare file f; declare -a deps; declare -i job tot=$#; for file; do let job++; f="$file"; lib.cache.name -f f; lib.cache.term.status "($job/$tot) scanning ${f} ..."; lib.cache.make.deps "$file"; lib.cache "$file"; lib.array.push deps `lib.cache.get ${file%.sh}.dep` done; (($#)) && lib.cache.term.status "`lib.array.count deps` dependency links chained"; unset -f lib.cache.make.deps lib.cache.scan.dep; } lib.cache.path () { echo '' >&2; set -- `lib.path.list -r $1`; lib.cache.term.status "caching $# resource$((($# > 1)) && printf s) ... "; for path do lib.cache $path; done; set -- `lib.cache.get dirs`; declare dirs=$#; set -- `lib.cache.get funcs`; declare funcs=$#; (( funcs )) && { lib.cache.term.status "$funcs functions in $dirs directories"; lib.cache.chain; } || { lib.cache.term.status "Warning: no functions present"; } } } lib.date.serial () { date +%s; } lib.file.close () { # specify /dev/fd/N or N ... (($#)) && eval $(printf 'exec '; for __arg; do printf ' %i>&-' "${__arg##*/}"; done; echo \;; ); } lib.file.open () { : lib.param.source required declare _Target=REPLY; eval "$(lib.param.source parse argument -v _Target)"; declare _Mode="$1" _File="$2"; _Mode="${_Mode/-rw/<>}"; _Mode="${_Mode/-r/<}"; _Mode="${_Mode/-w/>}"; _Mode="${_Mode/-a/>>}"; declare -i _Start=9; while [[ -e /dev/fd/$_Start ]]; do let _Start++; done; eval exec "$_Start${_Mode}${_File:-/dev/null}"; [[ "$_Target" != REPLY ]] && { printf -v "$_Target" %s "/dev/fd/$_Start"; } || { echo "/dev/fd/$_Start"; } } lib.func.declared () { declare -F "$1" >/dev/null; } lib.func.dump () { declare -f $@; } lib.func.list () { declare -pF | (while read backing flags func; do printf '%s\n' "$func"; done;) } lib.gen.temp () { declare NOW=''; lib.date.serial -v NOW; printf %08X%s\\n $(( SECONDS * RANDOM )) "$(printf -- .%08X \ $(( ( RANDOM * 314 ) + NOW )) $(( SECONDS * RANDOM )) $(( ( RANDOM * $$ ) + NOW )))"; } lib.lang.bash.comment () { lib.read.for line do "echo # "; } lib.lang.bash.doc () { declare data="$(lib.read.for)"; lib.bash.doc.fmt() { printf 'echo -E "%s";\n' "$1"; }; data="${data//\"/\\\"}"; data="${data//\$/\\\$}"; data="${data//\`/\\\`}"; printf %s "$data" | lib.read.for line do lib.bash.doc.fmt; unset -f lib.bash.doc.fmt; } lib.param.count () { printf %i "$#"; } lib.var.declared () { eval [[ "\${$1+declared}" == 'declared' ]]; } lib.param.parse () { [[ $1 == --cache ]] && { lib.var.declared ARGC && lib.var.declared ARGV || \ echo 'declare -i ARGC; declare -a ARGV;'; return; }; [[ $1 == --init ]] && { lib.var.declared opts && lib.var.declared optargs && \ lib.var.declared optl && lib.var.declared optargl || \ echo "declare opts optargs optl optargl;"; return; }; [[ $1 == --master ]] && { $FUNCNAME --cache; $FUNCNAME --init; return; }; eval `$FUNCNAME --master`; while [[ ${1:0:1} == - ]]; do [[ $1 == -- ]] && { shift; break; }; [[ $1 =~ ^(-la|-al|--arg-long|--long-arg)$ ]] && { optargl=${2}; shift 2; continue; }; [[ $1 =~ ^(-lo|-ol|--opt-long|--long-opt)$ ]] && { optl=$2; shift 2; continue; }; [[ $1 =~ ^(-vla|-val|--var-arg-long|--long-arg-var)$ ]] && { optargl="${!2}"; shift 2; continue; }; [[ $1 =~ ^(-vlo|-vol|--var-opt-long|--long-opt-var)$ ]] && { optl="${!2}"; shift 2; continue; }; [[ $1 =~ ^(-sa|-as|--arg-short|--short-arg)$ ]] && { optargs=$2; shift 2; continue; }; [[ $1 =~ ^(-so|-os|--opt-short|--short-opt)$ ]] && { opts=$2; shift 2; continue; }; [[ $1 =~ ^(-vsa|-vas|--var-arg-short|--short-arg-var)$ ]] && { optargs="${!2}"; shift 2; continue; }; [[ $1 =~ ^(-vso|-vos|--var-opt-short|--short-opt-var)$ ]] && { opts="${!2}"; shift 2; continue; }; break; done declare arg; for arg; do [[ $arg == -- ]] && { lib.array.push ARGV --; continue; }; [[ $arg =~ ^-- ]] && { lib.param.parse.long -- "$arg" continue; } [[ $arg =~ ^- ]] && { lib.param.parse.short -- "$arg"; continue; } lib.array.push ARGV "$arg"; done; for arg in "${ARGV[@]}"; do printf ' "%s"' "${arg//\"/\\\"}"; done; } lib.param.long () { eval `lib.param.parse --init`; declare dest=ARGV; while [[ ${1:0:1} == - ]]; do [[ $1 == -- ]] && { shift; break; }; [[ $1 == -a ]] && { dest=$2; shift 2; continue; }; [[ $1 =~ ^(-la|-al|--arg-long|--long-arg)$ ]] && { optargl=${2}; shift 2; continue; }; [[ $1 =~ ^(-lo|-ol|--opt-long|--long-opt)$ ]] && { optl=$2; shift 2; continue; }; [[ $1 =~ ^(-vla|-val|--var-arg-long|--long-arg-var)$ ]] && { optargl="${!2}"; shift 2; continue; }; [[ $1 =~ ^(-vlo|-vol|--var-opt-long|--long-opt-var)$ ]] && { optl="${!2}"; shift 2; continue; }; break; done optargl=${optargl//,/\|}; optl=${optl//,/\|}; [[ $1 =~ ^--(${optl})$ ]] && { lib.array.push $dest "--${BASH_REMATCH[1]}" return; } [[ $1 =~ ^--(${optargl})=?(.*)$ ]] && { lib.array.push $dest "--${BASH_REMATCH[1]}" [[ -n "${BASH_REMATCH[2]}" ]] && lib.array.push $dest "${BASH_REMATCH[2]}"; return; } } lib.param.short () { eval `lib.param.parse --init`; declare dest=ARGV; while [[ ${1:0:1} == - ]]; do [[ $1 == -- ]] && { shift; break; }; [[ $1 == -a ]] && { dest=$2; shift 2; continue; }; [[ $1 =~ ^(-sa|-as|--arg-short|--short-arg)$ ]] && { optargs=$2; shift 2; continue; }; [[ $1 =~ ^(-so|-os|--opt-short|--short-opt)$ ]] && { opts=$2; shift 2; continue; }; [[ $1 =~ ^(-vsa|-vas|--var-arg-short|--short-arg-var)$ ]] && { optargs="${!2}"; shift 2; continue; }; [[ $1 =~ ^(-vso|-vos|--var-opt-short|--short-opt-var)$ ]] && { opts="${!2}"; shift 2; continue; }; break; done { while read -rN1 char; do [[ $char =~ ^[$opts]$ ]] && { lib.array.push $dest "-$char"; continue; }; [[ $char =~ ^[$optargs]$ ]] && { lib.array.push $dest "-$char"; break; } return 3; done; [[ $char =~ [$optargs] ]] && { declare arg; read -rN0 arg; [[ "$arg" =~ ^[=\:"`echo -E \n\t' '`"](.*)$ ]] && arg="${arg:1}"; [[ -n "$arg" ]] && { lib.array.push $dest "$arg"; }; return; } } < <(echo -En "${1:1}"); } lib.path.relative () { declare -a path basedir; declare -i index=0; IFS=/ read -a path <<<"${1%%/}"; IFS=/ read -a basedir <<<"`pwd`"; while ((index < ${#basedir[@]})); do [[ "${path[index]}" == "${basedir[index]}" ]] && { let index++; continue; }; break; done; ((index == 1)) && { echo "$1"; return; }; for path in "${basedir[@]:${#basedir[@]}-index+1}"; do echo -n ../; done; printf -v path %s "${path[@]:index:1}`printf /%s "${path[@]:index+1}"`"; echo "${path%%/}"; } lib.session.owner () { read owner _ < <(who -m); printf '%s\n' "$owner"; } lib.session.tty () { declare link; read _ link < <(who -m); printf '%s\n' "/dev/$link"; } lib.shell.path () { type -p "$1"; } lib.shell.run () { declare -A param=$FUNCNAME \ param[shortopt]='\?hcbv' param[longopt]='help,usage,check-syntax,barebones,verbose' \ param[shortarg]='af' param[longarg]='file,alias' \ param[file]='/dev/stdin' param[alias]="$param" \ param[barebones]='0' param[verbose]='0' param[check-syntax]='0' \ param[execopt]='' param[bashopt]=''; [[ $1 =~ ^(-\?|-h|--help|--usage)$ ]] && { echo "USAGE: $param [-cbv] [-a alias] [-f script] [--] ARG ..."; echo ''; [[ ${BASH_REMATCH[1]} == -? ]] && { echo 'See --help for further information'; echo ''; return 1; } [[ ${BASH_REMATCH[1]} == --usage ]] && { echo 'See --help for further information'; echo ''; return; } echo ' Execute or check the syntax of the given source in a subshell as a'; echo ' named command.'; echo ''; [[ ${BASH_REMATCH[1]} == -h ]] && return; echo 'OPTIONS'; echo ' -c or --check-syntax'" Parse only, bash syntax check"; echo ' -b or --barebones'" Do not copy shell environment to"; echo ' '" subprocess"; echo ' -v or --verbose'" List source lines as they are parsed"; echo ' -f or --file'" Direct source from file if not provided,"; echo ' '" read stdin"; echo ' -a or --alias'" Set script argument \$0, if not provided"; echo ' '" default is: $param"; echo ''; echo ' Exit Status:'; echo ' Whatever the source reports as an exit status, or true if the syntax'; echo ' check succeeded.'; echo ''; return; } eval set -- "$(lib.param.parse \ -vsa param[shortarg] -vso param[shortopt] \ -vla param[longarg] -vlo param[longopt] -- "$@" )"; eval "$(lib.param.source shift loop - " $(lib.param.source parse option -- _ this break;) $(lib.param.source parse option '-b|--barebones' param[barebones] 1 continue;) $(lib.param.source parse option '-?|-h|--help|--usage' param[barebones] 1 "$param \${BASH_REMATCH[1]}; return;") $(lib.param.source parse option '-c|--check-syntax' param[check-syntax] 1 continue;) $(lib.param.source parse option '-v|--verbose' param[verbose] 1 continue;) $(lib.param.source parse argument '-a|--alias' param[alias] continue;) $(lib.param.source parse argument '-f|--file' param[file] continue;) " break; )"; # setup user config.. (( param[barebones] )) && param[execopt]=-c; (( param[verbose] )) && param[bashopt]=-v; (( param[check-syntax] )) && param[bashopt]=${param[bashopt]:--}n; # Create a new aliased shell. (exec ${param[execopt]} -a "${param[alias]}" -- bash ${param[bashopt]} -s -- "$@";) \ < "${param[file]}"; } lib.string.repeat () { declare __ovar__; printf -v __ovar__ %*s $2; printf %s ${__ovar__// /${1}}; } lib.val.calc () { math() { : } } lib.var.printf () { [[ "$1" =~ ^('-v')=?(.*)$ ]] && { declare _commit='' ; [[ -z "${BASH_REMATCH[2]}" ]] && { _commit="$(lib.var.id "$2")" || return; shift 2; } || { _commit="$(lib.var.id "${BASH_REMATCH[2]}")" || return; shift 1; }; (($#)) && { IFS='' read -rN0 "$_commit" < <(${FUNCNAME:-$0} -- "$@"); return; } || { IFS='' echo -E "$_commit"; return; }; } [[ "$1" == '--' ]] && shift; declare _vformat="$1" _pformat="$1" _fmt _tail; shift; while [[ -n "$_vformat" ]]; do if [[ "$_vformat" =~ ^([^\%]*)('%s['[\*[sv0-9]+']'|'%c['[\*[iv0-9]+']'|'%vt['[\*\ a-z0-9,]+\]|'%v'|%%?[^\%]*)?(.*) ]]; then builtin printf %b "${BASH_REMATCH[1]}"; _fmt="${BASH_REMATCH[2]}" _tail="${BASH_REMATCH[3]}"; [[ "${_fmt}" =~ ^'%vt['([\*\ a-z0-9,]+)']' ]] && { declare _match="${BASH_REMATCH[1]}"; [[ "$_match" == *s ]] && { _match="$1"; shift; }; [[ "$_match" == *v ]] && { _fmt="$(lib.var.id "$1")" || return; _match="${!_fmt}"; shift; }; _match="${_match/,/;}"; _match="${_match/default/0}"; _match="${_match//bright/1}"; _match="${_match//dim/2}"; _match="${_match//underline/4}"; _match="${_match//blink/5}"; _match="${_match//reverse/7}"; _match="${_match//hidden/8}"; _match="${_match// /}"; _match="${_match//fc/3}"; _match="${_match//bg/4}"; _match="${_match//black/0}"; _match="${_match//red/1}"; _match="${_match//green/2}"; _match="${_match//yellow/3}"; _match="${_match//blue/4}"; _match="${_match//magenta/5}"; _match="${_match//cyan/6}"; _match="${_match//white/7}"; builtin printf -- %b '\E['${_match}'m' || return; builtin printf -v _vformat %s "${_tail}"; continue; } [[ "${_fmt}" =~ ^'%c['([\*iv0-9]+)']' ]] && { declare _match="${BASH_REMATCH[1]}"; [[ "$_match" == '*i' ]] && { _match="$1"; shift; }; [[ "$_match" == '*v' ]] && { _fmt="$(lib.var.id "$1")" || return; _match="${!_fmt}"; shift; }; builtin printf -v _fmt '%*s' $_match; _fmt="${_fmt// /${1:0:1}}"; shift; builtin printf -- "%s" "${_fmt}" || return; shift; builtin printf -v _vformat %s "${_tail}"; continue; } [[ "${_fmt}" =~ ^'%s['([\*sv0-9]+)']' ]] && { declare _match="${BASH_REMATCH[1]}"; [[ "$_match" == '*s' ]] && { _match="$1"; shift; }; [[ "$_match" == '*v' ]] && { _fmt="$(lib.var.id "$1")" || return; _match="${!_fmt}"; shift; }; builtin printf -v _fmt '%*s' $_match; _fmt="${_fmt// /${1}}"; shift; builtin printf -- "%s" "${_fmt}" || return; shift; builtin printf -v _vformat %s "${_tail}"; continue; } [[ "${_fmt}" =~ ^'%v' ]] && { declare _v="$(lib.var.id "$1")" || return; builtin printf -- "%s" "${!_v}" || return; shift; builtin printf -v _vformat %s "${_tail}"; continue; } [[ "${_fmt}" =~ [^\\]\* ]] && { # the format requesting a parameter ... builtin printf -- "${_fmt}" "$1" "$2" || return; shift 2; } || { builtin printf -- "${_fmt}" "$1" || return; shift; } builtin printf -v _vformat %s "${_tail}"; fi; done ; (($#)) && $FUNCNAME "$_pformat" "$@"; } lib.var.root () { [[ "$1" =~ ^([a-zA-Z_][a-zA-Z0-9_]+)\.?(.*)$ ]] && { declare -gA ${BASH_REMATCH[1]}="${!BASH_REMATCH[1]}"; return; } } lib.var.type () { { if declare -pA ${1:-invalid.property} >/dev/null; then echo "hash"; elif declare -pa ${1:-invalid.property} >/dev/null; then echo "array"; elif declare -pi ${1:-invalid.property} >/dev/null; then echo "integer"; elif [[ $1 =~ ^(.+)\[.+\]$ ]]; then [[ `lib.var.type ${BASH_REMATCH[1]}` =~ ^(hash|array)$ ]] && { [[ ${BASH_REMATCH[1]} == hash ]] && { echo key; } || { [[ ${BASH_REMATCH[1]} == array ]] && echo index; } } elif lib.var.declared $1; then echo "string"; fi; } 2>/dev/null; }