-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathargs2array
executable file
·247 lines (213 loc) · 6.18 KB
/
args2array
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#!/bin/bash
[[ ${__ARGS_LOADED__} -eq 1 ]] && return 0
export __ARGS_LOADED__=1
source /usr/local/lib/backUP/logging
validate_option() {
# return 0 if option is valid and requires 1 or more arguments
# return 1 if option is valid and requires exactly 1 argument
# return 2 if option is valid and requires 0 arguments
# return 3 if option is invalid
local opt="$1" # option to search for
local lgth=${#opt}
local goffset
if [[ $lgth -eq 1 ]]; then
# opt is short
local optstr=$SMOL_OPTS
goffset=${optstr%%$opt*}
goffset=${#goffset}
if [[ $goffset -lt ${#optstr} ]]; then
# a match was found
if [[ "${optstr:$(( goffset + lgth )):1}" == ":" ]]; then
# the option requires 1 or more arguments
return 0
elif [[ "${optstr:$(( goffset + lgth )):1}" == "!" ]]; then
# the option requires exactly 1 argument
return 1
else
return 2
fi
fi
else # opt is long
local optstr="$LONG_OPTS"
local lastchar="${optstr: -1}"
local firstchar="${optstr:0:1}"
[[ "$firstchar" != "," ]] && optstr=",$optstr"
[[ "$lastchar" != "," ]] && optstr="${optstr},"
local -a fullstring_matches=(",${opt}," ",${opt}:," ",${opt}!,")
local match
for match in "${fullstring_matches[@]}" ; do
goffset=${optstr%%$match*}
goffset=${#goffset}
if [[ $goffset -lt ${#optstr} ]]; then
# a match was found
if [[ "${match: -2:1}" == ":" ]]; then
# the option requires one or more arguments
return 0
elif [[ "${match: -2:1}" == "!" ]]; then
# the option requires exactly one argument
return 1
else
# the option does not require any arguments
return 2
fi
fi
done
fi
return 3
}
expand_options() {
declare -n _opts=$1
local cmpd="$2"
cmpd="${cmpd//-/}"
_opts=()
local i
for (( i = 0; i < ${#cmpd}; i++ )); do
validate_option "${cmpd:$i:1}"
case "$?" in
0 | 1 ) _opts+=("-${cmpd:i:1}" "${cmpd:i+1}")
return 0
;;
2 ) _opts=("-${cmpd:i:1}" "${_opts[@]}")
;;
3 ) ecrit "option '-${cmpd:i:1}' is invalid."
exit 3
;;
esac
done
}
args2array() {
declare -n __arr=$1 && shift
local __exitcode __ctr=0 __i __exitcode __opt __temp
while (( $# > 0 )); do
etrace "first positional is '$1'"
if [[ ${1:0:1} == "-" ]]; then
# we're working with an option
if [[ ! "${1:1:1}" == "-" && ${#1} > 2 ]]; then
# interpret parameter as concatenated
expand_options __temp "${1//-/}"
shift
set -- "${__temp[@]}" "$@"
continue
elif [[ "${1:0:2}" == "--" && -n "${1//[^=]/}" ]]; then
__temp="$1"
shift
set -- "${__temp%=*}" "${__temp#*=}" "$@"
fi
__opt=${1//-/}
if [[ ${#__opt} -gt 1 ]]; then
__opt=${1#'--'}
else
__opt=${1#'-'}
fi
etrace "searching optstrings for '$__opt'"
validate_option "$__opt"
__exitcode=$?
if [[ $__exitcode -gt 2 ]]; then
ecrit "option '$1' is not a valid option"
exit $__exitcode
else
__ctr=0
edumpvar __opt __arr[$__opt]
if [[ $__exitcode -eq 0 ]]; then
# option requires one or more arguments
for __i in "${@:2}"; do
if [[ ${__i:0:1} == "-" ]]; then
break
else
if [[ ! ${__arr[$__opt]+isset} ]]; then
__arr[$__opt]="${__i}"
else
__arr[$__opt]="${__arr[$__opt]};${__i}"
fi
etrace "appending: '$__i' ' to __arr[$__opt] which is now '${__arr[$__opt]}'"
(( __ctr++ ))
fi
done
if [[ $__ctr -eq 0 ]]; then
ecrit "option '$1' requires an argument"
exit 1
fi
elif [[ $__exitcode -eq 1 ]]; then
# option requires exactly one argument
if [[ ! ${__arr[$__opt]+isset} && -n "$2" && ${2:0:1} != "-" ]]; then
# at least one parameter was passed
if [[ -z "$3" || "${3:0:1}" == "-" ]]; then
# at most one parameter was passed
__arr[$__opt]="$2"
__ctr=1
else
# too many arguments passed, no bueno
ecrit "option '$1' takes exactly one argument"
exit 5
fi
else
# not enough arguments passed, no bueno
ecrit "option '$1' takes exactly one argument"
exit 5
fi
else
# option does not accept any arguments
if [[ -n "$2" && ${2:0:1} != "-" ]]; then
# too many arguments passed to the option
ecrit "option '$1' does not take any argument"
exit 5
else
__arr[$__opt]=""
fi
fi
edumpvar __opt __arr[$__opt]
# all 3 blocks require a shift because each corresponds to a valid option which should be removed
shift $(( __ctr + 1 ))
fi
else
shift # ignore every option not starting with -
# can maybe (but not likely) be changed in the future for some sort of positional arguments...
fi
done
}
unpack_args() {
declare -n _a=$1 # xD
local _pld=$2
local IFS=';'
_a=($_pld)
}
# UNCOMMENT these lines and run the examples below for usage
# OUTPUT, RETURN CODES, CORE FUNCTIONS HAVE ALL CHANGED SINCE
# THESE EXAMPLES WERE COPIED, IT WILL PROBABLY CHANGE AGAIN...
# ---------------------------------------------------------------------
# SMOL_OPTS="a:b!c" # NOT comma separated, : denotes mandatory argument
# LONG_OPTS="alpha!,beta:,gamma" # comma separated, : denotes mandatory argument
# declare -A associative_array # must be declared BEFORE function call
# args2array associative_array "$@"
# Print the key=value pairs
# for key in "${!associative_array[@]}"; do
# printf "%s=%s\n" "$key" "'${associative_array[$key]% }'"
# done
# -----------------------------------------------------------------------
# EXAMPLE-1 USAGE
# $ args2array -a arg-1 arg\ 2 "arg 3" --alpha --beta arg -a arg-4 -b
# beta=''arg''
# alpha=''
# b=''
# a=''arg-1' 'arg 2' 'arg 3' 'arg-4''
# $ echo $?
# 0
# -----------------------------------------------------------------------
# EXAMPLE-2 USAGE
# $ args2array -a arg-1 -f
# error: option '-f' is not a valid option
# $ echo $?
# 2
# -----------------------------------------------------------------------
# EXAMPLE-3 USAGE
# $ args2array -a
# error: option '-a' requires an argument
# $ echo $?
# 1
# ------------------------------------------------------------------------
# EXAMPLE-4 USAGE
# $ args2array --beta
# error: option '--beta' requires an argument
# echo $?
# 1
# ------------------------------------------------------------------------