You've already forked sh-args-parser
mirror of
https://github.com/nikolaypronchev/sh-args-parser.git
synced 2026-04-17 05:56:31 +03:00
Add code
This commit is contained in:
273
README.md
Normal file
273
README.md
Normal file
@@ -0,0 +1,273 @@
|
|||||||
|
# Sh args parser
|
||||||
|
|
||||||
|
This is POSIX-compliant code for parsing shell script arguments. It helps you focus on writing the script logic by separating argument parsing and basic validation.
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
1. [Installation](#installation)
|
||||||
|
2. [Usage](#usage)
|
||||||
|
3. [Syntax conventions](#argument-syntax-conventions)
|
||||||
|
4. [Configuration](#configuration)
|
||||||
|
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Include the `parser.sh` file in your script using [`dot`](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#dot) or [`source`](https://www.gnu.org/software/bash/manual/bash.html#index-source).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
. parser.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Or copy the contents of the `parser.sh` file into your script.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The parser provides functions for working with arguments. They become available after passing all script arguments to the parser using `_parse`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
. parser.sh
|
||||||
|
|
||||||
|
# In most cases, all script arguments are passed to _parse: $@.
|
||||||
|
_parse --foo bar baz
|
||||||
|
|
||||||
|
_is_used_option '--foo' && echo "Option 'foo' is used"
|
||||||
|
_get_option_args_count '--foo'
|
||||||
|
_get_option_arg '--foo' 2
|
||||||
|
```
|
||||||
|
```
|
||||||
|
Option 'foo' is used
|
||||||
|
2
|
||||||
|
baz
|
||||||
|
```
|
||||||
|
|
||||||
|
### What's next?
|
||||||
|
|
||||||
|
1. [Learn about the argument syntax.](#argument-syntax-conventions)
|
||||||
|
2. [Configure the parser to suit your needs.](#configuration)
|
||||||
|
3. [Map commands.](#_map_command)
|
||||||
|
4. [Map options.](#_map_option)
|
||||||
|
5. [Learn about the functions for working with parsing results.](#functions-for-working-with-parsing-results)
|
||||||
|
|
||||||
|
## Argument Syntax Conventions
|
||||||
|
|
||||||
|
The argument syntax is based on, but does not fully comply with, the conventions used in POSIX <sup>[1](https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html), [2](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html)</sup>.
|
||||||
|
|
||||||
|
### General
|
||||||
|
- Commands, options, and positional arguments are separated by spaces.
|
||||||
|
- All script arguments are case-sensitive.
|
||||||
|
|
||||||
|
### Commands
|
||||||
|
A command typically represents the core action performed by the script: `run`, `build`, `issue`, etc. If the script is designed to perform a single action, a command is generally not required.
|
||||||
|
|
||||||
|
- A script may or may not accept a command.
|
||||||
|
- If the script accepts a command, it must be the first argument.
|
||||||
|
- A command can contain Latin letters, digits, `-`, and `_`.
|
||||||
|
|
||||||
|
### Positional Arguments
|
||||||
|
|
||||||
|
- Positional arguments are placed after the command, if present.
|
||||||
|
- The presence and number of positional arguments are determined by the script's logic.
|
||||||
|
- After the special argument --, all arguments are considered positional. This allows passing arguments that start with a dash and might be confused with options.
|
||||||
|
|
||||||
|
### Options
|
||||||
|
Options are script parameters. Each option has at least one alias by which it can be specified in the command line. Options often have both short and long aliases, such as `-h` and `--help`.
|
||||||
|
|
||||||
|
- Short aliases start with `-` and consist of a single Latin letter;
|
||||||
|
- Long aliases start with `--` and consist of Latin letters, digits, `-`, and `_`;
|
||||||
|
- Short aliases can be used individually or combined. For example, `-b -a -r` is equivalent to `-bar`;
|
||||||
|
- Options may have arguments. The presence and number of arguments are determined by the specific option and the script's logic.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Configuration is defined by assigning values to variables before using the parser. For example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
_accept_command=true
|
||||||
|
```
|
||||||
|
Configuration variables must be assigned before calling `_parse`.
|
||||||
|
|
||||||
|
| Name | Default Value | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| _accept_command | `auto` | `any` — The script accepts a command.<br>`none` — The script does not accept a command.<br>`mapped_only` — The script accepts only a mapped command.<br>`auto` — The script accepts a command if at least one has been mapped. |
|
||||||
|
| _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_min_positional_args | `0` | Minimum number of positional arguments. A different value can be set for each command (see [_map_command](#_map_command)). |
|
||||||
|
| _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)). |
|
||||||
|
| _option_duplicates_allowed | `false` | `true` — Multiple uses of options are allowed.<br>`false` — Multiple uses of options are not allowed.|
|
||||||
|
| _option_key_value_delimiter | `' '` | Option alias-args delimiter. |
|
||||||
|
| _option_values_delimiter | `' '` | Option values delimiter. |
|
||||||
|
| _option_variable_default_value | `true` | Default value assigned to the option variable (see [_map_option](#_map_option)). |
|
||||||
|
| _options_combination_allowed | `true` | `true` — Combining short option aliases into combinations is allowed.<br>`false` — Combining short option aliases is not allowed. |
|
||||||
|
| _options_combination_args_allowed | `true` | `true` — Passing arguments to the last option in a combination is allowed.<br>`false` — Passing arguments to the last option in a combination is not allowed. |
|
||||||
|
| _positional_args_placement | `any` | `any` — Positional arguments can be placed anywhere, including mixed with options.<br>`before_options` — Positional arguments are placed before options.<br>`after_options` — Positional arguments are placed after options. |
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
#### _parse
|
||||||
|
Parses the provided arguments. Typically, takes all command-line arguments `$@` as input.
|
||||||
|
```bash
|
||||||
|
# Parser configuration, command and option mapping above
|
||||||
|
|
||||||
|
_parse $@
|
||||||
|
|
||||||
|
# Script logic below
|
||||||
|
```
|
||||||
|
|
||||||
|
### Functions for command and option mapping
|
||||||
|
|
||||||
|
Mapping functions are used to specify the available commands and options of the script, as well as for their basic validation. Mapping functions must be used before calling `_parse`.
|
||||||
|
|
||||||
|
#### _map_command
|
||||||
|
|
||||||
|
Maps a command. Takes key-value pairs as arguments. Key and values list are separated by `_mapping_key_value_delimiter`.
|
||||||
|
|
||||||
|
| Key | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| name | Command name. Required key. |
|
||||||
|
| description | Command description. Currently not used. |
|
||||||
|
| min_args | Minimum number of positional arguments when using the command. |
|
||||||
|
| max_args | Maximum number of positional arguments when using the command. |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
_map_command \
|
||||||
|
name=foo \
|
||||||
|
min_args=1 \
|
||||||
|
max_args=2
|
||||||
|
```
|
||||||
|
|
||||||
|
### _map_option
|
||||||
|
|
||||||
|
Maps an option. Takes key-value pairs as arguments. Key and values list are separated by `_mapping_key_value_delimiter`. Values of the same key are separated by `_mapping_values_delimiter`.
|
||||||
|
|
||||||
|
| Key | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| aliases | List of option aliases. Required key. |
|
||||||
|
| description | Option description. Currently not used. |
|
||||||
|
| min_args | Minimum number of option arguments. |
|
||||||
|
| max_args | Maximum number of option arguments. |
|
||||||
|
| variable | Name of the variable that will store the value when the option is used. |
|
||||||
|
| variable_value | Value that will be assigned to the option variable when used. |
|
||||||
|
| required | If the `required` flag is present, the option will be considered mandatory. |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
_map_option \
|
||||||
|
aliases=-f,--foo \
|
||||||
|
min_args=1 \
|
||||||
|
max_args=10 \
|
||||||
|
required
|
||||||
|
```
|
||||||
|
|
||||||
|
### Functions for working with parsing results
|
||||||
|
|
||||||
|
#### _get_command
|
||||||
|
|
||||||
|
Outputs the used command.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
_accept_command=true
|
||||||
|
|
||||||
|
_parse foo bar baz
|
||||||
|
|
||||||
|
_get_command
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
foo
|
||||||
|
```
|
||||||
|
|
||||||
|
#### _is_used_command
|
||||||
|
|
||||||
|
Checks if the command passed as the first argument was used.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
_accept_command=true
|
||||||
|
|
||||||
|
_parse foo bar baz
|
||||||
|
|
||||||
|
_is_used_command foo && echo 'Command "foo" was used'
|
||||||
|
_is_used_command bar && echo 'Command "bar" was used'
|
||||||
|
```
|
||||||
|
```
|
||||||
|
Command "foo" was used
|
||||||
|
```
|
||||||
|
|
||||||
|
#### _get_positional_args_count
|
||||||
|
|
||||||
|
Outputs the number of positional arguments.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
_parse foo bar baz
|
||||||
|
_get_positional_args_count
|
||||||
|
```
|
||||||
|
```
|
||||||
|
3
|
||||||
|
```
|
||||||
|
|
||||||
|
#### _get_positional_arg
|
||||||
|
|
||||||
|
Outputs the positional argument at the index passed as the first argument. Indexes start from 1.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
_parse foo bar baz
|
||||||
|
_get_positional_arg 3
|
||||||
|
```
|
||||||
|
```
|
||||||
|
baz
|
||||||
|
```
|
||||||
|
|
||||||
|
#### _is_used_option
|
||||||
|
|
||||||
|
Checks if the option with the alias passed as the first argument was used.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
_parse foo --bar -abc
|
||||||
|
|
||||||
|
_is_used_option foo && echo 'Option "--foo" was used'
|
||||||
|
_is_used_option --bar && echo 'Option "--bar" was used'
|
||||||
|
_is_used_option bar && echo 'Option "bar" was used'
|
||||||
|
_is_used_option -c && echo 'Option "-c" was used'
|
||||||
|
|
||||||
|
```
|
||||||
|
```
|
||||||
|
Option "--bar" was used
|
||||||
|
Option "-c" was used
|
||||||
|
```
|
||||||
|
|
||||||
|
#### _get_option_args_count
|
||||||
|
|
||||||
|
Outputs the number of arguments for the option with the alias passed as the first argument.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
_parse -o foo bar baz
|
||||||
|
|
||||||
|
_get_option_args_count -o
|
||||||
|
```
|
||||||
|
```
|
||||||
|
3
|
||||||
|
```
|
||||||
|
|
||||||
|
#### _get_option_arg
|
||||||
|
|
||||||
|
Outputs the argument for the option with the alias passed as the first argument, at the index provided as the second argument. Indexes start from 1.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
_parse -o foo bar baz
|
||||||
|
|
||||||
|
_get_option_arg -o 3
|
||||||
|
```
|
||||||
|
```
|
||||||
|
baz
|
||||||
|
```
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
- Bug: required + variable/variable_value при разметке опций не имеет смысла, т.к. переменная будет константой;
|
||||||
|
- Add examples;
|
||||||
|
- Implement "Help" generation;
|
||||||
|
- Add tests.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the terms of the MIT license.
|
||||||
846
parser.sh
Executable file
846
parser.sh
Executable file
@@ -0,0 +1,846 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
_accept_command=auto # auto, none, any, mapped_only
|
||||||
|
_accept_options=auto # auto, none, any, mapped_only
|
||||||
|
_default_max_positional_args=""
|
||||||
|
_default_min_positional_args=0
|
||||||
|
_mapping_key_value_delimiter="="
|
||||||
|
_mapping_values_delimiter=","
|
||||||
|
_option_duplicates_allowed=true
|
||||||
|
_option_key_value_delimiter=" "
|
||||||
|
_option_variable_default_value=true
|
||||||
|
_option_values_delimiter=" "
|
||||||
|
_options_combination_allowed=true
|
||||||
|
_options_combination_args_allowed=true
|
||||||
|
_positional_args_placement=any # any, before_options, after_options
|
||||||
|
|
||||||
|
_mapped_commands_count=0
|
||||||
|
_mapped_options_count=0
|
||||||
|
_positional_args_count=0
|
||||||
|
|
||||||
|
_err() {
|
||||||
|
echo "$1"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_math() {
|
||||||
|
printf "%s" "$(($@))"
|
||||||
|
}
|
||||||
|
|
||||||
|
_is() {
|
||||||
|
[ "$1" = "true" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
_is_not() {
|
||||||
|
[ "$1" != "true" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
_is_int() {
|
||||||
|
case $1 in
|
||||||
|
[0-9])
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
[1-9][0-9]*)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
_assign() {
|
||||||
|
if ! _is_valid_var_name "$1"; then
|
||||||
|
_err "Invalid variable name: $1."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_value=$2
|
||||||
|
_escaped_value=""
|
||||||
|
|
||||||
|
while [ -n "$_value" ]; do
|
||||||
|
_part=${_value%%\'*}
|
||||||
|
_escaped_value="$_escaped_value$_part"
|
||||||
|
_value=${_value#"$_part"}
|
||||||
|
|
||||||
|
if [ -n "$_value" ]; then
|
||||||
|
_escaped_value="$_escaped_value'\''"
|
||||||
|
_value=${_value#\'}
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
eval "$1='$_escaped_value'"
|
||||||
|
}
|
||||||
|
|
||||||
|
_var_value() {
|
||||||
|
if _is_valid_var_name "$1"; then
|
||||||
|
eval "echo \"\$$1\""
|
||||||
|
else
|
||||||
|
_err "Invalid variable name: $1."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_starts_with() {
|
||||||
|
case "$1" in
|
||||||
|
"$2"*)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
_get_mapping_entry_key() {
|
||||||
|
echo "${1%%["${_mapping_key_value_delimiter}"]*}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_get_mapping_entry_value() {
|
||||||
|
case "$1" in
|
||||||
|
*"$_mapping_key_value_delimiter"*)
|
||||||
|
echo "${1#*"${_mapping_key_value_delimiter}"}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
_str_contains() {
|
||||||
|
case "$1" in
|
||||||
|
*"$2"*)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
_aliases_list_contains() {
|
||||||
|
_str_contains \
|
||||||
|
"${_mapping_values_delimiter}$1${_mapping_values_delimiter}" \
|
||||||
|
"${_mapping_values_delimiter}$2${_mapping_values_delimiter}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_is_valid_var_name() {
|
||||||
|
case "$1" in
|
||||||
|
[!a-zA-Z_]*)
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
*[!a-zA-Z0-9_]*)
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
_command_required() {
|
||||||
|
[ "$_accept_command" = "none" ] && return 1
|
||||||
|
[ "$_accept_command" != "auto" ] && return 0
|
||||||
|
|
||||||
|
_i=1
|
||||||
|
while [ "$_i" -le "$_mapped_commands_count" ]; do
|
||||||
|
_command_auto_mapped=$(_var_value "_commands_${_i}_auto")
|
||||||
|
|
||||||
|
if _is_not "$_command_auto_mapped"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
_i=$(_math "$_i + 1")
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_map_command() {
|
||||||
|
_command_index=$(_math "$_mapped_commands_count + 1")
|
||||||
|
_mapping_command_prefix="_commands_${_command_index}"
|
||||||
|
|
||||||
|
while [ "$#" -gt 0 ]; do
|
||||||
|
_map_entry="$1"
|
||||||
|
|
||||||
|
if _str_contains "$_map_entry" "$_mapping_key_value_delimiter"; then
|
||||||
|
_map_key=$(_get_mapping_entry_key "$_map_entry")
|
||||||
|
_map_value=$(_get_mapping_entry_value "$_map_entry")
|
||||||
|
if [ -z "$_map_key" ] || [ -z "$_map_value" ]; then
|
||||||
|
_err "Invalid command #${_command_index} mapping entry: $_map_entry."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
_map_key="$_map_entry"
|
||||||
|
_map_value=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Per-key command mapping validation.
|
||||||
|
|
||||||
|
if [ "$_map_key" = "description" ]; then
|
||||||
|
_validate_command_description "$_map_value"
|
||||||
|
elif [ "$_map_key" = "max_args" ]; then
|
||||||
|
_validate_command_max_args "$_map_value"
|
||||||
|
elif [ "$_map_key" = "min_args" ]; then
|
||||||
|
_validate_command_min_args "$_map_value"
|
||||||
|
elif [ "$_map_key" = "name" ]; then
|
||||||
|
_validate_command_name "$_map_value"
|
||||||
|
else
|
||||||
|
_err "Invalid command #${_command_index} mapping key: $_map_key."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_assign "${_mapping_command_prefix}_${_map_key}" "$_map_value"
|
||||||
|
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
# Post-mapping command validation.
|
||||||
|
|
||||||
|
if [ -z "$(_var_value "${_mapping_command_prefix}_name")" ]; then
|
||||||
|
_err "Missing command #${_command_index} name."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_mapped_commands_count=$_command_index
|
||||||
|
}
|
||||||
|
|
||||||
|
_map_command_auto() {
|
||||||
|
_command_index=$(_math "$_mapped_commands_count + 1")
|
||||||
|
_mapping_command_prefix="_commands_${_command_index}"
|
||||||
|
|
||||||
|
_validate_command_name "$1"
|
||||||
|
|
||||||
|
_assign "${_mapping_command_prefix}_name" "$1"
|
||||||
|
_assign "${_mapping_command_prefix}_auto" "true"
|
||||||
|
|
||||||
|
_mapped_commands_count=$_command_index
|
||||||
|
}
|
||||||
|
|
||||||
|
_map_option() {
|
||||||
|
_option_index=$(_math "$_mapped_options_count + 1")
|
||||||
|
_mapping_option_prefix="_options_${_option_index}"
|
||||||
|
|
||||||
|
while [ "$#" -gt 0 ]; do
|
||||||
|
_map_entry="$1"
|
||||||
|
|
||||||
|
if _str_contains "$_map_entry" "$_mapping_key_value_delimiter"; then
|
||||||
|
_map_key=$(_get_mapping_entry_key "$_map_entry")
|
||||||
|
_map_value=$(_get_mapping_entry_value "$_map_entry")
|
||||||
|
if [ -z "$_map_key" ] || [ -z "$_map_value" ]; then
|
||||||
|
_err "Invalid option #${_option_index} mapping entry: $_map_entry."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
_map_key="$_map_entry"
|
||||||
|
_map_value=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Per-key option mapping validation.
|
||||||
|
|
||||||
|
if [ "$_map_key" = "aliases" ]; then
|
||||||
|
_validate_option_aliases "$_map_value"
|
||||||
|
elif [ "$_map_key" = "variable" ]; then
|
||||||
|
_validate_option_variable "$_map_value"
|
||||||
|
elif [ "$_map_key" = "variable_value" ]; then
|
||||||
|
_validate_option_variable_value "$_map_value"
|
||||||
|
elif [ "$_map_key" = "description" ]; then
|
||||||
|
_validate_option_description "$_map_value"
|
||||||
|
elif [ "$_map_key" = "max_args" ]; then
|
||||||
|
_validate_option_max_args "$_map_value"
|
||||||
|
elif [ "$_map_key" = "min_args" ]; then
|
||||||
|
_validate_option_min_args "$_map_value"
|
||||||
|
elif [ "$_map_key" = "required" ]; then
|
||||||
|
_validate_option_required "$_map_value"
|
||||||
|
_map_value=true
|
||||||
|
else
|
||||||
|
_err "Invalid option #${_option_index} mapping key: $_map_key."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_assign "${_mapping_option_prefix}_${_map_key}" "$_map_value"
|
||||||
|
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
# Post-mapping option validation.
|
||||||
|
|
||||||
|
if [ -z "$(_var_value "${_mapping_option_prefix}_aliases")" ]; then
|
||||||
|
_err "Missing option #${_option_index} aliases."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_mapped_options_count=$_option_index
|
||||||
|
}
|
||||||
|
|
||||||
|
_map_option_auto() {
|
||||||
|
_option_index=$(_math "$_mapped_options_count + 1")
|
||||||
|
_mapping_option_prefix="_options_${_option_index}"
|
||||||
|
|
||||||
|
_validate_option_aliases "$1"
|
||||||
|
|
||||||
|
_assign "${_mapping_option_prefix}_aliases" "$1"
|
||||||
|
_assign "${_mapping_option_prefix}_auto" "true"
|
||||||
|
|
||||||
|
_mapped_options_count=$_option_index
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_validate_command_description() {
|
||||||
|
if [ -n "$(_var_value "${_mapping_command_prefix}_description")" ]; then
|
||||||
|
_err "Command #${_command_index} description is already mapped."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_validate_command_max_args() {
|
||||||
|
if [ -n "$(_var_value "${_mapping_command_prefix}_max_args")" ]; then
|
||||||
|
_err "Command #${_command_index} max args is already mapped."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
_err "Command #${_command_index} max args cannot be empty."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _is_int "$1"; then
|
||||||
|
_err "Command #${_command_index} max args is invalid: $1. Must be a non-negative integer."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_validate_command_min_args() {
|
||||||
|
if [ -n "$(_var_value "${_mapping_command_prefix}_min_args")" ]; then
|
||||||
|
_err "Command #${_command_index} min_args is already mapped."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
_err "Command #${_command_index} min args cannot be empty."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _is_int "$1"; then
|
||||||
|
_err "Command #${_command_index} min args is invalid: $1. Must be a non-negative integer."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_validate_command_name() {
|
||||||
|
_existing_command_name=$(_var_value "${_mapping_command_prefix}_name")
|
||||||
|
|
||||||
|
if [ -n "$_existing_command_name" ]; then
|
||||||
|
_err "Command #${_command_index} name is already mapped: $_existing_command_name."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if command name not empty.
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
_err "Command #${_command_index} name is required."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if command name is valid.
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
[!a-zA-Z0-9]*)
|
||||||
|
_err "Command #${_command_index} name is invalid: $1. Must start with an alphanumeric character."
|
||||||
|
;;
|
||||||
|
*[!a-z0-9\-_]*)
|
||||||
|
_err "Command #${_command_index} name is invalid: $1. Must be alphanumeric, hyphen and underscore only."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Check if command name is unique.
|
||||||
|
|
||||||
|
_i=1
|
||||||
|
while [ "$_i" -le "$_mapped_commands_count" ]; do
|
||||||
|
if [ "$1" = "$(_var_value "_commands_${_i}_name")" ]; then
|
||||||
|
_err "Command #${_command_index} already mapped: $1."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_i=$(_math "$_i + 1")
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
_validate_option_aliases() {
|
||||||
|
if [ -n "$(_var_value "${_mapping_option_prefix}_aliases")" ]; then
|
||||||
|
_err "Option #${_option_index} aliases are already mapped."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_old_ifs="$IFS"
|
||||||
|
IFS="$_mapping_values_delimiter"
|
||||||
|
|
||||||
|
_current_option_aliases_list="$_mapping_values_delimiter"
|
||||||
|
|
||||||
|
for _option_alias in $1; do
|
||||||
|
if _aliases_list_contains "$_current_option_aliases_list" "$_option_alias"; then
|
||||||
|
_err "Option #${_option_index} alias duplicate: $_option_alias."
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$_option_alias" in
|
||||||
|
--*)
|
||||||
|
_validate_long_option_alias "${_option_alias#??}"
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
_validate_short_option_alias "${_option_alias#?}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
_err "Option #${_option_index} alias is invalid: $_option_alias. Must start with: -- or -."
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
_current_option_aliases_list="${_current_option_aliases_list}${_option_alias}${_mapping_values_delimiter}"
|
||||||
|
done
|
||||||
|
|
||||||
|
IFS="$_old_ifs"
|
||||||
|
}
|
||||||
|
|
||||||
|
_validate_long_option_alias() {
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
_err "Option #${_option_index} alias cannot be empty."
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
[!a-zA-Z0-9]*)
|
||||||
|
_err "Option #${_option_index} alias is invalid: $1. Must start with an alphanumeric character."
|
||||||
|
;;
|
||||||
|
*[!a-z0-9\-_]*)
|
||||||
|
_err "Option #${_option_index} alias is invalid: $1. Must be alphanumeric, hyphen and underscore only."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
_validate_option_alias_uniqueness "--$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
_validate_short_option_alias() {
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
_err "Option #${_option_index} alias cannot be empty."
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
[!a-zA-Z])
|
||||||
|
_err "Option #${_option_index} alias is invalid: $1. Must be a single latin letter."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
_validate_option_alias_uniqueness "-$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
_validate_option_alias_uniqueness() {
|
||||||
|
_i=1
|
||||||
|
while [ "$_i" -le "$_mapped_options_count" ]; do
|
||||||
|
if _aliases_list_contains "$(_var_value "_options_${_i}_aliases")" "$1"; then
|
||||||
|
_err "Option #${_option_index} alias is already mapped for option #${_i}: $1."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_i=$(_math "$_i + 1")
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
_validate_option_variable() {
|
||||||
|
if [ -n "$(_var_value "${_mapping_option_prefix}_variable")" ]; then
|
||||||
|
_err "Option #${_option_index} variable is already mapped."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
_err "Option #${_option_index} variable cannot be empty."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _is_valid_var_name "$1"; then
|
||||||
|
_err "Option #${_option_index} variable is invalid: $1. Must be a valid variable name."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_i=1
|
||||||
|
while [ "$_i" -le "$_mapped_options_count" ]; do
|
||||||
|
if [ "$1" = "$(_var_value "_options_${_i}_variable")" ]; then
|
||||||
|
_err "Option #${_option_index} variable is already mapped for option #${_i}: $1."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_i=$(_math "$_i + 1")
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
_validate_option_variable_value() {
|
||||||
|
if [ -n "$(_var_value "${_mapping_option_prefix}_variable_value")" ]; then
|
||||||
|
_err "Option #${_option_index} variable value is already mapped."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
_err "Option #${_option_index} variable value cannot be empty."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_validate_option_description() {
|
||||||
|
if [ -n "$(_var_value "${_mapping_option_prefix}_description")" ]; then
|
||||||
|
_err "Option #${_option_index} description is already mapped."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
_err "Option #${_option_index} description cannot be empty."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_validate_option_max_args() {
|
||||||
|
if [ -n "$(_var_value "${_mapping_option_prefix}_max_args")" ]; then
|
||||||
|
_err "Option #${_option_index} max args are already mapped."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
_err "Option #${_option_index} max args cannot be empty."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _is_int "$1"; then
|
||||||
|
_err "Option #${_option_index} max args is invalid: $1. Must be a non-negative integer."
|
||||||
|
fi
|
||||||
|
|
||||||
|
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."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_validate_option_min_args() {
|
||||||
|
if [ -n "$(_var_value "${_mapping_option_prefix}_min_args")" ]; then
|
||||||
|
_err "Option #${_option_index} min args are already mapped."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
_err "Option #${_option_index} min args cannot be empty."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _is_int "$1"; then
|
||||||
|
_err "Option #${_option_index} min args is invalid: $1. Must be a non-negative integer."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_validate_option_required() {
|
||||||
|
if [ -n "$(_var_value "${_mapping_option_prefix}_required")" ]; then
|
||||||
|
_err "Option #${_option_index} required is already mapped."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$1" ]; then
|
||||||
|
_err "Option #${_option_index} required is invalid: $1. Must be used as a flag without value."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_option_max_args=$(_var_value "${_mapping_option_prefix}_max_args")
|
||||||
|
|
||||||
|
if [ -n "$_option_max_args" ] && [ "$_option_max_args" -eq 0 ]; then
|
||||||
|
_err "Option #${_option_index} must be removed as constant. It is required without arguments."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_get_mapped_option_index_by_alias() {
|
||||||
|
_i=1
|
||||||
|
while [ "$_i" -le "$_mapped_options_count" ]; do
|
||||||
|
if _aliases_list_contains "$(_var_value "_options_${_i}_aliases")" "$1"; then
|
||||||
|
echo "$_i"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
_i=$(_math "$_i + 1")
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_get_mapped_command_index_by_name() {
|
||||||
|
_i=1
|
||||||
|
while [ "$_i" -le "$_mapped_commands_count" ]; do
|
||||||
|
if [ "$(_var_value "_commands_${_i}_name")" = "$1" ]; then
|
||||||
|
echo "$_i"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
_i=$(_math "$_i + 1")
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_parse() {
|
||||||
|
_option_index=0
|
||||||
|
_used_command_index=0
|
||||||
|
|
||||||
|
if _command_required; then
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
_err "Command is required."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if _starts_with "$1" "-"; then
|
||||||
|
_err "Command is required. Found option instead: $1."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_use_command "$1"
|
||||||
|
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$_accept_options" = "none" ]; then
|
||||||
|
_parse_positional_args "$@"
|
||||||
|
else
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
_parse_positional_args "$@"
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
--*)
|
||||||
|
_parse_option "$1"
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
_parse_options_combination "$1"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ "$_option_index" -eq 0 ] || [ "$_option_key_value_delimiter" != " " ]; then
|
||||||
|
_parse_positional_args "$1"
|
||||||
|
else
|
||||||
|
_parse_option_args "$1"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
_i=1
|
||||||
|
while [ "$_i" -le "$_mapped_options_count" ]; do
|
||||||
|
_option_used=$(_var_value "_options_${_i}_used")
|
||||||
|
|
||||||
|
if (_is "$(_var_value "_options_${_i}_required")") && (_is_not "$_option_used"); then
|
||||||
|
_err "Option is required: $(_var_value "_options_${_i}_aliases")."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_option_min_args=$(_var_value "_options_${_i}_min_args")
|
||||||
|
|
||||||
|
if (_is "$_option_used") && [ -n "$_option_min_args" ] && [ "$_option_min_args" -gt 0 ]; then
|
||||||
|
_option_args_count=$(_var_value "_options_${_i}_args_count")
|
||||||
|
|
||||||
|
if [ -z "$_option_args_count" ] || [ "$_option_args_count" -lt "$_option_min_args" ]; then
|
||||||
|
_err "At least $_option_min_args argument(s) required for option: $(_var_value "_options_${_i}_used_alias")."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
_i=$(_math "$_i + 1")
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$_used_command_index" -ne 0 ]; then
|
||||||
|
_min_positional_args=$(_var_value "_commands_${_used_command_index}_min_args")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$_min_positional_args" ]; then
|
||||||
|
_min_positional_args=$_default_min_positional_args
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$_min_positional_args" -gt 0 ] && [ "$_positional_args_count" -lt "$_min_positional_args" ]; then
|
||||||
|
if [ "$_used_command_index" -eq 0 ]; then
|
||||||
|
_err "At least $_min_positional_args argument(s) required."
|
||||||
|
else
|
||||||
|
_err "At least $_min_positional_args argument(s) required for command: $(_var_value "_commands_${_used_command_index}_name")."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_parse_positional_args() {
|
||||||
|
if [ "$_positional_args_placement" = "before_options" ] && [ -n "$_option_index" ]; then
|
||||||
|
_err "Positional arguments must be placed before options: $1."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$_command_index" ]; then
|
||||||
|
_max_args_count="$_default_max_positional_args"
|
||||||
|
else
|
||||||
|
_max_args_count=$(_var_value "_commands_${_command_index}_max_args")
|
||||||
|
fi
|
||||||
|
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
_positional_arg_index=$(_math "$_positional_args_count + 1")
|
||||||
|
|
||||||
|
if [ -n "$_max_args_count" ] && [ "$_positional_arg_index" -gt "$_max_args_count" ]; then
|
||||||
|
if [ -z "$_command_index" ]; then
|
||||||
|
_err "Maximum $_max_args_count positional argument(s) allowed."
|
||||||
|
else
|
||||||
|
_err "Maximum $_max_args_count positional argument(s) allowed for command: $(_var_value "_commands_${_command_index}_name")."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
_assign "_positional_args_${_positional_arg_index}" "$1"
|
||||||
|
_positional_args_count=$_positional_arg_index
|
||||||
|
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
_parse_option() {
|
||||||
|
_option_alias="${1%%"$_option_key_value_delimiter"*}"
|
||||||
|
_use_option "$_option_alias"
|
||||||
|
|
||||||
|
if [ "$_option_key_value_delimiter" != " " ] && [ "$_option_alias" != "$1" ]; then
|
||||||
|
_parse_option_args "${1#*"$_option_key_value_delimiter"}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_parse_options_combination() {
|
||||||
|
_options_combination=${1%%"$_option_key_value_delimiter"*}
|
||||||
|
|
||||||
|
if [ ${#_options_combination} = 1 ]; then
|
||||||
|
_err "Unknown empty option: $1."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$_options_combination" != "$1" ] && (_is_not "$_options_combination_allowed"); then
|
||||||
|
_err "Short options combination is not allowed: $1."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_i=2
|
||||||
|
while [ "$_i" -le "${#_options_combination}" ]; do
|
||||||
|
_use_option "-$(printf '%s' "$_options_combination" | cut -c "$_i")"
|
||||||
|
|
||||||
|
_i=$(_math "$_i + 1")
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$_option_key_value_delimiter" != " " ] && [ "$_options_combination" != "$1" ]; then
|
||||||
|
_option_args=${1#*"$_option_key_value_delimiter"}
|
||||||
|
|
||||||
|
if [ ${#_options_combination} -gt 2 ] && (_is_not "$_options_combination_args_allowed"); then
|
||||||
|
_err "Arguments after short options combination are not allowed: $_option_args."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_parse_option_args "$_option_args"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ${#_options_combination} -gt 2 ] && (_is_not "$_options_combination_allowed"); then
|
||||||
|
_option_index=0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_use_option() {
|
||||||
|
if [ "$_positional_args_placement" = "after_options" ] && [ "$_positional_args_count" -gt 0 ]; then
|
||||||
|
_err "Positional arguments must be placed before options: $_positional_args_1."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_option_index=$(_get_mapped_option_index_by_alias "$1")
|
||||||
|
|
||||||
|
if [ -z "$_option_index" ]; then
|
||||||
|
if [ "$_accept_options" = "mapped_only" ]; then
|
||||||
|
_err "Unknown option: $1."
|
||||||
|
else
|
||||||
|
_map_option_auto "$1"
|
||||||
|
_option_index=$_mapped_options_count
|
||||||
|
fi
|
||||||
|
elif (_is_not "$_option_duplicates_allowed") && (_is "$(_var_value "_options_${_option_index}_used")"); then
|
||||||
|
_err "Option is already used: $1."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_assign "_options_${_option_index}_used" "true"
|
||||||
|
_assign "_options_${_option_index}_used_alias" "$1"
|
||||||
|
|
||||||
|
_option_variable=$(_var_value "_options_${_option_index}_variable")
|
||||||
|
|
||||||
|
if [ -n "$_option_variable" ]; then
|
||||||
|
_option_variable_value=$(_var_value "_options_${_option_index}_variable_value")
|
||||||
|
|
||||||
|
if [ -z "$_option_variable_value" ]; then
|
||||||
|
_option_variable_value="$_option_variable_default_value"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_assign "$_option_variable" "$_option_variable_value"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_parse_option_args() {
|
||||||
|
_old_ifs=$IFS
|
||||||
|
IFS=$_option_values_delimiter
|
||||||
|
|
||||||
|
for _option_arg in $1; do
|
||||||
|
_parse_option_arg "$_option_arg"
|
||||||
|
done
|
||||||
|
|
||||||
|
IFS=$_old_ifs
|
||||||
|
}
|
||||||
|
|
||||||
|
_parse_option_arg() {
|
||||||
|
_option_arg_index=$(_math "$(_var_value "_options_${_option_index}_args_count") + 1")
|
||||||
|
_max_args_count=$(_var_value "_options_${_option_index}_max_args")
|
||||||
|
|
||||||
|
if [ -n "$_max_args_count" ] && [ "$_option_arg_index" -gt "$_max_args_count" ]; then
|
||||||
|
_err "Maximum $_max_args_count argument(s) allowed for option: $(_var_value "_options_${_option_index}_used_alias")."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_assign "_options_${_option_index}_args_${_option_arg_index}" "$1"
|
||||||
|
_assign "_options_${_option_index}_args_count" "$_option_arg_index"
|
||||||
|
}
|
||||||
|
|
||||||
|
_use_command() {
|
||||||
|
_command_index=$(_get_mapped_command_index_by_name "$1")
|
||||||
|
|
||||||
|
if [ -z "$_command_index" ]; then
|
||||||
|
if [ "$_accept_command" = "mapped_only" ]; then
|
||||||
|
_err "Unknown command: $1."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_map_command_auto "$1"
|
||||||
|
_command_index=$_mapped_commands_count
|
||||||
|
fi
|
||||||
|
|
||||||
|
_used_command_index=$_command_index
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_get_command() {
|
||||||
|
_var_value "_commands_${_used_command_index}_name"
|
||||||
|
}
|
||||||
|
|
||||||
|
_is_used_command() {
|
||||||
|
_command_index=$(_get_mapped_command_index_by_name "$1")
|
||||||
|
[ -n "$_command_index" ] && [ -n "$_used_command_index" ] && [ "$_command_index" -eq "$_used_command_index" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
_get_positional_args_count() {
|
||||||
|
echo "$_positional_args_count"
|
||||||
|
}
|
||||||
|
|
||||||
|
_get_positional_arg() {
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
_err "Missing positional argument index."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _is_int "$1" || [ "$1" -lt 1 ]; then
|
||||||
|
_err "Invalid positional argument index: $1. Must be a positive integer."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$_positional_args_count" -ge "$1" ]; then
|
||||||
|
_var_value "_positional_args_$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_is_used_option() {
|
||||||
|
_option_index=$(_get_mapped_option_index_by_alias "$1")
|
||||||
|
[ -n "$_option_index" ] && _is "$(_var_value "_options_${_option_index}_used")"
|
||||||
|
}
|
||||||
|
|
||||||
|
_get_option_args_count() {
|
||||||
|
_option_index=$(_get_mapped_option_index_by_alias "$1")
|
||||||
|
|
||||||
|
if [ -n "$_option_index" ]; then
|
||||||
|
_args_count=$(_var_value "_options_${_option_index}_args_count")
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "${_args_count:=0}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_get_option_arg() {
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
_err "Missing option alias."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
_err "Missing option argument index."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _is_int "$2" || [ "$2" -lt 1 ]; then
|
||||||
|
_err "Invalid option argument index: $1. Must be a positive integer."
|
||||||
|
fi
|
||||||
|
|
||||||
|
_option_index=$(_get_mapped_option_index_by_alias "$1")
|
||||||
|
|
||||||
|
if [ -n "$_option_index" ]; then
|
||||||
|
_args_count=$(_var_value "_options_${_option_index}_args_count")
|
||||||
|
|
||||||
|
if [ -n "$_args_count" ] && [ "$_args_count" -ge "$2" ]; then
|
||||||
|
_var_value "_options_${_option_index}_args_$2"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user