From dacb3aeb09ec76e1c04c0e3d522d7bf433c2043b Mon Sep 17 00:00:00 2001 From: Tomas Mirchev Date: Fri, 31 Oct 2025 21:36:52 +0200 Subject: [PATCH] bash v2 --- barg | 100 ++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 57 insertions(+), 43 deletions(-) mode change 100644 => 100755 barg diff --git a/barg b/barg old mode 100644 new mode 100755 index deac21c..66fa9e0 --- a/barg +++ b/barg @@ -1,55 +1,61 @@ -# barg - Bash argument parser + tiny CLI framework -# Bash 5+ +#!/usr/bin/env bash -# --- helpers ----------------------------------------------------------------- join() { local out="" sep="" - for x in "$@"; do [[ -n "$x" ]] && { - out+="${sep}${x}" - sep="." - }; done + for x in "$@"; do + if [[ -n "$x" ]]; then + out+="${sep}${x}" + sep="." + fi + done printf '%s' "$out" } -# --- tokenizer --------------------------------------------------------------- tokenize_argv() { - local prog=$1 shift - TOKENS=() - TOKENS+=("root::${prog}") - local -a args=("$@") - while ((${#args[@]})); do - local t=${args[0]} - args=("${args[@]:1}") - if [[ "$t" == "--" ]]; then - TOKENS+=("rest::${args[*]}") + TOKENS=("root::dev") + local -a argv=("$@") + + while ((${#argv[@]})); do + local token=${argv[0]} + argv=("${argv[@]:1}") + + # Rest + if [[ "$token" == "--" ]]; then + TOKENS+=("rest::${argv[*]}") break fi - if [[ "$t" == --* ]]; then - local kv=${t#--} - local key=${kv%%=*} - TOKENS+=("narg::${key}") - [[ "$kv" == *"="* ]] && TOKENS+=("value::${kv#*=}") + + # Named Argument + Value: Option or Flag (long form) + if [[ "$token" == --* ]]; then + local key=${token#--} + TOKENS+=("narg::${key%%=*}") + [[ "$key" == *"="* ]] && TOKENS+=("value::${key#*=}") continue fi - if [[ "$t" == -* ]]; then - local sv=${t#-} - local flags=${sv%%=*} - local val= - [[ "$sv" == *"="* ]] && val=${sv#*=} - local i ch - for ((i = 0; i < ${#flags}; i++)); do - ch=${flags:i:1} - TOKENS+=("narg::${ch}") + + # Named Argument + Value: Option or Flag (short form) + if [[ "$token" == -* ]]; then + local key=${token#-} + local flags=${key%%=*} + local value= + [[ "$key" == *"="* ]] && value=${key#*=} + + local index flag + for ((index = 0; index < ${#flags}; index++)); do + flag=${flags:index:1} + TOKENS+=("narg::${flag}") done - [[ -n "$val" ]] && TOKENS+=("value::${val}") + + [[ -n "$value" ]] && TOKENS+=("value::${value}") continue fi - TOKENS+=("unk::${t}") + + # Unknown: Command, Positional or Value + TOKENS+=("unk::${token}") done } -# --- schema + parse ---------------------------------------------------------- declare -A S A _generate_schema() { @@ -57,29 +63,37 @@ _generate_schema() { A=() local spec_name=$1 local -n SPEC_REF="$spec_name" + local _id=100 local -a pos=() cmds=() + local root_added_help=0 for entry in "${SPEC_REF[@]}"; do - IFS=';' read -r -a parts <<<"$entry" - case "${parts[0]}" in + IFS=';' read -r -a elements <<<"$entry" + case "${elements[0]}" in command) local id=$_id ((_id++)) - IFS=',' read -r -a aliases <<<"${parts[1]}" + IFS=',' read -r -a aliases <<<"${elements[1]}" + + # Schema S["$id.entryType"]="command" S["$id.name"]="${aliases[0]}" - S["$id.help"]="${parts[2]}" + S["$id.help"]="${elements[2]}" S["$id.args"]="" + # Aliases if ((${#cmds[@]} == 0)); then A["cmd::root"]=$id else 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 + # Control cmds+=("$id") pos+=(0) @@ -108,12 +122,12 @@ _generate_schema() { argument) local id=$_id ((_id++)) - IFS=',' read -r -a aliases <<<"${parts[1]}" + IFS=',' read -r -a aliases <<<"${elements[1]}" local name="${aliases[0]}" local dest="$name" required="false" atype="positional" value="" help="" local i kv k v - for ((i = 2; i < ${#parts[@]}; i++)); do - kv=${parts[i]} + for ((i = 2; i < ${#elements[@]}; i++)); do + kv=${elements[i]} if [[ "$kv" == *":"* ]]; then k=${kv%%:*} v=${kv#*:} @@ -156,7 +170,7 @@ _generate_schema() { esac ;; *) - printf 'Error: Invalid entry type: "%s"\n' "${parts[0]}" >&2 + printf 'Error: Invalid entry type: "%s"\n' "${elements[0]}" >&2 return 1 ;; esac