This commit is contained in:
Tomas Mirchev 2025-10-31 21:36:52 +02:00
parent 6726f04f77
commit dacb3aeb09

96
barg Normal file → Executable file
View File

@ -1,55 +1,61 @@
# barg - Bash argument parser + tiny CLI framework #!/usr/bin/env bash
# Bash 5+
# --- helpers -----------------------------------------------------------------
join() { join() {
local out="" sep="" local out="" sep=""
for x in "$@"; do [[ -n "$x" ]] && { for x in "$@"; do
if [[ -n "$x" ]]; then
out+="${sep}${x}" out+="${sep}${x}"
sep="." sep="."
}; done fi
done
printf '%s' "$out" printf '%s' "$out"
} }
# --- tokenizer ---------------------------------------------------------------
tokenize_argv() { tokenize_argv() {
local prog=$1
shift shift
TOKENS=() TOKENS=("root::dev")
TOKENS+=("root::${prog}") local -a argv=("$@")
local -a args=("$@")
while ((${#args[@]})); do while ((${#argv[@]})); do
local t=${args[0]} local token=${argv[0]}
args=("${args[@]:1}") argv=("${argv[@]:1}")
if [[ "$t" == "--" ]]; then
TOKENS+=("rest::${args[*]}") # Rest
if [[ "$token" == "--" ]]; then
TOKENS+=("rest::${argv[*]}")
break break
fi fi
if [[ "$t" == --* ]]; then
local kv=${t#--} # Named Argument + Value: Option or Flag (long form)
local key=${kv%%=*} if [[ "$token" == --* ]]; then
TOKENS+=("narg::${key}") local key=${token#--}
[[ "$kv" == *"="* ]] && TOKENS+=("value::${kv#*=}") TOKENS+=("narg::${key%%=*}")
[[ "$key" == *"="* ]] && TOKENS+=("value::${key#*=}")
continue continue
fi fi
if [[ "$t" == -* ]]; then
local sv=${t#-} # Named Argument + Value: Option or Flag (short form)
local flags=${sv%%=*} if [[ "$token" == -* ]]; then
local val= local key=${token#-}
[[ "$sv" == *"="* ]] && val=${sv#*=} local flags=${key%%=*}
local i ch local value=
for ((i = 0; i < ${#flags}; i++)); do [[ "$key" == *"="* ]] && value=${key#*=}
ch=${flags:i:1}
TOKENS+=("narg::${ch}") local index flag
for ((index = 0; index < ${#flags}; index++)); do
flag=${flags:index:1}
TOKENS+=("narg::${flag}")
done done
[[ -n "$val" ]] && TOKENS+=("value::${val}")
[[ -n "$value" ]] && TOKENS+=("value::${value}")
continue continue
fi fi
TOKENS+=("unk::${t}")
# Unknown: Command, Positional or Value
TOKENS+=("unk::${token}")
done done
} }
# --- schema + parse ----------------------------------------------------------
declare -A S A declare -A S A
_generate_schema() { _generate_schema() {
@ -57,29 +63,37 @@ _generate_schema() {
A=() A=()
local spec_name=$1 local spec_name=$1
local -n SPEC_REF="$spec_name" local -n SPEC_REF="$spec_name"
local _id=100 local _id=100
local -a pos=() cmds=() local -a pos=() cmds=()
local root_added_help=0 local root_added_help=0
for entry in "${SPEC_REF[@]}"; do for entry in "${SPEC_REF[@]}"; do
IFS=';' read -r -a parts <<<"$entry" IFS=';' read -r -a elements <<<"$entry"
case "${parts[0]}" in case "${elements[0]}" in
command) command)
local id=$_id local id=$_id
((_id++)) ((_id++))
IFS=',' read -r -a aliases <<<"${parts[1]}" IFS=',' read -r -a aliases <<<"${elements[1]}"
# Schema
S["$id.entryType"]="command" S["$id.entryType"]="command"
S["$id.name"]="${aliases[0]}" S["$id.name"]="${aliases[0]}"
S["$id.help"]="${parts[2]}" S["$id.help"]="${elements[2]}"
S["$id.args"]="" S["$id.args"]=""
# Aliases
if ((${#cmds[@]} == 0)); then if ((${#cmds[@]} == 0)); then
A["cmd::root"]=$id A["cmd::root"]=$id
else else
local last=$((${#cmds[@]} - 1)) local last=$((${#cmds[@]} - 1))
for alias in "${aliases[@]}"; do A["$(join "${cmds[$last]}" "cmd::${alias}")"]=$id; done for alias in "${aliases[@]}"; do
A["$(join "${cmds[$last]}" "cmd::${alias}")"]=$id
done
fi fi
# Control
cmds+=("$id") cmds+=("$id")
pos+=(0) pos+=(0)
@ -108,12 +122,12 @@ _generate_schema() {
argument) argument)
local id=$_id local id=$_id
((_id++)) ((_id++))
IFS=',' read -r -a aliases <<<"${parts[1]}" IFS=',' read -r -a aliases <<<"${elements[1]}"
local name="${aliases[0]}" local name="${aliases[0]}"
local dest="$name" required="false" atype="positional" value="" help="" local dest="$name" required="false" atype="positional" value="" help=""
local i kv k v local i kv k v
for ((i = 2; i < ${#parts[@]}; i++)); do for ((i = 2; i < ${#elements[@]}; i++)); do
kv=${parts[i]} kv=${elements[i]}
if [[ "$kv" == *":"* ]]; then if [[ "$kv" == *":"* ]]; then
k=${kv%%:*} k=${kv%%:*}
v=${kv#*:} v=${kv#*:}
@ -156,7 +170,7 @@ _generate_schema() {
esac esac
;; ;;
*) *)
printf 'Error: Invalid entry type: "%s"\n' "${parts[0]}" >&2 printf 'Error: Invalid entry type: "%s"\n' "${elements[0]}" >&2
return 1 return 1
;; ;;
esac esac