Skip to content

Commit dbf9ad1

Browse files
committed
Add bpkg.json so docopt-lib can be installed as a bpkg dependency
1 parent 0bc7b76 commit dbf9ad1

File tree

2 files changed

+349
-0
lines changed

2 files changed

+349
-0
lines changed

bpkg.json

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"name": "docopt.sh",
3+
"version": "1.0.0-bpkg",
4+
"description": "The library component for docopt.sh. Does not contain the parser generator (yet).",
5+
"scripts": ["docopt-lib.sh"]
6+
}

docopt-lib.sh

+343
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
#!/usr/bin/env bash
2+
3+
if [[ $1 != '1.0.0' && ${DOCOPT_LIB_CHECK:-true} != 'false' ]]; then
4+
printf -- "cat <<'EOM' >&2\nThe version of the included docopt library (%s) \
5+
does not match the version of the invoking docopt parser (%s)\nEOM\nexit 70\n" \
6+
'1.0.0' "$1"
7+
exit 70
8+
fi
9+
parse() {
10+
if ${DOCOPT_DOC_CHECK:-true}; then
11+
local doc_hash
12+
if doc_hash=$(printf "%s" "$DOC" | (sha256sum 2>/dev/null || shasum -a 256)); then
13+
if [[ ${doc_hash:0:5} != "$digest" ]]; then
14+
stderr "The current usage doc (${doc_hash:0:5}) does not match \
15+
what the parser was generated with (${digest})
16+
Run \`docopt.sh\` to refresh the parser."
17+
_return 70
18+
fi
19+
fi
20+
fi
21+
22+
local root_idx=$1
23+
shift
24+
argv=("$@")
25+
parsed_params=()
26+
parsed_values=()
27+
left=()
28+
# testing depth counter, when >0 nodes only check for potential matches
29+
# when ==0 leafs will set the actual variable when a match is found
30+
testdepth=0
31+
32+
local arg
33+
while [[ ${#argv[@]} -gt 0 ]]; do
34+
if [[ ${argv[0]} = "--" ]]; then
35+
for arg in "${argv[@]}"; do
36+
parsed_params+=('a')
37+
parsed_values+=("$arg")
38+
done
39+
break
40+
elif [[ ${argv[0]} = --* ]]; then
41+
parse_long
42+
elif [[ ${argv[0]} = -* && ${argv[0]} != "-" ]]; then
43+
parse_shorts
44+
elif ${DOCOPT_OPTIONS_FIRST:-false}; then
45+
for arg in "${argv[@]}"; do
46+
parsed_params+=('a')
47+
parsed_values+=("$arg")
48+
done
49+
break
50+
else
51+
parsed_params+=('a')
52+
parsed_values+=("${argv[0]}")
53+
argv=("${argv[@]:1}")
54+
fi
55+
done
56+
local idx
57+
if ${DOCOPT_ADD_HELP:-true}; then
58+
for idx in "${parsed_params[@]}"; do
59+
[[ $idx = 'a' ]] && continue
60+
if [[ ${shorts[$idx]} = "-h" || ${longs[$idx]} = "--help" ]]; then
61+
stdout "$trimmed_doc"
62+
_return 0
63+
fi
64+
done
65+
fi
66+
if [[ ${DOCOPT_PROGRAM_VERSION:-false} != 'false' ]]; then
67+
for idx in "${parsed_params[@]}"; do
68+
[[ $idx = 'a' ]] && continue
69+
if [[ ${longs[$idx]} = "--version" ]]; then
70+
stdout "$DOCOPT_PROGRAM_VERSION"
71+
_return 0
72+
fi
73+
done
74+
fi
75+
76+
local i=0
77+
while [[ $i -lt ${#parsed_params[@]} ]]; do
78+
left+=("$i")
79+
((i++)) || true
80+
done
81+
82+
if ! required "$root_idx" || [ ${#left[@]} -gt 0 ]; then
83+
error
84+
fi
85+
return 0
86+
}
87+
88+
parse_shorts() {
89+
local token=${argv[0]}
90+
local value
91+
argv=("${argv[@]:1}")
92+
[[ $token = -* && $token != --* ]] || _return 88
93+
local remaining=${token#-}
94+
while [[ -n $remaining ]]; do
95+
local short="-${remaining:0:1}"
96+
remaining="${remaining:1}"
97+
local i=0
98+
local similar=()
99+
local match=false
100+
for o in "${shorts[@]}"; do
101+
if [[ $o = "$short" ]]; then
102+
similar+=("$short")
103+
[[ $match = false ]] && match=$i
104+
fi
105+
((i++)) || true
106+
done
107+
if [[ ${#similar[@]} -gt 1 ]]; then
108+
error "${short} is specified ambiguously ${#similar[@]} times"
109+
elif [[ ${#similar[@]} -lt 1 ]]; then
110+
match=${#shorts[@]}
111+
value=true
112+
shorts+=("$short")
113+
longs+=('')
114+
argcounts+=(0)
115+
else
116+
value=false
117+
if [[ ${argcounts[$match]} -ne 0 ]]; then
118+
if [[ $remaining = '' ]]; then
119+
if [[ ${#argv[@]} -eq 0 || ${argv[0]} = '--' ]]; then
120+
error "${short} requires argument"
121+
fi
122+
value=${argv[0]}
123+
argv=("${argv[@]:1}")
124+
else
125+
value=$remaining
126+
remaining=''
127+
fi
128+
fi
129+
if [[ $value = false ]]; then
130+
value=true
131+
fi
132+
fi
133+
parsed_params+=("$match")
134+
parsed_values+=("$value")
135+
done
136+
}
137+
138+
parse_long() {
139+
local token=${argv[0]}
140+
local long=${token%%=*}
141+
local value=${token#*=}
142+
local argcount
143+
argv=("${argv[@]:1}")
144+
[[ $token = --* ]] || _return 88
145+
if [[ $token = *=* ]]; then
146+
eq='='
147+
else
148+
eq=''
149+
value=false
150+
fi
151+
local i=0
152+
local similar=()
153+
local match=false
154+
for o in "${longs[@]}"; do
155+
if [[ $o = "$long" ]]; then
156+
similar+=("$long")
157+
[[ $match = false ]] && match=$i
158+
fi
159+
((i++)) || true
160+
done
161+
if [[ $match = false ]]; then
162+
i=0
163+
for o in "${longs[@]}"; do
164+
if [[ $o = $long* ]]; then
165+
similar+=("$long")
166+
[[ $match = false ]] && match=$i
167+
fi
168+
((i++)) || true
169+
done
170+
fi
171+
if [[ ${#similar[@]} -gt 1 ]]; then
172+
error "${long} is not a unique prefix: ${similar[*]}?"
173+
elif [[ ${#similar[@]} -lt 1 ]]; then
174+
[[ $eq = '=' ]] && argcount=1 || argcount=0
175+
match=${#shorts[@]}
176+
[[ $argcount -eq 0 ]] && value=true
177+
shorts+=('')
178+
longs+=("$long")
179+
argcounts+=("$argcount")
180+
else
181+
if [[ ${argcounts[$match]} -eq 0 ]]; then
182+
if [[ $value != false ]]; then
183+
error "${longs[$match]} must not have an argument"
184+
fi
185+
elif [[ $value = false ]]; then
186+
if [[ ${#argv[@]} -eq 0 || ${argv[0]} = '--' ]]; then
187+
error "${long} requires argument"
188+
fi
189+
value=${argv[0]}
190+
argv=("${argv[@]:1}")
191+
fi
192+
if [[ $value = false ]]; then
193+
value=true
194+
fi
195+
fi
196+
parsed_params+=("$match")
197+
parsed_values+=("$value")
198+
}
199+
200+
required() {
201+
local initial_left=("${left[@]}")
202+
local node_idx
203+
((testdepth++)) || true
204+
for node_idx in "$@"; do
205+
if ! "node_$node_idx"; then
206+
left=("${initial_left[@]}")
207+
((testdepth--)) || true
208+
return 1
209+
fi
210+
done
211+
if [[ $((--testdepth)) -eq 0 ]]; then
212+
left=("${initial_left[@]}")
213+
for node_idx in "$@"; do
214+
"node_$node_idx"
215+
done
216+
fi
217+
return 0
218+
}
219+
220+
either() {
221+
local initial_left=("${left[@]}")
222+
local best_match_idx
223+
local match_count
224+
local node_idx
225+
((testdepth++)) || true
226+
for node_idx in "$@"; do
227+
if "node_$node_idx"; then
228+
if [[ -z $match_count || ${#left[@]} -lt $match_count ]]; then
229+
best_match_idx=$node_idx
230+
match_count=${#left[@]}
231+
fi
232+
fi
233+
left=("${initial_left[@]}")
234+
done
235+
((testdepth--)) || true
236+
if [[ -n $best_match_idx ]]; then
237+
"node_$best_match_idx"
238+
return 0
239+
fi
240+
left=("${initial_left[@]}")
241+
return 1
242+
}
243+
244+
optional() {
245+
local node_idx
246+
for node_idx in "$@"; do
247+
"node_$node_idx"
248+
done
249+
return 0
250+
}
251+
252+
oneormore() {
253+
local i=0
254+
local prev=${#left[@]}
255+
while "node_$1"; do
256+
((i++)) || true
257+
[[ $prev -eq ${#left[@]} ]] && break
258+
prev=${#left[@]}
259+
done
260+
if [[ $i -ge 1 ]]; then
261+
return 0
262+
fi
263+
return 1
264+
}
265+
266+
_command() {
267+
local i
268+
local name=${2:-$1}
269+
for i in "${!left[@]}"; do
270+
local l=${left[$i]}
271+
if [[ ${parsed_params[$l]} = 'a' ]]; then
272+
if [[ ${parsed_values[$l]} != "$name" ]]; then
273+
return 1
274+
fi
275+
left=("${left[@]:0:$i}" "${left[@]:((i+1))}")
276+
[[ $testdepth -gt 0 ]] && return 0
277+
if [[ $3 = true ]]; then
278+
eval "((var_$1++)) || true"
279+
else
280+
eval "var_$1=true"
281+
fi
282+
return 0
283+
fi
284+
done
285+
return 1
286+
}
287+
288+
switch() {
289+
local i
290+
for i in "${!left[@]}"; do
291+
local l=${left[$i]}
292+
if [[ ${parsed_params[$l]} = "$2" ]]; then
293+
left=("${left[@]:0:$i}" "${left[@]:((i+1))}")
294+
[[ $testdepth -gt 0 ]] && return 0
295+
if [[ $3 = true ]]; then
296+
eval "((var_$1++))" || true
297+
else
298+
eval "var_$1=true"
299+
fi
300+
return 0
301+
fi
302+
done
303+
return 1
304+
}
305+
306+
value() {
307+
local i
308+
for i in "${!left[@]}"; do
309+
local l=${left[$i]}
310+
if [[ ${parsed_params[$l]} = "$2" ]]; then
311+
left=("${left[@]:0:$i}" "${left[@]:((i+1))}")
312+
[[ $testdepth -gt 0 ]] && return 0
313+
local value
314+
value=$(printf -- "%q" "${parsed_values[$l]}")
315+
if [[ $3 = true ]]; then
316+
eval "var_$1+=($value)"
317+
else
318+
eval "var_$1=$value"
319+
fi
320+
return 0
321+
fi
322+
done
323+
return 1
324+
}
325+
326+
stdout() {
327+
printf -- "cat <<'EOM'\n%s\nEOM\n" "$1"
328+
}
329+
330+
stderr() {
331+
printf -- "cat <<'EOM' >&2\n%s\nEOM\n" "$1"
332+
}
333+
334+
error() {
335+
[[ -n $1 ]] && stderr "$1"
336+
stderr "$usage"
337+
_return 1
338+
}
339+
340+
_return() {
341+
printf -- "exit %d\n" "$1"
342+
exit "$1"
343+
}

0 commit comments

Comments
 (0)