Add positional arg var

This commit is contained in:
2024-09-07 06:26:29 +00:00
parent c55c4383d2
commit 67e6bf8567
2 changed files with 83 additions and 24 deletions

View File

@@ -96,6 +96,7 @@ Configuration variables must be assigned before calling `_parse`.
| _accept_options | `auto` | `any` — The script accepts any options.<br>`none` — The script does not accept any options.<br>`mapped_only` — The script accepts only mapped options.<br>`auto` — The script accepts only mapped options if at least one has been mapped. Otherwise, it accepts any options. | | _accept_options | `auto` | `any` — The script accepts any options.<br>`none` — The script does not accept any options.<br>`mapped_only` — The script accepts only mapped options.<br>`auto` — The script accepts only mapped options if at least one has been mapped. Otherwise, it accepts any options. |
| _default_max_positional_args | | Maximum number of positional arguments. A different value can be set for each command (see [_map_command](#_map_command)). | | _default_max_positional_args | | Maximum number of positional arguments. A different value can be set for each command (see [_map_command](#_map_command)). |
| _default_min_positional_args | `0` | Minimum number of positional arguments. A different value can be set for each command (see [_map_command](#_map_command)). | | _default_min_positional_args | `0` | Minimum number of positional arguments. A different value can be set for each command (see [_map_command](#_map_command)). |
| _default_positional_arg_variable || Name of the variable that will store the single positional argument. Implicitly sets `_default_max_positional_args` and `_default_min_positional_args` to 1. Command-specific values for `max_args` and `arg_variable` disables this behavior. |
| _mapping_key_value_delimiter | `=` | Key-value delimiter for options mapping (see [_map_option](#_map_option)). | | _mapping_key_value_delimiter | `=` | Key-value delimiter for options mapping (see [_map_option](#_map_option)). |
| _mapping_values_delimiter | `,` | Values delimiter for options mapping (see [_map_option](#_map_option)). | | _mapping_values_delimiter | `,` | Values delimiter for options mapping (see [_map_option](#_map_option)). |
| _option_duplicates_allowed | `false` | `true` — Multiple uses of options are allowed.<br>`false` — Multiple uses of options are not allowed.| | _option_duplicates_allowed | `false` | `true` — Multiple uses of options are allowed.<br>`false` — Multiple uses of options are not allowed.|
@@ -131,6 +132,7 @@ Maps a command. Takes key-value pairs as arguments. Key and values list are sepa
| description | Command description. Currently not used. | | description | Command description. Currently not used. |
| min_args | Minimum number of positional arguments when using the command. | | min_args | Minimum number of positional arguments when using the command. |
| max_args | Maximum number of positional arguments when using the command. | | max_args | Maximum number of positional arguments when using the command. |
| arg_variable | Name of the variable that will store the command's positional argument. Implicitly sets `min_args` and `max_args` to 1. |
```bash ```bash
_map_command \ _map_command \

103
parser.sh
View File

@@ -4,6 +4,7 @@ _accept_command=auto # auto, none, any, mapped_only
_accept_options=auto # auto, none, any, mapped_only _accept_options=auto # auto, none, any, mapped_only
_default_max_positional_args="" _default_max_positional_args=""
_default_min_positional_args=0 _default_min_positional_args=0
_default_positional_arg_variable=""
_mapping_key_value_delimiter="=" _mapping_key_value_delimiter="="
_mapping_values_delimiter="," _mapping_values_delimiter=","
_option_duplicates_allowed=true _option_duplicates_allowed=true
@@ -151,6 +152,33 @@ _mapped_options_only() {
[ "$_mapped_options_count" -gt 0 ] [ "$_mapped_options_count" -gt 0 ]
} }
_is_free_var_name() {
if [ -n "$_default_positional_arg_variable" ] && [ "$_default_positional_arg_variable" = "$1" ]; then
echo "variable is already used as default positional arg variable: $1."
return 1
fi
_i=1
while [ "$_i" -le "$_mapped_options_count" ]; do
if [ "$1" = "$(_var_value "_options_${_i}_variable")" ]; then
echo "variable is already mapped for option #${_i}: $1."
return 1
fi
_i=$(_math "$_i + 1")
done
_i=1
while [ "$_i" -le "$_mapped_commands_count" ]; do
if [ "$1" = "$(_var_value "_commands_${_i}_arg_variable")" ]; then
echo "arg variable is already mapped for command #${_i}: $1."
return 1
fi
_i=$(_math "$_i + 1")
done
}
_map_command() { _map_command() {
_command_index=$(_math "$_mapped_commands_count + 1") _command_index=$(_math "$_mapped_commands_count + 1")
_mapping_command_prefix="_commands_${_command_index}" _mapping_command_prefix="_commands_${_command_index}"
@@ -179,6 +207,10 @@ _map_command() {
_validate_command_min_args "$_map_value" _validate_command_min_args "$_map_value"
elif [ "$_map_key" = "name" ]; then elif [ "$_map_key" = "name" ]; then
_validate_command_name "$_map_value" _validate_command_name "$_map_value"
elif [ "$_map_key" = "arg_variable" ]; then
_validate_command_arg_variable "$_map_value"
_assign "${_mapping_command_prefix}_min_args" 1
_assign "${_mapping_command_prefix}_max_args" 1
else else
_err "Invalid command #${_command_index} mapping key: $_map_key." _err "Invalid command #${_command_index} mapping key: $_map_key."
fi fi
@@ -233,6 +265,8 @@ _map_option() {
_validate_option_aliases "$_map_value" _validate_option_aliases "$_map_value"
elif [ "$_map_key" = "variable" ]; then elif [ "$_map_key" = "variable" ]; then
_validate_option_variable "$_map_value" _validate_option_variable "$_map_value"
_assign "${_mapping_option_prefix}_min_args" 1
_assign "${_mapping_option_prefix}_max_args" 1
elif [ "$_map_key" = "description" ]; then elif [ "$_map_key" = "description" ]; then
_validate_option_description "$_map_value" _validate_option_description "$_map_value"
elif [ "$_map_key" = "max_args" ]; then elif [ "$_map_key" = "max_args" ]; then
@@ -345,6 +379,31 @@ _validate_command_name() {
done done
} }
_validate_command_arg_variable() {
if [ -n "$(_var_value "${_mapping_command_prefix}_arg_variable")" ]; then
_err "Command #${_command_index} arg variable is already mapped."
fi
_min_args=$(_var_value "${_mapping_command_prefix}_min_args")
_max_args=$(_var_value "${_mapping_command_prefix}_max_args")
if { [ -n "$_min_args" ] && [ "$_min_args" -ne 1 ]; } || { [ -n "$_max_args" ] && [ "$_max_args" -ne 1 ]; }; then
_err "Command #${_command_index} arg variable can only be used with commands that requires single argument."
fi
if [ -z "$1" ]; then
_err "Command #${_command_index} arg variable cannot be empty."
fi
if ! _is_valid_var_name "$1"; then
_err "Command #${_command_index} arg variable is invalid: $1. Must be a valid variable name."
fi
if ! _description=$(_is_free_var_name "$1"); then
_err "Command #${_command_index} ${_description}"
fi
}
_validate_option_aliases() { _validate_option_aliases() {
if [ -n "$(_var_value "${_mapping_option_prefix}_aliases")" ]; then if [ -n "$(_var_value "${_mapping_option_prefix}_aliases")" ]; then
_err "Option #${_option_index} aliases are already mapped." _err "Option #${_option_index} aliases are already mapped."
@@ -444,14 +503,9 @@ _validate_option_variable() {
_err "Option #${_option_index} variable is invalid: $1. Must be a valid variable name." _err "Option #${_option_index} variable is invalid: $1. Must be a valid variable name."
fi fi
_i=1 if ! _description=$(_is_free_var_name "$1"); then
while [ "$_i" -le "$_mapped_options_count" ]; do _err "Option #${_option_index} ${_description}"
if [ "$1" = "$(_var_value "_options_${_i}_variable")" ]; then
_err "Option #${_option_index} variable is already mapped for option #${_i}: $1."
fi fi
_i=$(_math "$_i + 1")
done
} }
_validate_option_description() { _validate_option_description() {
@@ -477,10 +531,6 @@ _validate_option_max_args() {
_err "Option #${_option_index} max args is invalid: $1. Must be a non-negative integer." _err "Option #${_option_index} max args is invalid: $1. Must be a non-negative integer."
fi fi
if [ -n "$(_var_value "${_mapping_option_prefix}_variable")" ] && [ "$1" -ne 1 ]; then
_err "Option #${_option_index} max args is invalid: $1. Implicitly set to 1 when option variable was set."
fi
if (_is "$(_var_value "${_mapping_option_prefix}_required")") && [ "$1" -eq 0 ]; then if (_is "$(_var_value "${_mapping_option_prefix}_required")") && [ "$1" -eq 0 ]; then
_err "Option #${_option_index} must be removed as constant. It is required without arguments." _err "Option #${_option_index} must be removed as constant. It is required without arguments."
fi fi
@@ -498,10 +548,6 @@ _validate_option_min_args() {
if ! _is_int "$1"; then if ! _is_int "$1"; then
_err "Option #${_option_index} min args is invalid: $1. Must be a non-negative integer." _err "Option #${_option_index} min args is invalid: $1. Must be a non-negative integer."
fi fi
if [ -n "$(_var_value "${_mapping_option_prefix}_variable")" ] && [ "$1" -ne 1 ]; then
_err "Option #${_option_index} min args is invalid: $1. Implicitly set to 1 when option variable was set."
fi
} }
_validate_option_required() { _validate_option_required() {
@@ -640,25 +686,36 @@ _parse_positional_args() {
_err "Positional arguments must be placed before options: $1." _err "Positional arguments must be placed before options: $1."
fi fi
if [ -z "$_command_index" ]; then if [ -n "$_command_index" ]; then
_max_args_count="$_default_max_positional_args" _max_args=$(_var_value "_commands_${_command_index}_max_args")
else _arg_variable="$(_var_value "_commands_${_command_index}_arg_variable")"
_max_args_count=$(_var_value "_commands_${_command_index}_max_args") fi
if [ -z "$_max_args" ]; then
_max_args=$_default_max_positional_args
fi
if [ -z "$_arg_variable" ]; then
_arg_variable="$_default_positional_arg_variable"
fi fi
while [ $# -gt 0 ]; do while [ $# -gt 0 ]; do
_positional_arg_index=$(_math "$_positional_args_count + 1") _positional_arg_index=$(_math "$_positional_args_count + 1")
if [ -n "$_max_args_count" ] && [ "$_positional_arg_index" -gt "$_max_args_count" ]; then if [ -n "$_max_args" ] && [ "$_positional_arg_index" -gt "$_max_args" ]; then
if [ -z "$_command_index" ]; then if [ -z "$_command_index" ]; then
_err "Maximum $_max_args_count positional argument(s) allowed." _err "Maximum $_max_args positional argument(s) allowed."
else else
_err "Maximum $_max_args_count positional argument(s) allowed for command: $(_var_value "_commands_${_command_index}_name")." _err "Maximum $_max_args positional argument(s) allowed for command: $(_var_value "_commands_${_command_index}_name")."
fi fi
fi fi
_assign "_positional_args_${_positional_arg_index}" "$1" _assign "_positional_args_${_positional_arg_index}" "$1"
_positional_args_count=$_positional_arg_index _assign "_positional_args_count" "$_positional_arg_index"
if [ -n "$_arg_variable" ]; then
_assign "$_arg_variable" "$1"
fi
shift shift
done done